Files
k-os/crates/adapter-riscv/src/platform.rs

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),
),
});
}
}