mod.rs 8.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308
  1. mod trap_context;
  2. use super::config::platform::virt::*;
  3. use super::context::TaskContext;
  4. use core::arch::{global_asm, naked_asm};
  5. use core::mem::{offset_of, size_of};
  6. use core::num::NonZero;
  7. use core::ptr::NonNull;
  8. use eonix_hal_traits::{context::RawTaskContext, trap::TrapReturn};
  9. use riscv::register::sie::Sie;
  10. use riscv::register::stvec::TrapMode;
  11. use riscv::register::{scause, sepc, stval};
  12. use riscv::{
  13. asm::sfence_vma_all,
  14. register::{
  15. sie,
  16. stvec::{self, Stvec},
  17. },
  18. };
  19. use sbi::SbiError;
  20. pub use trap_context::*;
  21. #[repr(C)]
  22. pub struct TrapScratch {
  23. t1: u64,
  24. t2: u64,
  25. kernel_tp: Option<NonZero<u64>>,
  26. trap_context: Option<NonNull<TrapContext>>,
  27. handler: unsafe extern "C" fn(),
  28. capturer_context: TaskContext,
  29. }
  30. #[eonix_percpu::define_percpu]
  31. pub(crate) static TRAP_SCRATCH: TrapScratch = TrapScratch {
  32. t1: 0,
  33. t2: 0,
  34. kernel_tp: None,
  35. trap_context: None,
  36. handler: default_trap_handler,
  37. capturer_context: TaskContext::new(),
  38. };
  39. /// This value will never be used.
  40. static mut DIRTY_TRAP_CONTEXT: TaskContext = TaskContext::new();
  41. #[unsafe(naked)]
  42. unsafe extern "C" fn _raw_trap_entry() -> ! {
  43. naked_asm!(
  44. "csrrw t0, sscratch, t0", // Swap t0 and sscratch
  45. "sd t1, 0(t0)",
  46. "sd t2, 8(t0)",
  47. "csrr t1, sstatus",
  48. "andi t1, t1, 0x10",
  49. "beqz t1, 2f",
  50. // else SPP = 1, supervisor mode
  51. "addi t1, sp, -{trap_context_size}",
  52. "mv t2, tp",
  53. "j 3f",
  54. // SPP = 0, user mode
  55. "2:",
  56. "ld t1, 24(t0)", // Load captured TrapContext address
  57. "mv t2, tp",
  58. "ld tp, 16(t0)", // Restore kernel tp
  59. // t0: &mut TrapScratch, t1: &mut TrapContext, t2: tp before trap
  60. "3:",
  61. "sd ra, {ra}(t1)",
  62. "sd sp, {sp}(t1)",
  63. "sd gp, {gp}(t1)",
  64. "sd t2, {tp}(t1)",
  65. "ld ra, 0(t0)",
  66. "ld t2, 8(t0)",
  67. "sd ra, {t1}(t1)", // Save t1
  68. "sd t2, {t2}(t1)", // Save t2
  69. "ld ra, 32(t0)", // Load handler address
  70. "csrrw t2, sscratch, t0", // Swap to and sscratch
  71. "sd t2, {t0}(t1)",
  72. "sd a0, {a0}(t1)",
  73. "sd a1, {a1}(t1)",
  74. "sd a2, {a2}(t1)",
  75. "sd a3, {a3}(t1)",
  76. "sd a4, {a4}(t1)",
  77. "sd a5, {a5}(t1)",
  78. "sd a6, {a6}(t1)",
  79. "sd a7, {a7}(t1)",
  80. "sd t3, {t3}(t1)",
  81. "sd t4, {t4}(t1)",
  82. "sd t5, {t5}(t1)",
  83. "sd t6, {t6}(t1)",
  84. "csrr t2, sstatus",
  85. "csrr t3, sepc",
  86. "csrr t4, scause",
  87. "sd t2, {sstatus}(t1)",
  88. "sd t3, {sepc}(t1)",
  89. "sd t4, {scause}(t1)",
  90. "ret",
  91. trap_context_size = const size_of::<TrapContext>(),
  92. ra = const Registers::OFFSET_RA,
  93. sp = const Registers::OFFSET_SP,
  94. gp = const Registers::OFFSET_GP,
  95. tp = const Registers::OFFSET_TP,
  96. t1 = const Registers::OFFSET_T1,
  97. t2 = const Registers::OFFSET_T2,
  98. t0 = const Registers::OFFSET_T0,
  99. a0 = const Registers::OFFSET_A0,
  100. a1 = const Registers::OFFSET_A1,
  101. a2 = const Registers::OFFSET_A2,
  102. a3 = const Registers::OFFSET_A3,
  103. a4 = const Registers::OFFSET_A4,
  104. a5 = const Registers::OFFSET_A5,
  105. a6 = const Registers::OFFSET_A6,
  106. a7 = const Registers::OFFSET_A7,
  107. t3 = const Registers::OFFSET_T3,
  108. t4 = const Registers::OFFSET_T4,
  109. t5 = const Registers::OFFSET_T5,
  110. t6 = const Registers::OFFSET_T6,
  111. sstatus = const TrapContext::OFFSET_SSTATUS,
  112. sepc = const TrapContext::OFFSET_SEPC,
  113. scause = const TrapContext::OFFSET_SCAUSE,
  114. );
  115. }
  116. #[unsafe(naked)]
  117. unsafe extern "C" fn _raw_trap_return(ctx: &mut TrapContext) -> ! {
  118. naked_asm!(
  119. "ld ra, {ra}(a0)",
  120. "ld sp, {sp}(a0)",
  121. "ld gp, {gp}(a0)",
  122. "ld tp, {tp}(a0)",
  123. "ld t1, {t1}(a0)",
  124. "ld t2, {t2}(a0)",
  125. "ld t0, {t0}(a0)",
  126. "ld a1, {a1}(a0)",
  127. "ld a2, {a2}(a0)",
  128. "ld a3, {a3}(a0)",
  129. "ld a4, {a4}(a0)",
  130. "ld a5, {a5}(a0)",
  131. "ld a6, {a6}(a0)",
  132. "ld a7, {a7}(a0)",
  133. "ld t3, {t3}(a0)",
  134. "ld t4, {sepc}(a0)", // Load sepc from TrapContext
  135. "ld t5, {sstatus}(a0)", // Load sstatus from TrapContext
  136. "csrw sepc, t4", // Restore sepc
  137. "csrw sstatus, t5", // Restore sstatus
  138. "ld t4, {t4}(a0)",
  139. "ld t5, {t5}(a0)",
  140. "ld t6, {t6}(a0)",
  141. "ld a0, {a0}(a0)",
  142. "sret",
  143. ra = const Registers::OFFSET_RA,
  144. sp = const Registers::OFFSET_SP,
  145. gp = const Registers::OFFSET_GP,
  146. tp = const Registers::OFFSET_TP,
  147. t1 = const Registers::OFFSET_T1,
  148. t2 = const Registers::OFFSET_T2,
  149. t0 = const Registers::OFFSET_T0,
  150. a0 = const Registers::OFFSET_A0,
  151. a1 = const Registers::OFFSET_A1,
  152. a2 = const Registers::OFFSET_A2,
  153. a3 = const Registers::OFFSET_A3,
  154. a4 = const Registers::OFFSET_A4,
  155. a5 = const Registers::OFFSET_A5,
  156. a6 = const Registers::OFFSET_A6,
  157. a7 = const Registers::OFFSET_A7,
  158. t3 = const Registers::OFFSET_T3,
  159. t4 = const Registers::OFFSET_T4,
  160. t5 = const Registers::OFFSET_T5,
  161. t6 = const Registers::OFFSET_T6,
  162. sstatus = const TrapContext::OFFSET_SSTATUS,
  163. sepc = const TrapContext::OFFSET_SEPC,
  164. );
  165. }
  166. #[unsafe(naked)]
  167. unsafe extern "C" fn default_trap_handler() {
  168. unsafe extern "C" {
  169. fn _default_trap_handler(trap_context: &mut TrapContext);
  170. }
  171. naked_asm!(
  172. "andi sp, sp, -16", // Align stack pointer to 16 bytes
  173. "addi sp, sp, -16",
  174. "mv a0, t1", // TrapContext pointer in t1
  175. "sd a0, 0(sp)", // Save TrapContext pointer
  176. "",
  177. "call {default_handler}",
  178. "",
  179. "ld a0, 0(sp)", // Restore TrapContext pointer
  180. "j {trap_return}",
  181. default_handler = sym _default_trap_handler,
  182. trap_return = sym _raw_trap_return,
  183. );
  184. }
  185. #[unsafe(naked)]
  186. unsafe extern "C" fn captured_trap_handler() {
  187. naked_asm!(
  188. "la a0, {from_context}",
  189. "addi a1, t0, {capturer_context_offset}",
  190. "j {switch}",
  191. from_context = sym DIRTY_TRAP_CONTEXT,
  192. capturer_context_offset = const offset_of!(TrapScratch, capturer_context),
  193. switch = sym TaskContext::switch,
  194. );
  195. }
  196. #[unsafe(naked)]
  197. unsafe extern "C" fn captured_trap_return(trap_context: usize) -> ! {
  198. naked_asm!(
  199. "mv a0, sp",
  200. "j {raw_trap_return}",
  201. raw_trap_return = sym _raw_trap_return,
  202. );
  203. }
  204. impl TrapScratch {
  205. pub fn set_trap_context(&mut self, ctx: NonNull<TrapContext>) {
  206. self.trap_context = Some(ctx);
  207. }
  208. pub fn clear_trap_context(&mut self) {
  209. self.trap_context = None;
  210. }
  211. pub fn set_kernel_tp(&mut self, tp: NonNull<u8>) {
  212. self.kernel_tp = Some(NonZero::new(tp.addr().get() as u64).unwrap());
  213. }
  214. }
  215. impl TrapReturn for TrapContext {
  216. unsafe fn trap_return(&mut self) {
  217. let irq_states = disable_irqs_save();
  218. let old_handler = {
  219. let trap_scratch = TRAP_SCRATCH.as_mut();
  220. core::mem::replace(&mut trap_scratch.handler, captured_trap_handler)
  221. };
  222. let mut to_ctx = TaskContext::new();
  223. to_ctx.set_program_counter(captured_trap_return as _);
  224. to_ctx.set_stack_pointer(&raw mut *self as usize);
  225. to_ctx.set_interrupt_enabled(false);
  226. unsafe {
  227. TaskContext::switch(&mut TRAP_SCRATCH.as_mut().capturer_context, &mut to_ctx);
  228. }
  229. TRAP_SCRATCH.as_mut().handler = old_handler;
  230. irq_states.restore();
  231. }
  232. }
  233. fn setup_trap_handler(trap_entry_addr: usize) {
  234. let mut stvec_val = Stvec::from_bits(0);
  235. stvec_val.set_address(trap_entry_addr);
  236. stvec_val.set_trap_mode(TrapMode::Direct);
  237. unsafe {
  238. stvec::write(stvec_val);
  239. }
  240. }
  241. pub fn setup_trap() {
  242. setup_trap_handler(_raw_trap_entry as usize);
  243. }
  244. #[derive(Debug, Clone, Copy, PartialEq, Eq)]
  245. pub struct IrqState(Sie);
  246. impl IrqState {
  247. #[inline]
  248. pub fn save() -> Self {
  249. IrqState(sie::read())
  250. }
  251. #[inline]
  252. pub fn restore(self) {
  253. let Self(state) = self;
  254. unsafe {
  255. sie::write(state);
  256. }
  257. }
  258. }
  259. #[inline]
  260. pub fn disable_irqs() {
  261. unsafe {
  262. sie::clear_sext();
  263. sie::clear_stimer();
  264. sie::clear_ssoft();
  265. }
  266. }
  267. #[inline]
  268. pub fn enable_irqs() {
  269. unsafe {
  270. sie::set_sext();
  271. sie::set_stimer();
  272. sie::set_ssoft();
  273. }
  274. }
  275. #[inline]
  276. pub fn disable_irqs_save() -> IrqState {
  277. let state = IrqState::save();
  278. disable_irqs();
  279. state
  280. }