From f333223aeee6c5fed9f75e2b9dcfe3676f366ff1 Mon Sep 17 00:00:00 2001 From: Stefan Kalkowski Date: Fri, 29 Nov 2024 12:05:07 +0100 Subject: [PATCH] qemu-usb: prevent assertion by eager URB processing 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/genode#5389 --- repos/libports/src/lib/qemu-usb/host.cc | 35 ++++++++++++++++++++----- 1 file changed, 28 insertions(+), 7 deletions(-) diff --git a/repos/libports/src/lib/qemu-usb/host.cc b/repos/libports/src/lib/qemu-usb/host.cc index 977e26feb96..005a0fe5242 100644 --- a/repos/libports/src/lib/qemu-usb/host.cc +++ b/repos/libports/src/lib/qemu-usb/host.cc @@ -13,6 +13,7 @@ #include #include #include +#include #include #include @@ -244,6 +245,8 @@ class Interface : public List_model<::Interface>::Element template void for_each_endpoint(FN const &fn) { _endpoints.for_each([&] (Endpoint &endp) { fn(endp); }); } + + void io(); }; @@ -384,6 +387,8 @@ class Device : public List_model::Element _ifaces.for_each([&] (::Interface &iface) { if (iface.active()) fn(iface); }); } + + void io() { Signal_transmitter(_sigh_cap).submit(); } }; @@ -529,7 +534,7 @@ void Isoc_cache::_new_urb() sent = true; } - if (sent) _iface.update_urbs(); + if (sent) _iface.io(); } @@ -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) @@ -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(); } @@ -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; @@ -910,13 +932,12 @@ static void usb_host_handle_control(USBDevice *udev, USBPacket *p, _usb_session()->_space.apply({ 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; }