kernel/arch/riscv64/trap/
user.rs

1use core::arch::naked_asm;
2use core::sync::atomic::compiler_fence;
3use core::{arch::asm, mem::transmute};
4
5use super::exception::arch_exception_handler;
6use super::interrupt::arch_interrupt_handler;
7
8use crate::arch::{trap, Trapframe};
9
10#[unsafe(link_section = ".trampoline.text")]
11#[unsafe(export_name = "_user_trap_entry")]
12#[unsafe(naked)]
13pub extern "C" fn _user_trap_entry() {
14    unsafe {
15        naked_asm!("
16        .option norvc
17        .option norelax
18        .align 8
19                /* Disable the interrupt */
20                csrci   sstatus, 0x2
21                /* Save the current a0 to sscratch and load the trapframe pointer */
22                csrrw   a0, sscratch, a0
23                /* Save the context of the current hart */
24                sd      x0, 0(a0)
25                sd      x1, 8(a0)
26                sd      x2, 16(a0)
27                sd      x3, 24(a0)
28                sd      x4, 32(a0)
29                sd      x5, 40(a0)
30                sd      x6, 48(a0)
31                sd      x7, 56(a0)
32                sd      x8, 64(a0)
33                sd      x9, 72(a0)
34                // sd      x10, 80(a0)
35                sd      x11, 88(a0)
36                sd      x12, 96(a0)
37                sd      x13, 104(a0)
38                sd      x14, 112(a0)
39                sd      x15, 120(a0)
40                sd      x16, 128(a0)
41                sd      x17, 136(a0)
42                sd      x18, 144(a0)
43                sd      x19, 152(a0)
44                sd      x20, 160(a0)
45                sd      x21, 168(a0)
46                sd      x22, 176(a0)
47                sd      x23, 184(a0)
48                sd      x24, 192(a0)
49                sd      x25, 200(a0)
50                sd      x26, 208(a0)
51                sd      x27, 216(a0)
52                sd      x28, 224(a0)
53                sd      x29, 232(a0)
54                sd      x30, 240(a0)
55                sd      x31, 248(a0)
56                csrr    t0, sepc
57                sd      t0, 256(a0)
58
59                // Load and store a0 to trapframe
60                csrr    t0, sscratch
61                // Restore sscratch from a0
62                csrw   sscratch, a0
63
64                sd      t0, 80(a0)
65
66                /* Load the satp for the kernel space from trapframe */
67                ld      t0, 272(a0)
68                /* Switch to kernel memory space */
69                csrrw   t0, satp, t0
70                sfence.vma zero, zero
71                /* Store the user memory space */
72                sd      t0, 272(a0)
73
74                // Load kernel stack pointer
75                ld      sp, 280(a0)
76
77                /* Call the user trap handler */
78                /* Load the function pointer from the trapframe */
79                ld      ra, 288(a0)
80                jr      ra
81            "
82        );
83    }
84}
85
86
87#[unsafe(link_section = ".trampoline.text")]
88#[unsafe(export_name = "_user_trap_exit")]
89#[unsafe(naked)]
90pub extern "C" fn _user_trap_exit() -> ! {
91    unsafe {
92        naked_asm!("
93        .option norvc
94        .option norelax
95        .align 8
96                /* Restore the user memory space */
97                ld     t0, 272(a0)
98                csrrw  t0, satp, t0
99                sfence.vma zero, zero
100                /* Restore the kernel memory space to the trapframe */
101                sd     t0, 272(a0)
102
103                /* Restore the context of the current hart */ 
104                /* epc */
105                ld     t0, 256(a0)
106                csrw   sepc, t0
107                /* Register */
108                ld     x0, 0(a0)
109                ld     x1, 8(a0)
110                ld     x2, 16(a0)
111                ld     x3, 24(a0)
112                ld     x4, 32(a0)
113                ld     x5, 40(a0)
114                ld     x6, 48(a0)
115                ld     x7, 56(a0)
116                ld     x8, 64(a0)
117                ld     x9, 72(a0)
118                // ld     x10, 80(a0)
119                ld     x11, 88(a0)
120                ld     x12, 96(a0)
121                ld     x13, 104(a0)
122                ld     x14, 112(a0)
123                ld     x15, 120(a0)
124                ld     x16, 128(a0)
125                ld     x17, 136(a0)
126                ld     x18, 144(a0)
127                ld     x19, 152(a0)
128                ld     x20, 160(a0)
129                ld     x21, 168(a0)
130                ld     x22, 176(a0)
131                ld     x23, 184(a0)
132                ld     x24, 192(a0)
133                ld     x25, 200(a0)
134                ld     x26, 208(a0)
135                ld     x27, 216(a0)
136                ld     x28, 224(a0)
137                ld     x29, 232(a0)
138                ld     x30, 240(a0)
139                ld     x31, 248(a0)
140
141                /* Restore a0 from trapframe */
142                csrrw  zero, sscratch, a0
143                ld     a0, 80(a0)
144
145                sret
146            "
147        );
148    }
149}
150
151#[unsafe(export_name = "arch_user_trap_handler")]
152pub extern "C" fn arch_user_trap_handler(addr: usize) -> ! {
153    let trapframe: &mut Trapframe = unsafe { transmute(addr) };
154
155    let cause: usize;
156    unsafe {
157        asm!(
158            "csrr {0}, scause",
159            out(reg) cause,
160        );
161    }
162
163    let interrupt = cause & 0x8000000000000000 != 0;
164    if interrupt {
165        arch_interrupt_handler(trapframe, cause & !0x8000000000000000);
166    } else {
167        arch_exception_handler(trapframe, cause);
168    }
169    // Jump directly to user trap exit via trampoline
170    arch_switch_to_user_space(trapframe);
171}
172
173/// Switch to user space using the trampoline mechanism
174/// 
175/// This function prepares the trapframe for user space execution
176/// and jumps to the user trap exit handler using a trampoline.
177/// 
178/// # Arguments
179/// * `trapframe` - A mutable reference to the trapframe that contains the state to switch to user space.
180///
181/// This function is marked as `noreturn` because it will not return to the caller.
182/// It will jump to the user trap exit handler, which will then return to user space.
183#[unsafe(export_name = "arch_switch_to_user_space")]
184pub fn arch_switch_to_user_space(trapframe: &mut Trapframe) -> ! {
185    let addr = trapframe as *mut Trapframe as usize;
186    
187    // Get the trampoline address for _user_trap_exit
188    let trap_exit_offset = _user_trap_exit as usize - _user_trap_entry as usize;
189    let trampoline_base = crate::vm::get_trampoline_trap_vector();
190    let trap_exit_addr = trampoline_base + trap_exit_offset;
191    
192    unsafe {
193        asm!(
194            "mv t0, {trap_exit_addr}",    // Load jump target into t0 first
195            "mv a0, {trapframe_addr}",    // Load trapframe addr into a0
196            "jr t0",                      // Jump using t0 (preserves a0)
197            trapframe_addr = in(reg) addr,
198            trap_exit_addr = in(reg) trap_exit_addr,
199            options(noreturn, nostack)
200        );
201    }
202}