From: Junjie Cao <junjie.cao@linux.dev>
To: qemu-devel@nongnu.org
Cc: "Thomas Huth" <thuth@redhat.com>,
"Philippe Mathieu-Daudé" <philmd@oss.qualcomm.com>,
"Peter Maydell" <peter.maydell@linaro.org>,
"Fabiano Rosas" <farosas@suse.de>,
"Laurent Vivier" <lvivier@redhat.com>,
"Paolo Bonzini" <pbonzini@redhat.com>,
junjie.cao@linux.dev
Subject: [PATCH 2/2] tests/qtest/usb-hcd-xhci: test Address Device with an unreadable DCBAA
Date: Fri, 30 Oct 2026 22:37:25 -0500 [thread overview]
Message-ID: <20261031033725.1275414-3-junjie.cao@linux.dev> (raw)
In-Reply-To: <20261031033725.1275414-1-junjie.cao@linux.dev>
Point DCBAAP at unassigned memory before Address Device. The fixed
controller completes it with TRB Error and raises HCE; check that, and
that the 64 bytes at guest address 0, where the contexts used to be
written, stay intact. With DCBAAP restored the command then succeeds
on retry.
Signed-off-by: Junjie Cao <junjie.cao@linux.dev>
---
tests/qtest/usb-hcd-xhci-test.c | 87 ++++++++++++++++++++++++++++-----
1 file changed, 75 insertions(+), 12 deletions(-)
diff --git a/tests/qtest/usb-hcd-xhci-test.c b/tests/qtest/usb-hcd-xhci-test.c
index add2290bff..be09b838c5 100644
--- a/tests/qtest/usb-hcd-xhci-test.c
+++ b/tests/qtest/usb-hcd-xhci-test.c
@@ -56,6 +56,7 @@
#define ER_TRANSFER 32
#define ER_COMMAND_COMPLETE 33
#define CC_SUCCESS 1
+#define CC_TRB_ERROR 5
#define EP_TYPE_ISOCH_OUT 1
#define EP_TYPE_CONTROL 4
@@ -64,6 +65,8 @@
#define XHCI_RING_TRBS 64
#define XHCI_MICROFRAME_NS 125000
+/* in the PCI hole of the pc machine, nothing is mapped there */
+#define XHCI_UNASSIGNED_ADDR 0xf0000000
typedef struct XHCITest {
QTestState *qts;
@@ -71,7 +74,7 @@ typedef struct XHCITest {
QPCIBus *bus;
struct qhc hc;
uint32_t oper, runtime, doorbell;
- uint64_t cmd_ring, event_ring, input_ctx;
+ uint64_t dcbaa, cmd_ring, event_ring, input_ctx;
unsigned int cmd_idx, event_idx;
unsigned int port, slot;
} XHCITest;
@@ -226,8 +229,9 @@ static bool xhci_next_event(XHCITest *x, uint32_t *status, uint32_t *control)
return true;
}
-static unsigned int xhci_command(XHCITest *x, uint64_t parameter,
- uint32_t control)
+/* Submit a command and return its completion code. */
+static unsigned int xhci_submit_command(XHCITest *x, uint64_t parameter,
+ uint32_t control, unsigned int *slot)
{
uint32_t status;
@@ -238,17 +242,30 @@ static unsigned int xhci_command(XHCITest *x, uint64_t parameter,
g_assert_true(xhci_next_event(x, &status, &control));
g_assert_cmpuint(TRB_GET_TYPE(control), ==, ER_COMMAND_COMPLETE);
- g_assert_cmpuint(TRB_GET_CCODE(status), ==, CC_SUCCESS);
- return TRB_GET_SLOT(control);
+ if (slot) {
+ *slot = TRB_GET_SLOT(control);
+ }
+ return TRB_GET_CCODE(status);
+}
+
+/* Submit a command that has to succeed and return the slot ID. */
+static unsigned int xhci_command(XHCITest *x, uint64_t parameter,
+ uint32_t control)
+{
+ unsigned int slot;
+
+ g_assert_cmpuint(xhci_submit_command(x, parameter, control, &slot), ==,
+ CC_SUCCESS);
+ return slot;
}
/*
- * Start qemu-xhci with one USB device, run the controller and bring the
- * device to the Addressed state.
+ * Start qemu-xhci with one USB device, run the controller, enable a slot
+ * for the device and fill in the input context for Address Device.
*/
-static void xhci_test_start(XHCITest *x, const char *usb_device)
+static void xhci_test_init(XHCITest *x, const char *usb_device)
{
- uint64_t dcbaa, erst, ep0_ring;
+ uint64_t erst, ep0_ring;
unsigned int maxports;
memset(x, 0, sizeof(*x));
@@ -267,14 +284,14 @@ static void xhci_test_start(XHCITest *x, const char *usb_device)
xhci_writel(x, x->oper + XHCI_USBCMD, USBCMD_HCRST);
g_assert_false(xhci_readl(x, x->oper + XHCI_USBCMD) & USBCMD_HCRST);
- dcbaa = xhci_alloc_page(x);
+ x->dcbaa = xhci_alloc_page(x);
erst = xhci_alloc_page(x);
x->cmd_ring = xhci_alloc_page(x);
x->event_ring = xhci_alloc_page(x);
x->input_ctx = xhci_alloc_page(x);
xhci_writel(x, x->oper + XHCI_CONFIG, 1);
- xhci_writeq(x, x->oper + XHCI_DCBAAP, dcbaa);
+ xhci_writeq(x, x->oper + XHCI_DCBAAP, x->dcbaa);
qtest_writeq(x->qts, erst, x->event_ring);
qtest_writel(x->qts, erst + 8, XHCI_RING_TRBS);
xhci_writel(x, x->runtime + XHCI_ERSTSZ, 1);
@@ -296,7 +313,7 @@ static void xhci_test_start(XHCITest *x, const char *usb_device)
}
x->slot = xhci_command(x, 0, TRB_TYPE(CR_ENABLE_SLOT));
- qtest_writeq(x->qts, dcbaa + 8 * x->slot, xhci_alloc_page(x));
+ qtest_writeq(x->qts, x->dcbaa + 8 * x->slot, xhci_alloc_page(x));
/* input control context: add slot and ep0 */
qtest_writel(x->qts, x->input_ctx + 0x04, 0x3);
@@ -308,6 +325,12 @@ static void xhci_test_start(XHCITest *x, const char *usb_device)
qtest_writel(x->qts, x->input_ctx + 0x44,
(64 << 16) | (EP_TYPE_CONTROL << 3));
qtest_writeq(x->qts, x->input_ctx + 0x48, ep0_ring | 1);
+}
+
+/* xhci_test_init(), then bring the device to the Addressed state. */
+static void xhci_test_start(XHCITest *x, const char *usb_device)
+{
+ xhci_test_init(x, usb_device);
xhci_command(x, x->input_ctx,
TRB_TYPE(CR_ADDRESS_DEVICE) | (x->slot << 24));
}
@@ -355,6 +378,44 @@ static bool xhci_test_supported(const char *usb_device)
return true;
}
+/*
+ * Address Device reads the output context pointer from the DCBAA. Point
+ * DCBAAP at unassigned memory: the command has to fail instead of carrying
+ * on with the zero the failed read leaves behind, which used to put the
+ * contexts at guest address 0 and still report Success.
+ */
+static void test_xhci_address_device_dcbaa_read_error(void)
+{
+ uint8_t fill[64], low_mem[sizeof(fill)];
+ unsigned int ccode;
+ XHCITest x;
+
+ if (!xhci_test_supported("usb-kbd")) {
+ return;
+ }
+
+ xhci_test_init(&x, "-device usb-kbd");
+ memset(fill, 0xaa, sizeof(fill));
+ qtest_memwrite(x.qts, 0, fill, sizeof(fill));
+ xhci_writeq(&x, x.oper + XHCI_DCBAAP, XHCI_UNASSIGNED_ADDR);
+
+ ccode = xhci_submit_command(&x, x.input_ctx,
+ TRB_TYPE(CR_ADDRESS_DEVICE) | (x.slot << 24),
+ NULL);
+ g_assert_cmpuint(ccode, ==, CC_TRB_ERROR);
+ g_assert_cmphex(xhci_readl(&x, x.oper + XHCI_USBSTS) & USBSTS_HCE, ==,
+ USBSTS_HCE);
+ qtest_memread(x.qts, 0, low_mem, sizeof(low_mem));
+ g_assert_cmpmem(low_mem, sizeof(low_mem), fill, sizeof(fill));
+
+ /* The failed command left the slot usable. */
+ xhci_writeq(&x, x.oper + XHCI_DCBAAP, x.dcbaa);
+ xhci_command(&x, x.input_ctx,
+ TRB_TYPE(CR_ADDRESS_DEVICE) | (x.slot << 24));
+
+ xhci_test_end(&x);
+}
+
/*
* An isoch TD with SIA set is run at the next interval boundary. That has to
* hold once the microframe index no longer fits in 32 bits as well.
@@ -481,6 +542,8 @@ int main(int argc, char **argv)
if (qtest_has_device("usb-ccid")) {
qtest_add_func("/xhci/pci/hotplug/usb-ccid", test_usb_ccid_hotplug);
}
+ qtest_add_func("/xhci/pci/address-device/dcbaa-read-error",
+ test_xhci_address_device_dcbaa_read_error);
qtest_add_func("/xhci/pci/isoch/mfindex-32bit",
test_xhci_isoch_mfindex_32bit);
qtest_add_func("/xhci/pci/intr/mfindex-32bit",
--
2.43.0
prev parent reply other threads:[~2026-10-31 3:38 UTC|newest]
Thread overview: 3+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-10-31 3:37 [PATCH 0/2] hw/usb/hcd-xhci: check the DCBAA read in Address Device Junjie Cao
2026-10-31 3:37 ` [PATCH 1/2] hw/usb/hcd-xhci: fail Address Device when the DCBAA entry is unreadable Junjie Cao
2026-10-31 3:37 ` Junjie Cao [this message]
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20261031033725.1275414-3-junjie.cao@linux.dev \
--to=junjie.cao@linux.dev \
--cc=farosas@suse.de \
--cc=lvivier@redhat.com \
--cc=pbonzini@redhat.com \
--cc=peter.maydell@linaro.org \
--cc=philmd@oss.qualcomm.com \
--cc=qemu-devel@nongnu.org \
--cc=thuth@redhat.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.