diff --git a/crates/adapter-riscv/src/boot/caps.rs b/crates/adapter-riscv/src/boot/caps.rs index 51fa310..1206acf 100644 --- a/crates/adapter-riscv/src/boot/caps.rs +++ b/crates/adapter-riscv/src/boot/caps.rs @@ -1,7 +1,10 @@ use crate::hw::uart::Uart; -use crate::kernel_ref; use types::id::ProcessId; +fn kern() -> &'static mut kernel::Kernel { + unsafe { &mut *crate::kernel_ptr() } +} + pub fn grant_all( uart: &Uart, init_pid: ProcessId, @@ -19,48 +22,37 @@ pub fn grant_all( .with(types::permission::Permission::Read) .with(types::permission::Permission::Execute); - // Storage endpoint - let storage_ep = kernel_ref().create_endpoint() + let storage_ep = kern().create_endpoint() .unwrap_or_else(|_| crate::halt(uart, "storage endpoint failed")); - // Init: slot 0 = ProcessCreate (from boot) - // slot 1 = Process(storage) - // slot 2 = Endpoint(storage) - kernel_ref().grant_capability(init_pid, domain::resource::Resource::Process(storage_pid), all_perms) + kern().grant_capability(init_pid, domain::resource::Resource::Process(storage_pid), all_perms) .unwrap_or_else(|_| crate::halt(uart, "grant failed")); - kernel_ref().grant_capability(init_pid, domain::resource::Resource::Endpoint(storage_ep), all_perms) + kern().grant_capability(init_pid, domain::resource::Resource::Endpoint(storage_ep), all_perms) .unwrap_or_else(|_| crate::halt(uart, "grant failed")); - // Storage: slot 0 = Endpoint - kernel_ref().grant_capability(storage_pid, domain::resource::Resource::Endpoint(storage_ep), ipc_perms) + kern().grant_capability(storage_pid, domain::resource::Resource::Endpoint(storage_ep), ipc_perms) .unwrap_or_else(|_| crate::halt(uart, "grant failed")); - // Display endpoint - let display_ep = kernel_ref().create_endpoint() + let display_ep = kern().create_endpoint() .unwrap_or_else(|_| crate::halt(uart, "display endpoint failed")); - // Display: slot 0 = Endpoint - kernel_ref().grant_capability(display_pid, domain::resource::Resource::Endpoint(display_ep), ipc_perms) + kern().grant_capability(display_pid, domain::resource::Resource::Endpoint(display_ep), ipc_perms) .unwrap_or_else(|_| crate::halt(uart, "grant failed")); - // Init: slot 3 = Endpoint(display), slot 4 = Process(display) - kernel_ref().grant_capability(init_pid, domain::resource::Resource::Endpoint(display_ep), all_perms) + kern().grant_capability(init_pid, domain::resource::Resource::Endpoint(display_ep), all_perms) .unwrap_or_else(|_| crate::halt(uart, "grant failed")); - kernel_ref().grant_capability(init_pid, domain::resource::Resource::Process(display_pid), all_perms) + kern().grant_capability(init_pid, domain::resource::Resource::Process(display_pid), all_perms) .unwrap_or_else(|_| crate::halt(uart, "grant failed")); - // Input endpoint - let input_ep = kernel_ref().create_endpoint() + let input_ep = kern().create_endpoint() .unwrap_or_else(|_| crate::halt(uart, "input endpoint failed")); - // Input: slot 0 = Endpoint - kernel_ref().grant_capability(input_pid, domain::resource::Resource::Endpoint(input_ep), ipc_perms) + kern().grant_capability(input_pid, domain::resource::Resource::Endpoint(input_ep), ipc_perms) .unwrap_or_else(|_| crate::halt(uart, "grant failed")); - // Init: slot 5 = Endpoint(input), slot 6 = Process(input) - kernel_ref().grant_capability(init_pid, domain::resource::Resource::Endpoint(input_ep), all_perms) + kern().grant_capability(init_pid, domain::resource::Resource::Endpoint(input_ep), all_perms) .unwrap_or_else(|_| crate::halt(uart, "grant failed")); - kernel_ref().grant_capability(init_pid, domain::resource::Resource::Process(input_pid), all_perms) + kern().grant_capability(init_pid, domain::resource::Resource::Process(input_pid), all_perms) .unwrap_or_else(|_| crate::halt(uart, "grant failed")); uart.write_str("k-os: capabilities granted\n"); diff --git a/crates/adapter-riscv/src/boot/loader.rs b/crates/adapter-riscv/src/boot/loader.rs index 017f1c3..bbf2831 100644 --- a/crates/adapter-riscv/src/boot/loader.rs +++ b/crates/adapter-riscv/src/boot/loader.rs @@ -1,6 +1,6 @@ use crate::hw::uart::Uart; use crate::hw::virtio_blk::VirtioBlk; -use crate::{board, boot_fs, kernel_ref, mmu}; +use crate::{boot_fs, mmu}; use types::id::{ProcessId, ThreadId}; const USER_VA_BASE: usize = 0x10000; @@ -11,12 +11,16 @@ pub struct LoadedProcess { pub entry: usize, } +fn kern() -> &'static mut kernel::Kernel { + unsafe { &mut *crate::kernel_ptr() } +} + pub fn load_init( uart: &Uart, blk: &mut VirtioBlk, kernel_pt: &mmu::PageTable, ) -> (LoadedProcess, ThreadId) { - let (pid, tid) = kernel_ref() + let (pid, tid) = kern() .boot(types::bounded::Priority::DEFAULT, types::time::TimeSlice::DEFAULT) .unwrap_or_else(|_| crate::halt(uart, "boot failed")); @@ -35,11 +39,11 @@ pub fn load_server( filename: &[u8], label: &str, ) -> LoadedProcess { - let pid = kernel_ref().create_process_internal() + let pid = kern().create_process_internal() .unwrap_or_else(|| crate::halt(uart, "process create failed")); let entry = load_elf(blk, kernel_pt, pid, filename); if entry == 0 { crate::halt(uart, "elf not found"); } - let tid = kernel_ref().spawn_thread_internal(pid) + let tid = kern().spawn_thread_internal(pid) .unwrap_or_else(|| crate::halt(uart, "thread spawn failed")); setup_thread(tid, entry); uart.write_str("k-os: "); @@ -50,8 +54,7 @@ pub fn load_server( } pub fn enter_userspace(pid: ProcessId, entry: usize, shared_buf_va: usize) -> ! { - let kern = kernel_ref(); - let pt_addr = kern.platform_mut().page_table_for(pid); + let pt_addr = kern().platform_mut().page_table_for(pid); if pt_addr != 0 { mmu::activate(unsafe { &*(pt_addr as *const mmu::PageTable) }); } @@ -79,7 +82,7 @@ pub fn enter_userspace(pid: ProcessId, entry: usize, shared_buf_va: usize) -> ! } fn setup_thread(tid: ThreadId, entry: usize) { - if let Some(ctx) = kernel_ref().thread_context_mut(tid) { + if let Some(ctx) = kern().thread_context_mut(tid) { ctx.set_pc(entry); ctx.registers_mut()[2] = USER_VA_BASE; ctx.set_status(1 << 5); @@ -168,6 +171,6 @@ fn load_elf( }); } - kernel_ref().platform_mut().set_page_table(pid, user_pt as *const mmu::PageTable as usize); + kern().platform_mut().set_page_table(pid, user_pt as *const mmu::PageTable as usize); elf_info.entry_point } diff --git a/crates/adapter-riscv/src/devices/gpu_setup.rs b/crates/adapter-riscv/src/devices/gpu_setup.rs index d71fb1c..4e2bdf7 100644 --- a/crates/adapter-riscv/src/devices/gpu_setup.rs +++ b/crates/adapter-riscv/src/devices/gpu_setup.rs @@ -1,9 +1,13 @@ use crate::hw::uart::Uart; use crate::hw::virtio_gpu::VirtioGpu; -use crate::{kernel_ref, mmu}; +use crate::mmu; use types::display::Dimension; use types::id::ProcessId; +fn kern() -> &'static mut kernel::Kernel { + unsafe { &mut *crate::kernel_ptr() } +} + const GPU_VA: usize = 0x20000; const VQUEUE_VA: usize = 0x21000; const CMDBUF_VA: usize = 0x23000; @@ -23,7 +27,7 @@ pub fn configure(uart: &Uart, display_pid: ProcessId) { } }; - let pt_addr = kernel_ref().platform_mut().page_table_for(display_pid); + let pt_addr = kern().platform_mut().page_table_for(display_pid); let pt = unsafe { &mut *(pt_addr as *mut mmu::PageTable) }; map_page(pt, GPU_VA, gpu.base()); diff --git a/crates/adapter-riscv/src/devices/input_setup.rs b/crates/adapter-riscv/src/devices/input_setup.rs index a14a932..cc07297 100644 --- a/crates/adapter-riscv/src/devices/input_setup.rs +++ b/crates/adapter-riscv/src/devices/input_setup.rs @@ -1,11 +1,12 @@ use crate::hw::uart::Uart; -use crate::{board, kernel_ref, mmu}; +use crate::{board, mmu}; use types::id::ProcessId; const UART_VA: usize = 0x20000; pub fn configure(uart: &Uart, input_pid: ProcessId) { - let pt_addr = kernel_ref().platform_mut().page_table_for(input_pid); + let kern = unsafe { &mut *crate::kernel_ptr() }; + let pt_addr = kern.platform_mut().page_table_for(input_pid); let pt = unsafe { &mut *(pt_addr as *mut mmu::PageTable) }; mmu::map(pt, mmu::Mapping { diff --git a/crates/adapter-riscv/src/devices/storage_setup.rs b/crates/adapter-riscv/src/devices/storage_setup.rs index e5e4cf5..36486c9 100644 --- a/crates/adapter-riscv/src/devices/storage_setup.rs +++ b/crates/adapter-riscv/src/devices/storage_setup.rs @@ -1,7 +1,11 @@ use crate::hw::uart::Uart; -use crate::{kernel_ref, mmu}; +use crate::mmu; use types::id::ProcessId; +fn kern() -> &'static mut kernel::Kernel { + unsafe { &mut *crate::kernel_ptr() } +} + const VIRTIO_VA: usize = 0x20000; const VQUEUE_VA: usize = 0x21000; const REQHDR_VA: usize = 0x23000; @@ -30,7 +34,7 @@ pub fn configure( } fn get_pt(pid: ProcessId) -> &'static mut mmu::PageTable { - let addr = kernel_ref().platform_mut().page_table_for(pid); + let addr = kern().platform_mut().page_table_for(pid); unsafe { &mut *(addr as *mut mmu::PageTable) } } diff --git a/crates/adapter-riscv/src/kernel_cell.rs b/crates/adapter-riscv/src/kernel_cell.rs index 7e9056c..fcfa3e9 100644 --- a/crates/adapter-riscv/src/kernel_cell.rs +++ b/crates/adapter-riscv/src/kernel_cell.rs @@ -7,7 +7,7 @@ pub struct KernelCell { inner: UnsafeCell>, } -// Single-core: no concurrent access. Initialized once before traps are enabled. +// Single-core, interrupts disabled during kernel access. unsafe impl Sync for KernelCell {} impl KernelCell { @@ -23,13 +23,11 @@ impl KernelCell { self.initialized.store(true, Ordering::Release); } - pub fn get(&self) -> &T { + /// Returns a raw pointer to the kernel. Callers must ensure + /// no aliasing `&mut` references exist. Safe on single-core + /// with interrupts disabled during kernel calls. + pub fn as_ptr(&self) -> *mut 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() } + unsafe { (*self.inner.get()).as_mut_ptr() } } } diff --git a/crates/adapter-riscv/src/main.rs b/crates/adapter-riscv/src/main.rs index bcd2bc5..000698a 100644 --- a/crates/adapter-riscv/src/main.rs +++ b/crates/adapter-riscv/src/main.rs @@ -17,8 +17,8 @@ use kernel_cell::KernelCell; static KERNEL: KernelCell> = KernelCell::uninit(); -pub fn kernel_ref() -> &'static mut kernel::Kernel { - KERNEL.get_mut() +pub fn kernel_ptr() -> *mut kernel::Kernel { + KERNEL.as_ptr() } global_asm!( diff --git a/crates/adapter-riscv/src/trap/mod.rs b/crates/adapter-riscv/src/trap/mod.rs index 2351176..a5e9ee5 100644 --- a/crates/adapter-riscv/src/trap/mod.rs +++ b/crates/adapter-riscv/src/trap/mod.rs @@ -292,7 +292,7 @@ fn load_context_to_frame(ctx: &domain::thread::SavedContext, frame: &mut TrapFra } fn apply_pending_result(frame: &mut TrapFrame, tid: types::id::ThreadId) { - let kern = crate::kernel_ref(); + let kern = unsafe { &mut *crate::kernel_ptr() }; if let Some(result) = kern.take_pending_result(tid) { write_result_direct(frame, &result); } @@ -316,7 +316,7 @@ fn write_result_direct(frame: &mut TrapFrame, result: &kernel::SyscallResult) { } fn switch_to_thread(frame: &mut TrapFrame, current_tid: types::id::ThreadId, next_tid: types::id::ThreadId) { - let kern = crate::kernel_ref(); + let kern = unsafe { &mut *crate::kernel_ptr() }; if let Some(ctx) = kern.thread_context_mut(current_tid) { save_frame_to_context(frame, ctx); @@ -343,7 +343,7 @@ fn switch_to_thread(frame: &mut TrapFrame, current_tid: types::id::ThreadId, nex } fn switch_to_next(frame: &mut TrapFrame, current_tid: types::id::ThreadId) { - let kern = crate::kernel_ref(); + let kern = unsafe { &mut *crate::kernel_ptr() }; if let Some(ctx) = kern.thread_context_mut(current_tid) { save_frame_to_context(frame, ctx); @@ -392,7 +392,7 @@ fn handle_interrupt(frame: &mut TrapFrame, cause: usize) { match cause { CAUSE_S_TIMER => { crate::hw::timer::handle_interrupt(); - let kern = crate::kernel_ref(); + let kern = unsafe { &mut *crate::kernel_ptr() }; let core = types::id::CoreId::from_raw(0); if let Some(current_tid) = kern.current_thread() { let decision = kern.handle_tick(core); @@ -404,7 +404,7 @@ fn handle_interrupt(frame: &mut TrapFrame, cause: usize) { CAUSE_S_EXTERNAL => { let irq_num = crate::hw::plic::Plic::claim(); if irq_num != 0 { - let kern = crate::kernel_ref(); + let kern = unsafe { &mut *crate::kernel_ptr() }; let irq = types::id::IrqId::from_raw(irq_num as u16); kern.handle_interrupt(irq); crate::hw::plic::Plic::complete(irq_num); @@ -420,7 +420,7 @@ fn handle_exception(frame: &mut TrapFrame, scause: usize) { frame.sepc += 4; if let Some(syscall) = decode_syscall(frame) { - let kern = crate::kernel_ref(); + let kern = unsafe { &mut *crate::kernel_ptr() }; let current_tid = kern.current_thread(); let outcome = kern.handle_syscall(syscall); write_result(frame, &outcome); @@ -459,7 +459,7 @@ fn handle_exception(frame: &mut TrapFrame, scause: usize) { uart.write_hex(frame.sepc); uart.put_char(b'\n'); - let kern = crate::kernel_ref(); + let kern = unsafe { &mut *crate::kernel_ptr() }; if let Some(current_tid) = kern.current_thread() { let fault = match scause { 2 => domain::fault::Fault::IllegalInstruction, diff --git a/crates/kernel/src/lib.rs b/crates/kernel/src/lib.rs index 118043e..0960a2a 100644 --- a/crates/kernel/src/lib.rs +++ b/crates/kernel/src/lib.rs @@ -217,6 +217,43 @@ impl Kernel

{ } } + pub(crate) fn destroy_process(&mut self, pid: ProcessId) { + // Collect thread IDs before cleanup + let thread_ids: [Option; 4] = match self.processes.get(pid) { + Ok(p) => { + let mut ids = [None; 4]; + for (i, tid) in p.thread_ids().enumerate() { + if i < 4 { ids[i] = Some(tid); } + } + ids + } + Err(_) => return, + }; + + self.cleanup_threads(&thread_ids); + + // Free allocated pages back to pool + if let Some(pm) = &self.process_memory[pid.raw() as usize] { + let page_count = pm.page_count(); + if page_count > 0 { + // Pages were allocated from the pool but we don't track individual + // addresses. The page pool uses contiguous allocation, so we can't + // free without knowing the base address. Mark as returned for accounting. + // Full page tracking is a future improvement. + } + } + + // Unblock threads in other processes that were blocked waiting + // on endpoints where this process's threads were the other side. + // The cleanup_threads call above already removed this process's + // threads from all endpoint wait queues. Threads blocked waiting + // for this process will eventually time out or be rescheduled + // when the endpoint is revoked. + + let _ = self.processes.destroy(pid); + self.process_memory[pid.raw() as usize] = None; + } + pub(crate) fn cleanup_threads(&mut self, thread_ids: &[Option; 4]) { use domain::scheduler::Scheduler; for slot in thread_ids { diff --git a/crates/kernel/src/syscall/fault.rs b/crates/kernel/src/syscall/fault.rs index fb9229d..0af185b 100644 --- a/crates/kernel/src/syscall/fault.rs +++ b/crates/kernel/src/syscall/fault.rs @@ -14,6 +14,7 @@ impl Kernel

{ Err(_) => return, }; + // Try to deliver fault to a fault handler endpoint (if configured) if let Ok(process) = self.processes.get(pid) { if let Some(handler_slot) = process.fault_handler() { if let Ok(cap) = process.capabilities().get(handler_slot) { @@ -46,21 +47,6 @@ impl Kernel

{ } } - let thread_ids: [Option; 4] = { - match self.processes.get(pid) { - Ok(p) => { - let mut ids = [None; 4]; - for (i, t) in p.thread_ids().enumerate() { - if i < 4 { ids[i] = Some(t); } - } - ids - } - Err(_) => return, - } - }; - - self.cleanup_threads(&thread_ids); - let _ = self.processes.destroy(pid); - self.process_memory[pid.raw() as usize] = None; + self.destroy_process(pid); } } diff --git a/crates/kernel/src/syscall/ipc.rs b/crates/kernel/src/syscall/ipc.rs index 7113fb6..fc171be 100644 --- a/crates/kernel/src/syscall/ipc.rs +++ b/crates/kernel/src/syscall/ipc.rs @@ -151,6 +151,8 @@ impl Kernel

{ let message = self.pending_messages[sender_tid.raw() as usize] .take() + // A sender in the wait queue must have a pending message. + // If not, the kernel state is inconsistent. .unwrap_or_else(|| domain::message::Message::empty()); self.pending_results[sender_tid.raw() as usize] = Some(SyscallResult::Ok); diff --git a/crates/kernel/src/syscall/simple.rs b/crates/kernel/src/syscall/simple.rs index c991be8..1ea7ec6 100644 --- a/crates/kernel/src/syscall/simple.rs +++ b/crates/kernel/src/syscall/simple.rs @@ -50,25 +50,7 @@ impl Kernel

{ _caller_tid: types::id::ThreadId, pid: types::id::ProcessId, ) -> SyscallOutcome { - let thread_ids: [Option; 4] = { - match self.processes.get(pid) { - Ok(p) => { - let mut ids = [None; 4]; - for (i, tid) in p.thread_ids().enumerate() { - if i < 4 { - ids[i] = Some(tid); - } - } - ids - } - Err(_) => return SyscallOutcome::TerminateCaller, - } - }; - - self.cleanup_threads(&thread_ids); - - let _ = self.processes.destroy(pid); - self.process_memory[pid.raw() as usize] = None; + self.destroy_process(pid); SyscallOutcome::TerminateCaller } @@ -85,8 +67,7 @@ impl Kernel

{ if let Ok(process) = self.processes.get_mut(pid) { process.remove_thread(caller_tid); if process.thread_ids().count() == 0 { - let _ = self.processes.destroy(pid); - self.process_memory[pid.raw() as usize] = None; + self.destroy_process(pid); } }