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
Closes the contributor-capsule/trust-tier punch-list item. Decided
direction: QEMU-vs-real-hardware conditional enforcement.
Found before building on that decision: the obvious mechanism (expose
TimerInfo.vm_mode) only works on amd64 -- aarch64 and riscv64 both had
vm_mode hardcoded to 1 unconditionally, meaning they'd always report
"running under QEMU" even on real hardware. Built real detection for
both instead of shipping that: aarch64 checks the ACPI RSDP's OEM ID
for QEMU's "BOCHS " SeaBIOS-heritage signature; riscv64 checks the
devicetree root compatible property for "qemu". Confirmed vm_mode was
otherwise unread anywhere else in either file first -- zero risk to
existing timing behavior.
CAPSULE_FLAG_CONTRIB (mkcapsule.c: FLAG_CONTRIB) path-matches on
capsules/contrib/, mirroring FLAG_MAMA_INIT's exact-match pattern.
contrib_capsule_refused() (capsule_birth.c) enforces: no additional
check under QEMU (same WARN-only as everything else); on real hardware,
a contrib capsule additionally requires CAPSULE_SIG_OK, since it has no
other provenance to fall back on. Wired into capsule_birth_baby() and
capsule_run_experiment().
Also updates §I.7 (Milestone 9): its stated precondition (Milestone 7
closing) is now met, flagged as stale rather than treated as a green
light to design networking from nothing.
Verified 3-arch boot to ok> (amd64/aarch64/riscv64, each in the
foreground) -- compile/boot verification only; the real-hardware
enforcement branch is unverifiable from this environment, same as all
of §I.6. 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
Introduces src/starkernel/heartbeat.c as the shared top/bottom-half
implementation of heartbeat_init/tick/service/ticks/trust/state, replacing
the per-architecture duplicates in amd64/riscv64/aarch64 timer.c. Each
arch's timer.c now contributes only heartbeat_read_counter() (rdtsc /
rdtime / CNTPCT_EL0). Per the GAP-A1 ruling the top half stays counter+
latch only; heartbeat_service() (called every REPL idle iteration,
unconditionally per FABRIC.md's fidelity note) does the window/variance/
trust work outside interrupt context. vm_tick()'s call sites are
unchanged -- the engine still runs on the virtual tick.
Per FABRIC.md §26 (ruled 2026-08-03): wires Loop #7's execution-derived
stable/volatile signal into the physical re-arm period. vm_runtime.c's
existing Loop #7 site now calls heartbeat_set_adaptive_period_ns() with
tick_target_ns ratio-rescaled onto a 10ms kernel base (not the hosted
10us HEARTBEAT_TICK_NS -- see §26.3 for the scale mismatch). Each
architecture's re-arm function (apic_timer_rearm() on amd64/aarch64,
riscv64_timer_rearm()) now converts heartbeat_next_period_ns() to its
own raw counter units instead of a fixed constant; amd64 gained a
rearm function it didn't previously need, since periodic-mode auto-reload
never required one before this item.
Verified: all three architectures build with no new warnings and boot
cleanly to ok> with dict_hash=0x3d4e1daf289da94f, unchanged from the
pre-change baseline -- no regression. Verified NOT achieved: live re-arm
period variation under load. A temporary diagnostic (added and reverted)
confirmed Loop #7 never actually fired during a live QEMU session -- a
synthetic word-execution loop drove ~6,500 executions, past the 1000-tick
inference frequency, without tripping vm_tick_inference_engine()'s
pre-existing !vm->rolling_window.is_warm gate. That gate predates this
item and was not investigated -- out of scope. FABRIC.md's Done-when is
amended to record this honestly rather than claim it.
Punch list §25 item 0.8 complete (per amended, weaker acceptance -- see
the item's own annotation).
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Punch list §25 item 0.3 complete.
The functional work (FDT reader, `time` CSR switch, SBI TIME extension
arm/re-arm, sie.STIE) was committed separately by Captain Bob as accd79f,
honestly labeled "NOT complete." This finishes it: stale documentation
cleanup, then rigorous verification against the item's literal acceptance
text, which the prior commit had not yet done.
Doc cleanup: every remaining reference to `rdcycle` / "assumed 1 GHz" in
riscv64/timer.c and riscv64/apic.c rewritten to describe the actual `time`
CSR / SBI-armed behavior. Caught and corrected my own arithmetic error in
the process: a draft claimed the ns-overflow bound improved to "~58 years"
under the new counter; direct computation shows the bound is actually
~3.26 days (2^48 ns) and is *frequency-independent* -- s_ns_per_tick and
tick rate scale inversely and cancel. Verified with a script before
writing the final comment, not asserted.
Verification, since "boots to prompt" was not sufficient for this item's
acceptance ("heartbeat_ticks() advances ... within measurement noise"):
- No FORTH word exposes heartbeat_ticks() to the REPL, and adding one would
be a new primitive outside this item's scope. GDB-over-QEMU-stub reads of
the static counter failed ("Cannot access memory"), likely a virtual-vs-
runtime address mismatch; abandoned rather than debugged further, since a
better instrument was available.
- QEMU's own `-d int` trap tracing (independent of all guest code) shows
2,797 `cause:5 desc=s_timer` interrupts delivered by the time boot reaches
the prompt, and the interleaved `desc=supervisor_ecall` entries are exactly
the SBI set_timer calls from riscv64_timer_rearm(), confirming the full
interrupt -> handler -> re-arm -> SBI loop.
- Measured rate over a real 10.127 s window: 1,013 further interrupts,
100.028 Hz observed against 100 Hz configured -- 0.03% deviation. The
sustained, non-decaying rate is itself proof the one-shot re-arm succeeds
on every cycle, not just the first.
- Confirmed regression-free on amd64 and aarch64 too: uefi_loader.c, uefi.h,
boot_info_offsets.h and the new fdt.c/fdt.h are shared across all three
builds (amd64 also consumes the offset constants via kernel_entry.S), so
all three were rebuilt and booted. Identical dict_hash
0x3d4e1daf289da94f on all three, matching the item 0.1/0.2 baseline.
Reported, not fixed, per rule 3:
- DOE_INJECT=1's EXEC-DOE now fails as "UNKNOWN WORD" against the pruned
Hera-alone capsule -- doe.4th was never loaded by init.4th even before
item 0.1's prune, so this is a pre-existing gap the prune surfaced, not a
new defect. Discovered while chasing why a 200-rep injected DoE run
produced no new CSV rows after 25 minutes; it had failed in the first
millisecond, not run the whole time.
- repl.c's own comment claims a "Heartbeat: N ticks" diagnostic prints to
the serial log; no such print exists anywhere in the tree.
- riscv64/arch.c's arch_read_timestamp() still uses rdcycle with a stale
1 GHz comment, but it has zero callers on this architecture -- dead code,
left alone.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Punch list §25 item 0.3 NOT complete.
- Added `starkernel/fdt.h` and `fdt.c` for minimal read-only devicetree parsing: sufficient for boot-time lookups such as `timebase-frequency`.
- Bootloader now captures the devicetree blob (DTB) from `EFI_DTB_TABLE_GUID` into `BootInfo::dtb`.
- RISC-V timer subsystem now uses the `time` CSR as the primary timestamp source, abandoning the hardcoded `cycle` frequency assumption.
- Timer rate is read from `timebase-frequency` in the DTB when accessible; otherwise, a fallback value is used with a RELATIVE trust level.
- Integrated the SBI TIME extension for one-shot timer deadlines, ensuring re-arming occurs after each tick to avoid missing heartbeats.
Verified: riscv64 builds clean, boots to the ok> prompt with no regression; `riscv64/timer.c` reports accurate frequencies on QEMU's default firmware.
Signed-off-by: Robert Allan James <robert.allan.james@gmail.com>