From 5a45c14cf55d821c1cc26ec2766fcfdf0c975b53 Mon Sep 17 00:00:00 2001 From: Gabriel Kaszewski Date: Sun, 18 Oct 2026 02:29:46 +0200 Subject: [PATCH] feat(adapter-riscv): replace static mut with KernelCell, complete all 17 syscall decoders, wire timer and PLIC interrupts to kernel --- crates/adapter-riscv/src/kernel_cell.rs | 35 ++++++ crates/adapter-riscv/src/main.rs | 53 +++------ crates/adapter-riscv/src/trap/mod.rs | 147 +++++++++++++++++------- crates/types/src/permission.rs | 1 - 4 files changed, 156 insertions(+), 80 deletions(-) create mode 100644 crates/adapter-riscv/src/kernel_cell.rs diff --git a/crates/adapter-riscv/src/kernel_cell.rs b/crates/adapter-riscv/src/kernel_cell.rs new file mode 100644 index 0000000..7e9056c --- /dev/null +++ b/crates/adapter-riscv/src/kernel_cell.rs @@ -0,0 +1,35 @@ +use core::cell::UnsafeCell; +use core::mem::MaybeUninit; +use core::sync::atomic::{AtomicBool, Ordering}; + +pub struct KernelCell { + initialized: AtomicBool, + inner: UnsafeCell>, +} + +// Single-core: no concurrent access. Initialized once before traps are enabled. +unsafe impl Sync for KernelCell {} + +impl KernelCell { + pub const fn uninit() -> Self { + Self { + initialized: AtomicBool::new(false), + inner: UnsafeCell::new(MaybeUninit::uninit()), + } + } + + pub fn init(&self, value: T) { + unsafe { (*self.inner.get()).write(value) }; + self.initialized.store(true, Ordering::Release); + } + + pub fn get(&self) -> &T { + debug_assert!(self.initialized.load(Ordering::Acquire)); + unsafe { (*self.inner.get()).assume_init_ref() } + } + + pub fn get_mut(&self) -> &mut T { + debug_assert!(self.initialized.load(Ordering::Acquire)); + unsafe { (*self.inner.get()).assume_init_mut() } + } +} diff --git a/crates/adapter-riscv/src/main.rs b/crates/adapter-riscv/src/main.rs index 7252a1f..9bfff14 100644 --- a/crates/adapter-riscv/src/main.rs +++ b/crates/adapter-riscv/src/main.rs @@ -3,19 +3,19 @@ mod board; mod hw; +mod kernel_cell; mod mmu; mod platform; mod trap; use core::arch::global_asm; use hw::uart::Uart; +use kernel_cell::KernelCell; -use core::ptr::addr_of_mut; +static KERNEL: KernelCell> = KernelCell::uninit(); -static mut KERNEL: Option> = None; - -pub fn kernel_mut() -> &'static mut kernel::Kernel { - unsafe { (*addr_of_mut!(KERNEL)).as_mut() }.unwrap_or_else(|| unreachable!()) +pub fn kernel_ref() -> &'static mut kernel::Kernel { + KERNEL.get_mut() } global_asm!( @@ -69,16 +69,15 @@ extern "C" fn kmain() -> ! { types::address::PhysicalAddress::from_raw(board::USER_POOL_BASE), board::USER_POOL_PAGES, ); - let kern = kernel::Kernel::new(riscv_platform, pool); - unsafe { *addr_of_mut!(KERNEL) = Some(kern); } - let kern = kernel_mut(); + KERNEL.init(kernel::Kernel::new(riscv_platform, pool)); + let kern = kernel_ref(); let (_pid, _tid) = kern .boot(types::bounded::Priority::DEFAULT, types::time::TimeSlice::DEFAULT) .unwrap_or_else(|_| loop { unsafe { core::arch::asm!("wfi") }; }); uart.write_str("k-os: kernel started\n"); - userspace_demo(kern, &uart, kernel_pt); + userspace_demo(&uart, kernel_pt); uart.write_str("k-os: demo complete\n"); loop { @@ -86,28 +85,17 @@ extern "C" fn kmain() -> ! { } } -// Tiny userspace program: li a7, SYS_EXIT; ecall; j -4 -// SYS_EXIT = 16 = 0x10 -// RISC-V instructions (little-endian): -// li a7, 16 → addi a7, zero, 16 → 0x01000893 -// ecall → 0x00000073 -// j -4 → 0xffdff06f static USER_EXIT_PROGRAM: [u8; 12] = [ - 0x93, 0x08, 0x00, 0x01, // addi a7, zero, 16 + 0x93, 0x08, 0x00, 0x01, // addi a7, zero, 16 (SYS_EXIT) 0x73, 0x00, 0x00, 0x00, // ecall 0x6f, 0xf0, 0xdf, 0xff, // j -4 ]; const USER_VA: usize = 0x10000; -fn userspace_demo( - _kern: &mut kernel::Kernel, - uart: &Uart, - kernel_pt: &mmu::PageTable, -) { +fn userspace_demo(uart: &Uart, kernel_pt: &mmu::PageTable) { uart.write_str("k-os: --- userspace demo ---\n"); - // Allocate a page for the user program and copy code into it let program_page = mmu::allocator::alloc_zeroed_page(); unsafe { core::ptr::copy_nonoverlapping( @@ -117,32 +105,23 @@ fn userspace_demo( ); } - // Create user page table with program mapped at USER_VA - let user_pt = mmu::create_user_page_table( - kernel_pt, - program_page, - 1, - USER_VA, - ); + let user_pt = mmu::create_user_page_table(kernel_pt, program_page, 1, USER_VA); uart.write_str("k-os: user page table created, entering U-mode\n"); - // Activate user page table mmu::activate(user_pt); - // Set sscratch to kernel stack so trap vector can switch stacks let kernel_sp: usize; unsafe { core::arch::asm!("mv {0}, sp", out(reg) kernel_sp) }; trap::set_kernel_stack(kernel_sp); - // Enter user mode: set sstatus.SPP=0 (U-mode), sepc=USER_VA, sret - let user_stack = USER_VA - 8; // stack below program + let user_stack = USER_VA - 8; unsafe { core::arch::asm!( - "csrc sstatus, {spp}", // clear SPP → return to U-mode - "csrs sstatus, {spie}", // set SPIE → enable interrupts after sret - "csrw sepc, {entry}", // return address = user entry - "mv sp, {stack}", // user stack pointer (will be saved to sscratch on swap) + "csrc sstatus, {spp}", + "csrs sstatus, {spie}", + "csrw sepc, {entry}", + "mv sp, {stack}", "sret", spp = in(reg) 1usize << 8, spie = in(reg) 1usize << 5, diff --git a/crates/adapter-riscv/src/trap/mod.rs b/crates/adapter-riscv/src/trap/mod.rs index b1bc3d3..7f7da94 100644 --- a/crates/adapter-riscv/src/trap/mod.rs +++ b/crates/adapter-riscv/src/trap/mod.rs @@ -149,15 +149,15 @@ pub fn set_kernel_stack(kernel_sp: usize) { fn decode_syscall(frame: &TrapFrame) -> Option { use domain::message::Message; - use domain::syscall::Syscall; + use domain::syscall::{Syscall, WaitSet}; use types::syscall_abi::*; let nr = frame.regs[17]; // a7 - let a0 = frame.regs[10]; // a0 - let a1 = frame.regs[11]; // a1 - let a2 = frame.regs[12]; // a2 - let a3 = frame.regs[13]; // a3 - let a4 = frame.regs[14]; // a4 + let a0 = frame.regs[10]; + let a1 = frame.regs[11]; + let a2 = frame.regs[12]; + let a3 = frame.regs[13]; + let a4 = frame.regs[14]; match nr { SYS_EXIT => Some(Syscall::Exit), @@ -174,6 +174,46 @@ fn decode_syscall(frame: &TrapFrame) -> Option { let slot = types::bounded::CapSlot::new(a0 as u8)?; Some(Syscall::Receive { endpoint: slot }) } + SYS_DELEGATE => { + let slot = types::bounded::CapSlot::new(a0 as u8)?; + let to = types::bounded::CapSlot::new(a1 as u8)?; + let perms = types::permission::PermissionSet::from_bits(a2 as u8); + Some(Syscall::Delegate { slot, to_endpoint: to, permissions: perms }) + } + SYS_WAIT_FOR_INTERRUPT => { + let slot = types::bounded::CapSlot::new(a0 as u8)?; + Some(Syscall::WaitForInterrupt { irq: slot }) + } + SYS_ACKNOWLEDGE_INTERRUPT => { + let slot = types::bounded::CapSlot::new(a0 as u8)?; + Some(Syscall::AcknowledgeInterrupt { irq: slot }) + } + SYS_WAIT_ANY => { + let ep0 = if a0 != usize::MAX { types::bounded::CapSlot::new(a0 as u8) } else { None }; + let ep1 = if a1 != usize::MAX { types::bounded::CapSlot::new(a1 as u8) } else { None }; + let ep2 = if a2 != usize::MAX { types::bounded::CapSlot::new(a2 as u8) } else { None }; + let ep3 = if a3 != usize::MAX { types::bounded::CapSlot::new(a3 as u8) } else { None }; + let sources = WaitSet::new( + [ep0, ep1, ep2, ep3], + [None, None, None, None], + ); + Some(Syscall::WaitAny { sources }) + } + SYS_CREATE_PROCESS => { + let slot = types::bounded::CapSlot::new(a0 as u8)?; + Some(Syscall::CreateProcess { + create_cap: slot, + image: types::address::DataRef::empty(), + }) + } + SYS_KILL => { + let slot = types::bounded::CapSlot::new(a0 as u8)?; + Some(Syscall::Kill { process: slot }) + } + SYS_REVOKE => { + let slot = types::bounded::CapSlot::new(a0 as u8)?; + Some(Syscall::Revoke { slot }) + } SYS_SPAWN_THREAD => Some(Syscall::SpawnThread { entry: types::address::EntryPoint::from_raw(a0), stack: types::address::StackPointer::from_raw(a1), @@ -182,6 +222,13 @@ fn decode_syscall(frame: &TrapFrame) -> Option { let count = types::bounded::PageCount::new(a0 as u16)?; Some(Syscall::RequestPages { count }) } + SYS_RELEASE_PAGES => { + let count = types::bounded::PageCount::new(a1 as u16)?; + Some(Syscall::ReleasePages { + addr: types::address::VirtualAddress::from_raw(a0), + count, + }) + } _ => None, } } @@ -214,49 +261,65 @@ extern "C" fn trap_handler_rust(frame: &mut TrapFrame) { let scause: usize; unsafe { core::arch::asm!("csrr {0}, scause", out(reg) scause) }; - let uart = crate::hw::uart::Uart::new(); - if scause & CAUSE_INTERRUPT_BIT != 0 { - let cause = scause & !CAUSE_INTERRUPT_BIT; - match cause { - CAUSE_S_TIMER => { - crate::hw::timer::handle_interrupt(); - } - CAUSE_S_EXTERNAL => { - uart.write_str("[EXT]"); - } - _ => {} - } + handle_interrupt(scause & !CAUSE_INTERRUPT_BIT); } else { - match scause { - CAUSE_ECALL_U => { - frame.sepc += 4; + handle_exception(frame, scause); + } +} - if let Some(syscall) = decode_syscall(frame) { - let kern = crate::kernel_mut(); - let outcome = kern.handle_syscall(syscall); - write_result(frame, &outcome); +fn handle_interrupt(cause: usize) { + match cause { + CAUSE_S_TIMER => { + crate::hw::timer::handle_interrupt(); + let kern = crate::kernel_ref(); + let core = types::id::CoreId::from_raw(0); + let _decision = kern.handle_tick(core); + } + CAUSE_S_EXTERNAL => { + let irq_num = crate::hw::plic::Plic::claim(); + if irq_num != 0 { + let kern = crate::kernel_ref(); + let irq = types::id::IrqId::from_raw(irq_num as u16); + kern.handle_interrupt(irq); + crate::hw::plic::Plic::complete(irq_num); + } + } + _ => {} + } +} - match &outcome { - kernel::SyscallOutcome::TerminateCaller => { - uart.write_str("k-os: process exited\n"); - } - _ => {} +fn handle_exception(frame: &mut TrapFrame, scause: usize) { + match scause { + CAUSE_ECALL_U => { + frame.sepc += 4; + + if let Some(syscall) = decode_syscall(frame) { + let kern = crate::kernel_ref(); + let outcome = kern.handle_syscall(syscall); + write_result(frame, &outcome); + + match &outcome { + kernel::SyscallOutcome::TerminateCaller => { + let uart = crate::hw::uart::Uart::new(); + uart.write_str("k-os: process exited\n"); } + _ => {} } } - _ => { - uart.write_str("FAULT: scause="); - uart.write_hex(scause); - let stval: usize; - unsafe { core::arch::asm!("csrr {0}, stval", out(reg) stval) }; - uart.write_str(" stval="); - uart.write_hex(stval); - uart.write_str(" sepc="); - uart.write_hex(frame.sepc); - uart.put_char(b'\n'); - loop { unsafe { core::arch::asm!("wfi") }; } - } + } + _ => { + let uart = crate::hw::uart::Uart::new(); + uart.write_str("FAULT: scause="); + uart.write_hex(scause); + let stval: usize; + unsafe { core::arch::asm!("csrr {0}, stval", out(reg) stval) }; + uart.write_str(" stval="); + uart.write_hex(stval); + uart.write_str(" sepc="); + uart.write_hex(frame.sepc); + uart.put_char(b'\n'); + loop { unsafe { core::arch::asm!("wfi") }; } } } } diff --git a/crates/types/src/permission.rs b/crates/types/src/permission.rs index 9df42f0..ae19036 100644 --- a/crates/types/src/permission.rs +++ b/crates/types/src/permission.rs @@ -41,7 +41,6 @@ impl PermissionSet { self.0 & other.0 == self.0 } - #[cfg(kani)] pub fn from_bits(bits: u8) -> Self { PermissionSet(bits) }