Reorganize source tree: kernel/, v3/, v4/ split and board infrastructure
Source tree reorganization: - Move StarForth v3 engine to v3/ (src/, include/, Makefile) - Move kernel to kernel/ (src/, include/, linker/, Makefile) - Create v4/ skeleton for F18-ISA golden model (DECOMPOSITION.md, JUSTIFICATION.md) - Move FABRIC-0..4.md to docs/fabric/ - Move ONTOLOGY.md and ROADMAP.md to docs/ Board infrastructure: - Add boards/ser5/, boards/raspi/, boards/milkv/, boards/zynq7020/ - Each board has board.mk (ISA, CPU flags, boot recipe) and README.md - Root Makefile becomes thin dispatcher: boot_image, all, clean, docs take TARGET - make boot_image TARGET=SER5|RASPI|MILKV builds one GPT/MBR image per board - ZYNQ7020 target exists but stops with clear error (ARMv7 port not built yet) - scripts/mkdiskimage.sh builds disk images for all boards Docs pipeline: - docs/book/ with LaTeX master (main.tex) and Makefile - pandoc converts Markdown to LaTeX at build time - Two Lua filters: table-widths.lua (wide tables wrap), code-breaks.lua (inline code breaks) - make docs builds single PDF (754 pages, 0 missing characters) - make docs TARGET=<board> adds board appendix - build/docs/<book|board>/meta.tex stamps git commit into PDF Bug fixes: - 42 include paths that only worked by accident now use correct relative paths - clang-18 hardcode replaced with configurable CC variable (fixed aarch64 build) - Pi 5: kernel_2712.img linked at 0x80000, .bss zeroed, memory reserved - Doxyfile, .clang-tidy, README.md, Kconfig paths updated Verified: - Hosted v3 build passes 1012 tests, 0 failures - SER5 image boots in QEMU (OVMF), POST passes, K exact (65536 = Q48_ONE) - Milk-V image boots in QEMU (OpenSBI + U-Boot + bootefi), POST passes - make clean TARGET=<board> removes only that board and its ISA objects - make all builds all boards, hosted v3, and docs in one run Co-authored-by: Junie <junie@jetbrains.com>
This commit is contained in:
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,205 @@
|
||||
# FABRIC-3.7.md — Phase 8 PKI: the elevation entrypoint
|
||||
|
||||
**Status: OPEN — design only, no code written or authorized.**
|
||||
|
||||
**CORRECTION (2026-09-22, before any code was written against this document): §2's central
|
||||
claim — that the old `SEND-ELEVATE-REQUEST` passed a raw cross-VM address into `ELEVATE-GRANT`'s
|
||||
`waddr` — is wrong.** Found while starting Part A's implementation: reading the actual deleted
|
||||
source (`git show 3e201c8^:capsules/common/messaging.4th`, block 5040) shows
|
||||
`SEND-ELEVATE-REQUEST` copied the target word's **name as literal character bytes** (via
|
||||
`ELEVATE-REQ-APPEND`'s `CMOVE`) into a scratch buffer, building the text `S" <name-text>" <pk0>
|
||||
<pk1> <pk2> <pk3> ELEVATE-GRANT`, and sent *that whole string* to Hera. When Hera's own
|
||||
interpreter runs `S" <name-text>"`, it allocates a fresh string **in Hera's own memory** and
|
||||
pushes Hera's own valid address — no numeric cross-VM address ever appears anywhere in this
|
||||
flow. §2 was written from `ELEVATE-GRANT`'s signature alone, assuming the caller forwarded a raw
|
||||
address, without first reading how the caller actually built its message. It didn't.
|
||||
|
||||
**What is still real, much narrower than originally claimed:** if a future caller ever spliced
|
||||
*attacker-influenced* text into the name field without checking for an embedded `"` character,
|
||||
that could break out of the `S" ... "` literal early and inject arbitrary FORTH source, executed
|
||||
with Hera's privilege. That's an input-validation discipline question for whoever writes the new
|
||||
caller (validate: no embedded `"`, or just always use a compile-time-fixed literal name, never a
|
||||
runtime-supplied one) — not an architectural cross-VM-memory defect requiring the buffer/message
|
||||
redesign §3 originally called for. **§3's proposed mechanism (Hera-side fixed receive buffer,
|
||||
kernel-constructed integer-literal-only command) is not needed** — the original text-copy
|
||||
design was already safe against the bug as actually diagnosed. Kept below, struck through, for
|
||||
traceability, per this series' own rule against silently rewriting a prior state.
|
||||
|
||||
Successor to
|
||||
`FABRIC-3.5.md`/`FABRIC-3.6.md` (both CLOSED/ARCHIVAL at `v2.1.0`) for exactly one topic: the
|
||||
Ed25519-challenge-response elevation entrypoint that `.claude/CLAUDE.md`'s ACL section names as
|
||||
Phase 8, the last open item in the word-level ACL system. This is a **new document**, not a
|
||||
reopening of `FABRIC-3.6.md` — that document's own close header says future fleet work gets its
|
||||
own document, and this is that.
|
||||
|
||||
**Provenance.** Written 2026-09-22, immediately after `FABRIC-3.6.md`'s close, from a design
|
||||
conversation with Captain Bob about a security concern he raised directly: how to rebuild the
|
||||
elevation entrypoint that Phase 4's Category B strip left dangling, without reopening a hole.
|
||||
The design below was proposed, and Captain Bob asked for it in writing here rather than left
|
||||
only in session memory.
|
||||
|
||||
---
|
||||
|
||||
## 1. What's dangling, and why
|
||||
|
||||
`FABRIC-3.6.md` Phase 4 (Category B strip, 2026-09-22) deleted `capsules/common/messaging.4th`
|
||||
after every FORTH-owned message type had been cut over to kernel-Hermes. One casualty was
|
||||
collateral, not intended: `SEND-ELEVATE-REQUEST` (`messaging.4th` block 5040) was the only
|
||||
caller of both `KH-ELEVATE-SEND` (`src/starkernel/repl.c`) and, transitively, `ELEVATE-GRANT`
|
||||
(`capsules/zuse-eligibility.4th`, blocks 4021–4022). All three still exist in the tree.
|
||||
`ELEVATE-GRANT` is still loaded at boot (`capsules/init.4th:18`). Nothing can call it any more.
|
||||
|
||||
Captain Bob's decision at the time (`FABRIC-3.6.md`'s own Phase 4 entry): leave it unreachable,
|
||||
don't patch a caller back in as part of that strip. Phase 8 builds its own entrypoint instead of
|
||||
resuming this one. **This document is that entrypoint's design.**
|
||||
|
||||
<details>
|
||||
<summary>Original §2/§3 (WRONG — see the correction at the top of this document; kept for
|
||||
traceability, not current design)</summary>
|
||||
|
||||
### 2. The security hole in the old mechanism — found before any code was written
|
||||
|
||||
`ELEVATE-GRANT`'s signature, unchanged since it was written:
|
||||
|
||||
```
|
||||
ELEVATE-GRANT ( waddr wu pk0 pk1 pk2 pk3 -- )
|
||||
```
|
||||
|
||||
`waddr`/`wu` are an address/length pair meant to point at the string naming the word to elevate.
|
||||
`pk0`–`pk3` are the caller's Ed25519 pubkey, packed 8 bytes per cell (`ELEVATE-PUBKEY-UNPACK`,
|
||||
`mama_forth_words.c`).
|
||||
|
||||
**The old `SEND-ELEVATE-REQUEST` computed `waddr` in the *sending* VM's own address space, but
|
||||
`ELEVATE-GRANT` always executes on Hera** (`ELEVATE-GRANT always runs on Hera` — `repl.c`'s own
|
||||
comment on `KH-ELEVATE-SEND`, still there). A word's name string lives in the sending VM's
|
||||
memory. `ELEVATE-GRANT` dereferences `waddr` in Hera's memory. Those are not the same address
|
||||
space by construction — `vaddr_t` is per-VM.
|
||||
|
||||
**Consequence:** whoever controls `waddr` controls what bytes `NAME>XT` reads and resolves as a
|
||||
word name, in Hera's dictionary, not the caller's. This is not "the string might be malformed" —
|
||||
it is a primitive for making Hera's own `ELEVATE-GRANT` grant `ACL-ALLOW!`/`ACL-TTL!` on
|
||||
*whatever dictionary entry the attacker's chosen `waddr` happens to land on*, regardless of what
|
||||
word name the caller claims to be requesting elevation for. A caller who can influence `waddr`
|
||||
at all — not forge a signature, not defeat `zuse_eligibility_is_member()`, just choose a number
|
||||
— has a privilege-escalation primitive against the fleet governor.
|
||||
|
||||
This was never exploited (the entrypoint has had zero live callers since the file that called it
|
||||
was deleted), and is reported here as a design defect found by inspection, not a live incident.
|
||||
|
||||
### 3. The fix: never cross an address, only ever cross bytes
|
||||
|
||||
This project already solved the general version of this problem once, this same session
|
||||
(`FABRIC-3.6.md` tasks 3.8/3.9, the payload-aliasing fix): a kernel-Hermes message's payload
|
||||
must be **copied into the message's own storage**, never a pointer into the sender's memory that
|
||||
might be reused or freed before the receiver drains it. `SkHermesMessage.payload_buf`
|
||||
(`include/starkernel/vm/kernel_hermes.h:160`, `SK_HERMES_CHUNK_MAX_PAYLOAD` = 1024 bytes) is
|
||||
exactly that fix, already built, already proven on all three architectures.
|
||||
|
||||
**The elevation entrypoint's hole is the same defect one level up: an address crossing a
|
||||
boundary it isn't valid on the other side of.** The fix generalizes directly:
|
||||
|
||||
1. **Never send `waddr`/`wu` across the kernel-Hermes boundary.** Send the pubkey (32 bytes,
|
||||
already the right shape for `payload_buf`) and the target word's **name, as literal bytes**,
|
||||
copied inline into the message payload — not an address, the actual characters. This is
|
||||
already how `CONSOLE-CMD-EVENT`'s payload works (a command string's bytes, not a pointer to
|
||||
one), so this isn't a new pattern, it's applying the existing one to the one caller that
|
||||
still passed a raw address.
|
||||
|
||||
2. **On receipt, kernel-Hermes's C drain-checkpoint copies those name bytes into a small,
|
||||
fixed, kernel-owned buffer that already lives in Hera's own VM memory** — a receive-side
|
||||
mirror of the existing send-side pattern (`g_kh_elevate_buf`, `repl.c:445`, is the
|
||||
already-built precedent for "a static buffer this mechanism owns"; this needs its Hera-side
|
||||
counterpart). The buffer's address is a compile-time constant, known to the kernel, never
|
||||
computed from anything the caller supplied.
|
||||
|
||||
3. **The FORTH command handed to `vm_interpret()` on Hera references only that fixed buffer's
|
||||
address and length as plain integer literals.** Both are always kernel-controlled. Neither is
|
||||
ever derived from caller input. `ELEVATE-GRANT` itself does not change — same signature, same
|
||||
`zuse_eligibility_is_member()` check, same `ACL-ALLOW!`/`ACL-TTL!` grant. Policy logic stays
|
||||
in FORTH, per `ACL.4th`'s own rule (no new C primitive for policy) — this fix is entirely
|
||||
about how bytes get from one VM to another, not about who is allowed to grant what.
|
||||
|
||||
**Why this closes the hole structurally, not by validation:** there is no string to sanitize and
|
||||
no address to bounds-check, because the interpreted command never contains anything an attacker
|
||||
touched except opaque data bytes that get copied, never dereferenced as a pointer, by the
|
||||
receiving side. The class of bug (cross-address-space pointer confusion) becomes impossible by
|
||||
construction, the same way `payload_buf` made use-after-free impossible by construction rather
|
||||
than by careful lifetime tracking.
|
||||
|
||||
</details>
|
||||
|
||||
## 2 (corrected). What the old mechanism actually did, and the one real gap in it
|
||||
|
||||
Re-read from the actual deleted source (`git show 3e201c8^:capsules/common/messaging.4th`,
|
||||
blocks 5039–5040): `SEND-ELEVATE-REQUEST ( pk3 pk2 pk1 pk0 waddr wu -- )` used `waddr`/`wu` only
|
||||
to `CMOVE` the target word's **name bytes**, as text, into a scratch buffer
|
||||
(`ELEVATE-REQ-BUF`/`ELEVATE-REQ-APPEND`) it owned — building the literal string `S"
|
||||
<name-text>" <pk0> <pk1> <pk2> <pk3> ELEVATE-GRANT` entirely in the *sending* VM's own memory.
|
||||
Only that finished string — not `waddr` itself — went to `KH-ELEVATE-SEND` and across to Hera.
|
||||
When Hera's interpreter runs `S" <name-text>"`, Hera's own `S"` allocates a fresh string **in
|
||||
Hera's own memory** and pushes Hera's own valid address. `waddr`/`wu` never cross the VM
|
||||
boundary as numbers at any point — only as copied character content. There is no cross-VM
|
||||
pointer dereference anywhere in this flow.
|
||||
|
||||
**The one real, much narrower gap:** the name text is spliced into `S" ... "` with no check for
|
||||
an embedded `"` character. If a future caller ever passed attacker-influenced text as the name
|
||||
(none ever did — the word had zero live callers), a `"` in the name would close the string
|
||||
literal early and let the rest of the name execute as raw FORTH source, with Hera's privilege.
|
||||
This is a caller-discipline / input-validation question, not an architectural defect: either
|
||||
always use a compile-time-fixed name literal at the call site (no runtime input, no risk at
|
||||
all), or validate for an embedded `"` before building the command if a name ever does need to
|
||||
come from something less trusted than the call site's own source code.
|
||||
|
||||
**Net effect on Phase 8 v1's scope:** Part A, as originally conceived in §3 above, is not
|
||||
needed. If a `SEND-ELEVATE-REQUEST` replacement is ever built, it can follow the original
|
||||
text-copy design as-is, with the one-line `"`-check added if and only if the name is ever
|
||||
runtime-supplied rather than a fixed literal. No kernel-Hermes/`repl.c` changes required. Part B
|
||||
(`capsules/zuse.4th`, gating `ZUSE-ELIGIBILITY-ADD`) stands on its own, independently verified,
|
||||
unaffected by this correction.
|
||||
|
||||
## 4. What Phase 8 actually needs to build
|
||||
|
||||
Corrected per §2's re-read above. Concretely, when Phase 8 next picks this up:
|
||||
|
||||
- If a caller into `ELEVATE-GRANT` is ever needed again, rebuild it close to the original
|
||||
`SEND-ELEVATE-REQUEST` shape (`ELEVATE-REQ-BUF`/`ELEVATE-REQ-APPEND`/text-copy into `S" ...
|
||||
"`) — it was already safe. Add the one-line embedded-`"` check only if the name is ever
|
||||
runtime-supplied rather than a call-site literal. No `kernel_hermes.c`/`kernel_hermes.h`/
|
||||
`repl.c` changes needed for this.
|
||||
- `ELEVATE-GRANT` unchanged either way.
|
||||
- **Part B is done** (`capsules/zuse.4th`, committed and three-arch verified this session,
|
||||
2026-09-22) — `ZUSE-ELIGIBILITY-ADD` denied by default, granted only inside `ACL-ZUSE-BOOT`'s
|
||||
authenticated branch. This closes the actual "grant yourself eligibility with no real drive at
|
||||
all" path — a real, independently-confirmed gap, unaffected by this correction.
|
||||
- **Defending against a cloned drive — settled, 2026-09-23: not going to happen, by design.**
|
||||
Today, WIREBIND/MINT trust whatever identity is stored on an attached thumbdrive with no
|
||||
challenge at all (confirmed by grep: no `ed25519_sign`/`ed25519_verify` call anywhere in
|
||||
`capsule_wirebind.c` or `capsule_mint.c`), and the private key seed itself is stored in
|
||||
plaintext on the drive, read in the same devblock as the pubkey/cert. **This is accepted, not
|
||||
a gap.** Captain Bob, directly: *"nothing like a pin or a password or secret code or any
|
||||
bullshit... Everybody has secrets. There's only the drive."* Physical possession of the drive
|
||||
is the entire, deliberate credential model — a byte-for-byte clone being equivalent to the
|
||||
real drive is the accepted design, not a defect to close. A PIN/passphrase second factor was
|
||||
built, live-tested on all three architectures, and fully reverted before commit
|
||||
(`/home/rajames/.claude/plans/jiggly-cuddling-stallman.md`, now marked rejected; memory
|
||||
`feedback_no_knowledge_factor_identity`) — **do not revisit a knowledge-factor approach here.**
|
||||
Any future work in this space needs a fundamentally different mechanism (not something typed
|
||||
and known) or stays an accepted limitation.
|
||||
- **Phase 8 v3, 2026-09-23 — done, a distinct and narrower concern from the item above.** The
|
||||
"accepted limitation" above is about a drive image copied *outside* StarshipOS entirely (e.g.
|
||||
imaged on an external computer) — that's still accepted, unchanged by this item. Captain Bob
|
||||
separately asked to close a narrower, different threat: **cloning a device's block content
|
||||
from *within* StarshipOS's own console**, using its own stock, unpinned words
|
||||
(`<src> BLOCK <dst> BUFFER 1024 MOVE`/`RELOCATE-BLOCK`). That's now closed — `MOVE`/`CMOVE`/
|
||||
`CMOVE>`/`RELOCATE-BLOCK` all refuse a same-VM, cross-device copy, verified live on all three
|
||||
architectures. See `/home/rajames/.claude/plans/jiggly-cuddling-stallman.md`'s "Phase 8 v3"
|
||||
section for the full design and verification record. The identity record itself
|
||||
(seed/pubkey/cert) was already unreachable from FORTH before this — this closes the one real
|
||||
gap the research found: ordinary block content, not the identity record.
|
||||
|
||||
## 5. What this document is not
|
||||
|
||||
Not a reopening of `FABRIC-3.6.md`, not a change to anything currently built, not an
|
||||
authorization to write code. Per this series' own convention: design here, execution gets its
|
||||
own document when the work actually starts, the same relationship `FABRIC-3.5.md` had to
|
||||
`FABRIC-3.6.md`.
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,106 @@
|
||||
# FABRIC-4.md — forward-looking design notes
|
||||
|
||||
**Status:** Not a successor to `FABRIC-3.md` and not a punch-list document. `FABRIC-3.md` is
|
||||
the current living document (bare metal boot, opened 2026-09-04, successor to the now-closed
|
||||
`FABRIC-2.md`) — nothing here supersedes it, and this file doesn't follow the
|
||||
close-and-carry-forward discipline `FABRIC-0.md` → `FABRIC-1.md` → `FABRIC-2.md` → `FABRIC-3.md`
|
||||
used (that chain triggers on *closing* a document; `FABRIC-3.md` isn't closed). This is a
|
||||
separate, lower-discipline scratchpad for design ideas caught early — theory-stage,
|
||||
pre-punch-list, often missing a stated "why" on purpose (captured as raised, not fully
|
||||
justified yet). An idea graduates out of here into `FABRIC-3.md` (or wherever the living
|
||||
document is by then) once it has a real scope, not before.
|
||||
|
||||
---
|
||||
|
||||
## 1. Stadium-level "wheel" — a second clock alongside the heartbeat (2026-09-03)
|
||||
|
||||
Raised in conversation with Captain Bob, theory stage — no code, no scope, deliberately not
|
||||
punch-listed yet.
|
||||
|
||||
**The mechanism.** A second clock, independent of but derived from the true heartbeat
|
||||
(`HeartbeatState`, Loop #7), advanced by a fixed-point (Q48.16, this project's standard)
|
||||
phase accumulator: each master heartbeat tick adds a `rate` scalar to the wheel's own
|
||||
`phase`; whenever `phase` crosses `1.0` the wheel fires (advances its own state) and the
|
||||
crossing remainder carries forward. This is a continuous scalar, not an integer tick-divisor
|
||||
— `rate` can sit anywhere, including above `1.0`. A wheel with `rate > 1` fires more than
|
||||
once per master tick (multiple threshold-crossings per tick, remainder still carried); one
|
||||
with `rate < 1` accumulates across several master ticks before firing once. Nothing about the
|
||||
mechanism privileges either side of `1.0` — "runs ahead of baseline" and "runs stretched
|
||||
behind baseline" are the same math with a different scalar.
|
||||
|
||||
**What feeds it.** Not a new signal source — this wheel listens to two already-real, already-
|
||||
built mechanisms: `rolling_window_of_truth.c` (Loop #2's circular-buffer execution history —
|
||||
`rolling_window_measure_diversity()`, `rolling_window_find_hottest_word()`,
|
||||
`rolling_window_count_transition()`, `rolling_window_pattern_capture_rate()`,
|
||||
`rolling_window_is_warm()`) and `inference_engine.c` (Loops #5/#6 — `InferenceOutputs`:
|
||||
decay-slope, variance-inflection point, fit quality). Both exist today at the **per-VM**
|
||||
level (each patron/word-owning VM has its own rolling window and runs its own inference
|
||||
pass) — the wheel itself is meant to live at the **Stadium** level, one layer up. This is a
|
||||
genuinely new axis: nothing today aggregates RWOT/inference-engine output across the whole
|
||||
Stadium floor into one fleet-wide signal. **Open, not decided:** what the aggregation actually
|
||||
is (sum across patrons? mean? the hottest patron's own values only? something else) — flagged
|
||||
in conversation, not resolved.
|
||||
|
||||
**What it's for.** Not a sieve itself. The wheel is a *scheduler/gate*: it decides *when* to
|
||||
slip an appropriate sieve into a stack of sieves that doesn't exist yet (see §2 below) —
|
||||
running its own clock, potentially ahead of the true heartbeat, is what buys it lead time to
|
||||
notice a transition worth reacting to before the baseline heartbeat would get there on its
|
||||
own. It is not itself the thing doing the sieving.
|
||||
|
||||
**Build sequencing, decided in conversation.** `rate` starts as a fixed build parameter (same
|
||||
shape as `ACL-BASE-TTL`/`Q.SLOT` — a plain constant or Kconfig symbol, not adaptive from day
|
||||
one). Reasoning, Captain Bob's own: a fixed rate is the only version that can go through this
|
||||
project's existing DoE apparatus and produce a clean, attributable measurement (rate held
|
||||
constant, everything else varies) — if the rate self-tunes from day one there's no fixed
|
||||
baseline to compare "does the wheel actually help" against. Only *after* a real, measured
|
||||
baseline exists does `rate` itself graduate to adaptive/self-tuning — reusing the same
|
||||
inference-engine machinery the wheel already listens to, not new plumbing. This mirrors the
|
||||
L8 Jacquard selector's own real history: hardcoded compudynamics constant first, later
|
||||
replaced by the VM Fleet Attractor's dynamically-inferred rate
|
||||
(`docs/working/architecture/VM-FLEET-ATTRACTOR-DESIGN-20260705.md`). Same graduation, one
|
||||
level up the stack.
|
||||
|
||||
**Explicitly not decided yet, per Captain Bob ("we'll talk about why later"):**
|
||||
- The actual *purpose* — why this wheel, what real problem it solves. Deferred on purpose.
|
||||
- The sieve stack itself — what a "sieve" is concretely, what gets sieved, how many. A larger,
|
||||
separate vision (128–256 wheels, each fed by an "appropriate" — possibly learned/neural,
|
||||
vocabulary not yet resolved against anything this codebase currently has — source, forming
|
||||
a coincidence-pattern sieve) was raised earlier in the same conversation as a *distinct*,
|
||||
further-out idea; this single-wheel scheduler is deliberately scoped smaller and doesn't
|
||||
presuppose that larger picture is right.
|
||||
- Whether "trivial to add a wheel" (an earlier framing) still matters once there's only one —
|
||||
a generic `{rate, phase, state}` table is a premature abstraction for a single instance;
|
||||
build the one wheel concretely first, generalize only if/when a second one is actually
|
||||
needed (this project's own standing convention — three similar lines beat a premature
|
||||
abstraction).
|
||||
|
||||
## 2. A pinned GPIO VM per real-hardware board (2026-09-04)
|
||||
|
||||
Raised in conversation with Captain Bob during `FABRIC-3.md` §IV/§V's bare-metal-boot
|
||||
planning — theory stage, no code, no scope, deliberately not punch-listed yet.
|
||||
|
||||
**The idea, as stated:** the Raspberry Pi 5 will need a special pinned VM dedicated to GPIO —
|
||||
presumably following the same Tripod precedent Hermes/Artemis already established (a
|
||||
permanently-pinned, born-at-boot VM with a fixed role, per `FABRIC-2.md` §H.1's "pinned
|
||||
sessions never leave" model). Whether the Milk-V Mars needs the same treatment is explicitly
|
||||
**not yet decided** — Captain Bob's own framing: "same for Milk-V (? not sure here)." Worth
|
||||
noting the Mars does have its own 40-pin GPIO header (§VI), so the question isn't "does it
|
||||
have GPIO" but whether it needs its own *dedicated pinned VM* for it the same way the Pi 5
|
||||
does, or whether GPIO access there fits some other shape.
|
||||
|
||||
**Why a dedicated VM, not just a C driver, presumably (not yet confirmed as the actual
|
||||
reasoning — inferred from the Tripod precedent, not stated outright):** GPIO is shared,
|
||||
stateful hardware that multiple capsules/patrons might want to touch — the same category of
|
||||
problem Hermes (messaging) and Artemis (block storage) already solve by being a dedicated,
|
||||
addressable VM other patrons talk to, rather than a bare C primitive anyone can call directly.
|
||||
|
||||
**Explicitly not decided yet:**
|
||||
- Whether Milk-V Mars needs the same pinned-VM treatment, or something else.
|
||||
- What this VM's own vocabulary/interface would look like (a `GPIO-READ`/`GPIO-WRITE`-shaped
|
||||
word set? something richer, given the Pi 5's GPIO header also muxes UART/SPI per §IV.1?).
|
||||
- Whether this is one pinned VM per board doing double duty (GPIO + whatever else that board's
|
||||
bring-up needs) or GPIO specifically warrants its own separate VM distinct from, say, a
|
||||
future UART-handling VM.
|
||||
- How this interacts with §IV.1's own still-open native-boot-flow work — a GPIO VM needs GPIO
|
||||
register addresses from the DTB the same way the rest of that bring-up does, so this idea
|
||||
isn't independent of that work, just downstream of it.
|
||||
Reference in New Issue
Block a user