Implementation Status
CambiOS Implementation Status
Living status doc. This file is the single source of truth for “what is currently built.” It is auto-refreshed when feature work lands (see CLAUDE.md § Post-Change Review Protocol Step 8). Pure intent and plans live in CambiOS.md and the design docs; this file is for current state.
If you’re trying to figure out “is X done yet?” — this is the doc to read. If you’re trying to figure out “should X be done a certain way?” — read the linked design doc instead.
At a glance
- 447 unit tests passing on host (
x86_64-apple-darwin) - x86_64: clean release build, boots in QEMU with 2 CPUs, 6 boot modules running (policy-service, key-store, fs-service, virtio-blk, compositor, shell).
arcobj list/put/getworks end-to-end; objects persist across reboots on virtio-blk. Compositor is the Phase Scanout-1 scaffold (ADR-014) — registers endpoint 28, enters headless mode, idles; no scanout-driver bound yet. - AArch64: clean release build, boots in QEMU
virt,make img-aarch64now builds + includes virtio-blk + compositor (same 6-module limine.conf as x86_64). Driver’s port-I/O init path is x86_64-specific — on AArch64 the driver entersno_device_loop()and ObjectStore stays RAM-backed until AArch64 device IRQ routing lands. - Bare metal: USB boot tooling complete (
make img-usbbuilds GPT image;make usb DEVICE=/dev/diskNwrites safely); not yet tested on target hardware (Dell Precision 3630)
Subsystem status
| Subsystem | Status | Notes | Code | Design |
|---|---|---|---|---|
| Microkernel core | Done | Heap, frame allocator, page tables, GDT/IDT (x86), VBAR_EL1 (AArch64) | src/microkernel/, src/memory/ | CambiOS.md § The Microkernel |
| Per-CPU SMP scheduler | Done | Per-CPU schedulers, 4 priority bands, O(1) scheduling, task migration, push-based load balancing | src/scheduler/ | SCHEDULER.md, ADR-001 |
| Voluntary context switch | Done | yield_save_and_switch (x86_64 + AArch64), synthetic exception frame | src/arch/x86_64/mod.rs, src/arch/aarch64/mod.rs | — |
| Preemptive context switch | Done | Timer ISR with full register save, context switch hint, TLB shootdown | src/arch/*/mod.rs | ADR-001 |
| Capability-based IPC (control path) | Done | 256-byte fixed messages, three-layer enforcement, sender_principal stamping, sharded per-endpoint | src/ipc/ | ADR-000, ADR-002, ADR-005 |
| Capability bulk path (channels) | Done (Phase 3.2d) | Shared-memory channels: ChannelManager, 5 syscalls (28-32), CreateChannel system capability, channel-aware process exit cleanup, TLB shootdown on close/revoke, libsys wrappers. Producer/Consumer/Bidirectional roles with MMU-enforced access (RW/RO). | src/ipc/channel.rs, src/syscalls/dispatcher.rs, src/ipc/capability.rs, user/libsys/ | ADR-005 |
| Capability revocation | Done (Phase 3.1, bootstrap-only) | SYS_REVOKE_CAPABILITY (#27), CapabilityManager::revoke(), revoke_all_for_process() wired into handle_exit. Authority = bootstrap Principal only; grantor/revoke-right paths defer to Phase 3.4. Audit emit, channel mapping cleanup, policy cache invalidation, and active holder notification are in-code stubs citing Phase 3.2/3.3/3.4. | src/ipc/capability.rs, src/syscalls/dispatcher.rs | ADR-007 |
| CreateProcess capability | Done (Phase 3.2b) | CapabilityKind::CreateProcess system capability. handle_spawn checks authority before allocation. Granted to kernel processes (0-2) and all boot modules at boot. revoke_all_for_process clears system caps on exit. | src/ipc/capability.rs, src/syscalls/dispatcher.rs, src/microkernel/main.rs | ADR-008 § Migration Path |
| Boot-time-sized kernel object tables | Done (Phase 3.2a+3.2b+3.2c+3.2d) | MAX_PROCESSES removed as compile-time constant. num_slots computed at boot from config::ACTIVE_POLICY and frame allocator’s tracked memory. Kernel object table region allocated via FrameAllocator::allocate_contiguous, HHDM-mapped, carries ProcessTable and CapabilityManager slot storage as &'static mut slices. Per-process heap region allocated on demand and reclaimed on exit. Phase 3.2b: CapabilityKind::CreateProcess system capability. Phase 3.2c: ProcessId generation counters. Phase 3.2d: shared-memory channels (ChannelManager, 5 syscalls, CreateChannel cap), full process lifecycle cleanup (VMA reclaim, page table frame reclaim on exit), lock hierarchy renumbered (CHANNEL_MANAGER at position 5). CapabilityHandle refactor deferred to post-v1 handle table. | src/config/tier.rs, src/memory/object_table.rs, src/process.rs, src/ipc/capability.rs, src/ipc/mod.rs, src/syscalls/dispatcher.rs, src/loader/mod.rs, src/microkernel/main.rs, build.rs | ADR-008 |
| Deployment tiers / scope | Designed, policy-only | Three tiers (Tier 1 CambiOS-Embedded, Tier 2 CambiOS-Standard, Tier 3 CambiOS-Full). Single kernel binary across tiers; tier selection is an install-time choice that decides which TableSizingPolicy and which user-space services are loaded. No code gate yet. | — | ADR-009, GOVERNANCE.md |
| Audit infrastructure | Done (Phase 3.3) | Kernel→userspace event streaming for security observability. Per-CPU lock-free staging buffers → global audit ring (64 KiB, 1023 event slots). 16 event types, audit::emit() at 14 instrumentation points. IPC send/recv sampled 1-in-100. Drain via BSP timer ISR piggyback (100 Hz). SYS_AUDIT_ATTACH (33) maps ring RO into consumer. SYS_AUDIT_INFO (34) returns stats. | src/audit/, src/syscalls/dispatcher.rs, user/libsys/ | ADR-007 |
| Policy service | Designed, not implemented | User-space externalization of on_syscall decisions | — | ADR-006 |
| Cryptographic identity | Done (Phase 1C, hardware-backed + load-bearing) | Bootstrap Principal from compiled-in YubiKey pubkey, IPC sender stamping, BindPrincipal/GetPrincipal syscalls, identity gate in syscall dispatcher (unidentified processes can only Exit/Yield/GetPid/GetTime/Print/GetPrincipal), recv_verified in libsys (userspace services structurally reject anonymous IPC senders) | src/ipc/, src/syscalls/, user/libsys/, bootstrap_pubkey.bin | identity.md, ADR-003 |
| Signed ELF loading | Done | ARCSIG trailer, Ed25519 signature verification, SignedBinaryVerifier | src/loader/ | ADR-004 |
| Content-addressed ObjectStore | Done (Phase 1C, RAM-backed) | CambiObject with Blake3, Ed25519, ACL; RamObjectStore (256 objects) | src/fs/ | ADR-003, ADR-004 |
| Persistent ObjectStore | Done (Phase 4b) | DiskObjectStore<B: BlockDevice> — generic disk-backed impl of ObjectStore (Phase 4a.i). On-disk format in ADR-010: 4 KiB blocks, superblock + 2-block record slots, commit-by-header-magic-write crash consistency, bounded-iteration mount scan. Phase 4b restructured the lazy init: boot installs RamObjectStore; each SYS_OBJ_* handler calls ensure_disk_store() BEFORE acquiring OBJECT_STORE. The IPC handshake with virtio-blk happens lock-free, then the DiskObjectStore is swapped in under the lock. This closes the spinlock-while-yielding window that previously stalled arcobj. End-to-end arcobj list/put/get/delete verified across reboots on virtio-blk (disk superblock magic ARCOBJ00 survives power cycle). On AArch64 (no driver device yet), handshake fails fast and RAM store persists — arcobj works, objects don’t survive reboot until AArch64 virtio-blk lands. | src/fs/disk.rs, src/fs/block.rs, src/fs/lazy_disk.rs, src/fs/virtio_blk_device.rs, src/fs/mod.rs, src/syscalls/dispatcher.rs, src/lib.rs | ADR-010, FS-and-ID-design-plan.md |
| BlockDevice abstraction | Done (Phase 4a.i) | BlockDevice trait (read_block/write_block/flush/capacity_blocks at 4 KiB granularity) + in-kernel MemBlockDevice. The trait is the seam between DiskObjectStore and any storage backend — memory (testing), virtio-blk (4a.iii), NVMe/AHCI (post-v1). | src/fs/block.rs | ADR-010 |
| Key-store service | Done | User-space, IPC endpoint 17, runs in degraded mode (no runtime YubiKey access yet) | user/key-store-service/ | — |
| FS service | Done | User-space, IPC endpoint 16, ObjectStore gateway with sender_principal enforcement | user/fs-service/ | — |
| Virtio-net driver | Done | User-space, IPC endpoint 20, PCI discovery, TX/RX virtqueues, DMA bounce buffers. Shares the legacy-virtio queue-size bug fixed in virtio-blk (Phase 4a.ii) — driver clamps queue size to 32 but the device thinks it’s 256, so completions land at an offset the driver never reads. Re-enable in limine.conf after applying the virtio-blk fix (use device-reported queue size, bump MAX_QUEUE_SIZE to 256). Tracked as a known issue. | user/virtio-net/ | — |
| Virtio-blk driver | Done (Phase 4b) | User-space. Endpoint 24 (user clients) + endpoint 26 (kernel-only, no identity check — trust by endpoint choice, mirror of policy service at 22). PCI discovery (vendor 0x1AF4, device 0x1001 legacy / 0x1042 modern), single request virtqueue with 3-descriptor chains, DMA bounce buffers, DeviceValue<T> hostile-device validation. Kernel commands on 26: HANDSHAKE, READ_BLOCK, WRITE_BLOCK, FLUSH, CAPACITY. Responses flow to endpoint 25 via the handle_write intercept. Phase 4b: dual-endpoint service loop uses SYS_TRY_RECV_MSG = 37 (non-blocking) to poll both endpoints without parking on one — blocking on ep24 would miss wakes targeted at ep26. Now builds + runs on AArch64 too (make img-aarch64 includes it); driver falls through to no_device_loop when QEMU virt has no virtio-blk attached. | user/virtio-blk/ | ADR-010 |
| Intel I219-LM driver | Scaffolded, untested on hardware | User-space, same IPC interface as virtio-net for bare-metal target | user/i219-net/ | — |
| UDP/IP stack | Done | User-space, IPC endpoint 21, ARP, IPv4, UDP, NTP demo | user/udp-stack/ | — |
| DHCP client | Pre-work landed in udp-stack; client paused | UDP stack has CMD_SET_CONFIG and CMD_DHCP_SEND helpers; the client itself is paused pending channel architecture | partial in user/udp-stack/ | — |
| DNS resolver | Planned | Stub resolver over UDP, caches results | — | — |
| TCP stack | Planned | Connection state machine, retransmission, sliding window | — | — |
| Shell | Done | Interactive shell over serial, command parsing. Phase 4a.iv adds arcobj put/get/list/delete (fs-service client, shell endpoint 18) — exercises the full SYS_OBJ_* → LazyDiskStore → VirtioBlkDevice → driver path end-to-end. | user/shell/ | — |
| Spawn / WaitTask syscalls | Done | New process creation from boot module by name; parent waits for child exit | src/syscalls/dispatcher.rs, src/boot_modules.rs | — |
| PCI bus discovery | Done | Bus 0 scan at boot, device table via DeviceInfo syscall | src/pci/ | — |
| Device syscalls | Done | MapMmio, AllocDma, DeviceInfo, PortIo | src/syscalls/dispatcher.rs | — |
| Bootloader abstraction | Done (Phase GUI-0) | BootInfo + src/boot/ module isolates the kernel from Limine types (MemoryRegion, FramebufferInfo, ModuleInfo). boot::limine::populate is the only site that reads limine::* responses outside the one early HHDM read; every subsequent consumer uses boot::info(). Prepares for camBIOS firmware replacement without kernel-wide refactor. SMP/AP wakeup not yet abstracted (deeper coupling; deferred). | src/boot/mod.rs, src/boot/limine.rs, src/microkernel/main.rs | ADR-011 |
| SYS_MAP_FRAMEBUFFER + graphics caps | Done (Phase GUI-0, unwired) | SyscallNumber::MapFramebuffer = 35 returns a 32-byte FramebufferDescriptor to user-space (vaddr + geometry + pixel format). Capability-gated via CapabilityKind::MapFramebuffer. LegacyPortIo and LargeChannel capability kinds landed alongside; all three are unwired (granted to nobody today) awaiting Phase GUI-1+ consumers. libsys wrappers wait_irq + map_framebuffer added. | src/syscalls/dispatcher.rs, src/ipc/capability.rs, user/libsys/src/lib.rs | ADR-011 |
| Compositor scaffold | Done (Phase Scanout-1) | user/compositor boot module: registers COMPOSITOR_ENDPOINT = 28, selects a ScanoutBackend (today always HeadlessBackend since no scanout-driver service exists), enters no-op render loop. The full ScanoutBackend trait surface + wire-format types (DisplayInfo, Geometry, Mode, PixelFormat, ScanoutBuffer, ScanoutError, ScanoutEvent, Rect) are present as the protocol contract; VirtioGpuBackend / IntelGpuBackend / LimineFbBackend implementors land Scanout-2 onward. Compositor has zero hardware syscall surface (no MapMmio, no MapFramebuffer, no AllocDma) — modular boundary per ADR-014 is load-bearing. Boots cleanly on x86_64 QEMU; aarch64 builds but compositor requires no arch-specific behavior. | user/compositor/ | ADR-014 |
| GIC + ARM Generic Timer (AArch64) | Done | GICv3 (Distributor + Redistributor + ICC sysregs), CNTP at 100Hz | src/arch/aarch64/gic.rs, src/arch/aarch64/timer.rs | — |
| APIC + I/O APIC (x86_64) | Done | Local APIC timer at 100Hz, I/O APIC for device IRQs, SMP IPI | src/arch/x86_64/apic.rs, src/arch/x86_64/ioapic.rs | — |
| TLB shootdown | Done | x86_64 via vector 0xFE IPI; AArch64 via TLBI broadcast | src/arch/*/tlb.rs | — |
| AArch64 SMP timer on AP | Known issue | AP timer PPI not firing in QEMU virt; single-CPU works fully | — | — |
| AArch64 device IRQ routing | Gap | GIC enable_spi/set_spi_trigger exist but not wired into boot path | — | — |
| USB boot tooling | Done | make img-usb builds GPT-partitioned UEFI image; make usb DEVICE=... writes safely with confirmation | Makefile | — |
| Yggdrasil mesh networking | Planned | Identity-routed overlay network (post-DNS/TCP) | — | identity.md |
| TLS transport | Planned (post-v1) | TLS 1.3 over TCP | — | — |
| VFS / mount infrastructure | Planned (post-v1) | Mount table, path resolution, namespace isolation | — | — |
| USB HID driver | Planned (post-v1) | XHCI host controller, HID device support; prerequisite for runtime YubiKey | — | — |
| DID resolution | Planned (post-v1) | did:key method per identity.md | — | identity.md |
| Identity revocation (per identity.md) | Planned (post-v1) | Eventually-consistent revocation via signed objects in social log | — | identity.md |
| Process lifecycle cleanup | Done (Phase 3.2d.ii) | handle_exit performs full cleanup: capability revocation, channel revocation (unmap + TLB shootdown + frame free), VMA region reclaim, page table frame reclaim (PML4 + intermediates), heap reclaim. purge_task evicts exiting task from scheduler ready queues. Kernel stack dealloc deferred (bounded 32 KiB/process leak, requires scheduler-level deferred-free). | src/syscalls/dispatcher.rs, src/process.rs, src/memory/paging.rs, src/memory/mod.rs | — |
| AArch64 user-space services | Done | All boot modules build for both targets via libsys shared syscall wrappers (x86_64 syscall + AArch64 svc) | user/libsys/ | — |
| RISC-V (riscv64gc) port | In progress (Phase R-2 done 2026-04-16) | Third architecture backend, parity-targeted with x86_64/AArch64. Phase R-2 milestone: make run-riscv64 boots under OpenSBI, trampolines from physical 0x80200000 to higher-half VMA 0xffffffff80200000 via Sv48 paging, parses DTB for /memory region, brings up frame allocator (4 GiB tracked, ~4 GiB free) + 4 MiB kernel heap at phys 0x80400000, and Box::new(0xcab105deadbeef) round-trips cleanly. Implements: Sv48 boot page table in src/arch/riscv64/entry.rs (L3[0]+L3[256] via shared L2_IDENTITY, L3[511] via L2_KERNEL; gigapage leaves; HHDM at 0xffff800000000000); hand-rolled FDT parser in src/boot/riscv.rs (bounded iteration, /memory@* walk, OpenSBI/DTB/kernel reservations); overlay-aware init_kernel_heap (picks lowest-base non-Usable overlay first — handles the DTB “full RAM as one Usable + overlay reservations” model that would otherwise collide heap with OpenSBI’s PMP-protected range); non-Usable reservation pass in init_frame_allocator (portable improvement for any protocol delivering overlay reservations). Phase R-1 carry-forward: src/arch/riscv64/ skeleton (percpu via tp+sscratch, syscall/tlb/plic/timer stubs, _start asm), NS16550 UART, riscv64 arms across lib.rs/dispatcher/policy/platform/loader/audit, kmain_riscv64(hart_id, dtb_phys) entry. Phase R-2.d (shared paging module RISC-V PTE arm) deferred to R-3/R-4 where consumers land (early_map_mmio for PLIC in R-3, process page tables in R-4) — per feedback-skip-test-hooks: don’t build arms ahead of consumers. Bootloader = OpenSBI + custom S-mode _start (no Limine on RISC-V). Hardware target = TBD CambiOS-designed; QEMU virt for dev. | src/arch/riscv64/, src/boot/riscv.rs, src/microkernel/main.rs (kmain_riscv64, init_kernel_heap, init_frame_allocator), linker-riscv64.ld, Makefile | ADR-013 |
| AI pre-execution code analysis | Planned (post-v1) | JIT analysis of ELF binaries before execution | — | CambiOS.md § AI Integration |
| Behavioral anomaly detection (AI) | Planned (post-v1) | Runtime monitoring service consuming audit telemetry | — | ADR-007, PHILOSOPHY.md |
| AI compatibility layer (Win32) | Planned (post-v1) | Long-term vision item from CambiOS.md | — | CambiOS.md § Application Compatibility |
| Formal verification (Kani) | Started 2026-04-16 | First proof live: BuddyAllocator::free rejects every offset inside the reserved prefix, for all prefix sizes in [16, 256] bytes (Kani 0.67.0, 150 checks pass in ~18s). Proof crate path-includes the kernel’s buddy_allocator.rs so the proven source is the same source the kernel compiles — no fork. Run via make verify. Next candidates: allocate-then-free roundtrip, non-overlapping allocations, double-free rejection; widen prefix bound from 256 to allocator-state size (~20 KiB) once mark_range unwind cost is measured. | verification/buddy-proofs/ | — |
Phase markers
CambiOS uses informal phases to mark identity/storage milestones. These phases are referenced from identity.md and FS-and-ID-design-plan.md.
| Phase | Goal | Status |
|---|---|---|
| Phase 0 | Identity primitives in kernel + RAM-backed ObjectStore. Stamps unforgeable identity on every IPC message; gives every stored object an author and owner. | Done |
| Phase 1 | Real cryptography. Blake3 hashing, Ed25519 signature verification on objects, signed ELF modules, key store as user-space service. | Done |
| Phase 1B | Hardware-backed bootstrap identity. YubiKey-derived public key compiled into kernel; private key never enters kernel memory. | Done |
| Phase 1C | Key-store service degraded mode + signed ObjectStore puts. fs-service requests signing from key-store before ObjPutSigned; no unsigned fallback — objects cannot be stored without a valid signature. Identity is load-bearing: kernel identity gate + userspace recv_verified create structural dependency on the security model. | Done |
| Phase 2A | First user-space hardware driver. Virtio-net with PCI discovery, virtqueues, DMA bounce buffers, hostile-device validation. | Done |
| Phase 2B | First user-space network service. Stateless UDP/IP over virtio-net, with NTP demo. | Done |
| Phase 3 | Architecture: bulk data path (channels) + externalized policy + capability revocation + audit infrastructure. The substrate that real workloads (video, file I/O, AI inference) need. | In progress: 3.1 (revocation primitive) landed; 3.2a (boot-time-sized object tables) landed; 3.2b (CreateProcess capability) landed; 3.2c (ProcessId generation counter) landed; 3.2d (shared-memory channels + process lifecycle cleanup) landed; 3.3 (audit infrastructure) landed — see ADR-007. 3.4 (policy service) pending |
| Phase 4 | Persistent storage. Virtio-blk driver, disk-backed ObjectStore, CambiObject CLI in shell. | Done (Phase 4a: disk-format + driver + kernel adapter + arcobj CLI; Phase 4b: boot-cleanup pass + closed the IPC stall that prevented arcobj from actually completing). Phase 4b specifically landed: hello.elf removed from the boot chain (print-and-exit canary that masked the exit-path scheduler bug once, now eclipsed); [Tick] idle heartbeat removed (noise-only); AArch64 img-aarch64 now builds virtio-blk; SYS_TRY_RECV_MSG = 37 syscall (non-blocking recv for services polling multiple endpoints); REPLY_ENDPOINT registry fixes the msg.from_endpoint() routing bug (replies now land on the sender’s registered endpoint, not their pid slot); LazyDiskStore → ensure_disk_store() — lazy init moved outside the OBJECT_STORE spinlock. End-to-end arcobj list/put/get/delete verified across reboots. The originally-planned Phase 4b (“ObjectStore ownership into fs-service + bulk channel IPC”) is a separate, later piece of work — not required for v1 arcobj, deferred. |
| Phase 5 | Identity-routed networking. Yggdrasil peer service, Ed25519→IPv6 mapping, mesh routing without DNS. | Planned |
| Phase 6 | Biometric commitment + key recovery. Retinal/facial ZKP enrollment, social attestation, key rotation protocol. | Planned (post-v1) |
| Phase 7 | SSB bridge. Cross-instance capability grants and identity attestations over append-only logs. | Planned (post-v1) |
RISC-V port phases (parallel track — see ADR-013)
| Phase | Goal | Status |
|---|---|---|
| R-0 | Build infrastructure: rust-toolchain target, .cargo/config.toml block, linker-riscv64.ld, Makefile targets including make check-all tri-arch gate. Verify cargo build --target riscv64gc-unknown-none-elf resolves. | Done (2026-04-15) |
| R-1 | First serial output. OpenSBI hand-off, S-mode _start boot stub, NS16550 UART, minimal kmain_riscv64(hart_id, dtb_phys) reaches println. | Done (2026-04-16) — kernel boots in QEMU virt, prints banner, halts. Sv48 boot trampoline + DTB parser pulled forward into R-2 per ADR-013 Decision 3 fallback (R-1 ran at 0x80200000 physical=virtual with paging off). |
| R-2 | Memory management. Sv48 boot trampoline, higher-half kernel at 0xffffffff80000000, hand-rolled DTB parser for /memory, frame-allocator init with overlay-aware reservations (OpenSBI, DTB, kernel image), kernel heap, Box::new end-to-end. | Done (2026-04-16) — milestone: Sv48 higher-half boot + DTB parse + 4 MiB heap + Box::new(0xcab105deadbeef) round-trips. Fixed a pre-existing FDT field-order bug (size_dt_strings/size_dt_struct at offsets 32/36) surfaced by fresh DTB integration. R-2.d (shared paging module RISC-V PTE arm) deferred to R-3/R-4 consumers — no early compile-only arms. |
| R-3 | Interrupts + preemptive scheduling. Single trap vector, scause dispatch, SBI timer, PLIC driver, context switch (callee-saved + sepc/sstatus), GDT shim. | Planned |
| R-4 | User space. ELF EM_RISCV (0xF3), libsys ecall stubs, hello-riscv64 program, U/S privilege transition via sscratch/tp swap. | Planned |
| R-5 | SMP. Hart enumeration from DTB, sbi_hart_start, SBI IPI for remote TLB shootdown (probe Svinval). Triggers BootProtocol-trait factoring decision. | Planned |
| R-6 | Full service parity. PCI ECAM MMIO, virtio-mmio transport, boot modules via -initrd, all user-space services (policy, ks, fs, virtio-blk, shell). | Planned |
v1 Roadmap progress
The v1 milestone is “interactive, network-capable, identity-rooted OS running on real hardware with persistent storage.” Items in dependency order:
| # | Item | Status |
|---|---|---|
| 1 | Shell | Done |
| 2 | USB boot tooling (Dell 3630) | Done (untested on target hardware) |
| 3 | Intel I219-LM NIC driver | Scaffolded (untested on target hardware) |
| 4 | DHCP client | Paused (pre-work landed in udp-stack; pending Phase 3 architecture) |
| 5 | DNS resolver | Planned |
| 6 | TCP stack | Planned |
| 7 | Virtio-blk driver | Done (Phase 4a.ii + 4b cross-arch build) |
| 8 | Persistent ObjectStore | Done (Phase 4b: end-to-end arcobj via ensure_disk_store() + REPLY_ENDPOINT registry + SYS_TRY_RECV_MSG) |
| 9 | CambiObject CLI | Done (Phase 4a.iv — arcobj put/get/list/delete in the shell) |
| 10 | Yggdrasil peer service | Planned |
Currently blocking the v1 sequence: Phase 3.4 (policy service). Revocation (Phase 3.1), channels (Phase 3.2d), and audit infrastructure (Phase 3.3) are done. Once the policy service exists, items 4-10 sit on top of it and proceed in order.
Test coverage
| Subsystem | Tests | Notes |
|---|---|---|
| Scheduler | 35 | Creation, init, lifecycle, schedule, time slice, block/wake, IRQ/message wake, idle immutability, migration primitives, invariants |
| Capability manager | 40 | Grant, verify, delegation, escalation prevention, capacity limits, Principal bind/get, revocation authority checks, revoke_all_for_process cleanup, system capability (CreateProcess + CreateChannel) grant/check/revoke/idempotency/independence/cleanup, ProcessId generation counter stale-reference rejection, ProcessId encoding round-trip, error-path coverage |
| IPC interceptor | 13 | Payload validation, bounds, self-send, delegation policy, syscall filtering, custom interceptors |
| ELF verifier | 14 | W^X, kernel space rejection, overlapping segments, memory limits, entry point boundary cases, signed binary verifier |
| IPC sender_principal | 4 | Default None, kernel stamping, no-principal path, direct send bypass |
| ObjectStore types + crypto | 21 | Principal equality, Blake3 hashing, Ed25519 sign/verify, CambiObject creation/author immutability/owner/lineage, ObjectCapSet |
| RamObjectStore | 12 | Put/get, idempotency, invalid hash rejection, delete, list, capacity, slot reuse, author/owner preservation |
| BlockDevice abstraction (Phase 4a.i) | 11 | MemBlockDevice zero-init, read/write round-trip, block isolation, out-of-bounds, flush no-op, full-pattern sweep, error Display |
| DiskObjectStore (Phase 4a.i) | 30 | Superblock encode/decode + blank/wrong-magic/corrupt-checksum classification, record-header encode/decode + torn-write treated as free + oversized-content rejection, FreeMap ops, format+put+get, idempotent put, delete + slot reuse, capacity exhaustion, list, reboot preserves objects, reboot preserves signed-and-verified object, reboot after delete, reboot with store at capacity, generation counter bump on mount, corrupt-superblock rejection, torn-header invisible after remount, orphan-content-block is reusable (crash between content and header write), undersized device fails, LBA math |
| Memory subsystem | ~37 | Buddy allocator, frame allocator (including Phase 3.2a free_contiguous round-trip + atomicity tests), heap, paging primitives; allocate_contiguous at HEAP_PAGES (Phase GUI-0 bounds bump, ADR-011) |
| Tier configuration (Phase 3.2a) | 16 | TableSizingPolicy field bounds, num_slots_from clamp behavior, realistic memory sizes (256 MB / 4 GB / 8 GB / 32 GB / 1 TB) per tier, monotonicity, binding_constraint_for per clamp, slot-clamp-shadows-budget-clamp invariant |
| Kernel object table region (Phase 3.2a) | 5 | region_bytes_for page-aligned and monotonic, init produces disjoint valid slices with None initialization, rejects zero slots, propagates frame-alloc failure |
| Channel manager (Phase 3.2d) | 29 | ChannelId encoding, ChannelRole permissions, create/attach/close/revoke state machine, table full, principal mismatch, stale generation, slot reuse, revoke_all_for_process, preserve-bystander; create-at-MAX_CHANNEL_PAGES ceiling test (Phase GUI-0 bounds bump, ADR-011) |
| Process lifecycle cleanup (Phase 3.2d.ii) | 3 | VMA reclaim (empty, drains tracker, kernel task noop) |
| Audit staging buffer (Phase 3.3) | 14 | SPSC ring: push, drain, wrap-around, overflow, interleaved, capacity cycles, take_dropped |
| Audit event types (Phase 3.3) | 18 | Event kind discriminants, wire format size, builder round-trips for all 16 event types, timestamp/sequence encoding |
| Audit ring + drain (Phase 3.3) | 12 | Ring header magic/capacity, write/wrap, drain from staging, staging drop reporting, batch bound, consumer attach/detach, capacity math |
| AArch64 portable logic | 12 | PerCpu offsets, GIC register math, page table descriptor flags |
| Other | ~70 | Timer, IPC sync channel, ProcessTable, VMA tracker, syscall args, etc. |
| Total | 447 | All passing on x86_64-apple-darwin |
Run with: RUST_MIN_STACK=8388608 cargo test --lib --target x86_64-apple-darwin
Known issues
- AArch64 SMP timer on AP: PPI 30 (ARM Generic Timer) does not fire on the second CPU in QEMU
virt. Single-CPU mode works fully. Investigation pending; may be a QEMU configuration issue or a missing GIC redistributor configuration step on the AP path. - AArch64 device IRQ routing: GIC
enable_spi()/set_spi_trigger()exist as functions but are not called from the boot path orhandle_wait_irq(). Device IRQs (virtio, PL011 RX) are not yet functional on AArch64. Affects virtio-blk polling-mode viability too — deferred. - Legacy-virtio queue-size clamping (virtio-net):
user/virtio-net/src/main.rscaps the virtqueue at 32 entries, but the device advertises more (QEMU: 256) and legacy virtio’s Queue Size register is read-only — the driver MUST use the device-reported size. The mismatch puts avail/used rings at different offsets on the two sides, so completions never arrive. Diagnosed during Phase 4a.ii. Fix: bumpMAX_QUEUE_SIZEto 256 and drop the clamp (the virtio-blk driver does this). Re-enable the network drivers inlimine.confonly after fixing this. - fb-demo (Phase GUI-1) blocks Phase 4a services when both are enabled: When
fb-demois inlimine.confalongside the Phase 4a modules (fs-service, virtio-blk, shell), fb-demo’sSYS_MAP_FRAMEBUFFERcall completes kernel-side (kernel prints[fb-syscall] write_user_buffer rc=Ok(32)) but fb-demo’s userspace never prints[FB-DEMO] after syscall, and the subsequent boot modules (fs-service, virtio-blk, shell) never reach their service loops. Root cause undiagnosed; likely an issue in the framebuffer syscall’s return path or fb-demo’s expectations about the mapping. Temporarily disablingfb-demo.elfinlimine.conflets the Phase 4a chain come up cleanly. Not a Phase 4a bug — it’s a Phase GUI-1 concern — but listed here because it affects thearcobjinteractive demo. Boot module ordering is non-deterministicResolved. Sequential boot-time module loading landed:SYS_MODULE_READY = 36+BlockReason::BootGate+BOOT_MODULE_ORDERstatic. Each boot module’s_startcallssys::module_ready()after endpoint registration; modules boot in dependency order (policy → ks → fs → virtio-blk → shell → hello.elf).limine.confreordered accordingly.Intermittent kernel page fault inResolved. Root cause was two interacting bugs: (1)Scheduler::scheduleduring task-exit cleanuphandle_exitdid not purge the exiting task from the scheduler’s ready queues, leaving a staleTaskIdthat later dereferenced a freed slot; (2)ChannelManager::revoke_all_for_processreturned a[Option<ChannelRecord>; MAX_CHANNELS](~36 KiB) on the 8 KiB kernel stack, overflowing into adjacent task stacks and corrupting the BSP scheduler’s data. Fixes:Scheduler::purge_task(tid)helper added (called fromhandle_exitbeforeyield_save_and_switch),revoke_all_for_processchanged to returnVec<ChannelRecord>, andKERNEL_STACK_SIZEbumped from 8 KiB to 32 KiB.- ELF loader doesn’t merge overlapping segment permissions: If two PT_LOAD segments share a page with different permissions, the first segment’s permissions win. Worked around in user-space linker scripts via
ALIGN(4096)before.data. Loader fix is roadmap item 20. - Kernel stack not freed on process exit:
handle_exitnow performs full cleanup (capabilities, channels, VMAs, page table frames, heap) as of Phase 3.2d.ii. The 32 KiB kernel stack per task is the remaining leak — freeing it requires a deferred-dealloc mechanism (can’t free the stack you’re running on). The leak is bounded bynum_slots× 32 KiB (~6.4 MiB worst case). Scheduled for a dedicated cleanup pass. - Pre-existing user-space driver warnings:
cargo buildon theuser/virtio-net/anduser/i219-net/crates emitsdead_code/unused_importswarnings for scaffolded driver state (PCI field metadata, unused transport constants,phy_read/phy_writestubs,DmaBuf::zero, etc.). These are excluded from the main kernel workspace (Cargo.tomlexclude list) so they do not affect kernel builds, but surface whenmake runinvokes them. Not a correctness issue — the fields/methods are staged for future use. Tracking here so they get cleaned up when the respective drivers get their next real-hardware bring-up pass. - Virtio-net TX completion may require yield to idle on QEMU TCG: QEMU TCG defers virtio TX processing to its event loop, which runs during guest
hlt. The driver yields and the idle task hlts, which works for small bursts but the UDP stack’s ARP retry/timeout logic doesn’t yet exploit this fully. - Clippy warnings (~125 remaining, down from 164): Auto-fixable suggestions applied; doc formatting and module-level comment style fixed. Remaining breakdown: ~67
multiple_unsafe_ops_per_block(unsafe block splitting in arch code — debatable in hardware-adjacent code), ~25 missing// SAFETY:comments, ~12static_mut_refs(Rust 2024 edition migration — IDT/GDT/TSS patterns needUnsafeCelloraddr_of!), ~20new_without_defaultsuggestions. Scheduled for a dedicated cleanup pass between Phase 3.2d (channels) and Phase 3.3 (telemetry), before the static mut deprecation becomes a hard error.
Cross-references
- CambiOS.md — source-of-truth architecture document
- identity.md — identity architecture (Phases 0-7 are defined here)
- FS-and-ID-design-plan.md — settled decisions for the identity + storage layer
- SECURITY.md — enforcement status table (security-specific subset of this document)
- GOVERNANCE.md — project governance, deployment tiers, scope boundaries (companion to ADR-009)
- ASSUMPTIONS.md — catalog of every numeric bound in kernel code with SCAFFOLDING / ARCHITECTURAL / HARDWARE / TUNING category
- README.md — public-facing summary
- SCHEDULER.md — scheduler implementation reference
- docs/adr/ — architecture decision records (ADRs 000-013)
- CLAUDE.md — kernel technical reference and required-reading map