use memory_addr::VirtAddr;
use crate::TrapFrame;
pub struct UspaceContext(TrapFrame);
impl UspaceContext {
pub fn empty() -> Self {
Self(Default::default())
}
pub fn new(entry: usize, ustack_top: VirtAddr, arg0: usize) -> Self {
let mut trap_frame = TrapFrame::default();
const PPLV_UMODE: usize = 0b11;
const PIE: usize = 1 << 2;
trap_frame.regs.sp = ustack_top.as_usize();
trap_frame.era = entry;
trap_frame.prmd = PPLV_UMODE | PIE;
trap_frame.regs.a0 = arg0;
Self(trap_frame)
}
pub const fn from(trap_frame: &TrapFrame) -> Self {
Self(*trap_frame)
}
pub const fn get_ip(&self) -> usize {
self.0.era
}
pub const fn get_sp(&self) -> usize {
self.0.regs.sp
}
pub const fn set_ip(&mut self, pc: usize) {
self.0.era = pc;
}
pub const fn set_sp(&mut self, sp: usize) {
self.0.regs.sp = sp;
}
pub const fn set_retval(&mut self, a0: usize) {
self.0.regs.a0 = a0;
}
pub unsafe fn enter_uspace(&self, kstack_top: VirtAddr) -> ! {
use loongArch64::register::era;
crate::asm::disable_irqs();
era::set_pc(self.get_ip());
unsafe {
core::arch::asm!(
include_asm_macros!(),
"
move $sp, {tf}
csrwr $tp, KSAVE_TP
csrwr $r21, KSAVE_R21
LDD $tp, $sp, 32
csrwr $tp, LA_CSR_PRMD
csrwr {kstack_top}, KSAVE_KSP // save ksp into SAVE0 CSR
POP_GENERAL_REGS
LDD $tp, $sp, 2
LDD $r21, $sp, 21
LDD $sp, $sp, 3 // user sp
ertn",
tf = in (reg) &self.0,
kstack_top = in(reg) kstack_top.as_usize(),
options(noreturn),
)
}
}
}