dcavalca / rpms / qemu

Forked from rpms/qemu a year ago
Clone

Blame 0131-ehci-Validate-qh-is-not-changed-unexpectedly-by-the-.patch

5544c1
From 46bfd14f89404e4a0eb93c3d9c5b9745724cee2d Mon Sep 17 00:00:00 2001
Hans de Goede c8dfc6
From: Hans de Goede <hdegoede@redhat.com>
Hans de Goede c8dfc6
Date: Wed, 29 Aug 2012 10:37:37 +0200
5544c1
Subject: [PATCH] ehci: Validate qh is not changed unexpectedly by the guest
Hans de Goede c8dfc6
Hans de Goede c8dfc6
-combine the qh check with the check for devaddr changes
Hans de Goede c8dfc6
-also ensure that p gets set to NULL when the queue gets cancelled on
Hans de Goede c8dfc6
 devaddr change, which was not done properly before this patch
Hans de Goede c8dfc6
Hans de Goede c8dfc6
Signed-off-by: Hans de Goede <hdegoede@redhat.com>
5544c1
(cherry picked from commit dafe31fc2a8653b535d58f8c7b250c0827b14420)
5544c1
5544c1
Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com>
Hans de Goede c8dfc6
---
Hans de Goede c8dfc6
 hw/usb/hcd-ehci.c | 39 ++++++++++++++++++++++++++++-----------
Hans de Goede c8dfc6
 1 file changed, 28 insertions(+), 11 deletions(-)
Hans de Goede c8dfc6
Hans de Goede c8dfc6
diff --git a/hw/usb/hcd-ehci.c b/hw/usb/hcd-ehci.c
Hans de Goede c8dfc6
index e7c36f4..35eb441 100644
Hans de Goede c8dfc6
--- a/hw/usb/hcd-ehci.c
Hans de Goede c8dfc6
+++ b/hw/usb/hcd-ehci.c
Hans de Goede c8dfc6
@@ -780,6 +780,14 @@ static void ehci_cancel_queue(EHCIQueue *q)
Hans de Goede c8dfc6
     } while ((p = QTAILQ_FIRST(&q->packets)) != NULL);
Hans de Goede c8dfc6
 }
Hans de Goede c8dfc6
 
Hans de Goede c8dfc6
+static void ehci_reset_queue(EHCIQueue *q)
Hans de Goede c8dfc6
+{
Hans de Goede c8dfc6
+    trace_usb_ehci_queue_action(q, "reset");
Hans de Goede c8dfc6
+    ehci_cancel_queue(q);
Hans de Goede c8dfc6
+    q->dev = NULL;
Hans de Goede c8dfc6
+    q->qtdaddr = 0;
Hans de Goede c8dfc6
+}
Hans de Goede c8dfc6
+
Hans de Goede c8dfc6
 static void ehci_free_queue(EHCIQueue *q)
Hans de Goede c8dfc6
 {
Hans de Goede c8dfc6
     EHCIQueueHead *head = q->async ? &q->ehci->aqueues : &q->ehci->pqueues;
Hans de Goede c8dfc6
@@ -1755,8 +1763,9 @@ out:
Hans de Goede c8dfc6
 static EHCIQueue *ehci_state_fetchqh(EHCIState *ehci, int async)
Hans de Goede c8dfc6
 {
Hans de Goede c8dfc6
     EHCIPacket *p;
Hans de Goede c8dfc6
-    uint32_t entry, devaddr;
Hans de Goede c8dfc6
+    uint32_t entry, devaddr, endp;
Hans de Goede c8dfc6
     EHCIQueue *q;
Hans de Goede c8dfc6
+    EHCIqh qh;
Hans de Goede c8dfc6
 
Hans de Goede c8dfc6
     entry = ehci_get_fetch_addr(ehci, async);
Hans de Goede c8dfc6
     q = ehci_find_queue_by_qh(ehci, entry, async);
Hans de Goede c8dfc6
@@ -1774,17 +1783,25 @@ static EHCIQueue *ehci_state_fetchqh(EHCIState *ehci, int async)
Hans de Goede c8dfc6
     }
Hans de Goede c8dfc6
 
Hans de Goede c8dfc6
     get_dwords(ehci, NLPTR_GET(q->qhaddr),
Hans de Goede c8dfc6
-               (uint32_t *) &q->qh, sizeof(EHCIqh) >> 2);
Hans de Goede c8dfc6
-    ehci_trace_qh(q, NLPTR_GET(q->qhaddr), &q->qh);
Hans de Goede c8dfc6
+               (uint32_t *) &qh, sizeof(EHCIqh) >> 2);
Hans de Goede c8dfc6
+    ehci_trace_qh(q, NLPTR_GET(q->qhaddr), &qh;;
Hans de Goede c8dfc6
+
Hans de Goede c8dfc6
+    /*
Hans de Goede c8dfc6
+     * The overlay area of the qh should never be changed by the guest,
Hans de Goede c8dfc6
+     * except when idle, in which case the reset is a nop.
Hans de Goede c8dfc6
+     */
Hans de Goede c8dfc6
+    devaddr = get_field(qh.epchar, QH_EPCHAR_DEVADDR);
Hans de Goede c8dfc6
+    endp    = get_field(qh.epchar, QH_EPCHAR_EP);
Hans de Goede c8dfc6
+    if ((devaddr != get_field(q->qh.epchar, QH_EPCHAR_DEVADDR)) ||
Hans de Goede c8dfc6
+        (endp    != get_field(q->qh.epchar, QH_EPCHAR_EP)) ||
Hans de Goede c8dfc6
+        (memcmp(&qh.current_qtd, &q->qh.current_qtd,
Hans de Goede c8dfc6
+                                 9 * sizeof(uint32_t)) != 0) ||
Hans de Goede c8dfc6
+        (q->dev != NULL && q->dev->addr != devaddr)) {
Hans de Goede c8dfc6
+        ehci_reset_queue(q);
Hans de Goede c8dfc6
+        p = NULL;
Hans de Goede c8dfc6
+    }
Hans de Goede c8dfc6
+    q->qh = qh;
Hans de Goede c8dfc6
 
Hans de Goede c8dfc6
-    devaddr = get_field(q->qh.epchar, QH_EPCHAR_DEVADDR);
Hans de Goede c8dfc6
-    if (q->dev != NULL && q->dev->addr != devaddr) {
Hans de Goede c8dfc6
-        if (!QTAILQ_EMPTY(&q->packets)) {
Hans de Goede c8dfc6
-            /* should not happen (guest bug) */
Hans de Goede c8dfc6
-            ehci_cancel_queue(q);
Hans de Goede c8dfc6
-        }
Hans de Goede c8dfc6
-        q->dev = NULL;
Hans de Goede c8dfc6
-    }
Hans de Goede c8dfc6
     if (q->dev == NULL) {
Hans de Goede c8dfc6
         q->dev = ehci_find_device(q->ehci, devaddr);
Hans de Goede c8dfc6
     }
Hans de Goede c8dfc6
-- 
5544c1
1.7.12.1
Hans de Goede c8dfc6