ehci: Verify a queue's ep direction does not change

ehci_fill_queue assumes that there is a one on one relationship between an ep
and a qh, this patch adds a check to ensure this.

Note I don't expect this to ever trigger, this is just something I noticed
the guest might do while working on other stuff. The only way this check can
trigger is if a guest mixes in and out qtd-s in a single qh for a non
control ep.

Signed-off-by: Hans de Goede <hdegoede@redhat.com>
Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
This commit is contained in:
Hans de Goede 2012-12-14 14:35:29 +01:00 committed by Gerd Hoffmann
parent 51e0c5d029
commit bbbc39ccac
2 changed files with 20 additions and 0 deletions

View File

@ -527,6 +527,19 @@ static bool ehci_verify_qtd(EHCIPacket *p, EHCIqtd *qtd)
}
}
static bool ehci_verify_pid(EHCIQueue *q, EHCIqtd *qtd)
{
int ep = get_field(q->qh.epchar, QH_EPCHAR_EP);
int pid = ehci_get_pid(qtd);
/* Note the pid changing is normal for ep 0 (the control ep) */
if (q->last_pid && ep != 0 && pid != q->last_pid) {
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)
@ -634,6 +647,7 @@ static int ehci_reset_queue(EHCIQueue *q)
packets = ehci_cancel_queue(q);
q->dev = NULL;
q->qtdaddr = 0;
q->last_pid = 0;
return packets;
}
@ -1368,6 +1382,7 @@ static int ehci_execute(EHCIPacket *p, const char *action)
}
p->pid = ehci_get_pid(&p->qtd);
p->queue->last_pid = p->pid;
endp = get_field(p->queue->qh.epchar, QH_EPCHAR_EP);
ep = usb_ep_get(p->queue->dev, p->pid, endp);
@ -1883,6 +1898,10 @@ static int ehci_fill_queue(EHCIPacket *p)
if (!(qtd.token & QTD_TOKEN_ACTIVE)) {
break;
}
if (!ehci_verify_pid(q, &qtd)) {
ehci_trace_guest_bug(q->ehci, "guest queued token with wrong pid");
break;
}
p = ehci_alloc_packet(q);
p->qtdaddr = qtdaddr;
p->qtd = qtd;

View File

@ -248,6 +248,7 @@ struct EHCIQueue {
EHCIqh qh; /* copy of current QH (being worked on) */
uint32_t qhaddr; /* address QH read from */
uint32_t qtdaddr; /* address QTD read from */
int last_pid; /* pid of last packet executed */
USBDevice *dev;
QTAILQ_HEAD(pkts_head, EHCIPacket) packets;
};