ax_cpu/loongarch64/
uspace.rs1use core::ops::{Deref, DerefMut};
4
5use ax_memory_addr::VirtAddr;
6use loongArch64::register::{
7 badi, badv,
8 estat::{self, Exception, Trap},
9};
10
11pub use crate::uspace_common::{ExceptionKind, ReturnReason};
12use crate::{TrapFrame, trap::PageFaultFlags};
13
14#[derive(Debug, Clone, Copy)]
16#[repr(C)]
17pub struct UserContext(TrapFrame);
18
19impl UserContext {
20 pub fn new(entry: usize, ustack_top: VirtAddr, arg0: usize) -> Self {
23 let mut trap_frame = TrapFrame::default();
24 const PPLV_UMODE: usize = 0b11;
25 const PIE: usize = 1 << 2;
26 trap_frame.regs.sp = ustack_top.as_usize();
27 trap_frame.era = entry;
28 trap_frame.prmd = PPLV_UMODE | PIE;
29 trap_frame.regs.a0 = arg0;
30 Self(trap_frame)
31 }
32
33 pub fn prepare_clone_child_return_state(&mut self) {
35 const PPLV_MASK: usize = 0b11;
36 const PIE: usize = 1 << 2;
37 self.0.prmd = (self.0.prmd & !PPLV_MASK) | PPLV_MASK | PIE;
38 }
39
40 pub fn run(&mut self) -> ReturnReason {
47 unsafe extern "C" {
48 fn enter_user(uctx: &mut UserContext);
49 }
50
51 crate::asm::disable_irqs();
52 unsafe { enter_user(self) };
53
54 let estat = estat::read();
55 let badv = badv::read().vaddr();
56 let badi = badi::read().inst();
57
58 let ret = match estat.cause() {
59 Trap::Interrupt(_) => {
60 let irq_num: usize = estat.is().trailing_zeros() as usize;
61 crate::trap::irq_handler(irq_num);
62 ReturnReason::Interrupt
63 }
64 Trap::Exception(Exception::Syscall) => {
65 self.era += 4;
66 ReturnReason::Syscall
67 }
68 Trap::Exception(Exception::LoadPageFault)
69 | Trap::Exception(Exception::PageNonReadableFault) => {
70 ReturnReason::PageFault(va!(badv), PageFaultFlags::READ | PageFaultFlags::USER)
71 }
72 Trap::Exception(Exception::StorePageFault)
73 | Trap::Exception(Exception::PageModifyFault) => {
74 ReturnReason::PageFault(va!(badv), PageFaultFlags::WRITE | PageFaultFlags::USER)
75 }
76 Trap::Exception(Exception::FetchPageFault)
77 | Trap::Exception(Exception::PageNonExecutableFault) => {
78 ReturnReason::PageFault(va!(badv), PageFaultFlags::EXECUTE | PageFaultFlags::USER)
79 }
80 Trap::Exception(e) => ReturnReason::Exception(ExceptionInfo { e, badv, badi }),
81 _ => ReturnReason::Unknown,
82 };
83
84 crate::asm::enable_irqs();
85 ret
86 }
87}
88
89impl Deref for UserContext {
90 type Target = TrapFrame;
91
92 fn deref(&self) -> &Self::Target {
93 &self.0
94 }
95}
96
97impl DerefMut for UserContext {
98 fn deref_mut(&mut self) -> &mut Self::Target {
99 &mut self.0
100 }
101}
102
103#[derive(Debug, Clone, Copy)]
105pub struct ExceptionInfo {
106 pub e: Exception,
108 pub badv: usize,
110 pub badi: u32,
112}
113
114impl ExceptionInfo {
115 pub fn kind(&self) -> ExceptionKind {
117 match self.e {
118 Exception::Breakpoint => ExceptionKind::Breakpoint,
119 Exception::InstructionNotExist | Exception::InstructionPrivilegeIllegal => {
120 ExceptionKind::IllegalInstruction
121 }
122 Exception::AddressNotAligned => ExceptionKind::Misaligned,
123 _ => ExceptionKind::Other,
124 }
125 }
126}