Commit 4a71d0af authored by Peter Maydell's avatar Peter Maydell
Browse files

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: default avatarPeter Maydell <peter.maydell@linaro.org>
parents d86766a9 1be344b7
Loading
Loading
Loading
Loading
+3 −0
Original line number Diff line number Diff line
@@ -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;
+3 −0
Original line number Diff line number Diff line
@@ -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 */
+53 −21
Original line number Diff line number Diff line
@@ -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,

    /* 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);

    status = intp->status;
        sum += intp->len;
        len = intp->len;
    if (len > p->iov.size) {
        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 = p->iov.size;
            len -= (sum - p->iov.size);
            sum = p->iov.size;
            status = usb_redir_babble;
        }

        usb_packet_copy(p, intp->data, len);
    bufp_free(dev, intp, ep);

        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);
    }
    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) {
        /* 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
+5 −2
Original line number Diff line number Diff line
@@ -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,