mod.rs 9.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391
  1. mod trap_context;
  2. use core::arch::{asm, global_asm, naked_asm};
  3. use eonix_hal_traits::context::RawTaskContext;
  4. use eonix_hal_traits::trap::{IrqState as IrqStateTrait, TrapReturn};
  5. pub use trap_context::TrapContext;
  6. use super::context::TaskContext;
  7. unsafe extern "C" {
  8. fn _default_trap_handler(trap_context: &mut TrapContext);
  9. pub fn trap_stubs_start();
  10. fn _raw_trap_return();
  11. }
  12. #[eonix_percpu::define_percpu]
  13. static TRAP_HANDLER: unsafe extern "C" fn() = default_trap_handler;
  14. #[eonix_percpu::define_percpu]
  15. static CAPTURER_CONTEXT: TaskContext = TaskContext::new();
  16. /// This value will never be used.
  17. static mut DIRTY_TRAP_CONTEXT: TaskContext = TaskContext::new();
  18. /// State of the interrupt flag.
  19. pub struct IrqState(u64);
  20. global_asm!(
  21. r"
  22. .set RAX, 0x00
  23. .set RBX, 0x08
  24. .set RCX, 0x10
  25. .set RDX, 0x18
  26. .set RDI, 0x20
  27. .set RSI, 0x28
  28. .set R8, 0x30
  29. .set R9, 0x38
  30. .set R10, 0x40
  31. .set R11, 0x48
  32. .set R12, 0x50
  33. .set R13, 0x58
  34. .set R14, 0x60
  35. .set R15, 0x68
  36. .set RBP, 0x70
  37. .set INT_NO, 0x78
  38. .set ERRCODE, 0x80
  39. .set RIP, 0x88
  40. .set CS, 0x90
  41. .set FLAGS, 0x98
  42. .set RSP, 0xa0
  43. .set SS, 0xa8
  44. .macro cfi_all_same_value
  45. .cfi_same_value %rax
  46. .cfi_same_value %rbx
  47. .cfi_same_value %rcx
  48. .cfi_same_value %rdx
  49. .cfi_same_value %rdi
  50. .cfi_same_value %rsi
  51. .cfi_same_value %r8
  52. .cfi_same_value %r9
  53. .cfi_same_value %r10
  54. .cfi_same_value %r11
  55. .cfi_same_value %r12
  56. .cfi_same_value %r13
  57. .cfi_same_value %r14
  58. .cfi_same_value %r15
  59. .cfi_same_value %rbp
  60. .endm
  61. .globl {trap_stubs_start}
  62. {trap_stubs_start}:
  63. .altmacro
  64. .macro build_isr_no_err name
  65. .align 8
  66. .globl ISR\name
  67. .type ISR\name @function
  68. ISR\name:
  69. .cfi_startproc
  70. .cfi_signal_frame
  71. .cfi_def_cfa_offset 0x08
  72. .cfi_offset %rsp, 0x10
  73. cfi_all_same_value
  74. push %rbp # push placeholder for error code
  75. .cfi_def_cfa_offset 0x10
  76. call _raw_trap_entry
  77. .cfi_endproc
  78. .endm
  79. .altmacro
  80. .macro build_isr_err name
  81. .align 8
  82. .globl ISR\name
  83. .type ISR\name @function
  84. ISR\name:
  85. .cfi_startproc
  86. .cfi_signal_frame
  87. .cfi_def_cfa_offset 0x10
  88. .cfi_offset %rsp, 0x10
  89. cfi_all_same_value
  90. call _raw_trap_entry
  91. .cfi_endproc
  92. .endm
  93. build_isr_no_err 0
  94. build_isr_no_err 1
  95. build_isr_no_err 2
  96. build_isr_no_err 3
  97. build_isr_no_err 4
  98. build_isr_no_err 5
  99. build_isr_no_err 6
  100. build_isr_no_err 7
  101. build_isr_err 8
  102. build_isr_no_err 9
  103. build_isr_err 10
  104. build_isr_err 11
  105. build_isr_err 12
  106. build_isr_err 13
  107. build_isr_err 14
  108. build_isr_no_err 15
  109. build_isr_no_err 16
  110. build_isr_err 17
  111. build_isr_no_err 18
  112. build_isr_no_err 19
  113. build_isr_no_err 20
  114. build_isr_err 21
  115. build_isr_no_err 22
  116. build_isr_no_err 23
  117. build_isr_no_err 24
  118. build_isr_no_err 25
  119. build_isr_no_err 26
  120. build_isr_no_err 27
  121. build_isr_no_err 28
  122. build_isr_err 29
  123. build_isr_err 30
  124. build_isr_no_err 31
  125. .set i, 32
  126. .rept 0x80+1
  127. build_isr_no_err %i
  128. .set i, i+1
  129. .endr
  130. .globl _raw_trap_entry
  131. .type _raw_trap_entry @function
  132. _raw_trap_entry:
  133. .cfi_startproc
  134. .cfi_signal_frame
  135. .cfi_def_cfa %rsp, 0x18
  136. .cfi_offset %rsp, 0x10
  137. cfi_all_same_value
  138. sub $0x78, %rsp
  139. .cfi_def_cfa_offset CS
  140. mov %rax, RAX(%rsp)
  141. .cfi_rel_offset %rax, RAX
  142. mov %rbx, RBX(%rsp)
  143. .cfi_rel_offset %rbx, RBX
  144. mov %rcx, RCX(%rsp)
  145. .cfi_rel_offset %rcx, RCX
  146. mov %rdx, RDX(%rsp)
  147. .cfi_rel_offset %rdx, RDX
  148. mov %rdi, RDI(%rsp)
  149. .cfi_rel_offset %rdi, RDI
  150. mov %rsi, RSI(%rsp)
  151. .cfi_rel_offset %rsi, RSI
  152. mov %r8, R8(%rsp)
  153. .cfi_rel_offset %r8, R8
  154. mov %r9, R9(%rsp)
  155. .cfi_rel_offset %r9, R9
  156. mov %r10, R10(%rsp)
  157. .cfi_rel_offset %r10, R10
  158. mov %r11, R11(%rsp)
  159. .cfi_rel_offset %r11, R11
  160. mov %r12, R12(%rsp)
  161. .cfi_rel_offset %r12, R12
  162. mov %r13, R13(%rsp)
  163. .cfi_rel_offset %r13, R13
  164. mov %r14, R14(%rsp)
  165. .cfi_rel_offset %r14, R14
  166. mov %r15, R15(%rsp)
  167. .cfi_rel_offset %r15, R15
  168. mov %rbp, RBP(%rsp)
  169. .cfi_rel_offset %rbp, RBP
  170. mov INT_NO(%rsp), %rcx
  171. sub ${trap_stubs_start}, %rcx
  172. shr $3, %rcx
  173. mov %rcx, INT_NO(%rsp)
  174. cmpq $0x08, CS(%rsp)
  175. je 2f
  176. swapgs
  177. 2:
  178. mov %gs:0, %rcx
  179. add ${handler}, %rcx
  180. mov (%rcx), %rcx
  181. jmp *%rcx
  182. .cfi_endproc
  183. _raw_trap_return:
  184. .cfi_startproc
  185. .cfi_def_cfa %rsp, CS
  186. .cfi_rel_offset %rax, RAX
  187. .cfi_rel_offset %rbx, RBX
  188. .cfi_rel_offset %rcx, RCX
  189. .cfi_rel_offset %rdx, RDX
  190. .cfi_rel_offset %rdi, RDI
  191. .cfi_rel_offset %rsi, RSI
  192. .cfi_rel_offset %r8, R8
  193. .cfi_rel_offset %r9, R9
  194. .cfi_rel_offset %r10, R10
  195. .cfi_rel_offset %r11, R11
  196. .cfi_rel_offset %r12, R12
  197. .cfi_rel_offset %r13, R13
  198. .cfi_rel_offset %r14, R14
  199. .cfi_rel_offset %r15, R15
  200. .cfi_rel_offset %rbp, RBP
  201. .cfi_rel_offset %rsp, RSP
  202. mov RAX(%rsp), %rax
  203. .cfi_restore %rax
  204. mov RBX(%rsp), %rbx
  205. .cfi_restore %rbx
  206. mov RCX(%rsp), %rcx
  207. .cfi_restore %rcx
  208. mov RDX(%rsp), %rdx
  209. .cfi_restore %rdx
  210. mov RDI(%rsp), %rdi
  211. .cfi_restore %rdi
  212. mov RSI(%rsp), %rsi
  213. .cfi_restore %rsi
  214. mov R8(%rsp), %r8
  215. .cfi_restore %r8
  216. mov R9(%rsp), %r9
  217. .cfi_restore %r9
  218. mov R10(%rsp), %r10
  219. .cfi_restore %r10
  220. mov R11(%rsp), %r11
  221. .cfi_restore %r11
  222. mov R12(%rsp), %r12
  223. .cfi_restore %r12
  224. mov R13(%rsp), %r13
  225. .cfi_restore %r13
  226. mov R14(%rsp), %r14
  227. .cfi_restore %r14
  228. mov R15(%rsp), %r15
  229. .cfi_restore %r15
  230. mov RBP(%rsp), %rbp
  231. .cfi_restore %rbp
  232. cmpq $0x08, CS(%rsp)
  233. je 2f
  234. swapgs
  235. 2:
  236. lea RIP(%rsp), %rsp
  237. .cfi_def_cfa %rsp, 0x08
  238. .cfi_offset %rsp, 0x10
  239. iretq
  240. .cfi_endproc
  241. ",
  242. trap_stubs_start = sym trap_stubs_start,
  243. handler = sym _percpu_inner_TRAP_HANDLER,
  244. options(att_syntax),
  245. );
  246. /// Default handler handles the trap on the current stack and returns
  247. /// to the context before interrut.
  248. #[unsafe(naked)]
  249. unsafe extern "C" fn default_trap_handler() {
  250. naked_asm!(
  251. ".cfi_startproc",
  252. "mov %rsp, %rbx",
  253. ".cfi_def_cfa_register %rbx",
  254. "",
  255. "and $~0xf, %rsp",
  256. "",
  257. "mov %rbx, %rdi",
  258. "call {handle_trap}",
  259. "",
  260. "mov %rbx, %rsp",
  261. ".cfi_def_cfa_register %rsp",
  262. "",
  263. "jmp {trap_return}",
  264. ".cfi_endproc",
  265. handle_trap = sym _default_trap_handler,
  266. trap_return = sym _raw_trap_return,
  267. options(att_syntax),
  268. );
  269. }
  270. #[unsafe(naked)]
  271. unsafe extern "C" fn captured_trap_handler() {
  272. naked_asm!(
  273. "mov ${from_context}, %rdi",
  274. "mov %gs:0, %rsi",
  275. "add ${to_context}, %rsi",
  276. "",
  277. "mov %rdi, %rsp", // We need a temporary stack to use `switch()`.
  278. "",
  279. "jmp {switch}",
  280. from_context = sym DIRTY_TRAP_CONTEXT,
  281. to_context = sym _percpu_inner_CAPTURER_CONTEXT,
  282. switch = sym TaskContext::switch,
  283. options(att_syntax),
  284. );
  285. }
  286. #[unsafe(naked)]
  287. unsafe extern "C" fn captured_trap_return(trap_context: usize) -> ! {
  288. naked_asm!(
  289. "jmp {trap_return}",
  290. trap_return = sym _raw_trap_return,
  291. options(att_syntax),
  292. );
  293. }
  294. impl TrapReturn for TrapContext {
  295. type TaskContext = TaskContext;
  296. unsafe fn trap_return(&mut self) {
  297. let irq_states = disable_irqs_save();
  298. let old_handler = TRAP_HANDLER.swap(captured_trap_handler);
  299. let mut to_ctx = TaskContext::new();
  300. to_ctx.set_program_counter(captured_trap_return as _);
  301. to_ctx.set_stack_pointer(&raw mut *self as usize);
  302. to_ctx.set_interrupt_enabled(false);
  303. unsafe {
  304. TaskContext::switch(CAPTURER_CONTEXT.as_mut(), &mut to_ctx);
  305. }
  306. TRAP_HANDLER.set(old_handler);
  307. irq_states.restore();
  308. }
  309. }
  310. impl IrqStateTrait for IrqState {
  311. fn restore(self) {
  312. let Self(state) = self;
  313. unsafe {
  314. asm!(
  315. "push {state}",
  316. "popf",
  317. state = in(reg) state,
  318. options(att_syntax, nomem)
  319. );
  320. }
  321. }
  322. }
  323. pub fn enable_irqs() {
  324. unsafe {
  325. asm!("sti", options(att_syntax, nomem, nostack));
  326. }
  327. }
  328. pub fn disable_irqs() {
  329. unsafe {
  330. asm!("cli", options(att_syntax, nomem, nostack));
  331. }
  332. }
  333. pub fn disable_irqs_save() -> IrqState {
  334. let state: u64;
  335. unsafe {
  336. asm!(
  337. "pushf",
  338. "pop {state}",
  339. "cli",
  340. state = out(reg) state,
  341. options(att_syntax, nomem)
  342. );
  343. }
  344. IrqState(state)
  345. }