From ad3eb1829d1ec37387094dd100e4425fa0e58cfd Mon Sep 17 00:00:00 2001 From: brian218 Date: Mon, 18 Dec 2023 00:49:42 +0800 Subject: [PATCH] sys_usbd: Fix up sys_usbd_get_descriptor() error handling according to hardware test usb_device_emulated: Allow partial copy of desscriptors --- rpcs3/Emu/Cell/lv2/sys_usbd.cpp | 9 +++++++-- rpcs3/Emu/Io/usb_device.cpp | 35 ++++++++++++--------------------- 2 files changed, 20 insertions(+), 24 deletions(-) diff --git a/rpcs3/Emu/Cell/lv2/sys_usbd.cpp b/rpcs3/Emu/Cell/lv2/sys_usbd.cpp index 70fabbd13efe..50f2b1eb2267 100644 --- a/rpcs3/Emu/Cell/lv2/sys_usbd.cpp +++ b/rpcs3/Emu/Cell/lv2/sys_usbd.cpp @@ -850,6 +850,11 @@ error_code sys_usbd_get_descriptor(ppu_thread& ppu, u32 handle, u32 device_handl sys_usbd.trace("sys_usbd_get_descriptor(handle=0x%x, deviceNumber=0x%x, descriptor=0x%x, desc_size=0x%x)", handle, device_handle, descriptor, desc_size); + if (!descriptor) + { + return CELL_EINVAL; + } + auto& usbh = g_fxo->get>(); std::lock_guard lock(usbh.mutex); @@ -859,9 +864,9 @@ error_code sys_usbd_get_descriptor(ppu_thread& ppu, u32 handle, u32 device_handl return CELL_EINVAL; } - if (!descriptor) + if (!desc_size) { - return CELL_EFAULT; + return CELL_ENOMEM; } usbh.handled_devices[device_handle].second->device.write_data(reinterpret_cast(descriptor.get_ptr()), desc_size); diff --git a/rpcs3/Emu/Io/usb_device.cpp b/rpcs3/Emu/Io/usb_device.cpp index a12139c3c1e5..753f83016472 100644 --- a/rpcs3/Emu/Io/usb_device.cpp +++ b/rpcs3/Emu/Io/usb_device.cpp @@ -200,16 +200,14 @@ bool usb_device_emulated::open_device() u32 usb_device_emulated::get_descriptor(u8 type, u8 index, u8* buf, u32 buf_size) { - u32 expected_count = 2; + std::array header; + header = {header.size(), type}; - if (buf_size < expected_count) - { - sys_usbd.error("Illegal buf_size: get_descriptor(type=0x%02x, index=0x%02x, buf=*0x%x, buf_size=0x%x)", type, index, buf, buf_size); - return 0; - } + u32 expected_count = buf ? std::min(header.size(), buf_size) : 0; + memcpy(buf, header.data(), expected_count); - buf[0] = expected_count; - buf[1] = type; + if (expected_count < header.size()) + return expected_count; switch (type) { @@ -217,7 +215,7 @@ u32 usb_device_emulated::get_descriptor(u8 type, u8 index, u8* buf, u32 buf_size { buf[0] = device.bLength; expected_count = std::min(device.bLength, ::narrow(buf_size)); - memcpy(buf + 2, device.data, expected_count - 2); + memcpy(buf + header.size(), device.data, expected_count - header.size()); break; } case USB_DESCRIPTOR_CONFIG: @@ -226,7 +224,7 @@ u32 usb_device_emulated::get_descriptor(u8 type, u8 index, u8* buf, u32 buf_size { buf[0] = device.subnodes[index].bLength; expected_count = std::min(device.subnodes[index].bLength, ::narrow(buf_size)); - memcpy(buf + 2, device.subnodes[index].data, expected_count - 2); + memcpy(buf + header.size(), device.subnodes[index].data, expected_count - header.size()); } break; } @@ -236,19 +234,19 @@ u32 usb_device_emulated::get_descriptor(u8 type, u8 index, u8* buf, u32 buf_size { if (index == 0) { - constexpr u8 len = sizeof(u16) + 2; + constexpr u8 len = sizeof(u16) + header.size(); buf[0] = len; expected_count = std::min(len, ::narrow(buf_size)); constexpr le_t langid = 0x0409; // English (United States) - memcpy(buf + 2, &langid, expected_count - 2); + memcpy(buf + header.size(), &langid, expected_count - header.size()); } else { const std::u16string u16str = utf8_to_utf16(strings[index - 1]); - const u8 len = static_cast(std::min(u16str.size() * sizeof(u16) + 2, static_cast(0xFF))); + const u8 len = static_cast(std::min(u16str.size() * sizeof(u16) + header.size(), static_cast(0xFF))); buf[0] = len; expected_count = std::min(len, ::narrow(std::min(255, buf_size))); - memcpy(buf + 2, u16str.data(), expected_count - 2); + memcpy(buf + header.size(), u16str.data(), expected_count - header.size()); } } break; @@ -261,14 +259,7 @@ u32 usb_device_emulated::get_descriptor(u8 type, u8 index, u8* buf, u32 buf_size u32 usb_device_emulated::get_status(bool self_powered, bool remote_wakeup, u8* buf, u32 buf_size) { - constexpr u32 expected_count = sizeof(u16); - - if (buf_size < expected_count) - { - sys_usbd.error("Illegal buf_size: get_status(self_powered=0x%02x, remote_wakeup=0x%02x, buf=*0x%x, buf_size=0x%x)", self_powered, remote_wakeup, buf, buf_size); - return 0; - } - + const u32 expected_count = buf ? std::min(sizeof(u16), buf_size) : 0; const u16 device_status = static_cast(self_powered) | static_cast(remote_wakeup) << 1; memcpy(buf, &device_status, expected_count); return expected_count;