Root cause (found by a fresh subagent after an extended live-debugging
investigation into "identity 00 attaches slowly/stalls when Zuse never
attached first this boot"): blk_migration_idle_check() was generalized
earlier today to walk every attached device slot uniformly instead of
hardcoding first_disk_slot() (Artemis's own disk). But its per-slot scan
can only early-exit once it finds a devblock that is BOTH "hot" (claimed
and worn) AND "free" -- and a just-attached, never-claimed USB identity
drive can never satisfy the "hot" half by design (claiming only ever
happens via blk_firsttouch_claim(), which only ever targets
first_disk_slot()). So the scan ran to completion -- the drive's entire
~16,000 devblocks, mostly cache misses over slow emulated USB/BOT --
every single idle tick, forever, blocking sk_repl_idle() (and therefore
the console and the storage-attach message round-trip) each time.
Fix, in src/block_subsystem.c: a new has_ever_claimed flag on
blk_dev_slot_t (set in blk_set_meta(), the single choke point every
BLK_FLAG_CLAIMED transition passes through) skips the scan entirely,
O(1), for any slot nothing has ever claimed -- the common case for a
freshly-attached drive. A new migration_scan_lbn resume cursor bounds
*any* slot's per-tick cost to MIGRATION_SCAN_BUDGET (256) devblocks
examined, picking up where the previous tick left off instead of
restarting from start_lbn every time -- restores this function's own
documented "coarse cadence, cheap early-exit" design intent for every
device, not just the one it used to hardcode.
Also along the way (kept, all real improvements, verified live):
- src/starkernel/usb/xhci.c: xhci_wait_bit()/xhci_bot_wait_for_idle()
had zero yield hints in their MMIO-polling loops; added arch_relax()
to both (matches virtio_blk.c below) -- a tight loop of nothing but
MMIO reads can starve TCG's own host-side timer injection under QEMU.
- src/starkernel/virtio/virtio_blk.c: vblk_io()'s spin bound was 33M
iterations with zero logging on timeout; a single real (still not
fully root-caused) timeout cost 31+ minutes of CPU before this was
caught. Reduced to 1M and added a log line naming the failing sector,
turning a silent, effectively-unbounded stall into a fast, loud
failure -- callers already tolerate BLKIO_EIO.
- src/starkernel/repl.c: blk_migration_idle_check() deferred for any
idle tick where a storage-attach message round-trip is still pending,
to keep the two block-subsystem-touching paths from interleaving; the
existing MSG-TICK pump now checks the target VM's own dictionary for
MSG-TICK (vm_find_word + acl_allow) before VM-EXECing into it, instead
of spamming "VM-EXEC: ERROR" every tick for a VM that doesn't have --
or isn't allowed -- the word (e.g. a FORTH-79/83-locked-down identity);
fixed a real -Wunused-variable build break in the EMERGENCY_CONSOLE_
ENABLED=1 path (unused today, but needed live to reproduce this bug
with no identity attached at all).
- src/starkernel/capsule/capsule_mint.c: dropped the dead
S" common:messaging.4th" EXEC / MSG-CD-INIT lines from
MINT_RESTRICTED_PERSONALITY -- a FORTH-79/83-locked-down identity has
no legitimate use for a messaging vocabulary it can never call.
Status: the pathological CPU-climbing scan is confirmed fixed (verified
live: CPU stays flat across an extended run instead of climbing without
bound). The WIREBIND storage-attach message round-trip still does not
complete promptly in the "Zuse never attached, other identity attaches
first" scenario -- a separate, still-open issue in the message-delivery
path itself, not the scan. Tracked as follow-on work.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_014Ec88YKxxhZGG1RNnune78
FABRIC.md -> FABRIC-0.md
FABRIC-2.md -> FABRIC-1.md
FABRIC-3.md -> FABRIC-2.md (the current/living document)
FABRIC-4.md unchanged (new #3 to follow separately)
Every cross-reference repo-wide updated to match, including doc-comment
citations inside kernel source (.c/.h) files -- done via an ordered
placeholder substitution (FABRIC-3.md->placeholder2, FABRIC-2.md->
placeholder1, FABRIC.md->placeholder0, then placeholders resolved to
final names) in a single pass per file to avoid double-shifting
already-renamed references.
One line in capsules/font.4th grew past the 64-char block-format limit
as a side effect of the longer filename; shortened it and reverified
with mkcapsule --lint (34/34 pass) before rebuilding.
Verified 3-arch boot to ok> (amd64/aarch64/riscv64, each in the
foreground) after the fix; logs and DoE CSVs from this session's
verification runs included per this repo's own audit-artifact
convention.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019YcT3H2PQeyujrzjqS3Var
Code review fixes, all compile clean (hosted gcc + aarch64/riscv64 kernel flags):
- repl.c (H1): reentrancy guards on the MSG-TICK idle pump. sk_repl_idle()
now defers when Hera is mid-interpret (g_mama_interpreting) or when its
own vm_interpret is on the stack (g_idle_pump_active), so a blocking
KEY/EXPECT/QUERY inside a dispatched line can no longer re-enter the
interpreter and clobber the in-flight input buffer.
- virtio_rng.c: clamp device-returned used_len to VRNG_BUF_SIZE before the
caller's data_buf copy, closing a device-controlled OOB read.
- block_subsystem.c: first-write path now keys off created_time==0 instead
of dead magic==0 so fresh blocks get a real created_time stamp; first_free/
last_allocated fixed to absolute Forth LBNs (set in blk_compute_fresh_geometry
from slot->start_lbn, no longer the wrong physical-BAM-index values from
compute_totals_from_B); physical-bounds guard on blk_meta_zone_read/write
prevents unsigned underflow on a corrupt fence >= device size.
- capsule_zuse_boot.c / capsule_wirebind.c: identity seed validated magic ->
version -> CRC-64 (compute_crc64 over offsetof(crc)) before trusting it,
so a corrupt/format-mismatched record is refused, never loaded.
- log.h / starkernel/log.h: unused LOG_LINE_MAX 256 renamed LOG_MSG_LINE_MAX
to lift the include-order collision with vm.h's LOG_LINE_MAX 64; stale
include-order comments dropped (kernel_main.c, shim.c, capsule_birth.c).
- FABRIC-3.md: three stale-doc carry-forward items closed [x] with cbe7b49
notes.
Real KEY/?TERMINAL/QUERY/EXPECT bodies (console WIP):
- repl.h/repl.c: sk_console_getkey()/sk_console_key_available()/
sk_console_readline() public bodies; non-destructive peek buffers the
found byte so a following KEY returns it.
- shim.c: getchar()/fgetc()/fgets()/sf_terminal_ready() routed through the
real console paths instead of stubs; sf_terminal_ready() in platform_io.h
with sf_terminal_ready() implemented for the hosted build (linux/io.c,
POSIX select on fd 0) wired into Makefile.
- io_words.c: ?TERMINAL now returns actual terminal-readiness, not constant 0.
Artifacts: minted disk/artemis.img + rebuilt lfs kernel; BLOCK_MAP.md,
doe csv + qemu log regenerated.
The kernel's ed25519_verify() is deliberately verify-only -- no signing,
no keygen, no entropy source. That conflicts with the on-device MINT
word vision (Zuse signing new user certs live at runtime), so this
reopens that constraint on request rather than reshaping MINT around
verify-only.
vm_uuid.h already found the real gap: amd64 has RDRAND, riscv64 has Zkr,
but QEMU's aarch64 CPU models have neither -- confirmed against QEMU
10.2.1. A deterministic PRNG (fine for VM UUIDs) is not safe for key
generation, so this adds a virtio-rng device instead of a per-arch split:
real host entropy, identical guest-side protocol on all three arches.
New src/starkernel/virtio/virtio_rng.c + include/starkernel/virtio_rng.h,
transport plumbing mirroring the existing virtio_blk.c driver exactly.
Wired into kernel_main.c boot, -device virtio-rng-pci added to all three
QEMU targets.
Verified live (temp probe, written/run/captured/reverted): 16 real bytes
pulled through the full request/notify/poll round trip on all three
arches, three different values confirming real entropy. Final boot
against the reverted, permanent code: clean compile, clean boot to ok>
on amd64/aarch64/riscv64, Stadium conservation intact, no panics or
guest errors.
Ed25519 keygen/signing itself (Phase B) and the MINT word design
(Phase C) remain open, documented in FABRIC-3.md.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01U14ET9CWAtbQMbYqomKgXd
Punch list §25 item 4.3.5e complete.
Extended virtio_input.c with a GIC-routed interrupt path alongside 4.3.5c's
PLIC one -- same capability walk, feature negotiation, eventq handling
(confirming §27.5.1's prediction that these items would share most of the
driver). aarch64_irq_handler() dispatches to virtio_input_isr() before its
EOIR write, same claim-dispatch-complete ordering riscv64 uses. Verified
with a real QEMU sendkey keypress: exact KEY_A/press match, two real
interrupts serviced, identical result to riscv64. Found (not fixed) an
unrelated pre-existing bug: BYE's cold-reset path faults on aarch64,
discovered incidentally since nobody had exercised it from a monitored
session before. Three-arch acceptance boot clean.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Punch list §25 item 4.3.5c complete.
Amended from a nonexistent MMIO transport to PCI (matching the board's
actual virtio-blk-pci precedent). New virtio-input driver: eventq with
pre-posted buffers, PLIC source computed at runtime from PCI slot/pin
(derived live from this host's QEMU riscv64 DTB), mandatory ISR-status
read, PCI interrupt-disable-bit check. New VKBD-EVENT/VKBD-DEBUG FORTH
words. Verified with a real QEMU sendkey keypress: exact KEY_A/press
match, two real interrupts serviced, zero exceptions. Three-arch
acceptance boot clean.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>