sys_usbd: Fix up sys_usbd_get_descriptor() error handling according to hardware test

usb_device_emulated: Allow partial copy of desscriptors
This commit is contained in:
brian218 2023-12-18 00:49:42 +08:00 committed by Elad Ashkenazi
parent d18f929faf
commit 19d1e4dcc9
2 changed files with 20 additions and 24 deletions

View file

@ -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); 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<named_thread<usb_handler_thread>>(); auto& usbh = g_fxo->get<named_thread<usb_handler_thread>>();
std::lock_guard lock(usbh.mutex); 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; 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<u8*>(descriptor.get_ptr()), desc_size); usbh.handled_devices[device_handle].second->device.write_data(reinterpret_cast<u8*>(descriptor.get_ptr()), desc_size);

View file

@ -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 usb_device_emulated::get_descriptor(u8 type, u8 index, u8* buf, u32 buf_size)
{ {
u32 expected_count = 2; std::array<u8, 2> header;
header = {header.size(), type};
if (buf_size < expected_count) u32 expected_count = buf ? std::min<u32>(header.size(), buf_size) : 0;
{ memcpy(buf, header.data(), 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;
}
buf[0] = expected_count; if (expected_count < header.size())
buf[1] = type; return expected_count;
switch (type) 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; buf[0] = device.bLength;
expected_count = std::min(device.bLength, ::narrow<u8>(buf_size)); expected_count = std::min(device.bLength, ::narrow<u8>(buf_size));
memcpy(buf + 2, device.data, expected_count - 2); memcpy(buf + header.size(), device.data, expected_count - header.size());
break; break;
} }
case USB_DESCRIPTOR_CONFIG: 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; buf[0] = device.subnodes[index].bLength;
expected_count = std::min(device.subnodes[index].bLength, ::narrow<u8>(buf_size)); expected_count = std::min(device.subnodes[index].bLength, ::narrow<u8>(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; break;
} }
@ -236,19 +234,19 @@ u32 usb_device_emulated::get_descriptor(u8 type, u8 index, u8* buf, u32 buf_size
{ {
if (index == 0) if (index == 0)
{ {
constexpr u8 len = sizeof(u16) + 2; constexpr u8 len = sizeof(u16) + header.size();
buf[0] = len; buf[0] = len;
expected_count = std::min(len, ::narrow<u8>(buf_size)); expected_count = std::min(len, ::narrow<u8>(buf_size));
constexpr le_t<u16> langid = 0x0409; // English (United States) constexpr le_t<u16> langid = 0x0409; // English (United States)
memcpy(buf + 2, &langid, expected_count - 2); memcpy(buf + header.size(), &langid, expected_count - header.size());
} }
else else
{ {
const std::u16string u16str = utf8_to_utf16(strings[index - 1]); const std::u16string u16str = utf8_to_utf16(strings[index - 1]);
const u8 len = static_cast<u8>(std::min(u16str.size() * sizeof(u16) + 2, static_cast<usz>(0xFF))); const u8 len = static_cast<u8>(std::min(u16str.size() * sizeof(u16) + header.size(), static_cast<usz>(0xFF)));
buf[0] = len; buf[0] = len;
expected_count = std::min(len, ::narrow<u8>(std::min<u32>(255, buf_size))); expected_count = std::min(len, ::narrow<u8>(std::min<u32>(255, buf_size)));
memcpy(buf + 2, u16str.data(), expected_count - 2); memcpy(buf + header.size(), u16str.data(), expected_count - header.size());
} }
} }
break; 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) u32 usb_device_emulated::get_status(bool self_powered, bool remote_wakeup, u8* buf, u32 buf_size)
{ {
constexpr u32 expected_count = sizeof(u16); const u32 expected_count = buf ? std::min<u32>(sizeof(u16), buf_size) : 0;
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 u16 device_status = static_cast<int>(self_powered) | static_cast<int>(remote_wakeup) << 1; const u16 device_status = static_cast<int>(self_powered) | static_cast<int>(remote_wakeup) << 1;
memcpy(buf, &device_status, expected_count); memcpy(buf, &device_status, expected_count);
return expected_count; return expected_count;