mirror of https://github.com/xqemu/xqemu.git
xhci: Fix some DMA host endian bugs
The xhci device does correct endian switches on the results of some DMAs but not all. In particular, there are many DMAs of what are essentially arrays of 32-bit integers which never get byteswapped. This causes them to be interpreted incorrectly on big-endian hosts, since (as per the xhci spec) these arrays are always little-endian in guest memory. This patch adds some helper functions to fix these bugs. This may not be all the endian bugs in the xhci code, but it's certainly some of them and the Linux guest xhci driver certainly gets further with these fixes. Signed-off-by: David Gibson <david@gibson.dropbear.id.au> Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
This commit is contained in:
parent
ffd8a97fb3
commit
616b5d53ae
|
@ -634,6 +634,34 @@ static inline dma_addr_t xhci_mask64(uint64_t addr)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static inline void xhci_dma_read_u32s(XHCIState *xhci, dma_addr_t addr,
|
||||||
|
uint32_t *buf, size_t len)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
|
||||||
|
assert((len % sizeof(uint32_t)) == 0);
|
||||||
|
|
||||||
|
pci_dma_read(&xhci->pci_dev, addr, buf, len);
|
||||||
|
|
||||||
|
for (i = 0; i < (len / sizeof(uint32_t)); i++) {
|
||||||
|
buf[i] = le32_to_cpu(buf[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void xhci_dma_write_u32s(XHCIState *xhci, dma_addr_t addr,
|
||||||
|
uint32_t *buf, size_t len)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
uint32_t tmp[len / sizeof(uint32_t)];
|
||||||
|
|
||||||
|
assert((len % sizeof(uint32_t)) == 0);
|
||||||
|
|
||||||
|
for (i = 0; i < (len / sizeof(uint32_t)); i++) {
|
||||||
|
tmp[i] = cpu_to_le32(buf[i]);
|
||||||
|
}
|
||||||
|
pci_dma_write(&xhci->pci_dev, addr, tmp, len);
|
||||||
|
}
|
||||||
|
|
||||||
static XHCIPort *xhci_lookup_port(XHCIState *xhci, struct USBPort *uport)
|
static XHCIPort *xhci_lookup_port(XHCIState *xhci, struct USBPort *uport)
|
||||||
{
|
{
|
||||||
int index;
|
int index;
|
||||||
|
@ -1045,14 +1073,14 @@ static void xhci_set_ep_state(XHCIState *xhci, XHCIEPContext *epctx,
|
||||||
{
|
{
|
||||||
uint32_t ctx[5];
|
uint32_t ctx[5];
|
||||||
|
|
||||||
pci_dma_read(&xhci->pci_dev, epctx->pctx, ctx, sizeof(ctx));
|
xhci_dma_read_u32s(xhci, epctx->pctx, ctx, sizeof(ctx));
|
||||||
ctx[0] &= ~EP_STATE_MASK;
|
ctx[0] &= ~EP_STATE_MASK;
|
||||||
ctx[0] |= state;
|
ctx[0] |= state;
|
||||||
ctx[2] = epctx->ring.dequeue | epctx->ring.ccs;
|
ctx[2] = epctx->ring.dequeue | epctx->ring.ccs;
|
||||||
ctx[3] = (epctx->ring.dequeue >> 16) >> 16;
|
ctx[3] = (epctx->ring.dequeue >> 16) >> 16;
|
||||||
DPRINTF("xhci: set epctx: " DMA_ADDR_FMT " state=%d dequeue=%08x%08x\n",
|
DPRINTF("xhci: set epctx: " DMA_ADDR_FMT " state=%d dequeue=%08x%08x\n",
|
||||||
epctx->pctx, state, ctx[3], ctx[2]);
|
epctx->pctx, state, ctx[3], ctx[2]);
|
||||||
pci_dma_write(&xhci->pci_dev, epctx->pctx, ctx, sizeof(ctx));
|
xhci_dma_write_u32s(xhci, epctx->pctx, ctx, sizeof(ctx));
|
||||||
epctx->state = state;
|
epctx->state = state;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1881,14 +1909,14 @@ static TRBCCode xhci_address_slot(XHCIState *xhci, unsigned int slotid,
|
||||||
assert(slotid >= 1 && slotid <= xhci->numslots);
|
assert(slotid >= 1 && slotid <= xhci->numslots);
|
||||||
|
|
||||||
dcbaap = xhci_addr64(xhci->dcbaap_low, xhci->dcbaap_high);
|
dcbaap = xhci_addr64(xhci->dcbaap_low, xhci->dcbaap_high);
|
||||||
pci_dma_read(&xhci->pci_dev, dcbaap + 8*slotid, &poctx, sizeof(poctx));
|
poctx = ldq_le_pci_dma(&xhci->pci_dev, dcbaap + 8*slotid);
|
||||||
ictx = xhci_mask64(pictx);
|
ictx = xhci_mask64(pictx);
|
||||||
octx = xhci_mask64(le64_to_cpu(poctx));
|
octx = xhci_mask64(poctx);
|
||||||
|
|
||||||
DPRINTF("xhci: input context at "DMA_ADDR_FMT"\n", ictx);
|
DPRINTF("xhci: input context at "DMA_ADDR_FMT"\n", ictx);
|
||||||
DPRINTF("xhci: output context at "DMA_ADDR_FMT"\n", octx);
|
DPRINTF("xhci: output context at "DMA_ADDR_FMT"\n", octx);
|
||||||
|
|
||||||
pci_dma_read(&xhci->pci_dev, ictx, ictl_ctx, sizeof(ictl_ctx));
|
xhci_dma_read_u32s(xhci, ictx, ictl_ctx, sizeof(ictl_ctx));
|
||||||
|
|
||||||
if (ictl_ctx[0] != 0x0 || ictl_ctx[1] != 0x3) {
|
if (ictl_ctx[0] != 0x0 || ictl_ctx[1] != 0x3) {
|
||||||
fprintf(stderr, "xhci: invalid input context control %08x %08x\n",
|
fprintf(stderr, "xhci: invalid input context control %08x %08x\n",
|
||||||
|
@ -1896,8 +1924,8 @@ static TRBCCode xhci_address_slot(XHCIState *xhci, unsigned int slotid,
|
||||||
return CC_TRB_ERROR;
|
return CC_TRB_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
pci_dma_read(&xhci->pci_dev, ictx+32, slot_ctx, sizeof(slot_ctx));
|
xhci_dma_read_u32s(xhci, ictx+32, slot_ctx, sizeof(slot_ctx));
|
||||||
pci_dma_read(&xhci->pci_dev, ictx+64, ep0_ctx, sizeof(ep0_ctx));
|
xhci_dma_read_u32s(xhci, ictx+64, ep0_ctx, sizeof(ep0_ctx));
|
||||||
|
|
||||||
DPRINTF("xhci: input slot context: %08x %08x %08x %08x\n",
|
DPRINTF("xhci: input slot context: %08x %08x %08x %08x\n",
|
||||||
slot_ctx[0], slot_ctx[1], slot_ctx[2], slot_ctx[3]);
|
slot_ctx[0], slot_ctx[1], slot_ctx[2], slot_ctx[3]);
|
||||||
|
@ -1951,8 +1979,8 @@ static TRBCCode xhci_address_slot(XHCIState *xhci, unsigned int slotid,
|
||||||
DPRINTF("xhci: output ep0 context: %08x %08x %08x %08x %08x\n",
|
DPRINTF("xhci: output ep0 context: %08x %08x %08x %08x %08x\n",
|
||||||
ep0_ctx[0], ep0_ctx[1], ep0_ctx[2], ep0_ctx[3], ep0_ctx[4]);
|
ep0_ctx[0], ep0_ctx[1], ep0_ctx[2], ep0_ctx[3], ep0_ctx[4]);
|
||||||
|
|
||||||
pci_dma_write(&xhci->pci_dev, octx, slot_ctx, sizeof(slot_ctx));
|
xhci_dma_write_u32s(xhci, octx, slot_ctx, sizeof(slot_ctx));
|
||||||
pci_dma_write(&xhci->pci_dev, octx+32, ep0_ctx, sizeof(ep0_ctx));
|
xhci_dma_write_u32s(xhci, octx+32, ep0_ctx, sizeof(ep0_ctx));
|
||||||
|
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
@ -1985,17 +2013,17 @@ static TRBCCode xhci_configure_slot(XHCIState *xhci, unsigned int slotid,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pci_dma_read(&xhci->pci_dev, octx, slot_ctx, sizeof(slot_ctx));
|
xhci_dma_read_u32s(xhci, octx, slot_ctx, sizeof(slot_ctx));
|
||||||
slot_ctx[3] &= ~(SLOT_STATE_MASK << SLOT_STATE_SHIFT);
|
slot_ctx[3] &= ~(SLOT_STATE_MASK << SLOT_STATE_SHIFT);
|
||||||
slot_ctx[3] |= SLOT_ADDRESSED << SLOT_STATE_SHIFT;
|
slot_ctx[3] |= SLOT_ADDRESSED << SLOT_STATE_SHIFT;
|
||||||
DPRINTF("xhci: output slot context: %08x %08x %08x %08x\n",
|
DPRINTF("xhci: output slot context: %08x %08x %08x %08x\n",
|
||||||
slot_ctx[0], slot_ctx[1], slot_ctx[2], slot_ctx[3]);
|
slot_ctx[0], slot_ctx[1], slot_ctx[2], slot_ctx[3]);
|
||||||
pci_dma_write(&xhci->pci_dev, octx, slot_ctx, sizeof(slot_ctx));
|
xhci_dma_write_u32s(xhci, octx, slot_ctx, sizeof(slot_ctx));
|
||||||
|
|
||||||
return CC_SUCCESS;
|
return CC_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
pci_dma_read(&xhci->pci_dev, ictx, ictl_ctx, sizeof(ictl_ctx));
|
xhci_dma_read_u32s(xhci, ictx, ictl_ctx, sizeof(ictl_ctx));
|
||||||
|
|
||||||
if ((ictl_ctx[0] & 0x3) != 0x0 || (ictl_ctx[1] & 0x3) != 0x1) {
|
if ((ictl_ctx[0] & 0x3) != 0x0 || (ictl_ctx[1] & 0x3) != 0x1) {
|
||||||
fprintf(stderr, "xhci: invalid input context control %08x %08x\n",
|
fprintf(stderr, "xhci: invalid input context control %08x %08x\n",
|
||||||
|
@ -2003,8 +2031,8 @@ static TRBCCode xhci_configure_slot(XHCIState *xhci, unsigned int slotid,
|
||||||
return CC_TRB_ERROR;
|
return CC_TRB_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
pci_dma_read(&xhci->pci_dev, ictx+32, islot_ctx, sizeof(islot_ctx));
|
xhci_dma_read_u32s(xhci, ictx+32, islot_ctx, sizeof(islot_ctx));
|
||||||
pci_dma_read(&xhci->pci_dev, octx, slot_ctx, sizeof(slot_ctx));
|
xhci_dma_read_u32s(xhci, octx, slot_ctx, sizeof(slot_ctx));
|
||||||
|
|
||||||
if (SLOT_STATE(slot_ctx[3]) < SLOT_ADDRESSED) {
|
if (SLOT_STATE(slot_ctx[3]) < SLOT_ADDRESSED) {
|
||||||
fprintf(stderr, "xhci: invalid slot state %08x\n", slot_ctx[3]);
|
fprintf(stderr, "xhci: invalid slot state %08x\n", slot_ctx[3]);
|
||||||
|
@ -2016,8 +2044,7 @@ static TRBCCode xhci_configure_slot(XHCIState *xhci, unsigned int slotid,
|
||||||
xhci_disable_ep(xhci, slotid, i);
|
xhci_disable_ep(xhci, slotid, i);
|
||||||
}
|
}
|
||||||
if (ictl_ctx[1] & (1<<i)) {
|
if (ictl_ctx[1] & (1<<i)) {
|
||||||
pci_dma_read(&xhci->pci_dev, ictx+32+(32*i), ep_ctx,
|
xhci_dma_read_u32s(xhci, ictx+32+(32*i), ep_ctx, sizeof(ep_ctx));
|
||||||
sizeof(ep_ctx));
|
|
||||||
DPRINTF("xhci: input ep%d.%d context: %08x %08x %08x %08x %08x\n",
|
DPRINTF("xhci: input ep%d.%d context: %08x %08x %08x %08x %08x\n",
|
||||||
i/2, i%2, ep_ctx[0], ep_ctx[1], ep_ctx[2],
|
i/2, i%2, ep_ctx[0], ep_ctx[1], ep_ctx[2],
|
||||||
ep_ctx[3], ep_ctx[4]);
|
ep_ctx[3], ep_ctx[4]);
|
||||||
|
@ -2029,7 +2056,7 @@ static TRBCCode xhci_configure_slot(XHCIState *xhci, unsigned int slotid,
|
||||||
DPRINTF("xhci: output ep%d.%d context: %08x %08x %08x %08x %08x\n",
|
DPRINTF("xhci: output ep%d.%d context: %08x %08x %08x %08x %08x\n",
|
||||||
i/2, i%2, ep_ctx[0], ep_ctx[1], ep_ctx[2],
|
i/2, i%2, ep_ctx[0], ep_ctx[1], ep_ctx[2],
|
||||||
ep_ctx[3], ep_ctx[4]);
|
ep_ctx[3], ep_ctx[4]);
|
||||||
pci_dma_write(&xhci->pci_dev, octx+(32*i), ep_ctx, sizeof(ep_ctx));
|
xhci_dma_write_u32s(xhci, octx+(32*i), ep_ctx, sizeof(ep_ctx));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2041,7 +2068,7 @@ static TRBCCode xhci_configure_slot(XHCIState *xhci, unsigned int slotid,
|
||||||
DPRINTF("xhci: output slot context: %08x %08x %08x %08x\n",
|
DPRINTF("xhci: output slot context: %08x %08x %08x %08x\n",
|
||||||
slot_ctx[0], slot_ctx[1], slot_ctx[2], slot_ctx[3]);
|
slot_ctx[0], slot_ctx[1], slot_ctx[2], slot_ctx[3]);
|
||||||
|
|
||||||
pci_dma_write(&xhci->pci_dev, octx, slot_ctx, sizeof(slot_ctx));
|
xhci_dma_write_u32s(xhci, octx, slot_ctx, sizeof(slot_ctx));
|
||||||
|
|
||||||
return CC_SUCCESS;
|
return CC_SUCCESS;
|
||||||
}
|
}
|
||||||
|
@ -2066,7 +2093,7 @@ static TRBCCode xhci_evaluate_slot(XHCIState *xhci, unsigned int slotid,
|
||||||
DPRINTF("xhci: input context at "DMA_ADDR_FMT"\n", ictx);
|
DPRINTF("xhci: input context at "DMA_ADDR_FMT"\n", ictx);
|
||||||
DPRINTF("xhci: output context at "DMA_ADDR_FMT"\n", octx);
|
DPRINTF("xhci: output context at "DMA_ADDR_FMT"\n", octx);
|
||||||
|
|
||||||
pci_dma_read(&xhci->pci_dev, ictx, ictl_ctx, sizeof(ictl_ctx));
|
xhci_dma_read_u32s(xhci, ictx, ictl_ctx, sizeof(ictl_ctx));
|
||||||
|
|
||||||
if (ictl_ctx[0] != 0x0 || ictl_ctx[1] & ~0x3) {
|
if (ictl_ctx[0] != 0x0 || ictl_ctx[1] & ~0x3) {
|
||||||
fprintf(stderr, "xhci: invalid input context control %08x %08x\n",
|
fprintf(stderr, "xhci: invalid input context control %08x %08x\n",
|
||||||
|
@ -2075,12 +2102,12 @@ static TRBCCode xhci_evaluate_slot(XHCIState *xhci, unsigned int slotid,
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ictl_ctx[1] & 0x1) {
|
if (ictl_ctx[1] & 0x1) {
|
||||||
pci_dma_read(&xhci->pci_dev, ictx+32, islot_ctx, sizeof(islot_ctx));
|
xhci_dma_read_u32s(xhci, ictx+32, islot_ctx, sizeof(islot_ctx));
|
||||||
|
|
||||||
DPRINTF("xhci: input slot context: %08x %08x %08x %08x\n",
|
DPRINTF("xhci: input slot context: %08x %08x %08x %08x\n",
|
||||||
islot_ctx[0], islot_ctx[1], islot_ctx[2], islot_ctx[3]);
|
islot_ctx[0], islot_ctx[1], islot_ctx[2], islot_ctx[3]);
|
||||||
|
|
||||||
pci_dma_read(&xhci->pci_dev, octx, slot_ctx, sizeof(slot_ctx));
|
xhci_dma_read_u32s(xhci, octx, slot_ctx, sizeof(slot_ctx));
|
||||||
|
|
||||||
slot_ctx[1] &= ~0xFFFF; /* max exit latency */
|
slot_ctx[1] &= ~0xFFFF; /* max exit latency */
|
||||||
slot_ctx[1] |= islot_ctx[1] & 0xFFFF;
|
slot_ctx[1] |= islot_ctx[1] & 0xFFFF;
|
||||||
|
@ -2090,17 +2117,17 @@ static TRBCCode xhci_evaluate_slot(XHCIState *xhci, unsigned int slotid,
|
||||||
DPRINTF("xhci: output slot context: %08x %08x %08x %08x\n",
|
DPRINTF("xhci: output slot context: %08x %08x %08x %08x\n",
|
||||||
slot_ctx[0], slot_ctx[1], slot_ctx[2], slot_ctx[3]);
|
slot_ctx[0], slot_ctx[1], slot_ctx[2], slot_ctx[3]);
|
||||||
|
|
||||||
pci_dma_write(&xhci->pci_dev, octx, slot_ctx, sizeof(slot_ctx));
|
xhci_dma_write_u32s(xhci, octx, slot_ctx, sizeof(slot_ctx));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ictl_ctx[1] & 0x2) {
|
if (ictl_ctx[1] & 0x2) {
|
||||||
pci_dma_read(&xhci->pci_dev, ictx+64, iep0_ctx, sizeof(iep0_ctx));
|
xhci_dma_read_u32s(xhci, ictx+64, iep0_ctx, sizeof(iep0_ctx));
|
||||||
|
|
||||||
DPRINTF("xhci: input ep0 context: %08x %08x %08x %08x %08x\n",
|
DPRINTF("xhci: input ep0 context: %08x %08x %08x %08x %08x\n",
|
||||||
iep0_ctx[0], iep0_ctx[1], iep0_ctx[2],
|
iep0_ctx[0], iep0_ctx[1], iep0_ctx[2],
|
||||||
iep0_ctx[3], iep0_ctx[4]);
|
iep0_ctx[3], iep0_ctx[4]);
|
||||||
|
|
||||||
pci_dma_read(&xhci->pci_dev, octx+32, ep0_ctx, sizeof(ep0_ctx));
|
xhci_dma_read_u32s(xhci, octx+32, ep0_ctx, sizeof(ep0_ctx));
|
||||||
|
|
||||||
ep0_ctx[1] &= ~0xFFFF0000; /* max packet size*/
|
ep0_ctx[1] &= ~0xFFFF0000; /* max packet size*/
|
||||||
ep0_ctx[1] |= iep0_ctx[1] & 0xFFFF0000;
|
ep0_ctx[1] |= iep0_ctx[1] & 0xFFFF0000;
|
||||||
|
@ -2108,7 +2135,7 @@ static TRBCCode xhci_evaluate_slot(XHCIState *xhci, unsigned int slotid,
|
||||||
DPRINTF("xhci: output ep0 context: %08x %08x %08x %08x %08x\n",
|
DPRINTF("xhci: output ep0 context: %08x %08x %08x %08x %08x\n",
|
||||||
ep0_ctx[0], ep0_ctx[1], ep0_ctx[2], ep0_ctx[3], ep0_ctx[4]);
|
ep0_ctx[0], ep0_ctx[1], ep0_ctx[2], ep0_ctx[3], ep0_ctx[4]);
|
||||||
|
|
||||||
pci_dma_write(&xhci->pci_dev, octx+32, ep0_ctx, sizeof(ep0_ctx));
|
xhci_dma_write_u32s(xhci, octx+32, ep0_ctx, sizeof(ep0_ctx));
|
||||||
}
|
}
|
||||||
|
|
||||||
return CC_SUCCESS;
|
return CC_SUCCESS;
|
||||||
|
@ -2133,12 +2160,12 @@ static TRBCCode xhci_reset_slot(XHCIState *xhci, unsigned int slotid)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pci_dma_read(&xhci->pci_dev, octx, slot_ctx, sizeof(slot_ctx));
|
xhci_dma_read_u32s(xhci, octx, slot_ctx, sizeof(slot_ctx));
|
||||||
slot_ctx[3] &= ~(SLOT_STATE_MASK << SLOT_STATE_SHIFT);
|
slot_ctx[3] &= ~(SLOT_STATE_MASK << SLOT_STATE_SHIFT);
|
||||||
slot_ctx[3] |= SLOT_DEFAULT << SLOT_STATE_SHIFT;
|
slot_ctx[3] |= SLOT_DEFAULT << SLOT_STATE_SHIFT;
|
||||||
DPRINTF("xhci: output slot context: %08x %08x %08x %08x\n",
|
DPRINTF("xhci: output slot context: %08x %08x %08x %08x\n",
|
||||||
slot_ctx[0], slot_ctx[1], slot_ctx[2], slot_ctx[3]);
|
slot_ctx[0], slot_ctx[1], slot_ctx[2], slot_ctx[3]);
|
||||||
pci_dma_write(&xhci->pci_dev, octx, slot_ctx, sizeof(slot_ctx));
|
xhci_dma_write_u32s(xhci, octx, slot_ctx, sizeof(slot_ctx));
|
||||||
|
|
||||||
return CC_SUCCESS;
|
return CC_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue