use domain::memory::MemoryRegion; use domain::process::MAX_PROCESSES; use platform::Platform; use types::{ address::{EntryPoint, PhysicalAddress, StackPointer, VirtualAddress}, bounded::PageCount, id::{CoreId, IrqId, ProcessId}, permission::{Permission, PermissionSet}, time::{Ticks, TimerDuration}, }; use crate::board; use crate::hw::{plic::Plic, timer}; use crate::mmu; use crate::trap; pub struct RiscVPlatform { num_cores: u8, page_tables: [usize; MAX_PROCESSES], } impl RiscVPlatform { pub fn new(kernel_pt_addr: usize) -> Self { let mut pt = [0usize; MAX_PROCESSES]; pt[0] = kernel_pt_addr; Self { num_cores: 1, page_tables: pt } } pub fn page_table_for(&self, pid: ProcessId) -> usize { self.page_tables[pid.raw() as usize] } fn ensure_page_table(&mut self, pid: ProcessId) -> &mut mmu::PageTable { let idx = pid.raw() as usize; if self.page_tables[idx] == 0 { let kernel_pt = unsafe { &*(self.page_tables[0] as *const mmu::PageTable) }; let user_pt = mmu::create_user_page_table( kernel_pt, PhysicalAddress::from_raw(0), 0, VirtualAddress::from_raw(0x10000), ); self.page_tables[idx] = user_pt as *const mmu::PageTable as usize; } unsafe { &mut *(self.page_tables[idx] as *mut mmu::PageTable) } } } impl Platform for RiscVPlatform { fn configure_protection(&mut self, process: ProcessId, regions: &[MemoryRegion]) { let pt = self.ensure_page_table(process); for region in regions { mmu::map(pt, mmu::Mapping { va: VirtualAddress::from_raw(region.base().raw()), pa: region.base(), pages: region.size().value() as usize, flags: mmu::Sv39Flags::user(true, true, true), }); } } fn enable_user_mode(&mut self, entry: EntryPoint, stack: StackPointer) -> ! { let kernel_sp: usize; unsafe { core::arch::asm!("mv {0}, sp", out(reg) kernel_sp) }; trap::set_kernel_stack(kernel_sp); unsafe { core::arch::asm!( "csrc sstatus, {spp}", "csrs sstatus, {spie}", "csrw sepc, {entry}", "mv sp, {stack}", "sret", spp = in(reg) 1usize << 8, spie = in(reg) 1usize << 5, entry = in(reg) entry.raw(), stack = in(reg) stack.raw(), options(noreturn), ); } } fn set_timer(&mut self, _duration: TimerDuration) { let now = timer::read_time(); timer::set_next(now + board::TICK_INTERVAL); } fn current_ticks(&self) -> Ticks { Ticks::from_raw(timer::read_time()) } fn mask_irq(&mut self, irq: IrqId) { Plic::disable(irq.raw() as u32); } fn unmask_irq(&mut self, irq: IrqId) { Plic::enable(irq.raw() as u32); } fn send_ipi(&mut self, _target: CoreId) {} fn core_id(&self) -> CoreId { CoreId::from_raw(0) } fn num_cores(&self) -> u8 { self.num_cores } fn map_shared( &mut self, process: ProcessId, base: PhysicalAddress, size: PageCount, permissions: PermissionSet, ) { let pt = self.ensure_page_table(process); mmu::map(pt, mmu::Mapping { va: VirtualAddress::from_raw(base.raw()), pa: base, pages: size.value() as usize, flags: mmu::Sv39Flags::user( permissions.allows(Permission::Read), permissions.allows(Permission::Write), permissions.allows(Permission::Execute), ), }); } }