refactor(mmu): replace bool-heavy map_range with Mapping struct and MapFlags builders
This commit is contained in:
@@ -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};
|
||||||
|
|||||||
@@ -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
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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),
|
||||||
|
),
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user