kernel: build a freestanding machine image
1f842c56a5d21c631f6b76e032cebae970268fdc4efa3dadc5173f6b294cdc4a
Verified: make -C kernel check with the machine-capable emulator; explicit boot finish and hosted checks pass.
1 parent
9a9ad076
kernel/Makefile
added
+27 -0
| 1 | + | # Freestanding kernel and hosted mechanism checks. |
|
| 2 | + | EMU ?= $(or $(RAD_EMULATOR),emulator) |
|
| 3 | + | HOST_EMU ?= $(EMU) |
|
| 4 | + | COMPILER := ../bin/radiance.rv64.dev |
|
| 5 | + | COMPILE := $(HOST_EMU) -memory-size=385024 -data-size=348160 -stack-size=512 -run $(COMPILER) |
|
| 6 | + | MODULES := |
|
| 7 | + | ||
| 8 | + | .PHONY: all check clean compiler-check |
|
| 9 | + | all: kernel.rv64 |
|
| 10 | + | ||
| 11 | + | compiler-check: |
|
| 12 | + | ||
| 13 | + | $(COMPILER): compiler-check |
|
| 14 | + | $(MAKE) -C .. RAD_EMULATOR=$(abspath $(shell command -v $(HOST_EMU))) |
|
| 15 | + | ||
| 16 | + | kernel.rv64: main.rad arch/entry.ras $(MODULES) $(COMPILER) |
|
| 17 | + | $(COMPILE) -pkg kernel -start arch/entry.ras -mod main.rad $(addprefix -mod ,$(MODULES)) -o $@ |
|
| 18 | + | ||
| 19 | + | check.rv64: check.rad $(MODULES) $(COMPILER) |
|
| 20 | + | $(COMPILE) -pkg kernel -mod check.rad $(addprefix -mod ,$(MODULES)) -o $@ |
|
| 21 | + | ||
| 22 | + | check: all check.rv64 |
|
| 23 | + | $(HOST_EMU) -run check.rv64 |
|
| 24 | + | $(EMU) -machine -no-guard-stack -max-steps=1000000 -count-instructions -run kernel.rv64 |
|
| 25 | + | ||
| 26 | + | clean: |
|
| 27 | + | rm -f kernel.rv64 check.rv64 |
kernel/NOTES.md
added
+39 -0
| 1 | + | # Kernel implementation decisions |
|
| 2 | + | ||
| 3 | + | The specification at https://radiant.computer/system/kernel takes precedence |
|
| 4 | + | for fixed call numbers, handle layout, rights, and object behavior. These notes |
|
| 5 | + | record the contracts established through step 1 of the 22-step plan. |
|
| 6 | + | ||
| 7 | + | ## Source and trust boundary |
|
| 8 | + | ||
| 9 | + | - Kernel mechanisms use freestanding Radiance; RAS owns machine entry, register |
|
| 10 | + | state, atomics, and MMIO. Hosted checks exercise the same mechanism modules. |
|
| 11 | + | Make and shell provide build and verification plumbing. |
|
| 12 | + | - Use `Once` for explicit-consumption obligations and safe references for |
|
| 13 | + | ordinary mutation. Raw addresses belong at platform and user-memory boundaries. |
|
| 14 | + | - Image loading is restricted to trusted binary RIL. Pointer-provenance and |
|
| 15 | + | type-safety verification, including verifiable compiler output, are deferred. |
|
| 16 | + | The compiler IL contains machine-word types and raw address operations; source |
|
| 17 | + | compilation and structural decoding do not prove isolation from hostile code. |
|
| 18 | + | - All components that can change admitted executable bytes remain in the TCB, |
|
| 19 | + | whether loading occurs inside or outside M-mode. Executable image code is |
|
| 20 | + | immutable; writable image state is an instance resource. |
|
| 21 | + | - The reference machine uses RAD0 and the sibling emulator, not an assumed |
|
| 22 | + | QEMU `virt` memory map. Emulator execution is not evidence of real-hardware |
|
| 23 | + | cache behavior or timing bounds. Report instruction counts, not host timings. |
|
| 24 | + | ||
| 25 | + | ## Validation |
|
| 26 | + | ||
| 27 | + | Use the current machine-capable sibling emulator. Set `RAD_EMULATOR`, pass |
|
| 28 | + | `EMU` to the kernel Make invocation, or put `emulator` on PATH. The kernel build |
|
| 29 | + | checks compiler dependencies. From the repository root, run: |
|
| 30 | + | ||
| 31 | + | ```sh |
|
| 32 | + | make -C kernel check |
|
| 33 | + | ``` |
|
| 34 | + | ||
| 35 | + | The linked freestanding entry point and hosted runner must execute; an assertion failure must fail the check. |
|
| 36 | + | ||
| 37 | + | The entry probe uses explicit M-mode success/fault finish writes; secondary |
|
| 38 | + | harts idle. This checks machine entry, not user-domain execution. Finish writes |
|
| 39 | + | are a check protocol, not a domain-exit operation. |
kernel/PLAN.md
added
+92 -0
| 1 | + | # Kernel implementation plan |
|
| 2 | + | ||
| 3 | + | Specification: https://radiant.computer/system/kernel. |
|
| 4 | + | ||
| 5 | + | This is a 22-commit progression from a freestanding entry point to budgeted |
|
| 6 | + | multicore domain execution. Each step is a signed, buildable commit with the |
|
| 7 | + | mechanism and emulator checks available at that boundary. NOTES.md records |
|
| 8 | + | only established contracts; this plan describes the full dependency order. |
|
| 9 | + | ||
| 10 | + | ## Implementation boundary |
|
| 11 | + | ||
| 12 | + | - Use Radiance for kernel mechanisms and RAS for architectural entry, register |
|
| 13 | + | state, atomics, and MMIO. Make and shell provide build plumbing. User-space |
|
| 14 | + | scheduling and application policy are not kernel mechanisms. |
|
| 15 | + | - Load only trusted binary RIL through the Radiance compiler and shared RV64 |
|
| 16 | + | backend. Pointer-provenance and type-safety verification, including verifiable |
|
| 17 | + | compiler output, are deferred from the outset. Encoding and structural checks |
|
| 18 | + | do not provide isolation from hostile programs. Components able to change |
|
| 19 | + | executable bytes remain in the TCB. |
|
| 20 | + | - Keep modules single-purpose, below 1,000 lines with a 500-line target. Keep |
|
| 21 | + | kernel source below 10,000 non-comment lines. Do not duplicate native lowering. |
|
| 22 | + | - Compiler prerequisites occupy explicit dependency steps. No successful no-op |
|
| 23 | + | stands in for an operation, and no test claims a later stage's behavior. |
|
| 24 | + | ||
| 25 | + | ## Commit sequence |
|
| 26 | + | ||
| 27 | + | 1. **Freestanding machine image.** Build the Radiance/RAS entry point, failure path, linked RAD0 image, and hosted mechanism-check runner. Execute the machine entry point. |
|
| 28 | + | ||
| 29 | + | 2. **Bounded platform discovery.** Decode version-17 FDT data into RAM, reservations, hart topology, CLINT, PLIC, and device regions. Reject malformed and truncated descriptions. |
|
| 30 | + | ||
| 31 | + | 3. **Physical frame ownership.** Allocate and clear contiguous frames, exclude reserved memory, and enforce exact range and exhaustion checks. |
|
| 32 | + | ||
| 33 | + | 4. **Typed capability identities.** Define packed handles, object kinds, rights, slot generations, and retirement. Reject fabricated, stale, wrong-kind, and reserved-bit handles. |
|
| 34 | + | ||
| 35 | + | 5. **Domains and startup authority.** Create bounded Pending domains with private handle tables and Events state. Establish non-ambient self authority and terminal-event reservations. |
|
| 36 | + | ||
| 37 | + | 6. **Transactional capability operations.** Grant with attenuation, transfer atomically, and drop handles without inventing authority. Enforce Events locality and Interrupt exclusivity. |
|
| 38 | + | ||
| 39 | + | 7. **Aligned aggregate code generation.** Preserve proven alignment in aggregate copies and exact-width register returns. Exercise machine boot and the compiler regression without changing layout. |
|
| 40 | + | ||
| 41 | + | 8. **Persistent Page lifetimes.** Connect Page allocation and splitting to authority, object claims, and recipient-domain lifetime pins. Reclaim only after every claim and pin is gone. |
|
| 42 | + | ||
| 43 | + | 9. **Ordered event publication.** Publish complete shared-ring entries with acquire/release ordering, validate consumer progress, reserve terminal delivery, and coalesce IRQ notifications. |
|
| 44 | + | ||
| 45 | + | 10. **Architectural context boundary.** Save complete user register state on private machine frames, enter U-mode, return direct-call results, classify faults, and wake M-mode idle. |
|
| 46 | + | ||
| 47 | + | 11. **Defining-module layout resolution.** Prepare a nominal type’s defining imports before resolving its layout. Reject by-value cycles and retain pointer recursion. |
|
| 48 | + | ||
| 49 | + | 12. **Finite hart-bound budgets.** Implement conserved tick quantities, budget splitting and binding, incarnation-qualified context identities, exact-use accounting, and CLINT preemption. |
|
| 50 | + | ||
| 51 | + | 13. **Waits and one-shot timeouts.** Retain accepted timeouts under event backpressure, validate waits, authorize wakeups, and choose timer deadlines without granting execution budget. |
|
| 52 | + | ||
| 53 | + | 14. **Devices and external interrupts.** Validate bounded MMIO access and route exclusive interrupt ownership through masked PLIC claims, consumption, draining, and transfer. |
|
| 54 | + | ||
| 55 | + | 15. **Bounded assembler storage and fences.** Size linking tables from name tokens and encode memory/I/O and instruction-fetch fences. Exercise assembler and compiler regressions. |
|
| 56 | + | ||
| 57 | + | 16. **Binary RIL codec and standalone compilation.** Encode complete IL graphs in RIL0, validate binary structure, and compile decoded inputs through the existing RV64 backend. Keep provenance and type-safety verification deferred. |
|
| 58 | + | ||
| 59 | + | 17. **Shared image catalogs and native execution.** Link ordered, namespaced image catalogs through the shared RV64 backend. Add typed user primitives, seven source-compiled binary images, private native state, and machine trap execution. Make and shell provide build plumbing. |
|
| 60 | + | ||
| 61 | + | 18. **Complete image instances and contexts.** Create owned private image instances and activate complete argument/stack ranges. Add independent contexts, the instance workload, and checks for shared state within a domain and isolation between trusted instances. |
|
| 62 | + | ||
| 63 | + | 19. **Lifecycle and reclamation.** Implement exit, faults, administrative destruction, creation-ancestry cascades, reparenting, and deferred reclamation after context quiescence. Preserve terminal reports and surviving Page recipients. |
|
| 64 | + | ||
| 65 | + | 20. **Complete direct-call dispatch.** Validate every direct call and metadata query, including the budget/context additions and Delegate. Exercise authority, error returns, effects, and query error validation in hosted checks. |
|
| 66 | + | ||
| 67 | + | 21. **Hart startup and bounded mailboxes.** Publish shared boot state, start private per-hart machine stacks, serialize kernel mutation with linear lock ownership, and exchange bounded requests through CLINT software interrupts. Exercise 1, 2, and 8 harts. |
|
| 68 | + | ||
| 69 | + | 22. **Multicore runtime and complete boot.** Connect budgeted architectural owners, call effects, local continuations, remote admission, reserved Stop requests, and acknowledged teardown. Bootstrap real root authority and run control workloads on 1, 2, and 8 harts, including continued machine operation after root exit. |
|
| 70 | + | ||
| 71 | + | ## Validation |
|
| 72 | + | ||
| 73 | + | From the repository root, set `RAD_EMULATOR` to the sibling emulator executable |
|
| 74 | + | and run `make -C kernel check` at every step. Compiler/backend steps also run |
|
| 75 | + | `make std-test bin-test` and their focused compiler or machine regressions. |
|
| 76 | + | NOTES.md identifies each step's observable checks and emulator prerequisites. |
|
| 77 | + | ||
| 78 | + | - Exercise the actual changed machine path when a step adds architectural |
|
| 79 | + | behavior. Assertion failure must fail the check. Independent emulator changes |
|
| 80 | + | are signed in the sibling repository; record required revisions in NOTES.md. |
|
| 81 | + | - Test authority, resource bounds, state transitions, ABI results, and concurrency |
|
| 82 | + | invariants, not source spelling or wiring. Decode malformed binary encodings |
|
| 83 | + | and exercise resource exhaustion, event backpressure, and finite budgets. |
|
| 84 | + | - Final checks cover all direct calls, native image state, 1/2/8-hart control |
|
| 85 | + | workloads, acknowledged remote destruction, and root exit without shutdown. |
|
| 86 | + | Check final module sizes and the signed, buildable 22-step sequence. |
|
| 87 | + | - The emulator supplies shared RAM and independent hart architectural state; |
|
| 88 | + | machine U-mode/M-mode images cannot escape through hosted syscalls. Deterministic |
|
| 89 | + | interleaving tests are not measurements of hardware cache behavior or timing. |
|
| 90 | + | Instruction counts may describe a specific build, never establish isolation. |
|
| 91 | + | - The trusted binary-input requirement and deferred provenance/type-safety |
|
| 92 | + | verification remain explicit in every validation claim. |
kernel/arch/entry.ras
added
+20 -0
| 1 | + | // Machine entry with a boot-time trap sink. |
|
| 2 | + | .text; |
|
| 3 | + | la %t0 @bootFault; |
|
| 4 | + | csrw mtvec %t0; |
|
| 5 | + | csrr %a0 mhartid; |
|
| 6 | + | bnez %a0 @bootIdle; |
|
| 7 | + | call @"::default"; |
|
| 8 | + | li %t1 0x5555; |
|
| 9 | + | j @bootFinish; |
|
| 10 | + | @bootFault |
|
| 11 | + | csrr %t1 mcause; |
|
| 12 | + | slli %t1 %t1 16; |
|
| 13 | + | li %t0 0x3333; |
|
| 14 | + | or %t1 %t1 %t0; |
|
| 15 | + | @bootFinish |
|
| 16 | + | li %t0 0x10001000; |
|
| 17 | + | sw %t1 0(%t0); |
|
| 18 | + | @bootIdle |
|
| 19 | + | wfi; |
|
| 20 | + | j @bootIdle; |
kernel/check.rad
added
+6 -0
| 1 | + | //! Hosted entry for kernel mechanism checks. |
|
| 2 | + | ||
| 3 | + | /// Run the available kernel mechanism checks. |
|
| 4 | + | @default fn main() -> u32 { |
|
| 5 | + | return 0; |
|
| 6 | + | } |
kernel/main.rad
added
+10 -0
| 1 | + | //! Freestanding machine initialization. |
|
| 2 | + | ||
| 3 | + | /// Maximum online harts in this kernel build. |
|
| 4 | + | constant MAX_HARTS: u64 = 8; |
|
| 5 | + | ||
| 6 | + | /// Validate the entry hart before machine initialization. |
|
| 7 | + | @default fn main(hart: u64) -> u32 { |
|
| 8 | + | assert hart < MAX_HARTS; |
|
| 9 | + | return 0; |
|
| 10 | + | } |