refactor(mmu): replace bool-heavy map_range with Mapping struct and MapFlags builders

This commit is contained in:
2026-10-18 02:41:27 +02:00
parent 896c78088a
commit 7df3034fca
3 changed files with 108 additions and 36 deletions

View File

@@ -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};

View File

@@ -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);
map(root, Mapping {
va: user_va.wrapping_sub(PAGE_SIZE),
pa: stack_pa,
pages: 1,
flags: MapFlags::user_rw(),
});
}
root
}

View File

@@ -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),
),
});
}
}