Skip to content

Commit

Permalink
ehci: Add ehci_verify_qh and ehci_verify_qtd helper functions
Browse files Browse the repository at this point in the history
Signed-off-by: Hans de Goede <hdegoede@redhat.com>
Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
  • Loading branch information
jwrdegoede authored and kraxel committed Jan 7, 2013
1 parent f881c8d commit c643263
Showing 1 changed file with 35 additions and 16 deletions.
51 changes: 35 additions & 16 deletions hw/usb/hcd-ehci.c
Expand Up @@ -438,6 +438,36 @@ static inline bool ehci_periodic_enabled(EHCIState *s)
return ehci_enabled(s) && (s->usbcmd & USBCMD_PSE);
}

static bool ehci_verify_qh(EHCIQueue *q, EHCIqh *qh)
{
uint32_t devaddr = get_field(qh->epchar, QH_EPCHAR_DEVADDR);
uint32_t endp = get_field(qh->epchar, QH_EPCHAR_EP);
if ((devaddr != get_field(q->qh.epchar, QH_EPCHAR_DEVADDR)) ||
(endp != get_field(q->qh.epchar, QH_EPCHAR_EP)) ||
(qh->current_qtd != q->qh.current_qtd) ||
(q->async && qh->next_qtd != q->qh.next_qtd) ||
(memcmp(&qh->altnext_qtd, &q->qh.altnext_qtd,
7 * sizeof(uint32_t)) != 0) ||
(q->dev != NULL && q->dev->addr != devaddr)) {
return false;
} else {
return true;
}
}

static bool ehci_verify_qtd(EHCIPacket *p, EHCIqtd *qtd)
{
if (p->qtdaddr != p->queue->qtdaddr ||
(p->queue->async && !NLPTR_TBIT(p->qtd.next) &&
(p->qtd.next != qtd->next)) ||
(!NLPTR_TBIT(p->qtd.altnext) && (p->qtd.altnext != qtd->altnext)) ||
p->qtd.bufptr[0] != qtd->bufptr[0]) {
return false;
} else {
return true;
}
}

/* Finish executing and writeback a packet outside of the regular
fetchqh -> fetchqtd -> execute -> writeback cycle */
static void ehci_writeback_async_complete_packet(EHCIPacket *p)
Expand Down Expand Up @@ -1557,8 +1587,8 @@ static int ehci_state_fetchentry(EHCIState *ehci, int async)

static EHCIQueue *ehci_state_fetchqh(EHCIState *ehci, int async)
{
uint32_t entry;
EHCIPacket *p;
uint32_t entry, devaddr, endp;
EHCIQueue *q;
EHCIqh qh;

Expand Down Expand Up @@ -1588,15 +1618,7 @@ static EHCIQueue *ehci_state_fetchqh(EHCIState *ehci, int async)
* The overlay area of the qh should never be changed by the guest,
* except when idle, in which case the reset is a nop.
*/
devaddr = get_field(qh.epchar, QH_EPCHAR_DEVADDR);
endp = get_field(qh.epchar, QH_EPCHAR_EP);
if ((devaddr != get_field(q->qh.epchar, QH_EPCHAR_DEVADDR)) ||
(endp != get_field(q->qh.epchar, QH_EPCHAR_EP)) ||
(qh.current_qtd != q->qh.current_qtd) ||
(q->async && qh.next_qtd != q->qh.next_qtd) ||
(memcmp(&qh.altnext_qtd, &q->qh.altnext_qtd,
7 * sizeof(uint32_t)) != 0) ||
(q->dev != NULL && q->dev->addr != devaddr)) {
if (!ehci_verify_qh(q, &qh)) {
if (ehci_reset_queue(q) > 0) {
ehci_trace_guest_bug(ehci, "guest updated active QH");
}
Expand All @@ -1610,7 +1632,8 @@ static EHCIQueue *ehci_state_fetchqh(EHCIState *ehci, int async)
}

if (q->dev == NULL) {
q->dev = ehci_find_device(q->ehci, devaddr);
q->dev = ehci_find_device(q->ehci,
get_field(q->qh.epchar, QH_EPCHAR_DEVADDR));
}

if (p && p->async == EHCI_ASYNC_FINISHED) {
Expand Down Expand Up @@ -1768,11 +1791,7 @@ static int ehci_state_fetchqtd(EHCIQueue *q)

p = QTAILQ_FIRST(&q->packets);
if (p != NULL) {
if (p->qtdaddr != q->qtdaddr ||
(q->async && !NLPTR_TBIT(p->qtd.next) &&
(p->qtd.next != qtd.next)) ||
(!NLPTR_TBIT(p->qtd.altnext) && (p->qtd.altnext != qtd.altnext)) ||
p->qtd.bufptr[0] != qtd.bufptr[0]) {
if (!ehci_verify_qtd(p, &qtd)) {
ehci_cancel_queue(q);
ehci_trace_guest_bug(q->ehci, "guest updated active QH or qTD");
p = NULL;
Expand Down

0 comments on commit c643263

Please sign in to comment.