Files
k-os/docs/ADAPTERS.md

3.3 KiB

Writing Adapters

An adapter implements the Platform trait for a specific architecture. It is the only crate with unsafe code.

Scaffolding

scripts/new-adapter.sh <arch>

This generates crates/adapter-<arch>/ with the standard structure. Then:

  1. Add "crates/adapter-<arch>" to workspace members in Cargo.toml
  2. Fill in board.rs with device addresses for the target board
  3. Add boot assembly (global_asm! in main.rs or a .S file)
  4. Update linker.ld for the target's entry address and memory layout
  5. Implement the TODOs in hw/, mmu/, trap/, and platform.rs

Structure

Every adapter follows this layout:

crates/adapter-<arch>/
├── Cargo.toml
├── linker.ld
└── src/
    ├── main.rs          — boot entry, kmain
    ├── board.rs         — all board/SoC constants in one place
    ├── platform.rs      — impl Platform (the contract with the kernel)
    ├── hw/              — one file per hardware device
    │   ├── uart.rs      — serial output
    │   ├── irq.rs       — interrupt controller (PLIC, GIC, APIC, ...)
    │   └── timer.rs     — timer/clock
    ├── mmu/             — memory management
    │   ├── page_table.rs — architecture-specific page table format
    │   └── allocator.rs  — boot-time page allocator
    └── trap/            — trap/exception handling
        └── mod.rs       — trap vector + Rust handler

Rules

  • unsafe is the absolute bare minimum. Each unsafe block does exactly one hardware operation and is wrapped immediately in a safe function. You should be able to count every unsafe block on your fingers.
  • board.rs is the single source of truth for addresses. UART base, interrupt controller base, RAM start — all in one file. If someone ports to a different board with the same architecture, they change one file.
  • The kernel never changes. Kernel<P: Platform> is generic. Adding a new adapter means zero changes to domain/, kernel/, types/, or platform/.

Existing Adapters

Adapter Architecture Target Board Status
adapter-riscv RISC-V 64-bit QEMU virt Phase 2 complete — boots, MMU, traps, timer, IPC demo

Platform Trait

The adapter implements all methods of the Platform trait defined in crates/platform/src/lib.rs:

pub trait Platform {
    fn configure_protection(&mut self, process: ProcessId, regions: &[MemoryRegion]);
    fn context_switch(&mut self, from: &mut SavedContext, to: &SavedContext);
    fn enable_user_mode(&mut self, entry: EntryPoint, stack: StackPointer) -> !;
    fn set_timer(&mut self, duration: TimerDuration);
    fn current_ticks(&self) -> Ticks;
    fn mask_irq(&mut self, irq: IrqId);
    fn unmask_irq(&mut self, irq: IrqId);
    fn send_ipi(&mut self, target: CoreId);
    fn core_id(&self) -> CoreId;
    fn num_cores(&self) -> u8;
    fn map_shared(&mut self, process: ProcessId, base: PhysicalAddress, size: PageCount, permissions: PermissionSet);
}

Boot Flow

  1. Assembly entry (_start): set stack pointer, call kmain
  2. kmain: zero BSS, init UART, init MMU, init traps, init timer
  3. Create Kernel<AdapterPlatform>, call kernel.boot()
  4. Start scheduling