refactor(adapter-riscv): restructure into hw/, mmu/, trap/ modules with board constants
Add Priority::DEFAULT and TimeSlice::DEFAULT to types crate. All QEMU virt addresses consolidated in board.rs. Structure mirrors future adapter-arm/ layout.
This commit is contained in:
19
crates/adapter-riscv/src/mmu/allocator.rs
Normal file
19
crates/adapter-riscv/src/mmu/allocator.rs
Normal file
@@ -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
|
||||
}
|
||||
}
|
||||
5
crates/adapter-riscv/src/mmu/mod.rs
Normal file
5
crates/adapter-riscv/src/mmu/mod.rs
Normal file
@@ -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};
|
||||
149
crates/adapter-riscv/src/mmu/page_table.rs
Normal file
149
crates/adapter-riscv/src/mmu/page_table.rs
Normal file
@@ -0,0 +1,149 @@
|
||||
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;
|
||||
const PTE_X: u64 = 1 << 3;
|
||||
const PTE_U: u64 = 1 << 4;
|
||||
const PTE_G: u64 = 1 << 5;
|
||||
const PTE_A: u64 = 1 << 6;
|
||||
const PTE_D: u64 = 1 << 7;
|
||||
|
||||
#[derive(Clone, Copy)]
|
||||
#[repr(transparent)]
|
||||
pub struct PageTableEntry(u64);
|
||||
|
||||
impl PageTableEntry {
|
||||
pub fn empty() -> Self {
|
||||
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))
|
||||
}
|
||||
|
||||
pub fn new_branch(ppn: u64) -> Self {
|
||||
Self(PTE_V | (ppn << 10))
|
||||
}
|
||||
|
||||
pub fn is_valid(&self) -> bool {
|
||||
self.0 & PTE_V != 0
|
||||
}
|
||||
|
||||
pub fn ppn(&self) -> u64 {
|
||||
(self.0 >> 10) & 0xFFF_FFFF_FFFF
|
||||
}
|
||||
}
|
||||
|
||||
#[repr(C, align(4096))]
|
||||
pub struct PageTable {
|
||||
pub entries: [PageTableEntry; 512],
|
||||
}
|
||||
|
||||
impl PageTable {
|
||||
pub fn zero(&mut self) {
|
||||
for entry in &mut self.entries {
|
||||
*entry = PageTableEntry::empty();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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) {
|
||||
let vpn2 = vpn(va, 2);
|
||||
let vpn1 = vpn(va, 1);
|
||||
let vpn0 = vpn(va, 0);
|
||||
|
||||
if !root.entries[vpn2].is_valid() {
|
||||
let table = alloc_page_table();
|
||||
let ppn = (table as *const PageTable as u64) >> 12;
|
||||
root.entries[vpn2] = PageTableEntry::new_branch(ppn);
|
||||
}
|
||||
|
||||
let l1_addr = (root.entries[vpn2].ppn() << 12) as *mut PageTable;
|
||||
let l1 = unsafe { &mut *l1_addr };
|
||||
|
||||
if !l1.entries[vpn1].is_valid() {
|
||||
let table = alloc_page_table();
|
||||
let ppn = (table as *const PageTable as u64) >> 12;
|
||||
l1.entries[vpn1] = PageTableEntry::new_branch(ppn);
|
||||
}
|
||||
|
||||
let l0_addr = (l1.entries[vpn1].ppn() << 12) as *mut PageTable;
|
||||
let l0 = unsafe { &mut *l0_addr };
|
||||
|
||||
let ppn = (pa as u64) >> 12;
|
||||
l0.entries[vpn0] = PageTableEntry::new_leaf(ppn, read, write, exec, user, global);
|
||||
}
|
||||
|
||||
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 {
|
||||
let offset = i * PAGE_SIZE;
|
||||
map_page(root, va_start + offset, pa_start + offset, read, write, exec, user, global);
|
||||
}
|
||||
}
|
||||
|
||||
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_range(root, board::UART_BASE, board::UART_BASE, 1, true, true, false, false, true);
|
||||
|
||||
let plic_pages = 0x400000 / PAGE_SIZE;
|
||||
map_range(root, board::PLIC_BASE, board::PLIC_BASE, plic_pages, true, true, false, false, true);
|
||||
|
||||
let clint_pages = 0x10000 / PAGE_SIZE;
|
||||
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;
|
||||
unsafe {
|
||||
core::arch::asm!(
|
||||
"csrw satp, {0}",
|
||||
"sfence.vma",
|
||||
in(reg) satp,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn create_user_page_table(
|
||||
kernel_root: &PageTable,
|
||||
program_pa: usize,
|
||||
program_pages: usize,
|
||||
user_va: usize,
|
||||
) -> &'static mut PageTable {
|
||||
let root = alloc_page_table();
|
||||
|
||||
for i in 0..512 {
|
||||
if kernel_root.entries[i].is_valid() {
|
||||
root.entries[i] = kernel_root.entries[i];
|
||||
}
|
||||
}
|
||||
|
||||
map_range(root, user_va, program_pa, program_pages, true, false, true, true, false);
|
||||
|
||||
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);
|
||||
|
||||
root
|
||||
}
|
||||
Reference in New Issue
Block a user