FABRIC.md: insert 4.3.5a -- riscv64 has no software-controlled paging
Discovered live while implementing what was 4.3.5a (PLIC bring-up, renumbered 4.3.5b): riscv64 never activates its own page table (load_cr3() is a no-op outside __x86_64__, arch.c's Sv39/SATP setup is an explicit stub), so firmware's own mapping -- which doesn't cover the PLIC's MMIO window -- is what's live for the kernel's whole lifetime. Confirmed via a live store-page-fault, not inferred. Per Captain Bob's ruling: stop, scope as its own item, decide the fix (Bare mode vs. real Sv39) in a future session rather than embedded in the PLIC item. 4.3.5b-4.3.5e renumbered accordingly (4.3.5f was 4.3.5e); no items were executed under the old numbering, so this is free to do cleanly now. Documentation only. PLIC driver code (plic.c/plic.h, interrupts.c/ apic.c wiring, Makefile.starkernel) is written and reviewed but stays uncommitted -- it cannot be verified until 4.3.5a unblocks it, and riscv64 currently hangs in the fatal exception handler with it applied. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Sonnet 5
parent
6a97fa4c98
commit
e01c4e33e4
@@ -3919,30 +3919,59 @@ document and committing that amendment as its own item.*
|
||||
> aarch64, `logs/20260808-001637` riscv64) — the feature is amd64-only this item, so
|
||||
> aarch64/riscv64 are a regression check, not a keyboard test.
|
||||
|
||||
- [ ] **4.3.5a — riscv64: PLIC bring-up (external interrupt controller).** Does not exist
|
||||
- [ ] **4.3.5a — riscv64: minimal paging/addressing bring-up (prerequisite, blocks
|
||||
4.3.5b).** Discovered live 2026-08-08 while implementing 4.3.5b, not anticipated when
|
||||
4.3.5a-4.3.5f were originally scoped. **riscv64 has no software-controlled paging at
|
||||
all.** `arch/riscv64/arch.c`'s own comment is explicit: "Full Sv39/Sv48 page-table setup
|
||||
(SATP, PMP, etc.) is deferred to a later milestone" — it is a stub, `satp` is never
|
||||
written by this kernel. Separately, `memory/vmm.c` (header comment: "4-level paging
|
||||
Virtual Memory Manager (x86_64)") runs its `vmm_init()` unconditionally on all three
|
||||
architectures and builds a real x86-64-style page table in memory, but its activation
|
||||
step (`load_cr3()`) compiles to a no-op outside `__x86_64__` — so on riscv64 that table
|
||||
is dead, unused data. Whatever `satp` firmware (EDK2 RISC-V) left active at
|
||||
`ExitBootServices()` is what's live for the kernel's entire lifetime, and there is no
|
||||
documented or safe way for us to add entries to firmware's own page table post-handoff.
|
||||
This surfaced because 4.3.5b's PLIC threshold register (`PLIC_BASE + 0x201000`, deep
|
||||
into the PLIC's 0x600000-byte MMIO window) is not covered by firmware's mapping —
|
||||
confirmed via a live store-page-fault (`scause=0xF`) at exactly that address, not
|
||||
inferred. **Not fixed as part of surfacing it** — Captain Bob's ruling 2026-08-08: stop,
|
||||
scope as its own item, decide the approach (Bare-mode `satp=0` vs. real Sv39 bring-up)
|
||||
in a future session with fresh context, rather than deciding it embedded inside a PLIC
|
||||
item. 4.3.5b's driver code (`plic.c`/`plic.h`, `interrupts.c`/`apic.c` wiring,
|
||||
`Makefile.starkernel`) exists, written and reviewed, but **uncommitted** — it cannot be
|
||||
verified until this item unblocks it, and 4.3.5b's own acceptance ("three-arch QEMU boot
|
||||
unaffected") is currently violated (riscv64 hangs in the fatal exception handler).
|
||||
*Done when:* riscv64 has some working address-translation story (either genuinely
|
||||
activated Sv39 paging with a kernel-owned page table, or an explicit, deliberate switch
|
||||
to Bare mode) sufficient for `plic_init()`'s existing MMIO writes to succeed without
|
||||
faulting, three-arch QEMU boot clean, log committed.
|
||||
*Refs:* §27.5.
|
||||
|
||||
- [ ] **4.3.5b — riscv64: PLIC bring-up (external interrupt controller).** Does not exist
|
||||
anywhere in this tree — Phase 0 (0.2/0.3) only ever enabled the S-mode *timer* interrupt
|
||||
(`sie.STIE`); external interrupts (`sie.SEIE`, bit 9) were never touched, and
|
||||
`interrupts.c`'s own comment ("the PLIC replaces both") describes the architecture, not
|
||||
anything implemented. This item enables `sie.SEIE`, programs the PLIC's per-source
|
||||
priority, the hart context's threshold and enable bits, and wires the trap handler's
|
||||
external-interrupt case to `PLIC claim` → dispatch → `PLIC complete`. Prerequisite for
|
||||
4.3.5b; no keyboard code in this item.
|
||||
4.3.5c; no keyboard code in this item. **Blocked on 4.3.5a** (see that item) — driver
|
||||
code already written, not yet verifiable.
|
||||
*Done when:* a synthetic/known external interrupt source claims and completes correctly
|
||||
through the PLIC on riscv64, three-arch QEMU boot unaffected, log committed.
|
||||
*Refs:* §27.5.
|
||||
|
||||
- [ ] **4.3.5b — riscv64: virtio-keyboard-device, interrupt-driven.** Add
|
||||
- [ ] **4.3.5c — riscv64: virtio-keyboard-device, interrupt-driven.** Add
|
||||
`virtio-keyboard-device` (MMIO virtio, matching the existing MMIO virtio-blk pattern on
|
||||
this board) to the riscv64 `qemu`/`qemu-esp` targets in `Makefile.starkernel`. New driver
|
||||
under `src/starkernel/virtio/` for the virtio-input device class — decode `EV_KEY` events
|
||||
off the input event virtqueue. Unlike `virtio_blk.c`'s synchronous poll-the-used-ring
|
||||
pattern, this device must be interrupt-driven end to end: the used-ring notification
|
||||
arrives via the PLIC path from 4.3.5a, not a poll loop. Built on 4.3.5a.
|
||||
arrives via the PLIC path from 4.3.5b, not a poll loop. Built on 4.3.5b.
|
||||
*Done when:* a keypress in QEMU on riscv64 produces a captured `EV_KEY` event via the
|
||||
interrupt path with no polling loop, three-arch QEMU boot unaffected, log committed.
|
||||
*Refs:* §27.5.
|
||||
|
||||
- [ ] **4.3.5c — aarch64: GIC SPI wiring for virtio-input.** Item 0.6 scoped the GIC to
|
||||
- [ ] **4.3.5d — aarch64: GIC SPI wiring for virtio-input.** Item 0.6 scoped the GIC to
|
||||
"one interrupt" (the timer PPI) on purpose and explicitly called a general GIC driver
|
||||
out of scope. A PCI-attached `virtio-keyboard-pci` device signals via legacy INTx, which
|
||||
is an SPI, not a PPI — a different GIC distributor path (SPI target-CPU and priority
|
||||
@@ -3953,18 +3982,18 @@ document and committing that amendment as its own item.*
|
||||
PCI device, three-arch QEMU boot unaffected, log committed.
|
||||
*Refs:* §27.5.
|
||||
|
||||
- [ ] **4.3.5d — aarch64: virtio-keyboard-pci, interrupt-driven.** Add `virtio-keyboard-pci`
|
||||
- [ ] **4.3.5e — aarch64: virtio-keyboard-pci, interrupt-driven.** Add `virtio-keyboard-pci`
|
||||
to the aarch64 `qemu`/`qemu-esp` targets — the existing `virtio-blk-pci` device proves the
|
||||
PCI bus is already enumerated (`pci.c`) on this board, so this rides the same bus, a new
|
||||
device class. Same virtio-input driver shape as 4.3.5b (shared code where the transport
|
||||
device class. Same virtio-input driver shape as 4.3.5c (shared code where the transport
|
||||
allows — MMIO vs. PCI config-space discovery differs, the event-queue/`EV_KEY` decode
|
||||
should not). Built on 4.3.5c.
|
||||
should not). Built on 4.3.5d.
|
||||
*Done when:* a keypress in QEMU on aarch64 produces a captured `EV_KEY` event via the
|
||||
interrupt path with no polling loop, three-arch QEMU boot unaffected, log committed.
|
||||
*Refs:* §27.5.
|
||||
|
||||
- [ ] **4.3.5e — Checkpoint: one keyboard abstraction, three architectures, no polling.**
|
||||
Converge 4.3.5/4.3.5b/4.3.5d behind a single scancode/keycode interface so the REPL
|
||||
- [ ] **4.3.5f — Checkpoint: one keyboard abstraction, three architectures, no polling.**
|
||||
Converge 4.3.5/4.3.5c/4.3.5e behind a single scancode/keycode interface so the REPL
|
||||
keyboard-input work (M8, outside Stadium) has one thing to call, not three. Stop and
|
||||
review here — same posture as 4.3.4 — before scoping REPL wiring.
|
||||
*Done when:* a keypress on all three architectures produces the same shape of event at
|
||||
@@ -3973,7 +4002,7 @@ document and committing that amendment as its own item.*
|
||||
three-arch QEMU boot, logs committed.
|
||||
*Refs:* §27.5.
|
||||
|
||||
> **Sequencing noted 2026-08-07, not yet scoped:** keyboard input (4.3.5–4.3.5e) →
|
||||
> **Sequencing noted 2026-08-07, not yet scoped:** keyboard input (4.3.5–4.3.5f) →
|
||||
> glyph rendering (stroke-based font capsules) → REPL — in that order, before the 4.4
|
||||
> Artemis boundary. Recorded so the order is not lost between sessions; neither glyph
|
||||
> rendering nor REPL has *Done when* criteria yet. Per §25.0 rule 2, each gets scoped in
|
||||
@@ -4352,7 +4381,7 @@ not a quick add. Stop and review here before scoping the next 4.3.x item. Out-of
|
||||
for 4.3.1–4.3.4 is recorded once, at the 4.3 punch-list entry itself (§25.5), not repeated
|
||||
per sub-item.
|
||||
|
||||
### 27.5 Keyboard input, interrupt-driven (4.3.5–4.3.5e)
|
||||
### 27.5 Keyboard input, interrupt-driven (4.3.5–4.3.5f)
|
||||
|
||||
Scoped 2026-08-07, next after the 4.3.4 checkpoint. Purpose: get a real keypress into the
|
||||
kernel with no polling anywhere in the path, so the REPL keyboard-input work (M8, tracked
|
||||
@@ -4360,7 +4389,7 @@ outside Stadium — see `.claude/CLAUDE.md`'s roadmap section) has something to
|
||||
section is groundwork only, same as 27.1–27.4 was for the framebuffer — it stops at "a
|
||||
keypress produces an event at a shared interface," not REPL line-editing, not a scancode-
|
||||
to-ASCII layout, not repeat/modifier-key semantics. Those are later items, scoped once
|
||||
4.3.5e is reviewed.
|
||||
4.3.5f is reviewed.
|
||||
|
||||
**Why this split is bigger than 4.3.3's three-way split.** 4.3.3/4.3.3a/4.3.3b all built on
|
||||
interrupt/timer substrate Phase 0 already finished. Keyboard input does not have that
|
||||
@@ -4373,11 +4402,16 @@ luxury on two of three architectures:
|
||||
- **riscv64** has never enabled external interrupts at all — Phase 0 (0.2/0.3) scoped
|
||||
strictly to the S-mode timer interrupt (`sie.STIE`). The PLIC (`sie.SEIE`, bit 9) is
|
||||
unimplemented; `interrupts.c`'s existing comment naming the PLIC describes the
|
||||
architecture, not working code. 4.3.5a is that bring-up, split out as its own item because
|
||||
it is substrate, not keyboard-specific — same shape as Phase 0's per-ISA items.
|
||||
architecture, not working code. 4.3.5b is that bring-up, split out as its own item because
|
||||
it is substrate, not keyboard-specific — same shape as Phase 0's per-ISA items. **Found
|
||||
2026-08-08 while implementing 4.3.5b: that substrate assumption itself had a substrate
|
||||
gap underneath it** — riscv64 has no software-controlled paging at all (see 4.3.5a,
|
||||
inserted ahead of the PLIC item once this surfaced). Phase 0 never needed to touch memory
|
||||
translation because the timer only ever touches CSRs and SBI calls, never MMIO; PLIC
|
||||
bring-up is the first riscv64 item to need a real MMIO write, and that is what exposed it.
|
||||
- **aarch64**'s GIC (item 0.6) was deliberately scoped to one PPI (the timer) and explicitly
|
||||
ruled a general GIC driver out of scope. A PCI `virtio-keyboard-pci` device signals via an
|
||||
SPI, a distinct GIC path 0.6 never touched. 4.3.5c is the minimal SPI extension, held to
|
||||
SPI, a distinct GIC path 0.6 never touched. 4.3.5d is the minimal SPI extension, held to
|
||||
the same narrow-scope discipline 0.6 used.
|
||||
|
||||
**Hardware path differs by architecture, same as the framebuffer did.** amd64's `q35`
|
||||
@@ -4385,13 +4419,13 @@ machine has a real i8042 PS/2 controller (QEMU default, IRQ1) — 4.3.5. Neither
|
||||
(aarch64, riscv64) has PS/2 hardware; both get a `virtio-keyboard` device added to their
|
||||
QEMU command lines and a new virtio-input driver (this tree has none — `virtio_blk.c` is
|
||||
the only existing virtio driver, and it is fully synchronous/polled, so it is a transport
|
||||
reference only, not an interrupt-handling one) — 4.3.5b (riscv64, MMIO transport) and 4.3.5d
|
||||
reference only, not an interrupt-handling one) — 4.3.5c (riscv64, MMIO transport) and 4.3.5e
|
||||
(aarch64, PCI transport, riding the bus `pci.c` already enumerates for `virtio-blk-pci`).
|
||||
|
||||
**No polling, anywhere, in any of 4.3.5/4.3.5b/4.3.5d.** This is the one hard constraint
|
||||
**No polling, anywhere, in any of 4.3.5/4.3.5c/4.3.5e.** This is the one hard constraint
|
||||
carried through every sub-item — restated per item because it is the actual point of doing
|
||||
interrupt bring-up first rather than reading `0x64`'s status bit or spinning on a used-ring
|
||||
index, which would have been the fast/wrong way to get a key on screen quickly.
|
||||
|
||||
4.3.5e is the checkpoint, same posture as 4.3.4: converge the three architecture-specific
|
||||
4.3.5f is the checkpoint, same posture as 4.3.4: converge the three architecture-specific
|
||||
paths behind one interface before anything scopes REPL line input on top of it.
|
||||
|
||||
Reference in New Issue
Block a user