A second usb-storage device (a generated data volume, serial da7a0001,
an empty FAT with no /system) plugged in beside the boot volume: the
volume manager adopts both devices and spawns a confined fat per volume,
each mounted at its own content id-path.
The test surfaced a real coexistence bug. Every filesystem bound the
single "vfs" contract name under /protocol; the second volume's fat lost
the race, service.run refused-and-exited on the held name, and that
volume never mounted. Clients don't reach filesystems by that name —
fs_resolve routes a path to its backing endpoint through the kernel
mount table by prefix — and nothing consumes "vfs", so the fix is to
bind no shared name: the harness's service_name now defaults to null.
This is the "this fades" the harness comment anticipated for the
volume-manager era; a filesystem's endpoint still serves as its mount
backend without a name.
fat logs "is a data volume" for the non-system branch so the test can
positively assert content-based detection. make-fat-image gains
--serial/--label (default unchanged) so a second image gets a distinct
id-path; the data image is generated per run, never committed. The case
fails against the pre-fix harness (the data volume's fat exits on the
refused bind) — toggle-demonstrated.
Full suite 129/129 (128 + two-volumes); the single-volume path is
unaffected by dropping the vestigial name bind.
The EFI loader now ENUMERATES /system rather than opening files by name,
so the on-disk name must be exact, not merely case-insensitively
findable. make-fat-image.py stored 8.3-fitting lowercase names as bare
uppercase short entries ('init' -> INIT), garbling the ramdisk paths;
now any name whose case the 8.3 entry cannot reproduce gets a long-name
chain carrying the exact name.
device-manager's driver table stored names in 24 bytes — silently
truncating '/system/drivers/usb-xhci-bus' and failing the spawn; widen
to 64 (= abi.maximum_process_name). The usb-report harness regex learns
that restart lines name drivers by path.
The system now boots off a real FAT32 filesystem on a USB mass-storage device
instead of QEMU's synthesized VVFAT drive. A new in-repo image builder formats
that filesystem from the FHS boot tree, and both QEMU call sites (the run step
and the test harness) attach it as a usb-storage device on the xHCI bus, so
every boot exercises the full USB path OVMF -> BOOTX64.efi -> kernel.
- tools/make-fat-image.py: a Python 3 stdlib-only FAT32 formatter (mirrors
tools/make-initial-ramdisk.py — no external host dependencies). It lays down
the boot sector + BPB/EBPB32, FSInfo, backup boot sector, two FATs, and the
root/subdir/file cluster chains, emitting long-name entries where a name is
not 8.3. Packs the four boot inputs (EFI/BOOT/BOOTX64.efi, system/kernel,
system/services/init, boot/initial-ramdisk.img) into their boot paths. A
--verify subcommand re-checks the 0xAA55 signature, recomputes the cluster
count -> FAT32, and resolves EFI/BOOT/BOOTX64.efi, all with no dependencies.
- build.zig: a mk_fat step builds zig-out/danos-usb.img from the four boot
artifacts (so changing -Dtest-case rebuilds the image with that kernel), a
check-fat-image step runs --verify, and run-x86-64 boots the image on a
usb-storage device (if=none,id=bootusb + usb-storage,bus=xhci.0,bootindex=0),
keeping usb-kbd/usb-mouse on the same controller.
- test/qemu_test.py: the default boot config now boots off danos-usb.img on a
usb-storage device (xHCI + usb-kbd + usb-mouse + the boot stick). The seven
per-case qemu_extra blocks that added their own qemu-xhci/usb-kbd/usb-mouse
(or a VVFAT stick) collided on id=xhci and are removed — the default provides
the bus and the boot device. usb-storage and fat-mount now exercise the real
FAT32 boot image (usb-storage reads its 0x55AA boot sector; fat mounts it at
/mnt/usb). A build_case override lets a case reuse another's kernel, used by a
new usb-boot case: an explicit, named boot-from-USB regression guard.
Verified: zig build, zig build test, and zig build check-fat-image are green
(FAT32, 128992 clusters, BOOTX64.efi present); a broad sequential QEMU sweep
passes — smoke, init, vfs, input, device-manager, usb-report, usb-hid,
usb-storage, fat-mount, device-list, driver-restart, acpi-report, iommu,
orderly-shutdown, usb-boot, dma, msi, initial-ramdisk, args, process — proving
the boot switch holds across kernel tests, the full init tree, the USB stack,
the FAT mount, and orderly shutdown.