summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPeter Maydell <peter.maydell@linaro.org>2019-08-22 15:10:51 +0100
committerPeter Maydell <peter.maydell@linaro.org>2019-08-22 15:10:51 +0100
commit4a71d0af7b9c4ab861c9db2111db73771999c81b (patch)
tree4f472d6356a0ab976e78786620915d6761c39a75
parentd86766a9d0e5c4d9cfb2186bf0b7a6f0f17e1831 (diff)
parent1be344b7ad25d572dadeee46d80f0103354352b2 (diff)
downloadqemu-4a71d0af7b9c4ab861c9db2111db73771999c81b.zip
Merge remote-tracking branch 'remotes/kraxel/tags/usb-20190822-pull-request' into staging
usb: bugfixes and minor improvements. # gpg: Signature made Thu 22 Aug 2019 07:52:32 BST # gpg: using RSA key 4CB6D8EED3E87138 # gpg: Good signature from "Gerd Hoffmann (work) <kraxel@redhat.com>" [full] # gpg: aka "Gerd Hoffmann <gerd@kraxel.org>" [full] # gpg: aka "Gerd Hoffmann (private) <kraxel@gmail.com>" [full] # Primary key fingerprint: A032 8CFF B93A 17A7 9901 FE7D 4CB6 D8EE D3E8 7138 * remotes/kraxel/tags/usb-20190822-pull-request: ehci: fix queue->dev null ptr dereference usb: reword -usb command-line option and mention xHCI xhci: Add No Op Command usb-redir: merge interrupt packets usbredir: fix buffer-overflow on vmload Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
-rw-r--r--hw/usb/hcd-ehci.c3
-rw-r--r--hw/usb/hcd-xhci.c3
-rw-r--r--hw/usb/redirect.c74
-rw-r--r--qemu-options.hx7
4 files changed, 64 insertions, 23 deletions
diff --git a/hw/usb/hcd-ehci.c b/hw/usb/hcd-ehci.c
index 9ca7b87a80..56ab2f457f 100644
--- a/hw/usb/hcd-ehci.c
+++ b/hw/usb/hcd-ehci.c
@@ -1838,6 +1838,9 @@ static int ehci_state_fetchqtd(EHCIQueue *q)
ehci_set_state(q->ehci, q->async, EST_EXECUTING);
break;
}
+ } else if (q->dev == NULL) {
+ ehci_trace_guest_bug(q->ehci, "no device attached to queue");
+ ehci_set_state(q->ehci, q->async, EST_HORIZONTALQH);
} else {
p = ehci_alloc_packet(q);
p->qtdaddr = q->qtdaddr;
diff --git a/hw/usb/hcd-xhci.c b/hw/usb/hcd-xhci.c
index f698224c8a..f578264948 100644
--- a/hw/usb/hcd-xhci.c
+++ b/hw/usb/hcd-xhci.c
@@ -2543,6 +2543,9 @@ static void xhci_process_commands(XHCIState *xhci)
case CR_GET_PORT_BANDWIDTH:
event.ccode = xhci_get_port_bandwidth(xhci, trb.parameter);
break;
+ case CR_NOOP:
+ event.ccode = CC_SUCCESS;
+ break;
case CR_VENDOR_NEC_FIRMWARE_REVISION:
if (xhci->nec_quirks) {
event.type = 48; /* NEC reply */
diff --git a/hw/usb/redirect.c b/hw/usb/redirect.c
index fc9fe0c00f..e0f5ca6f81 100644
--- a/hw/usb/redirect.c
+++ b/hw/usb/redirect.c
@@ -819,8 +819,8 @@ static void usbredir_handle_interrupt_in_data(USBRedirDevice *dev,
USBPacket *p, uint8_t ep)
{
/* Input interrupt endpoint, buffered packet input */
- struct buf_packet *intp;
- int status, len;
+ struct buf_packet *intp, *intp_to_free;
+ int status, len, sum;
if (!dev->endpoint[EP2I(ep)].interrupt_started &&
!dev->endpoint[EP2I(ep)].interrupt_error) {
@@ -839,9 +839,17 @@ static void usbredir_handle_interrupt_in_data(USBRedirDevice *dev,
dev->endpoint[EP2I(ep)].bufpq_dropping_packets = 0;
}
- intp = QTAILQ_FIRST(&dev->endpoint[EP2I(ep)].bufpq);
+ /* check for completed interrupt message (with all fragments) */
+ sum = 0;
+ QTAILQ_FOREACH(intp, &dev->endpoint[EP2I(ep)].bufpq, next) {
+ sum += intp->len;
+ if (intp->len < dev->endpoint[EP2I(ep)].max_packet_size ||
+ sum >= p->iov.size)
+ break;
+ }
+
if (intp == NULL) {
- DPRINTF2("interrupt-token-in ep %02X, no intp\n", ep);
+ DPRINTF2("interrupt-token-in ep %02X, no intp, buffered %d\n", ep, sum);
/* Check interrupt_error for stream errors */
status = dev->endpoint[EP2I(ep)].interrupt_error;
dev->endpoint[EP2I(ep)].interrupt_error = 0;
@@ -852,18 +860,42 @@ static void usbredir_handle_interrupt_in_data(USBRedirDevice *dev,
}
return;
}
- DPRINTF("interrupt-token-in ep %02X status %d len %d\n", ep,
- intp->status, intp->len);
- status = intp->status;
- len = intp->len;
- if (len > p->iov.size) {
- ERROR("received int data is larger then packet ep %02X\n", ep);
- len = p->iov.size;
- status = usb_redir_babble;
+ /* copy of completed interrupt message */
+ sum = 0;
+ status = usb_redir_success;
+ intp_to_free = NULL;
+ QTAILQ_FOREACH(intp, &dev->endpoint[EP2I(ep)].bufpq, next) {
+ if (intp_to_free) {
+ bufp_free(dev, intp_to_free, ep);
+ }
+ DPRINTF("interrupt-token-in ep %02X fragment status %d len %d\n", ep,
+ intp->status, intp->len);
+
+ sum += intp->len;
+ len = intp->len;
+ if (status == usb_redir_success) {
+ status = intp->status;
+ }
+ if (sum > p->iov.size) {
+ ERROR("received int data is larger then packet ep %02X\n", ep);
+ len -= (sum - p->iov.size);
+ sum = p->iov.size;
+ status = usb_redir_babble;
+ }
+
+ usb_packet_copy(p, intp->data, len);
+
+ intp_to_free = intp;
+ if (intp->len < dev->endpoint[EP2I(ep)].max_packet_size ||
+ sum >= p->iov.size)
+ break;
+ }
+ if (intp_to_free) {
+ bufp_free(dev, intp_to_free, ep);
}
- usb_packet_copy(p, intp->data, len);
- bufp_free(dev, intp, ep);
+ DPRINTF("interrupt-token-in ep %02X summary status %d len %d\n", ep,
+ status, sum);
usbredir_handle_status(dev, p, status);
}
@@ -1499,6 +1531,11 @@ static void usbredir_check_bulk_receiving(USBRedirDevice *dev)
for (i = EP2I(USB_DIR_IN); i < MAX_ENDPOINTS; i++) {
dev->endpoint[i].bulk_receiving_enabled = 0;
}
+
+ if (dev->interface_info.interface_count == NO_INTERFACE_INFO) {
+ return;
+ }
+
for (i = 0; i < dev->interface_info.interface_count; i++) {
quirks = usb_get_quirks(dev->device_info.vendor_id,
dev->device_info.product_id,
@@ -2036,22 +2073,17 @@ static void usbredir_interrupt_packet(void *priv, uint64_t id,
}
if (ep & USB_DIR_IN) {
- bool q_was_empty;
-
if (dev->endpoint[EP2I(ep)].interrupt_started == 0) {
DPRINTF("received int packet while not started ep %02X\n", ep);
free(data);
return;
}
- q_was_empty = QTAILQ_EMPTY(&dev->endpoint[EP2I(ep)].bufpq);
-
/* bufp_alloc also adds the packet to the ep queue */
bufp_alloc(dev, data, data_len, interrupt_packet->status, ep, data);
- if (q_was_empty) {
- usb_wakeup(usb_ep_get(&dev->dev, USB_TOKEN_IN, ep & 0x0f), 0);
- }
+ /* insufficient data solved with USB_RET_NAK */
+ usb_wakeup(usb_ep_get(&dev->dev, USB_TOKEN_IN, ep & 0x0f), 0);
} else {
/*
* We report output interrupt packets as completed directly upon
diff --git a/qemu-options.hx b/qemu-options.hx
index a308e5f5aa..ea0638e92d 100644
--- a/qemu-options.hx
+++ b/qemu-options.hx
@@ -1436,12 +1436,15 @@ STEXI
ETEXI
DEF("usb", 0, QEMU_OPTION_usb,
- "-usb enable the USB driver (if it is not used by default yet)\n",
+ "-usb enable on-board USB host controller (if not enabled by default)\n",
QEMU_ARCH_ALL)
STEXI
@item -usb
@findex -usb
-Enable the USB driver (if it is not used by default yet).
+Enable USB emulation on machine types with an on-board USB host controller (if
+not enabled by default). Note that on-board USB host controllers may not
+support USB 3.0. In this case @option{-device qemu-xhci} can be used instead
+on machines with PCI.
ETEXI
DEF("usbdevice", HAS_ARG, QEMU_OPTION_usbdevice,