Skip to content

Commit dfcd8f4

Browse files
riccajasonclaude
andcommitted
kernel: ADR-018 step 7 — boot integration: init runs as PID 1 (coexistence, x86_64)
The coexistence milestone (ADR-018 § 6): the kernel boot path now verifies + transcribes the manifest, creates init as PID 1, maps the manifest blob into it, and init parses + validates in userspace and idles — while the legacy BOOT_MODULE_ORDER chain still starts every service, byte-for-byte. Full machinery exercised, zero behavior change. Boot proof (x86_64, 3 consecutive runs, 8.9s): ✓ Boot manifest transcribed: 15 spawn row(s), 1 reserved endpoint(s) ✓ Registered init (created after manifest transcription) ✓ init created as PID 1: task 16 process 18 (endpoint 1, manifest at 0x1000000) [init] CambiOS init starting [init] manifest valid: 15 service(s) described; supervision starts at the step-8 cutover Init's register_endpoint(1) is the step-3 reservation gate's first live customer — admitted because the kernel bound init's manifest-declared AID at creation and the transcribed reservation names the same AID. Kernel (src/microkernel/main.rs): the module loop gains an init arm (register spawn-only, never auto-started, never boot-gated — neither the manifest nor init consumes the module-0-boots-Ready slot); after the loop, create_init_process runs iff a manifest was transcribed. It loads init's signed ELF, maps the manifest module's pages read-only at MANIFEST_USER_VADDR (module physical memory, shared with the boot-module registry, deliberately NOT VMA-tracked — destroy_process reclaims VMA-tracked regions and these pages are not init's to free; the fixed address sits below VMA_ALLOC_BASE per the ELF-segment convention; Limine module addresses are HHDM-virtual, so the mapping converts via hhdm_offset), installs the narrow ADR-018 § 4 capability set (receive on init's endpoint + CreateProcess — nothing else), binds the manifest-declared AID, and calls set_init_process — arming the step-5 handle_spawn manifest branch. Runs while the boot path still exclusively borrows the BSP scheduler, so all setup lands before init's first instruction. Manifest-without-init is a broken image ⇒ typed InitModuleMissing; init-without-manifest degrades to legacy boot. BootError gains InitModuleMissing + InitCreationFailed; the error.rs test variant lists (drifted since the step-4 additions) are caught up and now exhaustive. First-boot bug caught and fixed in-session: create_init_process originally mapped init's OWN ELF bytes at MANIFEST_USER_VADDR (the manifest module's bytes were transcribed in-loop but never stashed), so init read an ELF header where CBOSMANI belonged and refused. The function now takes (init_elf, manifest_blob) as two named buffer pairs — the conflation is unrepresentable at the signature. The failure mode itself validated the coexistence design: init exited 1, the legacy chain was untouched, boot completed. Coexistence scaffolding (both retire at the step-8 cutover, per the ADR's staged plan): - tools/build-manifest --init-only-reservations + `make manifest-step7`: emits entries with reservations suppressed (only init's endpoint 1 lands in the reservation table — old-chain services are bootstrap-bound and must still register their own endpoints). Grants, dependencies, and lifetimes emit at full fidelity; the spawn table is dormant until init spawns. - user/init `supervise` cargo feature (default OFF): the spawn wave is compiled out — running it now would double-spawn everything the legacy chain starts. Engine construction (DAG + permutation validation) still runs, so step 7 exercises the full parse path. Boot image (x86_64): `make iso` stages signed init.elf + manifest.bin (signed once by manifest-step7 — NOT re-signed in the ISO recipe; stacked trailers would break verification); limine.conf lists both ahead of the service chain. aarch64/riscv64 staging deferred — the create-init arm never fires there (absent manifest ⇒ legacy boot; STATUS.md carries the step-8 revisit trigger, including verifying riscv initrd module-address semantics before enabling the phys conversion). cambios-manifest: INIT_MODULE_NAME const; the kernel-side InitIdentity (AID + endpoint) is captured at transcription in src/manifest.rs (BOOTSTRAP_PRINCIPAL lifecycle, like its sibling tables). CLAUDE.md: Quick Reference gains manifest / manifest-step7 / init targets (the `make manifest` line was owed since step 2), and the load-bearing endpoint list gains init=1 + the endpoint-0 sentinel note. Verification: RUST_MIN_STACK=8388608 cargo test --lib --target x86_64-apple-darwin — 926 passed; user/init 7/7 (both feature states build); cambios-manifest 31/31; make check-all — three arches clean; make check-clippy — tri-arch 0 warnings; make check-boot-panics — 0 flagged (create-init path fully typed); make check-unsafe-coverage — 0 new (2 new SAFETY-documented blocks); make run-quiet ×3 — 8.9s green with the banner chain above; make check-deferrals — 485, 0 new (init's status print reworded rather than growing the baseline; 6 symmetric line-shift pairs refreshed); make check-assumptions — 307, 0 new (MANIFEST_MAPPING_BUDGET is derived + tagged at site); make check-adrs OK. Pre-existing fs test-code warnings (flagged at step 5) remain, untouched. Staged files: - CLAUDE.md - Makefile - STATUS.md - cambios-manifest/src/lib.rs - limine.conf - src/boot/error.rs - src/manifest.rs - src/microkernel/main.rs - tools/build-manifest/src/main.rs - tools/check-deferrals-baseline.txt - user/init/Cargo.toml - user/init/src/main.rs Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
1 parent a413f22 commit dfcd8f4

12 files changed

Lines changed: 408 additions & 24 deletions

File tree

CLAUDE.md

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -290,6 +290,9 @@ make symbols
290290
# Standalone builds
291291
make fs-service # user/fs-service — separate crate, uses CARGO_ENCODED_RUSTFLAGS to override parent .cargo/config.toml
292292
make sign-tool # tools/sign-elf — host-side, own .cargo/config.toml targeting aarch64-apple-darwin
293+
make manifest # ADR-018: emit manifest.bin from manifest.toml via tools/build-manifest, sign with sign-elf (full reservation set — ships at the step-8 cutover)
294+
make manifest-step7 # ADR-018 step-7 coexistence variant (what `make iso` stages): --init-only-reservations suppresses entry endpoint reservations so only init's endpoint 1 is reserved; retires at cutover
295+
make init # user/init — PID 1 supervisor (init-aarch64 / init-riscv64 for other arches); host tests: cd user/init && cargo test --target aarch64-apple-darwin
293296
make gen-dev-piv-keys # tools/gen-dev-piv-keys — derives dev Ed25519+X25519 keys from a persistent per-developer seed at tools/gen-dev-piv-keys/.dev-seed.bin (gitignored); writes dev_bootstrap_pubkey.bin (workspace root) + dev_slot_9c_seed.bin (workspace root, for sign-elf via SIGN_MODE=dev-piv) + user/key-store-service/dev_piv_secret.bin. Idempotent; required before any `--features dev-piv` build (kernel + key-store-service must both be built with this feature for SwPivBackend's pubkey to match the kernel-baked bootstrap pubkey).
294297
make format-volume # tools/format-volume — host tool that writes a fresh signed ADR-032 volume header to a raw disk image. Run as `tools/format-volume/target/aarch64-apple-darwin/release/format-volume <disk-image>`. Requires gen-dev-piv-keys to have run first. The header pairs with the dev_bootstrap_pubkey.bin baked into the kernel under `--features dev-piv`; fde-mount reads + verifies + unwraps the master key at boot. Stream A A-v.e.
295298

@@ -455,7 +458,7 @@ Run `tree -L 2 src/ user/ tools/` for the current layout; file names and purpose
455458

456459
- **`build.rs`** reads `CAMBIOS_TIER` (default `tier3`) and emits `--cfg tierN` for `src/config/tier.rs`. See [ADR-008](docs/adr/008-boot-time-sized-object-tables.md) / [ADR-009](docs/adr/009-purpose-tiers-scope.md).
457460
- **Arch split:** portable modules (`scheduler/`, `ipc/`, `process.rs`, `loader/elf.rs`, `memory/buddy_allocator.rs` + `frame_allocator.rs`, `syscalls/mod.rs`) contain no arch-specific code. All arch backends live under `src/arch/<target>/`. `src/arch/mod.rs` is the cfg-gated shim.
458-
- **Service endpoints (load-bearing numbers):** fs-service=16, key-store-service=17, virtio-net=20, udp-stack=21, virtio-blk=24 (user clients, `recv_verified`) + 26 (kernel-only commands, `recv_msg`, no cap check) + 25 (kernel's reply endpoint, `handle_write` intercept), scanout-virtio-gpu=27, compositor=28, compositor-input=30.
461+
- **Service endpoints (load-bearing numbers):** init=1 (ADR-018 readiness pings; reserved to init's AID via the boot manifest — the only reservation during step-7 coexistence), fs-service=16, key-store-service=17, virtio-net=20, udp-stack=21, virtio-blk=24 (user clients, `recv_verified`) + 26 (kernel-only commands, `recv_msg`, no cap check) + 25 (kernel's reply endpoint, `handle_write` intercept), scanout-virtio-gpu=27, compositor=28, compositor-input=30. Endpoint 0 is the REPLY_ENDPOINT "unset" sentinel — structurally unusable.
459462
- **`tools/sign-elf/`** — host-side Ed25519 ELF signer (YubiKey or seed), produces the ARCSIG trailer. Own `.cargo/config.toml` targeting `aarch64-apple-darwin`.
460463

461464
## Key Technical Details

Makefile

Lines changed: 24 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -206,7 +206,7 @@ else
206206
SIGN_FLAGS :=
207207
endif
208208

209-
.PHONY: all kernel iso run run-gui run-uefi test clean symbols img-x86 run-img-x86 img-usb run-img-usb usb verify-usb disk-img kernel-aarch64 img-aarch64 run-aarch64 run-aarch64-gui kernel-riscv64 img-riscv64 run-riscv64 check-all check-stable check-x86 check-aarch64 check-riscv64 check-clippy check-clippy-x86 check-clippy-aarch64 check-clippy-riscv64 check-adrs new-adr check-doc-refs update-doc-refs-baseline audit-taxonomy check-audit-taxonomy check-index-isolation check-deferrals update-deferrals-baseline claude-preflight sync-site sync-site-check user-elf fs-service key-store-service virtio-net virtio-blk virtio-input usb-host ccid i219-net udp-stack shell policy-service init fb-demo compositor scanout-limine scanout-virtio-gpu hello-window tree worm ping sprouty terminal-window audit-tail fde-mount user-elf-aarch64 fs-service-aarch64 key-store-service-aarch64 virtio-net-aarch64 virtio-blk-aarch64 usb-host-aarch64 ccid-aarch64 i219-net-aarch64 udp-stack-aarch64 shell-aarch64 policy-service-aarch64 init-aarch64 fb-demo-aarch64 compositor-aarch64 scanout-limine-aarch64 scanout-virtio-gpu-aarch64 virtio-input-aarch64 hello-window-aarch64 tree-aarch64 worm-aarch64 ping-aarch64 sprouty-aarch64 terminal-window-aarch64 audit-tail-aarch64 fde-mount-aarch64 fs-service-riscv64 key-store-service-riscv64 virtio-blk-riscv64 usb-host-riscv64 ccid-riscv64 virtio-net-riscv64 udp-stack-riscv64 shell-riscv64 policy-service-riscv64 init-riscv64 scanout-virtio-gpu-riscv64 virtio-input-riscv64 compositor-riscv64 hello-window-riscv64 tree-riscv64 worm-riscv64 ping-riscv64 sprouty-riscv64 terminal-window-riscv64 audit-tail-riscv64 fde-mount-riscv64 sign-tool manifest mkinitrd gen-dev-piv-keys format-volume bake-font export-pubkey kernel-dev-piv key-store-service-dev-piv iso-dev-piv run-quiet-dev-piv
209+
.PHONY: all kernel iso run run-gui run-uefi test clean symbols img-x86 run-img-x86 img-usb run-img-usb usb verify-usb disk-img kernel-aarch64 img-aarch64 run-aarch64 run-aarch64-gui kernel-riscv64 img-riscv64 run-riscv64 check-all check-stable check-x86 check-aarch64 check-riscv64 check-clippy check-clippy-x86 check-clippy-aarch64 check-clippy-riscv64 check-adrs new-adr check-doc-refs update-doc-refs-baseline audit-taxonomy check-audit-taxonomy check-index-isolation check-deferrals update-deferrals-baseline claude-preflight sync-site sync-site-check user-elf manifest-step7 fs-service key-store-service virtio-net virtio-blk virtio-input usb-host ccid i219-net udp-stack shell policy-service init fb-demo compositor scanout-limine scanout-virtio-gpu hello-window tree worm ping sprouty terminal-window audit-tail fde-mount user-elf-aarch64 fs-service-aarch64 key-store-service-aarch64 virtio-net-aarch64 virtio-blk-aarch64 usb-host-aarch64 ccid-aarch64 i219-net-aarch64 udp-stack-aarch64 shell-aarch64 policy-service-aarch64 init-aarch64 fb-demo-aarch64 compositor-aarch64 scanout-limine-aarch64 scanout-virtio-gpu-aarch64 virtio-input-aarch64 hello-window-aarch64 tree-aarch64 worm-aarch64 ping-aarch64 sprouty-aarch64 terminal-window-aarch64 audit-tail-aarch64 fde-mount-aarch64 fs-service-riscv64 key-store-service-riscv64 virtio-blk-riscv64 usb-host-riscv64 ccid-riscv64 virtio-net-riscv64 udp-stack-riscv64 shell-riscv64 policy-service-riscv64 init-riscv64 scanout-virtio-gpu-riscv64 virtio-input-riscv64 compositor-riscv64 hello-window-riscv64 tree-riscv64 worm-riscv64 ping-riscv64 sprouty-riscv64 terminal-window-riscv64 audit-tail-riscv64 fde-mount-riscv64 sign-tool manifest mkinitrd gen-dev-piv-keys format-volume bake-font export-pubkey kernel-dev-piv key-store-service-dev-piv iso-dev-piv run-quiet-dev-piv
210210

211211
all: iso
212212

@@ -750,6 +750,21 @@ manifest: sign-tool
750750
$(SIGN_ELF) $(SIGN_FLAGS) manifest.bin
751751
@echo "=== manifest.bin ready (signed) ==="
752752

753+
# ADR-018 step-7 coexistence variant: entry endpoint reservations are
754+
# suppressed so the kernel's reservation table holds only init's
755+
# endpoint — old-chain services are still bootstrap-bound and must be
756+
# able to register their own endpoints. This is what the ISO stages
757+
# during coexistence; the plain `manifest` target above emits the full
758+
# reservation set that ships at the step-8 cutover (this target
759+
# retires there).
760+
manifest-step7: sign-tool
761+
@echo "=== Building build-manifest tool ==="
762+
cd $(BUILD_MANIFEST_DIR) && cargo build --release --target $(HOST_TARGET)
763+
@echo "=== Emitting + signing manifest.bin (step-7: init-only reservations) ==="
764+
$(BUILD_MANIFEST) manifest.toml -o manifest.bin --init-only-reservations
765+
$(SIGN_ELF) $(SIGN_FLAGS) manifest.bin
766+
@echo "=== manifest.bin ready (signed, init-only reservations) ==="
767+
753768
mkinitrd:
754769
@echo "=== Building mkinitrd host tool ==="
755770
cd $(MKINITRD_DIR) && cargo build --release --target $(HOST_TARGET)
@@ -830,7 +845,7 @@ iso-dev-piv: kernel-dev-piv key-store-service-dev-piv gen-dev-piv-keys format-vo
830845
@echo "=== Re-assembling ISO with --features dev-piv binaries ==="
831846
$(MAKE) --assume-old=kernel --assume-old=key-store-service SIGN_MODE=dev-piv iso
832847

833-
iso: kernel fs-service key-store-service virtio-blk virtio-net udp-stack virtio-input usb-host ccid shell policy-service fb-demo compositor scanout-virtio-gpu tree worm ping sprouty terminal-window audit-tail fde-mount sign-tool limine
848+
iso: kernel fs-service key-store-service virtio-blk virtio-net udp-stack virtio-input usb-host ccid shell policy-service init manifest-step7 fb-demo compositor scanout-virtio-gpu tree worm ping sprouty terminal-window audit-tail fde-mount sign-tool limine
834849
@echo "=== Building ISO (signing mode: $(SIGN_MODE)) ==="
835850
rm -rf iso_root
836851
mkdir -p iso_root/boot
@@ -863,6 +878,13 @@ iso: kernel fs-service key-store-service virtio-blk virtio-net udp-stack virtio-
863878
cp $(WORM_ELF) iso_root/boot/worm.elf
864879
cp $(AUDIT_TAIL_ELF) iso_root/boot/audit-tail.elf
865880
cp $(FDE_MOUNT_ELF) iso_root/boot/fde-mount.elf
881+
# ADR-018 step 7: init + the signed manifest blob. manifest.bin
882+
# arrives already signed by the manifest-step7 prerequisite — do
883+
# NOT re-sign it here (sign-elf appends a trailer; a second pass
884+
# would stack trailers and break verification).
885+
cp $(INIT_ELF) iso_root/boot/init.elf
886+
cp manifest.bin iso_root/boot/manifest.bin
887+
$(SIGN_ELF) $(SIGN_FLAGS) iso_root/boot/init.elf
866888
$(SIGN_ELF) $(SIGN_FLAGS) iso_root/boot/policy-service.elf
867889
$(SIGN_ELF) $(SIGN_FLAGS) iso_root/boot/key-store-service.elf
868890
$(SIGN_ELF) $(SIGN_FLAGS) iso_root/boot/fs-service.elf

STATUS.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
doc_type: implementation_reference
33
owns: project-wide implementation status
44
auto_refresh: required
5-
last_synced_to_code: 2026-07-12 (ADR-018 step 6: user/init crate — SupervisorEngine + shell, payload_extent, READY_PING_TAG; 2026-07-10 step 5: handle_spawn manifest branch — kernel-typed spawn table, rights normalization, INIT_PROCESS gate; same day step 4: kernel manifest transcription + spawn-grant table + module-capacity 128, boot-stall flake documented; 2026-07-08: ADR-018 accepted + steps 1-3: cambios-manifest crate, build-manifest tool + manifest.toml registry, kernel endpoint-reservation table; 2026-07-06: ADR-037 Phase 1 port sweep COMPLETE — all 22 services on service_main!; 2026-07-05: virtio-blk driver port + try_recv_verified + poll helpers; terminal-window onto `service_main!` heap arm + no-endpoint macro arms; 2026-07-04 L1: `user/libipc` ServiceError + Reader/Writer + ServiceLoop, policy-service loop ported; 2026-07-03 L0: `user/libsys-rt` `service_main!` entry macro + policy-service port — first framework consumer; 2026-07-02: audit-concurrency worktree merge bd50b76: aarch64 + riscv64 TLB-shootdown weak-memory ordering fixes, riscv64 PLIC source enabled on SYS_WAIT_IRQ, linker `.got` placement fix, CLAIMS.md C-16/C-17; same day Kani proofs CI path-gated c0b921d; 2026-06-24/25 audit-taxonomy follow-ups: audit-tail renders canonical names, ADR-007 amendment)
5+
last_synced_to_code: 2026-07-16 (ADR-018 step 7: init runs as PID 1 — kernel create-init path, blob mapping, manifest-step7 coexistence variant, supervise feature; 2026-07-12 step 6: user/init crate — SupervisorEngine + shell, payload_extent, READY_PING_TAG; 2026-07-10 step 5: handle_spawn manifest branch — kernel-typed spawn table, rights normalization, INIT_PROCESS gate; same day step 4: kernel manifest transcription + spawn-grant table + module-capacity 128, boot-stall flake documented; 2026-07-08: ADR-018 accepted + steps 1-3: cambios-manifest crate, build-manifest tool + manifest.toml registry, kernel endpoint-reservation table; 2026-07-06: ADR-037 Phase 1 port sweep COMPLETE — all 22 services on service_main!; 2026-07-05: virtio-blk driver port + try_recv_verified + poll helpers; terminal-window onto `service_main!` heap arm + no-endpoint macro arms; 2026-07-04 L1: `user/libipc` ServiceError + Reader/Writer + ServiceLoop, policy-service loop ported; 2026-07-03 L0: `user/libsys-rt` `service_main!` entry macro + policy-service port — first framework consumer; 2026-07-02: audit-concurrency worktree merge bd50b76: aarch64 + riscv64 TLB-shootdown weak-memory ordering fixes, riscv64 PLIC source enabled on SYS_WAIT_IRQ, linker `.got` placement fix, CLAIMS.md C-16/C-17; same day Kani proofs CI path-gated c0b921d; 2026-06-24/25 audit-taxonomy follow-ups: audit-tail renders canonical names, ADR-007 amendment)
66
authoritative_for: what is built vs designed vs planned, current test counts, current phase status
77
convention: Keep `last_synced_to_code` a single date. Chronological narrative
88
goes in the "Recent landings" section below — rotate out after ~3 weeks so
@@ -30,6 +30,7 @@ belongs in the linked ADR, not here.
3030

3131
Chronological, newest first. ~3 week window — older items rotate out; git log has the full history.
3232

33+
- **2026-07-16** — ADR-018 step 7: **boot integration, coexistence — init runs as PID 1** (x86_64). The kernel's boot path now: transcribes the manifest (in-loop, as at step 4), registers `init` spawn-only, and after the module loop creates init — signed-ELF load, manifest blob mapped read-only at `MANIFEST_USER_VADDR` (module physical pages, deliberately not VMA-tracked — `destroy_process` reclaims VMA regions and these pages are shared with the boot-module registry; fixed address below `VMA_ALLOC_BASE` per the ELF-segment convention), narrow caps (receive on endpoint 1 + `CreateProcess`, nothing else), manifest-declared AID bound, `set_init_process` armed (the step-5 spawn branch is now live for init's callers). Manifest-without-init is a typed `InitModuleMissing` boot failure; init-without-manifest degrades to legacy boot. Boot proof: `✓ init created as PID 1` → `[init] manifest valid: 15 service(s) described; supervision starts at the step-8 cutover` → unchanged service chain → 8.9s sentinel ×3. Init's `register_endpoint(1)` is the reservation gate's first live customer (AID-matched). Coexistence machinery: `build-manifest --init-only-reservations` + `make manifest-step7` (ISO stages this variant; entries keep full grants/deps, only reservations suppressed) and the `supervise` cargo feature on user/init (default OFF — the legacy chain still starts services; the wave would double-spawn. Step 8 flips it and removes the chain; flag + target retire there). First-boot bug caught and fixed in-session: create-init originally mapped init's own ELF bytes as the manifest blob (init read an ELF header where CBOSMANI belonged); the two-buffer signature now makes the conflation unrepresentable. `BootError` gains `InitModuleMissing`/`InitCreationFailed` (+ the drifted step-4 variant lists in error.rs tests caught up). Verified: 926 kernel + 7 init + 31 manifest host tests, tri-arch build + clippy clean, check-boot-panics 0, run-quiet ×3 at 8.9s. **aarch64/riscv64 staging deferred**: limine-aarch64.conf + FAT image and riscv initrd don't carry manifest.bin/init.elf yet — the create-init arm never fires there (absent manifest ⇒ legacy boot). Revisit when: step-8 cutover prep starts (its per-arch boot proof requires all-arch manifests; also verify riscv initrd module addresses are HHDM-virtual before enabling the phys conversion there). Next: step 8 (cutover) — gated on the bootstrap-equality sweep.
3334
- **2026-07-12** — ADR-018 step 6: **`user/init` crate** (dormant until step 7 — nothing loads the ELF or maps the blob yet). Engine/shell split: `user/init/src/engine.rs` is a pure `SupervisorEngine` (explicit per-service state machine `NotSpawned → Spawned{task} → Ready | SpawnFailed | DepFailed`, fixed arrays, no allocator per the ADR — revisit only if init ever needs an `alloc`-pulling dependency), sequencing per ADR-018 § 4: one spawn in flight, readiness matched by kernel-stamped sender AID against the entry AID, dependency-failure cascade with bounded fixpoint; 7 host tests. `src/main.rs` is the hand-rolled `_start` shell (init is kernel-created PID 1 outside the boot gate, so no `service_main!` — both macro arms emit `module_ready()`): sizes its parse slice via the new `cambios-manifest::payload_extent` (a slice must never extend past the kernel's page-granular blob mapping, so "parse with a max window" was unsound), registers the header-declared init endpoint, supervises, then idles blocking on recv. cambios-manifest additions: `READY_PING_TAG` (step-8 ready-ping wire tag; identity comes from the stamp, not the payload), derived `MANIFEST_MAX_BYTES` ceiling (ASSUMPTIONS.md row), `payload_extent` + 3 tests (31 total). Makefile: `init`/`init-aarch64`/`init-riscv64`; workspace exclude gains `user/init`. Not built by any ISO/CI path until step 7 staging (accepted one-step window). Verified: init 7/7 host tests warning-free, init ELFs build on all three targets, kernel 926 host tests, `make check-all`, tri-arch clippy clean, `run-quiet` 10.0s. Next: step 7 (boot integration, coexistence — kernel creates init as PID 1).
3435
- **2026-07-10** — ADR-018 step 5: **`handle_spawn` manifest branch** (dormant until step 7). Spawn-table rows now hold *kernel-typed* grants: `SpawnGrantTable::install` transcribes wire grants at boot (exhaustive `system_caps` → `CapabilityKind` mapping, endpoint bounds vs `MAX_ENDPOINTS`, typed rejects boot-fatal) and rights-normalizes — per-endpoint unions with `AllEndpoints` bits folded in, because the per-process `grant()` *replaces* rights on regrant and the emitter writes narrow-before-wide (in-order apply would have left every service's own endpoint send-only, unable to receive; caught at implementation, pinned by test). `handle_spawn`: when the caller `is_init_process` and the manifest declared the module, `install_manifest_row` installs exactly the row's grants + binds the row's AID — no blanket loop, no inherited system caps; all other callers take the legacy arm unchanged (whitespace-only reindent). `INIT_PROCESS` write-once static (generation-aware; never set until step 7 ⇒ branch provably dead — boots byte-identical). `validate_payload` also rejects zero AIDs (the `Principal::ZERO` sentinel must be unmintable once AIDs bind). Verified: 926 host tests (7 new), tri-arch, tri-arch clippy 0 warnings, check-boot-panics 0, 3× `run-quiet` green (9.8–9.9s). Next: step 6 (`user/init` crate).
3536
- **2026-07-10** — ADR-018 step 4: **kernel manifest transcription**. `src/manifest.rs`: verify the `manifest.bin` boot module's ARCSIG trailer against the bootstrap pubkey (same trailer path as signed ELFs), parse via `cambios-manifest` (shared total-validator), populate the endpoint-reservation table + the new spawn-grant table (module name → AID + grants, `BOOTSTRAP_PRINCIPAL` write-once lifecycle, ~64 KiB .bss). Present-but-invalid manifest = typed `BootError` (4 new variants) — booting permissively on corrupt security config would be the vulnerability; absent manifest = empty tables = behavior unchanged. `load_boot_modules` threads `Result<(), BootError>` per ADR-021. `MAX_MODULES`/`MAX_BOOT_MODULES` 32 → 128 (lockstep trio with `MAX_MANIFEST_ENTRIES`). Verified: 919 host tests (5 new), tri-arch, check-boot-panics 0, end-to-end smoke (endpoints-stripped manifest module in the chain → "15 spawn rows, 1 reserved endpoint" + clean boot), 5× consecutive `run-quiet` green at final config. Next: step 5 (handle_spawn manifest branch).

0 commit comments

Comments
 (0)