usb: bugfixes and minor improvements.

-----BEGIN PGP SIGNATURE-----
 Version: GnuPG v2.0.22 (GNU/Linux)
 
 iQIcBAABAgAGBQJdXjuwAAoJEEy22O7T6HE4sMwP/0TUW3o7jmrhN4HtlAX+Rcy3
 V8uyCw5sMBeK1b78JAP85KjmB2PV1a4AZE8El8Vy1dEaxE6oBbZXMZGvf5lNfbxM
 6sx5tEYjl5RqUvpQvhx7vA7NU1dTB53dj2/QKFrNp1YIT4xDS5M0J6vf22fizLAJ
 ad3fBIx2C/SAQBd5wfcHV8QqeeqHJhioKv9E56qcH+YSs4tc0nxtqzYL6VhkGTi7
 4asvI0F3XgIo66HJv/x26Dv5ZN0zDQsgjfT3zOHRXnzGb2AYh9aIU/Bui/a66C1J
 CWrT7zs/Qgqj46pBKi+Vzy1fU7hew7XOlc9Cka7V0yFkwkIKiWA1GZ6IkJPcXFsC
 avIjAHsiIvcYRkHq5kOlYDyMpt2kMFDxbtGFcL5M28ngGyZcDenpe2uAqos3nqvV
 YrN+/n+8dZ0a1xe4M1Azvv0LSinYlUbOkpvs6W3Q7eSmhTCGhxZtp7nCS2gJ2cYj
 U5gnVq3R2UvYqx+rqaDVs/f5X0XXan4sm0hb7cmAi6qvsjjIKeEC41O766EZdTKs
 JdM+iZLBNmfqi5mSLee9dCgZrE06e7Bn0IcRkQPHfpWHWhVzKwUoLOfruvgLIR82
 pIxWv9fQjq7di1pbphxd8fvpQ3azpiVz/LucEOnXVirUxC5ZjT7W9eeNTGgPDkJC
 vrhDZAFzeCSSa16puGzS
 =LuqP
 -----END PGP SIGNATURE-----

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>
This commit is contained in:
Peter Maydell 2019-08-22 15:10:51 +01:00
commit 4a71d0af7b
4 changed files with 64 additions and 23 deletions

View File

@ -1838,6 +1838,9 @@ static int ehci_state_fetchqtd(EHCIQueue *q)
ehci_set_state(q->ehci, q->async, EST_EXECUTING); ehci_set_state(q->ehci, q->async, EST_EXECUTING);
break; 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 { } else {
p = ehci_alloc_packet(q); p = ehci_alloc_packet(q);
p->qtdaddr = q->qtdaddr; p->qtdaddr = q->qtdaddr;

View File

@ -2543,6 +2543,9 @@ static void xhci_process_commands(XHCIState *xhci)
case CR_GET_PORT_BANDWIDTH: case CR_GET_PORT_BANDWIDTH:
event.ccode = xhci_get_port_bandwidth(xhci, trb.parameter); event.ccode = xhci_get_port_bandwidth(xhci, trb.parameter);
break; break;
case CR_NOOP:
event.ccode = CC_SUCCESS;
break;
case CR_VENDOR_NEC_FIRMWARE_REVISION: case CR_VENDOR_NEC_FIRMWARE_REVISION:
if (xhci->nec_quirks) { if (xhci->nec_quirks) {
event.type = 48; /* NEC reply */ event.type = 48; /* NEC reply */

View File

@ -819,8 +819,8 @@ static void usbredir_handle_interrupt_in_data(USBRedirDevice *dev,
USBPacket *p, uint8_t ep) USBPacket *p, uint8_t ep)
{ {
/* Input interrupt endpoint, buffered packet input */ /* Input interrupt endpoint, buffered packet input */
struct buf_packet *intp; struct buf_packet *intp, *intp_to_free;
int status, len; int status, len, sum;
if (!dev->endpoint[EP2I(ep)].interrupt_started && if (!dev->endpoint[EP2I(ep)].interrupt_started &&
!dev->endpoint[EP2I(ep)].interrupt_error) { !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; 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) { 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 */ /* Check interrupt_error for stream errors */
status = dev->endpoint[EP2I(ep)].interrupt_error; status = dev->endpoint[EP2I(ep)].interrupt_error;
dev->endpoint[EP2I(ep)].interrupt_error = 0; dev->endpoint[EP2I(ep)].interrupt_error = 0;
@ -852,18 +860,42 @@ static void usbredir_handle_interrupt_in_data(USBRedirDevice *dev,
} }
return; return;
} }
DPRINTF("interrupt-token-in ep %02X status %d len %d\n", ep,
intp->status, intp->len);
status = intp->status; /* copy of completed interrupt message */
len = intp->len; sum = 0;
if (len > p->iov.size) { status = usb_redir_success;
ERROR("received int data is larger then packet ep %02X\n", ep); intp_to_free = NULL;
len = p->iov.size; QTAILQ_FOREACH(intp, &dev->endpoint[EP2I(ep)].bufpq, next) {
status = usb_redir_babble; 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;
} }
usb_packet_copy(p, intp->data, len); if (intp_to_free) {
bufp_free(dev, intp, ep); bufp_free(dev, intp_to_free, ep);
}
DPRINTF("interrupt-token-in ep %02X summary status %d len %d\n", ep,
status, sum);
usbredir_handle_status(dev, p, status); 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++) { for (i = EP2I(USB_DIR_IN); i < MAX_ENDPOINTS; i++) {
dev->endpoint[i].bulk_receiving_enabled = 0; 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++) { for (i = 0; i < dev->interface_info.interface_count; i++) {
quirks = usb_get_quirks(dev->device_info.vendor_id, quirks = usb_get_quirks(dev->device_info.vendor_id,
dev->device_info.product_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) { if (ep & USB_DIR_IN) {
bool q_was_empty;
if (dev->endpoint[EP2I(ep)].interrupt_started == 0) { if (dev->endpoint[EP2I(ep)].interrupt_started == 0) {
DPRINTF("received int packet while not started ep %02X\n", ep); DPRINTF("received int packet while not started ep %02X\n", ep);
free(data); free(data);
return; return;
} }
q_was_empty = QTAILQ_EMPTY(&dev->endpoint[EP2I(ep)].bufpq);
/* bufp_alloc also adds the packet to the ep queue */ /* bufp_alloc also adds the packet to the ep queue */
bufp_alloc(dev, data, data_len, interrupt_packet->status, ep, data); bufp_alloc(dev, data, data_len, interrupt_packet->status, ep, data);
if (q_was_empty) { /* insufficient data solved with USB_RET_NAK */
usb_wakeup(usb_ep_get(&dev->dev, USB_TOKEN_IN, ep & 0x0f), 0); usb_wakeup(usb_ep_get(&dev->dev, USB_TOKEN_IN, ep & 0x0f), 0);
}
} else { } else {
/* /*
* We report output interrupt packets as completed directly upon * We report output interrupt packets as completed directly upon

View File

@ -1436,12 +1436,15 @@ STEXI
ETEXI ETEXI
DEF("usb", 0, QEMU_OPTION_usb, 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) QEMU_ARCH_ALL)
STEXI STEXI
@item -usb @item -usb
@findex -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 ETEXI
DEF("usbdevice", HAS_ARG, QEMU_OPTION_usbdevice, DEF("usbdevice", HAS_ARG, QEMU_OPTION_usbdevice,