kernel/arch/riscv64/trap/
user.rs1use 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 arch_switch_to_user_space(trapframe);
171}
172
173#[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 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}", "mv a0, {trapframe_addr}", "jr t0", trapframe_addr = in(reg) addr,
198 trap_exit_addr = in(reg) trap_exit_addr,
199 options(noreturn, nostack)
200 );
201 }
202}