Skip to main content

ax_cpu/
uspace_common.rs

1use ax_memory_addr::VirtAddr;
2
3use crate::{TrapFrame, trap::PageFaultFlags, uspace::ExceptionInfo};
4
5/// A reason as to why the control of the CPU is returned from
6/// the user space to the kernel.
7#[derive(Debug, Clone, Copy)]
8pub enum ReturnReason {
9    /// An interrupt.
10    Interrupt,
11    /// A system call.
12    Syscall,
13    /// A page fault.
14    PageFault(VirtAddr, PageFaultFlags),
15    /// Other kinds of exceptions.
16    Exception(ExceptionInfo),
17    /// Unknown reason.
18    Unknown,
19}
20
21/// A generalized kind for [`ExceptionInfo`].
22#[derive(Debug, Clone, Copy, PartialEq, Eq)]
23pub enum ExceptionKind {
24    /// A breakpoint exception.
25    Breakpoint,
26    /// An illegal instruction exception.
27    IllegalInstruction,
28    /// A misaligned access exception.
29    Misaligned,
30    /// Other kinds of exceptions.
31    Other,
32}
33
34#[repr(C)]
35#[derive(Debug, PartialEq, Eq)]
36struct ExceptionTableEntry {
37    #[cfg(target_arch = "aarch64")]
38    from: i32,
39    #[cfg(target_arch = "aarch64")]
40    to: i32,
41    #[cfg(not(target_arch = "aarch64"))]
42    from: usize,
43    #[cfg(not(target_arch = "aarch64"))]
44    to: usize,
45}
46
47impl ExceptionTableEntry {
48    #[inline]
49    fn from_addr(&self) -> usize {
50        #[cfg(target_arch = "aarch64")]
51        {
52            let base = (&self.from as *const i32) as isize;
53            return (base + self.from as isize) as usize;
54        }
55
56        #[cfg(not(target_arch = "aarch64"))]
57        {
58            self.from
59        }
60    }
61
62    #[inline]
63    fn to_addr(&self) -> usize {
64        #[cfg(target_arch = "aarch64")]
65        {
66            let base = (&self.to as *const i32) as isize;
67            return (base + self.to as isize) as usize;
68        }
69
70        #[cfg(not(target_arch = "aarch64"))]
71        {
72            self.to
73        }
74    }
75}
76
77unsafe extern "C" {
78    static _ex_table_start: [ExceptionTableEntry; 0];
79    static _ex_table_end: [ExceptionTableEntry; 0];
80}
81
82impl TrapFrame {
83    pub(crate) fn fixup_exception(&mut self) -> bool {
84        let entries = unsafe {
85            core::slice::from_raw_parts(
86                _ex_table_start.as_ptr(),
87                _ex_table_end
88                    .as_ptr()
89                    .offset_from_unsigned(_ex_table_start.as_ptr()),
90            )
91        };
92        match entries.binary_search_by_key(&self.ip(), ExceptionTableEntry::from_addr) {
93            Ok(entry) => {
94                self.set_ip(entries[entry].to_addr());
95                true
96            }
97            Err(_) => false,
98        }
99    }
100}
101
102pub(crate) fn init_exception_table() {
103    // Sort exception table
104    let ex_table = unsafe {
105        core::slice::from_raw_parts_mut(
106            _ex_table_start.as_ptr().cast_mut(),
107            _ex_table_end
108                .as_ptr()
109                .offset_from_unsigned(_ex_table_start.as_ptr()),
110        )
111    };
112    ex_table.sort_unstable_by_key(ExceptionTableEntry::from_addr);
113}