diff --git a/crates/adapter-riscv/src/board.rs b/crates/adapter-riscv/src/board.rs new file mode 100644 index 0000000..8ce59bf --- /dev/null +++ b/crates/adapter-riscv/src/board.rs @@ -0,0 +1,8 @@ +pub const RAM_BASE: usize = 0x80000000; +pub const RAM_SIZE: usize = 128 * 1024 * 1024; +pub const UART_BASE: usize = 0x10000000; +pub const PLIC_BASE: usize = 0x0C000000; +pub const CLINT_BASE: usize = 0x02000000; +pub const USER_POOL_BASE: usize = 0x84000000; +pub const USER_POOL_PAGES: usize = 256; +pub const TICK_INTERVAL: u64 = 10_000_000; diff --git a/crates/adapter-riscv/src/hw/mod.rs b/crates/adapter-riscv/src/hw/mod.rs new file mode 100644 index 0000000..88a95ab --- /dev/null +++ b/crates/adapter-riscv/src/hw/mod.rs @@ -0,0 +1,3 @@ +pub mod plic; +pub mod timer; +pub mod uart; diff --git a/crates/adapter-riscv/src/plic.rs b/crates/adapter-riscv/src/hw/plic.rs similarity index 77% rename from crates/adapter-riscv/src/plic.rs rename to crates/adapter-riscv/src/hw/plic.rs index 4620b93..308d115 100644 --- a/crates/adapter-riscv/src/plic.rs +++ b/crates/adapter-riscv/src/hw/plic.rs @@ -1,14 +1,14 @@ -const PLIC_BASE: usize = 0x0C000000; -const PLIC_PRIORITY: usize = PLIC_BASE; -const PLIC_S_ENABLE: usize = PLIC_BASE + 0x2080; // S-mode hart 0 context = 1 -const PLIC_S_THRESHOLD: usize = PLIC_BASE + 0x201000; -const PLIC_S_CLAIM: usize = PLIC_BASE + 0x201004; +use crate::board; + +const PLIC_PRIORITY: usize = board::PLIC_BASE; +const PLIC_S_ENABLE: usize = board::PLIC_BASE + 0x2080; +const PLIC_S_THRESHOLD: usize = board::PLIC_BASE + 0x201000; +const PLIC_S_CLAIM: usize = board::PLIC_BASE + 0x201004; pub struct Plic; impl Plic { pub fn init() { - // set threshold to 0 (accept all priorities) unsafe { core::ptr::write_volatile(PLIC_S_THRESHOLD as *mut u32, 0) }; } @@ -20,7 +20,6 @@ impl Plic { let current = core::ptr::read_volatile(addr as *const u32); core::ptr::write_volatile(addr as *mut u32, current | (1 << bit)); } - // set priority > 0 let prio_addr = PLIC_PRIORITY + (irq as usize) * 4; unsafe { core::ptr::write_volatile(prio_addr as *mut u32, 1) }; } diff --git a/crates/adapter-riscv/src/timer.rs b/crates/adapter-riscv/src/hw/timer.rs similarity index 56% rename from crates/adapter-riscv/src/timer.rs rename to crates/adapter-riscv/src/hw/timer.rs index 0c3f856..7726e71 100644 --- a/crates/adapter-riscv/src/timer.rs +++ b/crates/adapter-riscv/src/hw/timer.rs @@ -1,4 +1,4 @@ -const TICK_INTERVAL: u64 = 10_000_000; // 1 second at 10MHz +use crate::board; pub fn read_time() -> u64 { let time: u64; @@ -12,21 +12,21 @@ fn sbi_set_timer(stime: u64) { "ecall", in("a0") stime, in("a6") 0usize, - in("a7") 0x54494D45usize, // SBI Timer extension ID + in("a7") 0x54494D45usize, ); } } -pub fn init_timer() { +pub fn init() { let now = read_time(); - sbi_set_timer(now + TICK_INTERVAL); + sbi_set_timer(now + board::TICK_INTERVAL); } -pub fn set_next_timer(deadline: u64) { +pub fn set_next(deadline: u64) { sbi_set_timer(deadline); } -pub fn handle_timer_interrupt() { +pub fn handle_interrupt() { let now = read_time(); - sbi_set_timer(now + TICK_INTERVAL); + sbi_set_timer(now + board::TICK_INTERVAL); } diff --git a/crates/adapter-riscv/src/uart.rs b/crates/adapter-riscv/src/hw/uart.rs similarity index 94% rename from crates/adapter-riscv/src/uart.rs rename to crates/adapter-riscv/src/hw/uart.rs index 6b6e55d..9735968 100644 --- a/crates/adapter-riscv/src/uart.rs +++ b/crates/adapter-riscv/src/hw/uart.rs @@ -1,4 +1,4 @@ -const UART_BASE: usize = 0x10000000; +use crate::board; pub struct Uart { base: usize, @@ -6,7 +6,7 @@ pub struct Uart { impl Uart { pub fn new() -> Self { - Self { base: UART_BASE } + Self { base: board::UART_BASE } } pub fn put_char(&self, byte: u8) { diff --git a/crates/adapter-riscv/src/main.rs b/crates/adapter-riscv/src/main.rs index 115dc4b..97e31e8 100644 --- a/crates/adapter-riscv/src/main.rs +++ b/crates/adapter-riscv/src/main.rs @@ -1,15 +1,14 @@ #![no_std] #![no_main] -mod page_table; +mod board; +mod hw; +mod mmu; mod platform; -mod plic; -mod timer; mod trap; -mod uart; use core::arch::global_asm; -use uart::Uart; +use hw::uart::Uart; global_asm!( r#" @@ -47,27 +46,24 @@ extern "C" fn kmain() -> ! { uart.write_str("k-os: booted on RISC-V\n"); let heap_start = unsafe { &_heap_start as *const u8 as usize }; - page_table::init_page_allocator(heap_start); - let kernel_pt = page_table::init_kernel_page_table(); - page_table::activate(kernel_pt); + mmu::init_allocator(heap_start); + let kernel_pt = mmu::init_kernel_page_table(); + mmu::activate(kernel_pt); uart.write_str("k-os: MMU enabled (Sv39)\n"); - trap::init_trap(); - timer::init_timer(); - plic::Plic::init(); + trap::init(); + hw::timer::init(); + hw::plic::Plic::init(); uart.write_str("k-os: traps and timer initialized\n"); let riscv_platform = platform::RiscVPlatform::new(); let pool = domain::memory::page_pool::PagePool::new( - types::address::PhysicalAddress::from_raw(0x84000000), - 256, + types::address::PhysicalAddress::from_raw(board::USER_POOL_BASE), + board::USER_POOL_PAGES, ); let mut kern = kernel::Kernel::new(riscv_platform, pool); let (pid, tid) = kern - .boot( - types::bounded::Priority::new(16).unwrap_or_else(|| unreachable!()), - types::time::TimeSlice::new(100), - ) + .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 (pid="); @@ -100,8 +96,7 @@ fn ipc_demo( uart.write_str("k-os: --- IPC demo ---\n"); - // Create process B using init's ProcessCreate cap (slot 0) - let proc_b_slot = match kern.handle_syscall(Syscall::CreateProcess { + let _proc_b_slot = match kern.handle_syscall(Syscall::CreateProcess { create_cap: CapSlot::new(0).unwrap_or_else(|| unreachable!()), image: DataRef::empty(), }) { @@ -115,10 +110,8 @@ fn ipc_demo( let tid_b = ThreadId::from_raw(1); uart.write_str("k-os: process B created\n"); - // Create an endpoint let ep_id = kern.create_endpoint().unwrap_or_else(|_| unreachable!()); - // Grant endpoint caps to both processes let ep_cap_a = kern.grant_capability( init_pid, Resource::Endpoint(ep_id), @@ -137,10 +130,8 @@ fn ipc_demo( uart.write_str("k-os: endpoint created, caps granted\n"); - // Process B calls Receive (blocks — no sender yet) kern.switch_to_thread(tid_b); - let outcome = kern.handle_syscall(Syscall::Receive { endpoint: ep_cap_b }); - match &outcome { + match kern.handle_syscall(Syscall::Receive { endpoint: ep_cap_b }) { SyscallOutcome::BlockCaller(_) => { uart.write_str("k-os: process B blocked on Receive\n"); } @@ -150,15 +141,13 @@ fn ipc_demo( } } - // Process A calls Send (finds B waiting → delivers message) let tid_a = ThreadId::from_raw(0); kern.switch_to_thread(tid_a); let msg = Message::from_words([42, 7, 0, 0]); - let outcome = kern.handle_syscall(Syscall::Send { + match kern.handle_syscall(Syscall::Send { endpoint: ep_cap_a, message: msg, - }); - match &outcome { + }) { SyscallOutcome::SwitchTo(target) => { uart.write_str("k-os: Send delivered, switching to thread "); uart.write_dec(target.raw() as usize); @@ -170,7 +159,6 @@ fn ipc_demo( } } - // Check B's pending result match kern.pending_result(tid_b) { Some(SyscallResult::Message(m)) => { uart.write_str("k-os: IPC complete — received: ["); diff --git a/crates/adapter-riscv/src/mmu/allocator.rs b/crates/adapter-riscv/src/mmu/allocator.rs new file mode 100644 index 0000000..e34b128 --- /dev/null +++ b/crates/adapter-riscv/src/mmu/allocator.rs @@ -0,0 +1,19 @@ +use super::page_table::{PageTable, PAGE_SIZE}; + +// Boot-time bump allocator for page tables. +// Only used during init before the scheduler starts. +static mut NEXT_FREE: usize = 0; + +pub fn init_allocator(start: usize) { + unsafe { NEXT_FREE = start; } +} + +pub fn alloc_page_table() -> &'static mut PageTable { + unsafe { + let addr = NEXT_FREE; + NEXT_FREE += PAGE_SIZE; + let table = &mut *(addr as *mut PageTable); + table.zero(); + table + } +} diff --git a/crates/adapter-riscv/src/mmu/mod.rs b/crates/adapter-riscv/src/mmu/mod.rs new file mode 100644 index 0000000..866596a --- /dev/null +++ b/crates/adapter-riscv/src/mmu/mod.rs @@ -0,0 +1,5 @@ +pub mod allocator; +pub mod page_table; + +pub use allocator::init_allocator; +pub use page_table::{activate, init_kernel_page_table, create_user_page_table, PageTable, PAGE_SIZE}; diff --git a/crates/adapter-riscv/src/page_table.rs b/crates/adapter-riscv/src/mmu/page_table.rs similarity index 75% rename from crates/adapter-riscv/src/page_table.rs rename to crates/adapter-riscv/src/mmu/page_table.rs index b48bf97..2a750ed 100644 --- a/crates/adapter-riscv/src/page_table.rs +++ b/crates/adapter-riscv/src/mmu/page_table.rs @@ -1,4 +1,8 @@ +use crate::board; +use super::allocator::alloc_page_table; + pub const PAGE_SIZE: usize = 4096; + const PTE_V: u64 = 1 << 0; const PTE_R: u64 = 1 << 1; const PTE_W: u64 = 1 << 2; @@ -53,22 +57,6 @@ impl PageTable { } } -static mut PAGE_ALLOC_NEXT: usize = 0; - -pub fn init_page_allocator(start: usize) { - unsafe { PAGE_ALLOC_NEXT = start; } -} - -pub fn alloc_page_table() -> &'static mut PageTable { - unsafe { - let addr = PAGE_ALLOC_NEXT; - PAGE_ALLOC_NEXT += PAGE_SIZE; - let table = &mut *(addr as *mut PageTable); - table.zero(); - table - } -} - fn vpn(va: usize, level: usize) -> usize { (va >> (12 + 9 * level)) & 0x1FF } @@ -110,27 +98,23 @@ fn map_range(root: &mut PageTable, va_start: usize, pa_start: usize, pages: usiz pub fn init_kernel_page_table() -> &'static mut PageTable { let root = alloc_page_table(); - let ram_start = 0x80000000usize; - let ram_pages = 128 * 1024 * 1024 / PAGE_SIZE; // 128 MiB - map_range(root, ram_start, ram_start, ram_pages, true, true, true, false, true); + let ram_pages = board::RAM_SIZE / PAGE_SIZE; + map_range(root, board::RAM_BASE, board::RAM_BASE, ram_pages, true, true, true, false, true); - let uart_start = 0x10000000usize; - map_range(root, uart_start, uart_start, 1, true, true, false, false, true); + map_range(root, board::UART_BASE, board::UART_BASE, 1, true, true, false, false, true); - let plic_start = 0x0C000000usize; let plic_pages = 0x400000 / PAGE_SIZE; - map_range(root, plic_start, plic_start, plic_pages, true, true, false, false, true); + map_range(root, board::PLIC_BASE, board::PLIC_BASE, plic_pages, true, true, false, false, true); - let clint_start = 0x02000000usize; let clint_pages = 0x10000 / PAGE_SIZE; - map_range(root, clint_start, clint_start, clint_pages, true, true, false, false, true); + map_range(root, board::CLINT_BASE, board::CLINT_BASE, clint_pages, true, true, false, false, true); root } pub fn activate(root: &PageTable) { let ppn = (root as *const PageTable as u64) >> 12; - let satp = (8u64 << 60) | ppn; // mode=8 (Sv39), ASID=0 + let satp = (8u64 << 60) | ppn; unsafe { core::arch::asm!( "csrw satp, {0}", @@ -148,18 +132,14 @@ pub fn create_user_page_table( ) -> &'static mut PageTable { let root = alloc_page_table(); - // Copy kernel mappings (upper half — entries 256-511 cover high VA space) - // For identity mapping, copy all valid entries from kernel root for i in 0..512 { if kernel_root.entries[i].is_valid() { root.entries[i] = kernel_root.entries[i]; } } - // Map user program pages map_range(root, user_va, program_pa, program_pages, true, false, true, true, false); - // Map user stack (1 page at user_va - PAGE_SIZE) let stack_va = user_va.wrapping_sub(PAGE_SIZE); let stack_table = alloc_page_table(); let stack_pa = stack_table as *const PageTable as usize; diff --git a/crates/adapter-riscv/src/platform.rs b/crates/adapter-riscv/src/platform.rs index 9e03556..4b5b3fa 100644 --- a/crates/adapter-riscv/src/platform.rs +++ b/crates/adapter-riscv/src/platform.rs @@ -9,8 +9,8 @@ use types::{ time::{Ticks, TimerDuration}, }; -use crate::plic::Plic; -use crate::timer; +use crate::board; +use crate::hw::{plic::Plic, timer}; pub struct RiscVPlatform { num_cores: u8, @@ -23,22 +23,17 @@ impl RiscVPlatform { } impl Platform for RiscVPlatform { - fn configure_protection(&mut self, _process: ProcessId, _regions: &[MemoryRegion]) { - // page table activation happens separately per context switch - } + fn configure_protection(&mut self, _process: ProcessId, _regions: &[MemoryRegion]) {} - fn context_switch(&mut self, _from: &mut SavedContext, _to: &SavedContext) { - // context switch is handled by the trap vector assembly - } + fn context_switch(&mut self, _from: &mut SavedContext, _to: &SavedContext) {} fn enable_user_mode(&mut self, _entry: EntryPoint, _stack: StackPointer) -> ! { - // handled by setting up TrapFrame and sret in the main loop loop { unsafe { core::arch::asm!("wfi") }; } } fn set_timer(&mut self, _duration: TimerDuration) { let now = timer::read_time(); - timer::set_next_timer(now + 10_000_000); + timer::set_next(now + board::TICK_INTERVAL); } fn current_ticks(&self) -> Ticks { @@ -53,9 +48,7 @@ impl Platform for RiscVPlatform { Plic::enable(irq.raw() as u32); } - fn send_ipi(&mut self, _target: CoreId) { - // single core — no-op - } + fn send_ipi(&mut self, _target: CoreId) {} fn core_id(&self) -> CoreId { CoreId::from_raw(0) @@ -72,6 +65,5 @@ impl Platform for RiscVPlatform { _size: PageCount, _permissions: PermissionSet, ) { - // page table mapping for shared memory — deferred to full MMU integration } } diff --git a/crates/adapter-riscv/src/trap.rs b/crates/adapter-riscv/src/trap/mod.rs similarity index 81% rename from crates/adapter-riscv/src/trap.rs rename to crates/adapter-riscv/src/trap/mod.rs index 849e9f6..eee9fcf 100644 --- a/crates/adapter-riscv/src/trap.rs +++ b/crates/adapter-riscv/src/trap/mod.rs @@ -2,7 +2,7 @@ use core::arch::global_asm; #[repr(C)] pub struct TrapFrame { - pub regs: [usize; 32], // x0-x31 + pub regs: [usize; 32], pub sepc: usize, pub sstatus: usize, } @@ -17,7 +17,7 @@ impl TrapFrame { } } -// sscratch = 0 when in S-mode, = kernel_stack_top when in U-mode +// sscratch = 0 when in S-mode, = kernel_stack_top when in U-mode. // On trap: swap sp/sscratch. If sp==0 after swap, we came from S-mode (undo swap). global_asm!(r#" .align 4 @@ -25,10 +25,8 @@ global_asm!(r#" trap_vector: csrrw sp, sscratch, sp bnez sp, _from_user - # came from S-mode: sscratch had 0, sp is now 0, old sp is in sscratch - csrrw sp, sscratch, sp # undo: sp = old kernel sp, sscratch = 0 + csrrw sp, sscratch, sp _from_user: - # sp is now a valid kernel stack (either kept or swapped in) addi sp, sp, -272 sd x1, 8(sp) @@ -62,7 +60,6 @@ _from_user: sd x30, 240(sp) sd x31, 248(sp) - # save user sp from sscratch (0 if from S-mode, user sp if from U-mode) csrr t0, sscratch sd t0, 16(sp) @@ -79,12 +76,9 @@ _from_user: ld t0, 264(sp) csrw sstatus, t0 - # check if returning to U-mode: sstatus.SPP (bit 8) - # if SPP=0 (user mode), restore sscratch with user sp andi t1, t0, 0x100 bnez t1, _restore_smode - # returning to U-mode: put user sp in sscratch ld t0, 16(sp) csrw sscratch, t0 @@ -122,11 +116,10 @@ _restore_smode: addi sp, sp, 272 - # if returning to U-mode, swap sp/sscratch to restore user sp csrr t0, sstatus andi t0, t0, 0x100 bnez t0, _sret_smode - csrrw sp, sscratch, sp # sp = user sp, sscratch = kernel sp (for next trap) + csrrw sp, sscratch, sp _sret_smode: sret "#); @@ -136,21 +129,15 @@ const CAUSE_S_TIMER: usize = 5; const CAUSE_S_EXTERNAL: usize = 9; const CAUSE_ECALL_U: usize = 8; -pub fn init_trap() { +pub fn init() { unsafe extern "C" { fn trap_vector(); } unsafe { let addr = trap_vector as usize; core::arch::asm!("csrw stvec, {0}", in(reg) addr); - - // sscratch = 0 means "currently in S-mode" core::arch::asm!("csrw sscratch, zero"); - - // enable supervisor interrupts core::arch::asm!("csrs sstatus, {0}", in(reg) 1usize << 1); - - // enable timer + external + software interrupts in sie let sie_bits = (1usize << 5) | (1usize << 9) | (1usize << 1); core::arch::asm!("csrs sie, {0}", in(reg) sie_bits); } @@ -167,13 +154,13 @@ 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::uart::Uart::new(); + 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::timer::handle_timer_interrupt(); + crate::hw::timer::handle_interrupt(); } CAUSE_S_EXTERNAL => { uart.write_str("[EXT]"); diff --git a/crates/types/src/bounded.rs b/crates/types/src/bounded.rs index a6fbbef..0c9635f 100644 --- a/crates/types/src/bounded.rs +++ b/crates/types/src/bounded.rs @@ -3,3 +3,8 @@ use crate::macros::bounded; bounded!(CapSlot, u8, 0, 63); bounded!(Priority, u8, 0, 31); bounded!(PageCount, u16, 1, 1024); + +impl Priority { + pub const DEFAULT: Self = Self(16); +} + diff --git a/crates/types/src/time.rs b/crates/types/src/time.rs index 32dbdad..7b5ea7c 100644 --- a/crates/types/src/time.rs +++ b/crates/types/src/time.rs @@ -25,6 +25,11 @@ pub struct TimeSlice { } impl TimeSlice { + pub const DEFAULT: Self = Self { + remaining: 100, + quantum: 100, + }; + pub fn new(quantum: u32) -> Self { Self { remaining: quantum,