Give each xHCI usb-storage device its own port; fix stale ZUSEDISK default
Build / build-amd64-iso (push) Waiting to run
Build / build-aarch64-iso (push) Waiting to run
Build / build-riscv64-img (push) Waiting to run

FABRIC-3.md §IX.5's "4th-device enumeration failure" was never a driver
bug: QEMU's default qemu-xhci controller (p2=4,p3=4) exposes only 4 real
dual-role ports, not 8 as the parameter names suggest. Attaching more
devices than that on bus=xhci0.0 without an explicit port= makes QEMU
silently auto-insert a USB2 hub past the 4th slot; the xHCI/BOT driver
correctly reports that hub as "not a Mass Storage/SCSI/BOT device" because
it genuinely isn't one, and every drive behind it is unreachable (no hub
descent in this driver). Confirmed live via QEMU's own `info usb` before
touching any kernel code.

Fix is entirely in the QEMU test harness, not the kernel:
- New XHCI_PORTS Make variable (default 16, overridable) sizes p2/p3 on
  all three arches' qemu-xhci controller with real headroom above the
  current 9-device identity roster, per Bob's standing ruling against
  hardcoding a bound to today's scale (FABRIC-3.md §VII.4).
- ZUSEDISK_QEMU_ARGS now gives Zuse's drive an explicit port=1.
- QEMU_EXTRA's own doc comment shows the port= pattern for additional
  devices.

Also fixed in passing: ZUSEDISK's default path (disk/zuse.img) was stale
-- that file was deleted from git at c3db963, superseded by
disk/thumbdrives/zuse-thumb-ident.img, but the Makefile default was never
updated, so a plain `make qemu` silently failed to attach Zuse at all.
Now defaults to the real minted image.

Not addressed here, flagged for later: scripts/bleach_zuse_img.sh and
disk/README.md still reference the deleted disk/zuse.img path. The
9-device concurrent enumeration itself (the scenario that originally
surfaced §IX.5) remains unverified against the real kernel -- this change
only confirms single-device boots are unaffected on all three arches.

