trap.rs 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552
  1. use core::arch::asm;
  2. use fast_trap::{trap_entry, FastContext, FastResult};
  3. use riscv::register::{
  4. mcause::{self, Exception as E, Trap as T},
  5. mepc, mie, mstatus, mtval, satp, sstatus,
  6. };
  7. use rustsbi::RustSBI;
  8. use crate::board::SBI_IMPL;
  9. use crate::riscv_spec::{current_hartid, CSR_TIME, CSR_TIMEH};
  10. use crate::sbi::console;
  11. use crate::sbi::hsm::local_hsm;
  12. use crate::sbi::ipi;
  13. use crate::sbi::rfence::{self, local_rfence, RFenceType};
  14. // Constants for page and TLB management
  15. const PAGE_SIZE: usize = 4096;
  16. // TODO: `TLB_FLUSH_LIMIT` is a platform-dependent parameter
  17. const TLB_FLUSH_LIMIT: usize = 4 * PAGE_SIZE;
  18. /// Trap vector table entry point. Maps different trap types to their handlers.
  19. #[naked]
  20. pub(crate) unsafe extern "C" fn trap_vec() {
  21. asm!(
  22. ".align 2",
  23. ".option push",
  24. ".option norvc",
  25. "j {default}", // exception
  26. "j {default}", // supervisor software
  27. "j {default}", // reserved
  28. "j {msoft} ", // machine software
  29. "j {default}", // reserved
  30. "j {default}", // supervisor timer
  31. "j {default}", // reserved
  32. "j {mtimer}", // machine timer
  33. "j {default}", // reserved
  34. "j {default}", // supervisor external
  35. "j {default}", // reserved
  36. "j {default}", // machine external
  37. ".option pop",
  38. default = sym trap_entry,
  39. msoft = sym msoft,
  40. mtimer = sym mtimer,
  41. options(noreturn)
  42. )
  43. }
  44. /// Machine timer interrupt handler.
  45. /// Saves context, clears mtimecmp, sets STIP bit, and restores context.
  46. ///
  47. /// # Safety
  48. ///
  49. /// This is a naked function that directly manipulates registers and stack.
  50. #[naked]
  51. unsafe extern "C" fn mtimer() {
  52. asm!(
  53. // Switch stacks: sp <-> mscratch
  54. " csrrw sp, mscratch, sp",
  55. // Save registers to stack
  56. " addi sp, sp, -30*8",
  57. " sd ra, 0*8(sp)
  58. sd gp, 2*8(sp)
  59. sd tp, 3*8(sp)
  60. sd t0, 4*8(sp)
  61. sd t1, 5*8(sp)
  62. sd t2, 6*8(sp)
  63. sd s0, 7*8(sp)
  64. sd s1, 8*8(sp)
  65. sd a0, 9*8(sp)
  66. sd a1, 10*8(sp)
  67. sd a2, 11*8(sp)
  68. sd a3, 12*8(sp)
  69. sd a4, 13*8(sp)
  70. sd a5, 14*8(sp)
  71. sd a6, 15*8(sp)
  72. sd a7, 16*8(sp)
  73. sd s2, 17*8(sp)
  74. sd s3, 18*8(sp)
  75. sd s4, 19*8(sp)
  76. sd s5, 20*8(sp)
  77. sd s6, 21*8(sp)
  78. sd s7, 22*8(sp)
  79. sd s8, 23*8(sp)
  80. sd s9, 24*8(sp)
  81. sd s10, 25*8(sp)
  82. sd s11, 26*8(sp)
  83. sd t3, 27*8(sp)
  84. sd t4, 28*8(sp)
  85. sd t5, 29*8(sp)
  86. sd t6, 1*8(sp)",
  87. // Clear machine timer compare register
  88. " call {clear_mtime}",
  89. // Set supervisor timer interrupt pending bit
  90. " li a0, {mip_stip}
  91. csrrs zero, mip, a0
  92. ",
  93. // Restore registers from stack
  94. " ld ra, 0*8(sp)
  95. ld gp, 2*8(sp)
  96. ld tp, 3*8(sp)
  97. ld t0, 4*8(sp)
  98. ld t1, 5*8(sp)
  99. ld t2, 6*8(sp)
  100. ld s0, 7*8(sp)
  101. ld s1, 8*8(sp)
  102. ld a0, 9*8(sp)
  103. ld a1, 10*8(sp)
  104. ld a2, 11*8(sp)
  105. ld a3, 12*8(sp)
  106. ld a4, 13*8(sp)
  107. ld a5, 14*8(sp)
  108. ld a6, 15*8(sp)
  109. ld a7, 16*8(sp)
  110. ld s2, 17*8(sp)
  111. ld s3, 18*8(sp)
  112. ld s4, 19*8(sp)
  113. ld s5, 20*8(sp)
  114. ld s6, 21*8(sp)
  115. ld s7, 22*8(sp)
  116. ld s8, 23*8(sp)
  117. ld s9, 24*8(sp)
  118. ld s10, 25*8(sp)
  119. ld s11, 26*8(sp)
  120. ld t3, 27*8(sp)
  121. ld t4, 28*8(sp)
  122. ld t5, 29*8(sp)
  123. ld t6, 1*8(sp)",
  124. " addi sp, sp, 30*8",
  125. // Switch stacks back: sp <-> mscratch
  126. " csrrw sp, mscratch, sp",
  127. // Return from machine mode
  128. " mret",
  129. mip_stip = const 1 << 5,
  130. clear_mtime = sym ipi::clear_mtime,
  131. options(noreturn)
  132. )
  133. }
  134. /// Machine software interrupt handler.
  135. ///
  136. /// Handles inter-processor interrupts.
  137. #[naked]
  138. pub unsafe extern "C" fn msoft() -> ! {
  139. asm!(
  140. ".align 2",
  141. // Switch stacks
  142. "csrrw sp, mscratch, sp",
  143. // Allocate stack space
  144. "addi sp, sp, -32*8",
  145. // Save registers
  146. "sd ra, 0*8(sp)
  147. sd gp, 2*8(sp)
  148. sd tp, 3*8(sp)
  149. sd t0, 4*8(sp)
  150. sd t1, 5*8(sp)
  151. sd t2, 6*8(sp)
  152. sd s0, 7*8(sp)
  153. sd s1, 8*8(sp)
  154. sd a0, 9*8(sp)
  155. sd a1, 10*8(sp)
  156. sd a2, 11*8(sp)
  157. sd a3, 12*8(sp)
  158. sd a4, 13*8(sp)
  159. sd a5, 14*8(sp)
  160. sd a6, 15*8(sp)
  161. sd a7, 16*8(sp)
  162. sd s2, 17*8(sp)
  163. sd s3, 18*8(sp)
  164. sd s4, 19*8(sp)
  165. sd s5, 20*8(sp)
  166. sd s6, 21*8(sp)
  167. sd s7, 22*8(sp)
  168. sd s8, 23*8(sp)
  169. sd s9, 24*8(sp)
  170. sd s10, 25*8(sp)
  171. sd s11, 26*8(sp)
  172. sd t3, 27*8(sp)
  173. sd t4, 28*8(sp)
  174. sd t5, 29*8(sp)
  175. sd t6, 30*8(sp)",
  176. // Save mepc and mscratch
  177. "csrr t0, mepc
  178. sd t0, 31*8(sp)",
  179. "csrr t2, mscratch",
  180. "sd t2, 1*8(sp)",
  181. // Call handler with context pointer
  182. "mv a0, sp",
  183. "call {msoft_handler}",
  184. // Restore mepc
  185. "ld t0, 31*8(sp)
  186. csrw mepc, t0",
  187. // Restore registers
  188. "ld ra, 0*8(sp)
  189. ld gp, 2*8(sp)
  190. ld tp, 3*8(sp)
  191. ld t0, 4*8(sp)
  192. ld t1, 5*8(sp)
  193. ld t2, 6*8(sp)
  194. ld s0, 7*8(sp)
  195. ld s1, 8*8(sp)
  196. ld a0, 9*8(sp)
  197. ld a1, 10*8(sp)
  198. ld a2, 11*8(sp)
  199. ld a3, 12*8(sp)
  200. ld a4, 13*8(sp)
  201. ld a5, 14*8(sp)
  202. ld a6, 15*8(sp)
  203. ld a7, 16*8(sp)
  204. ld s2, 17*8(sp)
  205. ld s3, 18*8(sp)
  206. ld s4, 19*8(sp)
  207. ld s5, 20*8(sp)
  208. ld s6, 21*8(sp)
  209. ld s7, 22*8(sp)
  210. ld s8, 23*8(sp)
  211. ld s9, 24*8(sp)
  212. ld s10, 25*8(sp)
  213. ld s11, 26*8(sp)
  214. ld t3, 27*8(sp)
  215. ld t4, 28*8(sp)
  216. ld t5, 29*8(sp)
  217. ld t6, 30*8(sp)",
  218. // Restore stack pointer
  219. "addi sp, sp, 32*8",
  220. // Switch stacks back
  221. "csrrw sp, mscratch, sp",
  222. // Return from machine mode
  223. "mret",
  224. msoft_handler = sym msoft_handler,
  225. options(noreturn)
  226. );
  227. }
  228. /// Machine software interrupt handler implementation.
  229. ///
  230. /// Handles HSM (Hart State Management) and RFence operations.
  231. pub extern "C" fn msoft_handler(ctx: &mut SupervisorContext) {
  232. #[inline(always)]
  233. fn boot(ctx: &mut SupervisorContext, start_addr: usize, opaque: usize) {
  234. unsafe {
  235. sstatus::clear_sie();
  236. satp::write(0);
  237. }
  238. ctx.a0 = current_hartid();
  239. ctx.a1 = opaque;
  240. ctx.mepc = start_addr;
  241. }
  242. match local_hsm().start() {
  243. // Handle HSM Start
  244. Ok(next_stage) => {
  245. ipi::clear_msip();
  246. unsafe {
  247. mstatus::set_mpie();
  248. mstatus::set_mpp(next_stage.next_mode);
  249. mie::set_msoft();
  250. mie::set_mtimer();
  251. }
  252. boot(ctx, next_stage.start_addr, next_stage.opaque);
  253. }
  254. // Handle HSM Stop
  255. Err(rustsbi::spec::hsm::HART_STOP) => {
  256. ipi::clear_msip();
  257. unsafe {
  258. mie::set_msoft();
  259. }
  260. riscv::asm::wfi();
  261. }
  262. // Handle RFence
  263. _ => {
  264. msoft_ipi_handler();
  265. }
  266. }
  267. }
  268. /// Handles a single remote fence operation.
  269. pub fn rfence_single_handler() {
  270. let rfence_context = local_rfence().unwrap().get();
  271. if let Some((ctx, id)) = rfence_context {
  272. match ctx.op {
  273. // Handle instruction fence
  274. RFenceType::FenceI => unsafe {
  275. asm!("fence.i");
  276. rfence::remote_rfence(id).unwrap().sub();
  277. },
  278. // Handle virtual memory address fence
  279. RFenceType::SFenceVma => {
  280. // If the flush size is greater than the maximum limit then simply flush all
  281. if (ctx.start_addr == 0 && ctx.size == 0)
  282. || (ctx.size == usize::MAX)
  283. || (ctx.size > TLB_FLUSH_LIMIT)
  284. {
  285. unsafe {
  286. asm!("sfence.vma");
  287. }
  288. } else {
  289. for offset in (0..ctx.size).step_by(PAGE_SIZE) {
  290. let addr = ctx.start_addr + offset;
  291. unsafe {
  292. asm!("sfence.vma {}", in(reg) addr);
  293. }
  294. }
  295. }
  296. rfence::remote_rfence(id).unwrap().sub();
  297. }
  298. // Handle virtual memory address fence with ASID
  299. RFenceType::SFenceVmaAsid => {
  300. let asid = ctx.asid;
  301. // If the flush size is greater than the maximum limit then simply flush all
  302. if (ctx.start_addr == 0 && ctx.size == 0)
  303. || (ctx.size == usize::MAX)
  304. || (ctx.size > TLB_FLUSH_LIMIT)
  305. {
  306. unsafe {
  307. asm!("sfence.vma {}, {}", in(reg) 0, in(reg) asid);
  308. }
  309. } else {
  310. for offset in (0..ctx.size).step_by(PAGE_SIZE) {
  311. let addr = ctx.start_addr + offset;
  312. unsafe {
  313. asm!("sfence.vma {}, {}", in(reg) addr, in(reg) asid);
  314. }
  315. }
  316. }
  317. rfence::remote_rfence(id).unwrap().sub();
  318. }
  319. rfencetype => {
  320. error!("Unsupported RFence Type: {:?}!", rfencetype);
  321. }
  322. }
  323. }
  324. }
  325. /// Process all pending remote fence operations.
  326. pub fn rfence_handler() {
  327. while !local_rfence().unwrap().is_empty() {
  328. rfence_single_handler();
  329. }
  330. }
  331. /// Handle machine software inter-processor interrupts.
  332. pub fn msoft_ipi_handler() {
  333. use ipi::get_and_reset_ipi_type;
  334. ipi::clear_msip();
  335. let ipi_type = get_and_reset_ipi_type();
  336. // Handle supervisor software interrupt
  337. if (ipi_type & ipi::IPI_TYPE_SSOFT) != 0 {
  338. unsafe {
  339. riscv::register::mip::set_ssoft();
  340. }
  341. }
  342. // Handle fence operation
  343. if (ipi_type & ipi::IPI_TYPE_FENCE) != 0 {
  344. rfence_handler();
  345. }
  346. }
  347. /// Fast trap handler for SBI calls and illegal instructions.
  348. pub extern "C" fn fast_handler(
  349. mut ctx: FastContext,
  350. a1: usize,
  351. a2: usize,
  352. a3: usize,
  353. a4: usize,
  354. a5: usize,
  355. a6: usize,
  356. a7: usize,
  357. ) -> FastResult {
  358. #[inline]
  359. fn resume(mut ctx: FastContext, start_addr: usize, opaque: usize) -> FastResult {
  360. unsafe {
  361. sstatus::clear_sie();
  362. satp::write(0);
  363. }
  364. ctx.regs().a[0] = current_hartid();
  365. ctx.regs().a[1] = opaque;
  366. ctx.regs().pc = start_addr;
  367. ctx.call(2)
  368. }
  369. match mcause::read().cause() {
  370. // Handle SBI calls
  371. T::Exception(E::SupervisorEnvCall) => {
  372. use sbi_spec::{base, hsm, legacy};
  373. let mut ret = unsafe { SBI_IMPL.assume_init_ref() }.handle_ecall(
  374. a7,
  375. a6,
  376. [ctx.a0(), a1, a2, a3, a4, a5],
  377. );
  378. if ret.is_ok() {
  379. match (a7, a6) {
  380. // Handle non-retentive suspend
  381. (hsm::EID_HSM, hsm::HART_SUSPEND)
  382. if matches!(ctx.a0() as u32, hsm::suspend_type::NON_RETENTIVE) =>
  383. {
  384. return resume(ctx, a1, a2);
  385. }
  386. // Handle legacy console probe
  387. (base::EID_BASE, base::PROBE_EXTENSION)
  388. if matches!(
  389. ctx.a0(),
  390. legacy::LEGACY_CONSOLE_PUTCHAR | legacy::LEGACY_CONSOLE_GETCHAR
  391. ) =>
  392. {
  393. ret.value = 1;
  394. }
  395. _ => {}
  396. }
  397. } else {
  398. match a7 {
  399. legacy::LEGACY_CONSOLE_PUTCHAR => {
  400. ret.error = console::putchar(ctx.a0());
  401. ret.value = a1;
  402. }
  403. legacy::LEGACY_CONSOLE_GETCHAR => {
  404. ret.error = console::getchar();
  405. ret.value = a1;
  406. }
  407. _ => {}
  408. }
  409. }
  410. ctx.regs().a = [ret.error, ret.value, a2, a3, a4, a5, a6, a7];
  411. mepc::write(mepc::read() + 4);
  412. ctx.restore()
  413. }
  414. // Handle illegal instructions
  415. T::Exception(E::IllegalInstruction) => {
  416. if mstatus::read().mpp() == mstatus::MPP::Machine {
  417. panic!("Cannot handle illegal instruction exception from M-MODE");
  418. }
  419. ctx.regs().a = [ctx.a0(), a1, a2, a3, a4, a5, a6, a7];
  420. if !illegal_instruction_handler(&mut ctx) {
  421. delegate();
  422. }
  423. ctx.restore()
  424. }
  425. // Handle other traps
  426. trap => {
  427. println!(
  428. "
  429. -----------------------------
  430. > trap: {trap:?}
  431. > mepc: {:#018x}
  432. > mtval: {:#018x}
  433. -----------------------------
  434. ",
  435. mepc::read(),
  436. mtval::read()
  437. );
  438. panic!("Stopped with unsupported trap")
  439. }
  440. }
  441. }
  442. /// Delegate trap handling to supervisor mode.
  443. #[inline]
  444. fn delegate() {
  445. use riscv::register::{mcause, mepc, mtval, scause, sepc, sstatus, stval, stvec};
  446. unsafe {
  447. // TODO: 当支持中断嵌套时,需要从ctx里获取mpec。当前ctx.reg().pc与mepc不一致
  448. sepc::write(mepc::read());
  449. scause::write(mcause::read().bits());
  450. stval::write(mtval::read());
  451. sstatus::clear_sie();
  452. if mstatus::read().mpp() == mstatus::MPP::Supervisor {
  453. sstatus::set_spp(sstatus::SPP::Supervisor);
  454. } else {
  455. sstatus::set_spp(sstatus::SPP::User);
  456. }
  457. mstatus::set_mpp(mstatus::MPP::Supervisor);
  458. mepc::write(stvec::read().address());
  459. }
  460. }
  461. /// Handle illegal instructions, particularly CSR access.
  462. #[inline]
  463. fn illegal_instruction_handler(ctx: &mut FastContext) -> bool {
  464. use riscv::register::{mepc, mtval};
  465. use riscv_decode::{decode, Instruction};
  466. let inst = decode(mtval::read() as u32);
  467. match inst {
  468. Ok(Instruction::Csrrs(csr)) => match csr.csr() {
  469. CSR_TIME => {
  470. assert!(
  471. 10 <= csr.rd() && csr.rd() <= 17,
  472. "Unsupported CSR rd: {}",
  473. csr.rd()
  474. );
  475. ctx.regs().a[(csr.rd() - 10) as usize] = unsafe { SBI_IMPL.assume_init_ref() }
  476. .ipi
  477. .as_ref()
  478. .unwrap()
  479. .get_time();
  480. }
  481. CSR_TIMEH => {
  482. assert!(
  483. 10 <= csr.rd() && csr.rd() <= 17,
  484. "Unsupported CSR rd: {}",
  485. csr.rd()
  486. );
  487. ctx.regs().a[(csr.rd() - 10) as usize] = unsafe { SBI_IMPL.assume_init_ref() }
  488. .ipi
  489. .as_ref()
  490. .unwrap()
  491. .get_timeh();
  492. }
  493. _ => return false,
  494. },
  495. _ => return false,
  496. }
  497. mepc::write(mepc::read() + 4);
  498. true
  499. }
  500. /// Supervisor context structure containing saved register state.
  501. #[derive(Debug)]
  502. #[repr(C)]
  503. pub struct SupervisorContext {
  504. pub ra: usize, // 0
  505. pub sp: usize,
  506. pub gp: usize,
  507. pub tp: usize,
  508. pub t0: usize,
  509. pub t1: usize,
  510. pub t2: usize,
  511. pub s0: usize,
  512. pub s1: usize,
  513. pub a0: usize,
  514. pub a1: usize,
  515. pub a2: usize,
  516. pub a3: usize,
  517. pub a4: usize,
  518. pub a5: usize,
  519. pub a6: usize,
  520. pub a7: usize,
  521. pub s2: usize,
  522. pub s3: usize,
  523. pub s4: usize,
  524. pub s5: usize,
  525. pub s6: usize,
  526. pub s7: usize,
  527. pub s8: usize,
  528. pub s9: usize,
  529. pub s10: usize,
  530. pub s11: usize,
  531. pub t3: usize,
  532. pub t4: usize,
  533. pub t5: usize,
  534. pub t6: usize, // 30
  535. pub mepc: usize, // 31
  536. }