mirror of
https://github.com/genodelabs/genode.git
synced 2024-12-18 21:27:56 +00:00
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
This commit is contained in:
parent
b21c8729ea
commit
b529b1eac6
@ -13,6 +13,7 @@
|
|||||||
#include <usb_session/device.h>
|
#include <usb_session/device.h>
|
||||||
#include <util/list_model.h>
|
#include <util/list_model.h>
|
||||||
#include <util/xml_node.h>
|
#include <util/xml_node.h>
|
||||||
|
#include <os/backtrace.h>
|
||||||
|
|
||||||
#include <extern_c_begin.h>
|
#include <extern_c_begin.h>
|
||||||
#include <qemu_emul.h>
|
#include <qemu_emul.h>
|
||||||
@ -244,6 +245,8 @@ class Interface : public List_model<::Interface>::Element
|
|||||||
template <typename FN>
|
template <typename FN>
|
||||||
void for_each_endpoint(FN const &fn) {
|
void for_each_endpoint(FN const &fn) {
|
||||||
_endpoints.for_each([&] (Endpoint &endp) { fn(endp); }); }
|
_endpoints.for_each([&] (Endpoint &endp) { fn(endp); }); }
|
||||||
|
|
||||||
|
void io();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
@ -384,6 +387,8 @@ class Device : public List_model<Device>::Element
|
|||||||
_ifaces.for_each([&] (::Interface &iface) {
|
_ifaces.for_each([&] (::Interface &iface) {
|
||||||
if (iface.active()) fn(iface); });
|
if (iface.active()) fn(iface); });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void io() { Signal_transmitter(_sigh_cap).submit(); }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
@ -529,7 +534,7 @@ void Isoc_cache::_new_urb()
|
|||||||
sent = true;
|
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) \
|
#define USB_HOST_DEVICE(obj) \
|
||||||
OBJECT_CHECK(USBHostDevice, (obj), TYPE_USB_HOST_DEVICE)
|
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_devices();
|
||||||
usb_host_update_ep(udev);
|
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);
|
usb_generic_async_ctrl_complete(udev, p);
|
||||||
return;
|
return;
|
||||||
case USB_ENDPOINT_XFER_BULK:
|
case USB_ENDPOINT_XFER_BULK:
|
||||||
case USB_ENDPOINT_XFER_INT:
|
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);
|
usb_packet_complete(udev, p);
|
||||||
break;
|
return;
|
||||||
default:
|
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)
|
new (_usb_session()->_alloc)
|
||||||
::Urb(_usb_session()->_urb_registry,
|
::Urb(_usb_session()->_urb_registry,
|
||||||
iface, endp, type, usb_packet_size(p), p);
|
iface, endp, type, usb_packet_size(p), p);
|
||||||
iface.update_urbs();
|
iface.io();
|
||||||
return;
|
return;
|
||||||
case USB_ENDPOINT_XFER_ISOC:
|
case USB_ENDPOINT_XFER_ISOC:
|
||||||
p->status = USB_RET_SUCCESS;
|
p->status = USB_RET_SUCCESS;
|
||||||
@ -910,13 +932,12 @@ static void usb_host_handle_control(USBDevice *udev, USBPacket *p,
|
|||||||
|
|
||||||
_usb_session()->_space.apply<Device>({ handle },
|
_usb_session()->_space.apply<Device>({ handle },
|
||||||
[&] (Device & device) {
|
[&] (Device & device) {
|
||||||
|
p->status = USB_RET_ASYNC;
|
||||||
new (_usb_session()->_alloc)
|
new (_usb_session()->_alloc)
|
||||||
Device::Urb(device, request & 0xff, (request >> 8) & 0xff,
|
Device::Urb(device, request & 0xff, (request >> 8) & 0xff,
|
||||||
value, index, length, p);
|
value, index, length, p);
|
||||||
device.update_urbs();
|
device.io();
|
||||||
});
|
});
|
||||||
|
|
||||||
p->status = USB_RET_ASYNC;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user