Artemis Milestone 2e: real connect drives Enable Slot, slot ID correlated

xhci_poll_events()'s Port Status Change connect branch now calls
xhci_cmd_enable_slot() directly (the earlier boot-time smoke test call is
gone), tracked via a new dev->pending_connect_port_id -- since this
driver only ever has one command outstanding at a time, that alone
identifies which port a later Command Completion Event answers, without
needing to match the Command TRB Pointer yet. On success the returned
Slot ID is recorded in a new dev->port_slot_id[], a fixed
uint32_t[XHCI_MAX_TRACKED_PORTS] (32) indexed by port. Disconnect clears
the port's tracked slot (real teardown -- Disable Slot, DCBAA clear,
Section U callback -- is still a later increment).

Fixed array, not heap-allocated: a first attempt sized port_slot_id
dynamically via kmalloc_aligned(dev->max_ports * sizeof(uint32_t), 64)
inside xhci_bringup() and it crashed amd64 with a page fault (IFETCH at
RIP=CR2=0xA0000, the legacy VGA hole) during the unrelated Mama-VM-birth
phase afterward -- a heap-corruption signature, not chased to root cause.
Switching to a fixed array (matching this driver's existing preference
for fixed over dynamic allocation) made the crash go away; the crashing
boot's log is kept (logs/20260822-102516/) as the evidence trail.

Verified live via QMP hotplug, all three architectures: connect ->
"enable slot command submitted" -> "enable slot succeeded", with a
disconnect/reconnect cycle repeating cleanly and no port wedge.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01HZ8kNoTuP63pbQtro4qvrm
This commit is contained in:
Robert Allan James
2026-08-22 10:33:37 -04:00
co-authored by Claude Sonnet 5
parent dd043bbfeb
commit 6d330efdd8
12 changed files with 36185 additions and 27 deletions
+37 -7
View File
@@ -3207,8 +3207,9 @@ Final three-arch acceptance (probe-free, `clean qemu`): all three boot to `ok>`
**2e. Hotplug detection (the actual trigger for everything in Section U)**
- [x] On a Port Status Change event, read the corresponding Port Register to determine
connect vs. disconnect — **done 2026-08-22**, see writeup below
- [ ] On connect: allocate a Device Slot (Enable Slot command via the Command Ring), address
the device (Address Device command), read its device descriptor
- [x] On connect: allocate a Device Slot (Enable Slot command via the Command Ring) — **Enable
Slot done 2026-08-22**, see writeup below; Address Device + device descriptor read still
open (needs enumeration groundwork from 2f)
- [ ] On disconnect: tear down the corresponding device slot and signal to whatever higher-
level code (Section U's identity/VM logic) that the device is gone — **this is the
first point where Section U/V's design actually gets a real trigger to hang off**
@@ -3251,11 +3252,40 @@ Full connect→disconnect→connect cycle confirmed on amd64
(`logs/20260822-100654/amd64/`); single connect confirmed on aarch64
(`logs/20260822-100814/aarch64/`) and riscv64 (`logs/20260822-100940/riscv64/`).
Still open: correlating the Command Completion Event back to its issuing command (currently
only logged, slot ID/context bookkeeping not read from the event TRB), actually calling Enable
Slot / Address Device from the connect path above (today's Enable Slot call remains the
boot-time smoke test from the previous increment, not yet triggered by a real connect event),
and the callback surface into Section U's higher-level code.
**Connect -> Enable Slot -> slot correlation, done 2026-08-22.** The boot-time smoke test call
is gone; a real connect event now drives `xhci_cmd_enable_slot()` directly from
`xhci_poll_events()`'s PSC branch. Correlation between "which port asked for a slot" and "which
Command Completion Event answered" uses a new `dev->pending_connect_port_id` (0 = idle, else
the port whose Enable Slot is outstanding) rather than matching the Command TRB Pointer in the
completion's `parameter` field — sound today because this driver only ever has one command
in flight (synchronous with respect to connect events, not a queue); revisit with real TRB
Pointer matching once Address Device commands can also be outstanding concurrently. On success
the returned Slot ID (`XHCI_EVT_SLOT_ID()`, decoded from `control[31:24]`) is recorded in a new
`dev->port_slot_id[]`, indexed by port — a **fixed** `uint32_t[XHCI_MAX_TRACKED_PORTS]` (32),
not heap-allocated. That fixed-size choice wasn't cosmetic: a first attempt sized this
dynamically via `kmalloc_aligned(dev->max_ports * sizeof(uint32_t), 64)` inside
`xhci_bringup()` and it crashed on amd64 — a page fault (`IFETCH` at `RIP=CR2=0xA0000`,
inside the legacy VGA hole) during the unrelated Mama-VM-birth phase that runs afterward,
strongly suggesting heap corruption rather than a fault in the new code itself. Root cause not
chased further — reverting to a fixed array matching this driver's own existing preference
(xhci.h's ring-sizing rationale) sidesteps the heap interaction entirely and is simpler besides.
If a future device genuinely needs >32 tracked ports, that heap interaction needs revisiting
before growing this array dynamically again.
Disconnect clears the port's tracked slot ID (real teardown — Disable Slot command, DCBAA entry
clear, Section U callback — is still a later increment; this only stops treating the port as
occupied so a future connect on it isn't confused for one already in progress).
Verified live via QMP hotplug, all three architectures: connect logs `port status change --
device connected` -> `enable slot command submitted` -> `enable slot succeeded`; a
disconnect/reconnect cycle repeats cleanly with no wedge. Full cycle on amd64
(`logs/20260822-102849/amd64/`); single connect confirmed on aarch64
(`logs/20260822-103005/aarch64/`) and riscv64 (`logs/20260822-103137/riscv64/`).
Still open: correlating the Command Completion Event back to its issuing command via the real
Command TRB Pointer (not needed yet, see above), Address Device + device descriptor read
(needs 2f's enumeration groundwork), and the callback surface into Section U's higher-level
code.
**2f. USB device enumeration (post-connect, before it's usable as storage)**
- [ ] Request and parse the device descriptor (confirm vendor/product IDs are even needed,