forked from M-Labs/artiq
riscv: impl pmp
This commit is contained in:
parent
790a20edf6
commit
a0bf11b465
|
@ -1,4 +1,5 @@
|
||||||
use super::cache;
|
use super::{cache, pmp};
|
||||||
|
use riscv::register::*;
|
||||||
|
|
||||||
pub unsafe fn reset() -> ! {
|
pub unsafe fn reset() -> ! {
|
||||||
llvm_asm!(r#"
|
llvm_asm!(r#"
|
||||||
|
@ -16,3 +17,14 @@ pub unsafe fn jump(addr: usize) -> ! {
|
||||||
"# : : "r"(addr) : : "volatile");
|
"# : : "r"(addr) : : "volatile");
|
||||||
loop {}
|
loop {}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub unsafe fn start_user(addr: usize) -> ! {
|
||||||
|
pmp::enable_user_memory();
|
||||||
|
mstatus::set_mpp(mstatus::MPP::User);
|
||||||
|
mepc::write(addr);
|
||||||
|
llvm_asm!(
|
||||||
|
"mret"
|
||||||
|
: : : : "volatile"
|
||||||
|
);
|
||||||
|
unreachable!()
|
||||||
|
}
|
||||||
|
|
|
@ -1,2 +1,3 @@
|
||||||
pub mod cache;
|
pub mod cache;
|
||||||
pub mod boot;
|
pub mod boot;
|
||||||
|
pub mod pmp;
|
||||||
|
|
|
@ -0,0 +1,55 @@
|
||||||
|
use riscv::register::{pmpaddr0, pmpaddr1, pmpaddr2, pmpaddr3, pmpcfg0};
|
||||||
|
|
||||||
|
static mut THREAD_DEPTH: u8 = 0;
|
||||||
|
|
||||||
|
const PMP_L : usize = 0b10000000;
|
||||||
|
const PMP_NAPOT: usize = 0b00011000;
|
||||||
|
const PMP_X : usize = 0b00000100;
|
||||||
|
const PMP_W : usize = 0b00000010;
|
||||||
|
const PMP_R : usize = 0b00000001;
|
||||||
|
const PMP_OFF : usize = 0b00000000;
|
||||||
|
|
||||||
|
#[inline(always)]
|
||||||
|
pub unsafe fn init_stack_guard(guard_base: usize) {
|
||||||
|
pmpaddr2::write((guard_base >> 2) | ((0x1000 - 1) >> 3));
|
||||||
|
pmpcfg0::write((PMP_L | PMP_NAPOT) << 16);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline(always)]
|
||||||
|
pub fn enable_user_memory() {
|
||||||
|
pmpaddr3::write((0x80000000 - 1) >> 3);
|
||||||
|
pmpcfg0::write((PMP_L | PMP_NAPOT | PMP_X | PMP_W | PMP_R) << 24);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline(always)]
|
||||||
|
pub unsafe fn push_pmp_region(addr: usize) {
|
||||||
|
let pmp_addr = (addr >> 2) | ((0x1000 - 1) >> 3);
|
||||||
|
match THREAD_DEPTH {
|
||||||
|
// Activate PMP0 when switching from main stack to thread
|
||||||
|
0 => {
|
||||||
|
pmpaddr0::write(pmp_addr);
|
||||||
|
pmpcfg0::write(PMP_NAPOT);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Temporarily activate PMP1 when spawning a thread from a thread
|
||||||
|
// The thread should swap back to the main stack very soon after init
|
||||||
|
1 => {
|
||||||
|
pmpaddr1::write(pmp_addr);
|
||||||
|
pmpcfg0::write(PMP_NAPOT << 8 | PMP_NAPOT);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Thread *running* another thread should not be possible
|
||||||
|
_ => unreachable!()
|
||||||
|
}
|
||||||
|
THREAD_DEPTH += 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline(always)]
|
||||||
|
pub unsafe fn pop_pmp_region() {
|
||||||
|
THREAD_DEPTH -= 1;
|
||||||
|
match THREAD_DEPTH {
|
||||||
|
0 => pmpcfg0::write(PMP_OFF),
|
||||||
|
1 => pmpcfg0::write(PMP_NAPOT),
|
||||||
|
_ => unreachable!()
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue