diff --git a/crates/adapter-riscv/src/mmu/mod.rs b/crates/adapter-riscv/src/mmu/mod.rs index fb7f864..e84f952 100644 --- a/crates/adapter-riscv/src/mmu/mod.rs +++ b/crates/adapter-riscv/src/mmu/mod.rs @@ -2,4 +2,4 @@ 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, map_range, PageTable, PAGE_SIZE}; +pub use page_table::{activate, init_kernel_page_table, create_user_page_table, map, MapFlags, Mapping, PageTable, PAGE_SIZE}; diff --git a/crates/adapter-riscv/src/mmu/page_table.rs b/crates/adapter-riscv/src/mmu/page_table.rs index 90716e9..547b7ff 100644 --- a/crates/adapter-riscv/src/mmu/page_table.rs +++ b/crates/adapter-riscv/src/mmu/page_table.rs @@ -12,6 +12,49 @@ const PTE_G: u64 = 1 << 5; const PTE_A: u64 = 1 << 6; const PTE_D: u64 = 1 << 7; +#[derive(Clone, Copy)] +pub struct MapFlags { + bits: u64, +} + +impl MapFlags { + pub fn kernel_rwx() -> Self { + Self { bits: PTE_R | PTE_W | PTE_X | PTE_G } + } + + pub fn kernel_rw() -> Self { + Self { bits: PTE_R | PTE_W | PTE_G } + } + + pub fn user_rx() -> Self { + Self { bits: PTE_R | PTE_X | PTE_U } + } + + pub fn user_rw() -> Self { + Self { bits: PTE_R | PTE_W | PTE_U } + } + + pub fn user(read: bool, write: bool, exec: bool) -> Self { + let mut bits = PTE_U; + if read { bits |= PTE_R; } + if write { bits |= PTE_W; } + if exec { bits |= PTE_X; } + Self { bits } + } + + fn to_pte_flags(self) -> u64 { + PTE_V | PTE_A | PTE_D | self.bits + } +} + +#[derive(Clone, Copy)] +pub struct Mapping { + pub va: usize, + pub pa: usize, + pub pages: usize, + pub flags: MapFlags, +} + #[derive(Clone, Copy)] #[repr(transparent)] pub struct PageTableEntry(u64); @@ -21,17 +64,11 @@ impl PageTableEntry { Self(0) } - pub fn new_leaf(ppn: u64, read: bool, write: bool, exec: bool, user: bool, global: bool) -> Self { - let mut flags = PTE_V | PTE_A | PTE_D; - if read { flags |= PTE_R; } - if write { flags |= PTE_W; } - if exec { flags |= PTE_X; } - if user { flags |= PTE_U; } - if global { flags |= PTE_G; } - Self(flags | (ppn << 10)) + fn new_leaf(ppn: u64, flags: MapFlags) -> Self { + Self(flags.to_pte_flags() | (ppn << 10)) } - pub fn new_branch(ppn: u64) -> Self { + fn new_branch(ppn: u64) -> Self { Self(PTE_V | (ppn << 10)) } @@ -61,7 +98,7 @@ fn vpn(va: usize, level: usize) -> usize { (va >> (12 + 9 * level)) & 0x1FF } -fn map_page(root: &mut PageTable, va: usize, pa: usize, read: bool, write: bool, exec: bool, user: bool, global: bool) { +fn map_page(root: &mut PageTable, va: usize, pa: usize, flags: MapFlags) { let vpn2 = vpn(va, 2); let vpn1 = vpn(va, 1); let vpn0 = vpn(va, 0); @@ -85,29 +122,46 @@ fn map_page(root: &mut PageTable, va: usize, pa: usize, read: bool, write: bool, let l0 = unsafe { &mut *l0_addr }; let ppn = (pa as u64) >> 12; - l0.entries[vpn0] = PageTableEntry::new_leaf(ppn, read, write, exec, user, global); + l0.entries[vpn0] = PageTableEntry::new_leaf(ppn, flags); } -pub fn map_range(root: &mut PageTable, va_start: usize, pa_start: usize, pages: usize, read: bool, write: bool, exec: bool, user: bool, global: bool) { - for i in 0..pages { +pub fn map(root: &mut PageTable, mapping: Mapping) { + for i in 0..mapping.pages { let offset = i * PAGE_SIZE; - map_page(root, va_start + offset, pa_start + offset, read, write, exec, user, global); + map_page(root, mapping.va + offset, mapping.pa + offset, mapping.flags); } } pub fn init_kernel_page_table() -> &'static mut PageTable { let root = alloc_page_table(); - let ram_pages = board::RAM_SIZE / PAGE_SIZE; - map_range(root, board::RAM_BASE, board::RAM_BASE, ram_pages, true, true, true, false, true); + map(root, Mapping { + va: board::RAM_BASE, + pa: board::RAM_BASE, + pages: board::RAM_SIZE / PAGE_SIZE, + flags: MapFlags::kernel_rwx(), + }); - map_range(root, board::UART_BASE, board::UART_BASE, 1, true, true, false, false, true); + map(root, Mapping { + va: board::UART_BASE, + pa: board::UART_BASE, + pages: 1, + flags: MapFlags::kernel_rw(), + }); - let plic_pages = 0x400000 / PAGE_SIZE; - map_range(root, board::PLIC_BASE, board::PLIC_BASE, plic_pages, true, true, false, false, true); + map(root, Mapping { + va: board::PLIC_BASE, + pa: board::PLIC_BASE, + pages: 0x400000 / PAGE_SIZE, + flags: MapFlags::kernel_rw(), + }); - let clint_pages = 0x10000 / PAGE_SIZE; - map_range(root, board::CLINT_BASE, board::CLINT_BASE, clint_pages, true, true, false, false, true); + map(root, Mapping { + va: board::CLINT_BASE, + pa: board::CLINT_BASE, + pages: 0x10000 / PAGE_SIZE, + flags: MapFlags::kernel_rw(), + }); root } @@ -138,12 +192,23 @@ pub fn create_user_page_table( } } - map_range(root, user_va, program_pa, program_pages, true, false, true, true, false); + if program_pages > 0 { + map(root, Mapping { + va: user_va, + pa: program_pa, + pages: program_pages, + flags: MapFlags::user_rx(), + }); - 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; - map_range(root, stack_va, stack_pa, 1, true, true, false, true, false); + let stack_table = alloc_page_table(); + let stack_pa = stack_table as *const PageTable as usize; + map(root, Mapping { + va: user_va.wrapping_sub(PAGE_SIZE), + pa: stack_pa, + pages: 1, + flags: MapFlags::user_rw(), + }); + } root } diff --git a/crates/adapter-riscv/src/platform.rs b/crates/adapter-riscv/src/platform.rs index 9b68b35..3245aa3 100644 --- a/crates/adapter-riscv/src/platform.rs +++ b/crates/adapter-riscv/src/platform.rs @@ -45,9 +45,12 @@ impl Platform for RiscVPlatform { fn configure_protection(&mut self, process: ProcessId, regions: &[MemoryRegion]) { let pt = self.ensure_page_table(process); for region in regions { - let base_pa = region.base().raw(); - let pages = region.size().value() as usize; - mmu::map_range(pt, base_pa, base_pa, pages, true, true, true, true, false); + mmu::map(pt, mmu::Mapping { + va: region.base().raw(), + pa: region.base().raw(), + pages: region.size().value() as usize, + flags: mmu::MapFlags::user(true, true, true), + }); } } @@ -107,11 +110,15 @@ impl Platform for RiscVPlatform { permissions: PermissionSet, ) { let pt = self.ensure_page_table(process); - let pa = base.raw(); - let pages = size.value() as usize; - let read = permissions.allows(Permission::Read); - let write = permissions.allows(Permission::Write); - let exec = permissions.allows(Permission::Execute); - mmu::map_range(pt, pa, pa, pages, read, write, exec, true, false); + mmu::map(pt, mmu::Mapping { + va: base.raw(), + pa: base.raw(), + pages: size.value() as usize, + flags: mmu::MapFlags::user( + permissions.allows(Permission::Read), + permissions.allows(Permission::Write), + permissions.allows(Permission::Execute), + ), + }); } }