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 mod page_table;
pub use allocator::init_allocator; 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_A: u64 = 1 << 6;
const PTE_D: u64 = 1 << 7; 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)] #[derive(Clone, Copy)]
#[repr(transparent)] #[repr(transparent)]
pub struct PageTableEntry(u64); pub struct PageTableEntry(u64);
@@ -21,17 +64,11 @@ impl PageTableEntry {
Self(0) Self(0)
} }
pub fn new_leaf(ppn: u64, read: bool, write: bool, exec: bool, user: bool, global: bool) -> Self { fn new_leaf(ppn: u64, flags: MapFlags) -> Self {
let mut flags = PTE_V | PTE_A | PTE_D; Self(flags.to_pte_flags() | (ppn << 10))
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))
} }
pub fn new_branch(ppn: u64) -> Self { fn new_branch(ppn: u64) -> Self {
Self(PTE_V | (ppn << 10)) Self(PTE_V | (ppn << 10))
} }
@@ -61,7 +98,7 @@ fn vpn(va: usize, level: usize) -> usize {
(va >> (12 + 9 * level)) & 0x1FF (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 vpn2 = vpn(va, 2);
let vpn1 = vpn(va, 1); let vpn1 = vpn(va, 1);
let vpn0 = vpn(va, 0); 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 l0 = unsafe { &mut *l0_addr };
let ppn = (pa as u64) >> 12; 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) { pub fn map(root: &mut PageTable, mapping: Mapping) {
for i in 0..pages { for i in 0..mapping.pages {
let offset = i * PAGE_SIZE; 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 { pub fn init_kernel_page_table() -> &'static mut PageTable {
let root = alloc_page_table(); let root = alloc_page_table();
let ram_pages = board::RAM_SIZE / PAGE_SIZE; map(root, Mapping {
map_range(root, board::RAM_BASE, board::RAM_BASE, ram_pages, true, true, true, false, true); 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(root, Mapping {
map_range(root, board::PLIC_BASE, board::PLIC_BASE, plic_pages, true, true, false, false, true); va: board::PLIC_BASE,
pa: board::PLIC_BASE,
pages: 0x400000 / PAGE_SIZE,
flags: MapFlags::kernel_rw(),
});
let clint_pages = 0x10000 / PAGE_SIZE; map(root, Mapping {
map_range(root, board::CLINT_BASE, board::CLINT_BASE, clint_pages, true, true, false, false, true); va: board::CLINT_BASE,
pa: board::CLINT_BASE,
pages: 0x10000 / PAGE_SIZE,
flags: MapFlags::kernel_rw(),
});
root 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_table = alloc_page_table();
let stack_pa = stack_table as *const PageTable as usize; 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 root
} }

View File

@@ -45,9 +45,12 @@ impl Platform for RiscVPlatform {
fn configure_protection(&mut self, process: ProcessId, regions: &[MemoryRegion]) { fn configure_protection(&mut self, process: ProcessId, regions: &[MemoryRegion]) {
let pt = self.ensure_page_table(process); let pt = self.ensure_page_table(process);
for region in regions { for region in regions {
let base_pa = region.base().raw(); mmu::map(pt, mmu::Mapping {
let pages = region.size().value() as usize; va: region.base().raw(),
mmu::map_range(pt, base_pa, base_pa, pages, true, true, true, true, false); 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, permissions: PermissionSet,
) { ) {
let pt = self.ensure_page_table(process); let pt = self.ensure_page_table(process);
let pa = base.raw(); mmu::map(pt, mmu::Mapping {
let pages = size.value() as usize; va: base.raw(),
let read = permissions.allows(Permission::Read); pa: base.raw(),
let write = permissions.allows(Permission::Write); pages: size.value() as usize,
let exec = permissions.allows(Permission::Execute); flags: mmu::MapFlags::user(
mmu::map_range(pt, pa, pa, pages, read, write, exec, true, false); permissions.allows(Permission::Read),
permissions.allows(Permission::Write),
permissions.allows(Permission::Execute),
),
});
} }
} }