130 lines
3.8 KiB
Rust
130 lines
3.8 KiB
Rust
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),
|
|
),
|
|
});
|
|
}
|
|
}
|