Artemis Milestone 2h: blkio_usb.c backend -- USB thumb drive is now a real block device

Wires a hot-plugged USB Mass Storage device into the block subsystem's
unified LBN chain. blkio_usb.c/blkio_usb.h mirror virtio_blk.c/
virtio_blk.h's established shape exactly (singleton state, blkio_vtable_t,
a blkio_usb_open_msc() "find" function playing virtio_blk_find_artemis()'s
role): read() translates a Forth block into a SCSI LBA/count pair and
calls xhci_bot_read_block() + xhci_bot_wait_for_idle(); write() returns
BLKIO_ENOSUP (no SCSI WRITE(10) exists yet, and blk_format_or_load_disk()
never writes at attach time, so read-only is sufficient -- confirmed by
reading that function first, not assumed). Refuses (-2) if the reported
SCSI block size doesn't evenly divide the 1024-byte Forth block size.

Connect-time wiring reuses the bot_msc_attach_pending/consume-in-
sk_repl_idle() shape the prior increment's temp probe already validated,
now made permanent: SET_CONFIGURATION sets the flag, sk_repl_idle()
(strictly after its own xhci_poll_events() call returns) calls
blkio_usb_open_msc() then blk_subsys_attach_device().

Verified live via hot-attach: full chain from USB connect through
'blkio_usb: MSC device ready' to 'blk: disk 'StarForth Volume' v2 LBN
26074..75184 (49111 user blocks)' -- real attachment, disk image confirmed
byte-for-byte untouched after. Chased a real debugging detour along the
way: the attach initially appeared silent (no blk: log line) -- traced to
LOG_INFO filtering at the default LOG_WARN boot level, not a functional
bug (settled via a temporary log-level bump, reverted after capture; also
found and reported, but did not fix, a pre-existing unrelated
Makefile.starkernel bug where --log-level=info via KERNEL_ARGS breaks
printf parsing). All three architectures re-verified clean. FABRIC-2.md
Section X 2h updated -- only hot-detach remains for 2h.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01CXjAPTEKrgY2Mrk25KoLDn
This commit is contained in:
Robert Allan James
2026-08-25 12:55:53 -04:00
co-authored by Claude Sonnet 5
parent d686f28853
commit 3b085dd875
17 changed files with 46077 additions and 9 deletions
+68 -8
View File
@@ -3699,14 +3699,15 @@ afterward, all three architectures, clean boots with no BOT activity: `logs/2026
`logs/20260825-114114/aarch64/`, `logs/20260825-114321/riscv64/`.
**2h. Integration with the existing block subsystem**
- [ ] Wire a working USB MSC device into `blk_subsys_attach_device()` (or
- [x] Wire a working USB MSC device into `blk_subsys_attach_device()` (or
`blk_subsys_add_raw_device()`, whichever fits — confirm which, since USB is
persistent+removable, a hybrid of the two existing categories) — this is the point
where Milestone 2's work actually becomes visible to everything in Section U/V's
block-layout design
- [ ] Confirm a plugged-in USB drive shows up in the LBN chain at the expected offset
block-layout design. **Done 2026-08-25**, `blk_subsys_attach_device()` confirmed the
right call (per the "Confirmed with Captain Bob" note below), see writeup below
- [x] Confirm a plugged-in USB drive shows up in the LBN chain at the expected offset
(today: attach-order-based, per Section V area A — item below in Milestone 3 changes
this to identity-derived)
this to identity-derived). **Done 2026-08-25** — see writeup below
**Confirmed with Captain Bob, 2026-08-22: `blk_subsys_attach_device()` is the right call, not
`blk_subsys_add_raw_device()`.** Re-read the `block_subsystem.c` header comment
@@ -3789,10 +3790,69 @@ permanent, reusable substrate for the next 2h increment (the actual `blkio_usb.c
Re-verified probe-free afterward, all three architectures, clean boots with no BOT activity:
`logs/20260825-122016/amd64/`, `logs/20260825-122318/aarch64/`, `logs/20260825-122527/riscv64/`.
Still ahead for 2h: the `blkio_usb.c` backend itself (per `blk_format_or_load_disk()`'s own
"NEVER writes to disk here" discipline at attach time, a read-only backend is sufficient to land
first — WRITE(10) doesn't exist in this driver yet and isn't a prerequisite), the connect-time
call site wiring a ready `blkio_dev*` into `blk_subsys_attach_device()`, and the hot-detach path.
**`blkio_usb.c` backend + connect-time attach, done 2026-08-25 — a USB thumb drive is now a real
block device.** `src/starkernel/usb/blkio_usb.c`/`include/starkernel/blkio_usb.h` mirror
`virtio_blk.c`/`virtio_blk.h`'s own established shape exactly (singleton state struct,
`static const blkio_vtable_t`, a `blkio_usb_open_msc()` "find" function playing the same role
`virtio_blk_find_artemis()` does): `read()` translates a Forth block number into a SCSI LBA/
block-count pair (`lba = fblock * blocks_per_fblock`, matching `virtio_blk.h`'s own
`VBLK_SECTORS_PER_BLOK` precedent for the same 1 KiB-Forth-block-as-N-SCSI-blocks idea) and
calls `xhci_bot_read_block()` + `xhci_bot_wait_for_idle()`; `write()` returns `BLKIO_ENOSUP`
(no SCSI WRITE(10) exists in this driver yet, and per `blk_format_or_load_disk()`'s own "NEVER
writes to disk here" discipline at attach time, a read-only backend is sufficient — confirmed
by reading that function before writing any code, not assumed); `open()`/`info()` are cheap
(capacity discovery already happened in `blkio_usb_open_msc()` itself, matching `vblk_open()`'s
own precedent of not re-discovering what a "find" function already found). `blkio_usb_open_msc()`
refuses (`-2`) if the reported SCSI block size doesn't evenly divide `BLKIO_FORTH_BLOCK_SIZE`
(1024) — this backend has no way to serve a partial Forth block, so it refuses rather than
silently misbehaving (advisor-flagged before writing any code).
Connect-time wiring reuses the exact `bot_msc_attach_pending`/consume-in-`sk_repl_idle()` shape
the previous increment's temp probe already validated, just made permanent: the
SET_CONFIGURATION completion handler sets the flag once a device is confirmed Mass Storage/BOT
and configured; `sk_repl_idle()`, strictly after its own `xhci_poll_events()` call has already
returned, consumes it by calling `blkio_usb_open_msc()` then `blk_subsys_attach_device()` — both
synchronous, both requiring the same "outside `xhci_poll_events()`'s own call frame" constraint
`xhci_bot_wait_for_idle()` itself carries.
**A real, if minor, debugging detour: the attach appeared to silently do nothing.** First live
run (`logs/20260825-123339/amd64/`) showed the full TUR→READ CAPACITY10→PASS→`blkio_usb: MSC
device ready`→four TUR+READ10 cycles (the block subsystem's own 4 KiB header read, one cycle per
1 KiB Forth block) — but no `blk: disk ...`/`blk: unrecognised ...` line ever appeared, and
nothing else looked wrong either. Traced to `blk_subsys_attach_device()`'s own success log being
`LOG_INFO`, filtered at this kernel's default `LOG_WARN` boot level — confirmed by grepping the
same log for the *existing* virtio-blk/Artemis attach's own `blk: disk ...` line from earlier in
the same boot and finding it equally absent, ruling out a regression before chasing one. Passing
`--log-level=info` via `KERNEL_ARGS` turned out to be a dead end (a pre-existing, unrelated
`Makefile.starkernel` bug: `printf '$(KERNEL_ARGS)\n'` misparses any value starting with `--` as
a `printf` option itself, and GNU Make strips leading whitespace from command-line variable
assignments too, so no quoting trick routes around it from the command line — reported here per
this project's "report broken tooling, don't silently fix it unprompted" convention, not fixed).
Settled instead by temporarily bumping `kernel_main.c`'s compiled-in default from `LOG_WARN` to
`LOG_INFO` for one diagnostic boot (marked `TEMP PROBE`, reverted immediately after capture, same
discipline as every other probe in this project) — `logs/20260825-123803/amd64/` is that run,
and it settled the question cleanly: `blk: disk 'StarForth Volume' v2 LBN 26074..75184 (49111
user blocks); devblocks=16384 bam=2 base=3 total=49143 free=49111`, appended right after the
existing RAM/ramdrive/Artemis `blk:` lines in the same unified LBN chain — the USB drive was
attached correctly the entire time, this was purely a log-visibility artifact, not a functional
bug. `git status`/`sha256sum` on `disk/usb-thumbdrive-test.img` after this run confirmed the
image byte-for-byte unchanged, as expected for a read-only backend. `PROVISIONAL` (not
`FORMATTED`) is the correct outcome here too — the label reads `"StarForth Volume"` regardless of
format state (it's `blk_compute_fresh_geometry()`'s own fixed placeholder string for *any* fresh/
unrecognized disk, not something read back off this blank test image, confirmed by grepping
`block_subsystem.c` itself rather than assumed from the log line alone).
Reverted the diagnostic log-level bump; rebuilt and re-verified live via hot-attach one more time
with the reverted (default `LOG_WARN`) tree to confirm the attach still succeeds without the INFO
logging crutch (it does — same silent-but-working behavior as the very first run). All three
architectures then re-verified clean with nothing hot-attached (this backend has no boot-time
call site of its own — USB is inherently hotplug, so a boot with no device connected exercises
none of this new code, same as every earlier BOT increment's own probe-free acceptance runs):
`logs/20260825-124143/amd64/`, `logs/20260825-124323/aarch64/`, `logs/20260825-124909/riscv64/`.
Still ahead for 2h: only the hot-**detach** path remains — `chain_append()` only adds, there is
no removal function yet (Section V area A's identity-derived-offset work in Milestone 3 is a
separate, later concern, not blocking here).
### Milestone 3 — Block subsystem extensions (Section U items 3-6, Section V area A)