Skip to main content

ax_cpu/loongarch64/
uspace.rs

1//! Structures and functions for user space.
2
3use 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/// Context to enter user space.
15#[derive(Debug, Clone, Copy)]
16#[repr(C)]
17pub struct UserContext(TrapFrame);
18
19impl UserContext {
20    /// Creates a new context with the given entry point, user stack pointer,
21    /// and the argument.
22    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    /// Normalizes a cloned user context so it can safely return to user mode.
34    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    /// Enter user space.
41    ///
42    /// It restores the user registers and jumps to the user entry point
43    /// (saved in `sepc`).
44    ///
45    /// This function returns when an exception or syscall occurs.
46    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/// Information about an exception that occurred in user space.
104#[derive(Debug, Clone, Copy)]
105pub struct ExceptionInfo {
106    /// The raw exception.
107    pub e: Exception,
108    /// The faulting address (from `badv`).
109    pub badv: usize,
110    /// The instruction causing the fault (from `badi`).
111    pub badi: u32,
112}
113
114impl ExceptionInfo {
115    /// Returns a generalized kind of this exception.
116    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}