Skip to content

Commit

Permalink
qemu-usb: prevent assertion by eager URB processing
Browse files Browse the repository at this point in the history
Instead of directly process URBs whenever a USBPacket arrives from
the Qemu ported XHCI layer, send a local signal to the I/O handler,
which will process the requests after leaving certain sensible
code pathes like usb_packet_complete. Otherwise, it might happen
that a packet, which was still marked as being queued gets already
completed, which leads to an assertion and hang of the library.

Fix genodelabs#5389
  • Loading branch information
skalk committed Dec 2, 2024
1 parent 1873030 commit f333223
Showing 1 changed file with 28 additions and 7 deletions.
35 changes: 28 additions & 7 deletions repos/libports/src/lib/qemu-usb/host.cc
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
#include <usb_session/device.h>
#include <util/list_model.h>
#include <util/xml_node.h>
#include <os/backtrace.h>

#include <extern_c_begin.h>
#include <qemu_emul.h>
Expand Down Expand Up @@ -244,6 +245,8 @@ class Interface : public List_model<::Interface>::Element
template <typename FN>
void for_each_endpoint(FN const &fn) {
_endpoints.for_each([&] (Endpoint &endp) { fn(endp); }); }

void io();
};


Expand Down Expand Up @@ -384,6 +387,8 @@ class Device : public List_model<Device>::Element
_ifaces.for_each([&] (::Interface &iface) {
if (iface.active()) fn(iface); });
}

void io() { Signal_transmitter(_sigh_cap).submit(); }
};


Expand Down Expand Up @@ -529,7 +534,7 @@ void Isoc_cache::_new_urb()
sent = true;
}

if (sent) _iface.update_urbs();
if (sent) _iface.io();
}


Expand Down Expand Up @@ -634,6 +639,12 @@ Usb::Interface &::Interface::_session()
};


void ::Interface::io()
{
Signal_transmitter(_device.sigh_cap()).submit();
}


#define USB_HOST_DEVICE(obj) \
OBJECT_CHECK(USBHostDevice, (obj), TYPE_USB_HOST_DEVICE)

Expand Down Expand Up @@ -742,15 +753,26 @@ void complete_packet(USBPacket * const p, Usb::Tagged_packet::Return_value v)
usb_host_update_devices();
usb_host_update_ep(udev);
}
if (p->state != USB_PACKET_ASYNC) {
error("Unexpected packet state for control xfer ", (int)p->state);
break;
}
usb_generic_async_ctrl_complete(udev, p);
return;
case USB_ENDPOINT_XFER_BULK:
case USB_ENDPOINT_XFER_INT:
if (p->state != USB_PACKET_ASYNC) {
error("Unexpected packet state for irq/bulk xfer ", (int)p->state);
break;
}
usb_packet_complete(udev, p);
break;
return;
default:
error("cannot produce data for unknown packet");
error("cannot complete unknown packet type");
}

/* unexpected outcome */
backtrace();
}


Expand Down Expand Up @@ -871,7 +893,7 @@ static void usb_host_handle_data(USBDevice *udev, USBPacket *p)
new (_usb_session()->_alloc)
::Urb(_usb_session()->_urb_registry,
iface, endp, type, usb_packet_size(p), p);
iface.update_urbs();
iface.io();
return;
case USB_ENDPOINT_XFER_ISOC:
p->status = USB_RET_SUCCESS;
Expand Down Expand Up @@ -910,13 +932,12 @@ static void usb_host_handle_control(USBDevice *udev, USBPacket *p,

_usb_session()->_space.apply<Device>({ handle },
[&] (Device & device) {
p->status = USB_RET_ASYNC;
new (_usb_session()->_alloc)
Device::Urb(device, request & 0xff, (request >> 8) & 0xff,
value, index, length, p);
device.update_urbs();
device.io();
});

p->status = USB_RET_ASYNC;
}


Expand Down

0 comments on commit f333223

Please sign in to comment.