Three-arch clean qemu acceptance passed (single Zuse device, port 1):
amd64, aarch64, riscv64 all reached POST: PASSED / PARITY:OK / "Zuse:
identity confirmed from attached thumbdrive" / (zuse) ok>.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_014Ec88YKxxhZGG1RNnune78
This commit is contained in:
Robert Allan James
2026-09-06 20:24:05 -04:00
co-authored by Claude Sonnet 5
parent 2c1b3cd695
commit 30c26ade3d
14 changed files with 71885 additions and 7 deletions
+31 -6
View File
@@ -105,6 +105,20 @@ DOE_LATEST_DIR := experiments/bare_metal/latest
CAPSULES_DIR ?= capsules
ARTDISK ?= disk/artemis.img
# XHCI_PORTS -- real top-level port count the qemu-xhci controller exposes on the
# xhci0.0 bus (p2 == p3 == this value; these are the SAME physical dual-role ports
# counted from the USB2 and USB3 register sets respectively, NOT additive to p2+p3 --
# confirmed live 2026-09-06, the stock default p2=4,p3=4 exposes exactly 4 real ports,
# not 8). Every usb-storage device attached below or via QEMU_EXTRA must get its own
# explicit port=N less than this value: exceed it and QEMU silently drops the overflow
# onto an auto-inserted internal USB2 hub, which the xHCI/BOT driver correctly refuses
# to treat as Mass Storage (root cause of the FABRIC-3.md §IX.5 "4th-device enumeration
# failure" -- misread as a driver bug at the time, it never was one). Sized with real
# headroom above the current 9-device identity roster (Zuse + 8 minted identities)
# rather than matching it exactly, per Bob's standing ruling against hardcoding a bound
# to today's scale (FABRIC-3.md §VII.4). Override if a future test needs more, e.g.
# `make -f Makefile.starkernel qemu XHCI_PORTS=32`.
XHCI_PORTS ?= 16
# ZUSEDISK -- Zuse's own minted USB thumbdrive, attached by default so a
# plain `make qemu` lands already authenticated into the Zuse identity
# (Captain Bob, 2026-08-28). Attached at QEMU launch time via -drive/
@@ -114,7 +128,7 @@ ARTDISK ?= disk/artemis.img
# xhci_poll_events() alone is purely hotplug-event-driven and would never
# see a device present before controller reset. Override to "" (empty) to
# boot without Zuse attached, e.g. `make -f Makefile.starkernel qemu ZUSEDISK=`.
ZUSEDISK ?= disk/zuse.img
ZUSEDISK ?= disk/thumbdrives/zuse-thumb-ident.img
# Precomputed (not inlined as $(if ...,...)) because the drive/device specs
# below are comma-heavy and GNU make's $(if) function splits its own
# arguments on every top-level comma -- inlining it silently truncated the
@@ -122,7 +136,7 @@ ZUSEDISK ?= disk/zuse.img
# dropped, confirmed live via `ps aux` showing the truncated qemu command
# line (2026-08-28).
ifneq ($(strip $(ZUSEDISK)),)
ZUSEDISK_QEMU_ARGS := -drive if=none,id=zusedrv,file=$(ZUSEDISK),format=raw -device usb-storage,bus=xhci0.0,drive=zusedrv
ZUSEDISK_QEMU_ARGS := -drive if=none,id=zusedrv,file=$(ZUSEDISK),format=raw -device usb-storage,bus=xhci0.0,port=1,drive=zusedrv
else
ZUSEDISK_QEMU_ARGS :=
endif
@@ -768,7 +782,18 @@ QEMU_DISPLAY ?= gtk
# boot). Existing use: attaching a disposable USB test image for WRITE(10)
# validation, e.g.
# QEMU_EXTRA="-drive if=none,id=usbtest,file=disk/usbwrite-test.img,format=raw \
# -device usb-storage,bus=xhci0.0,drive=usbtest"
# -device usb-storage,bus=xhci0.0,port=2,drive=usbtest"
# Give every extra usb-storage device its own explicit port= (ZUSEDISK_QEMU_ARGS
# above already claims port 1), distinct from every other device attached on
# bus=xhci0.0 -- without it, QEMU's own port auto-assignment fills the
# controller's real top-level ports in device order and then silently drops
# any further device behind an auto-inserted internal USB2 hub, which the
# xHCI/BOT driver correctly refuses to treat as Mass Storage (confirmed live,
# 2026-09-06, root cause of the FABRIC-3.md §IX.5 "4th-device enumeration
# failure" -- it was never a driver bug, the emulated controller only exposes
# 4 real ports for p2=4,p3=4 despite the port count parameters implying 8).
# The qemu-xhci controller below is sized via XHCI_PORTS (see its own doc comment
# above) to give real ports to Zuse plus every identity drive attached this way.
QEMU_EXTRA ?=
qemu: all
@@ -816,7 +841,7 @@ ifeq ($(ARCH),amd64)
-cdrom $(QEMU_ISO) -boot d \
-drive id=artdisk,file=$(ARTDISK),format=raw,if=none \
-device virtio-blk-pci,drive=artdisk \
-device qemu-xhci,id=xhci0 \
-device qemu-xhci,id=xhci0,p2=$(XHCI_PORTS),p3=$(XHCI_PORTS) \
$(ZUSEDISK_QEMU_ARGS) \
-object rng-random,id=rng0,filename=/dev/urandom \
-device virtio-rng-pci,rng=rng0 \
@@ -900,7 +925,7 @@ else ifeq ($(ARCH),aarch64)
-drive id=artdisk,file=$(ARTDISK),format=raw,if=none \
-device virtio-blk-pci,drive=artdisk \
-device virtio-keyboard-pci,addr=0x3 \
-device qemu-xhci,id=xhci0,addr=0x4 \
-device qemu-xhci,id=xhci0,addr=0x4,p2=$(XHCI_PORTS),p3=$(XHCI_PORTS) \
$(ZUSEDISK_QEMU_ARGS) \
-object rng-random,id=rng0,filename=/dev/urandom \
-device virtio-rng-pci,rng=rng0,addr=0x5 \
@@ -990,7 +1015,7 @@ else ifeq ($(ARCH),riscv64)
-drive id=artdisk,file=$(ARTDISK),format=raw,if=none \
-device virtio-blk-pci,drive=artdisk,addr=0x1 \
-device virtio-keyboard-pci,addr=0x3 \
-device qemu-xhci,id=xhci0,addr=0x4 \
-device qemu-xhci,id=xhci0,addr=0x4,p2=$(XHCI_PORTS),p3=$(XHCI_PORTS) \
$(ZUSEDISK_QEMU_ARGS) \
-object rng-random,id=rng0,filename=/dev/urandom \
-device virtio-rng-pci,rng=rng0,addr=0x5 \