trap.rs 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463
  1. use aclint::SifiveClint as Clint;
  2. use core::arch::asm;
  3. use fast_trap::{trap_entry, FastContext, FastResult};
  4. use riscv::register::{
  5. mcause::{self, Exception as E, Trap as T},
  6. mepc, mie, mstatus, mtval, satp, sstatus,
  7. };
  8. use rustsbi::RustSBI;
  9. use crate::board::SBI;
  10. use crate::clint::{self, SIFIVECLINT};
  11. use crate::hsm::local_hsm;
  12. use crate::rfence::{local_rfence, RFenceType};
  13. use crate::riscv_spec::{current_hartid, CSR_TIME, CSR_TIMEH};
  14. const PAGE_SIZE: usize = 4096;
  15. // TODO: `TLB_FLUSH_LIMIT` is a platform-dependent parameter
  16. const TLB_FLUSH_LIMIT: usize = 4 * PAGE_SIZE;
  17. #[naked]
  18. pub(crate) unsafe extern "C" fn trap_vec() {
  19. asm!(
  20. ".align 2",
  21. ".option push",
  22. ".option norvc",
  23. "j {default}", // exception
  24. "j {default}", // supervisor software
  25. "j {default}", // reserved
  26. "j {msoft} ", // machine software
  27. "j {default}", // reserved
  28. "j {default}", // supervisor timer
  29. "j {default}", // reserved
  30. "j {mtimer}", // machine timer
  31. "j {default}", // reserved
  32. "j {default}", // supervisor external
  33. "j {default}", // reserved
  34. "j {default}", // machine external
  35. ".option pop",
  36. default = sym trap_entry,
  37. msoft = sym msoft,
  38. mtimer = sym mtimer,
  39. options(noreturn)
  40. )
  41. }
  42. /// machine timer 中断代理
  43. ///
  44. /// # Safety
  45. ///
  46. /// 裸函数。
  47. #[naked]
  48. unsafe extern "C" fn mtimer() {
  49. asm!(
  50. // 换栈:
  51. // sp : M sp
  52. // mscratch: S sp
  53. " csrrw sp, mscratch, sp",
  54. // 保护
  55. " addi sp, sp, -4*8
  56. sd ra, 0*8(sp)
  57. sd a0, 1*8(sp)
  58. sd a1, 2*8(sp)
  59. sd a2, 3*8(sp)
  60. ",
  61. // 清除 mtimecmp
  62. " la a0, {clint_ptr}
  63. ld a0, (a0)
  64. csrr a1, mhartid
  65. addi a2, zero, -1
  66. call {set_mtimecmp}
  67. ",
  68. // 设置 stip
  69. " li a0, {mip_stip}
  70. csrrs zero, mip, a0
  71. ",
  72. // 恢复
  73. " ld ra, 0*8(sp)
  74. ld a0, 1*8(sp)
  75. ld a1, 2*8(sp)
  76. ld a2, 3*8(sp)
  77. addi sp, sp, 4*8
  78. ",
  79. // 换栈:
  80. // sp : S sp
  81. // mscratch: M sp
  82. " csrrw sp, mscratch, sp",
  83. // 返回
  84. " mret",
  85. mip_stip = const 1 << 5,
  86. clint_ptr = sym SIFIVECLINT,
  87. // Clint::write_mtimecmp_naked(&self, hart_idx, val)
  88. set_mtimecmp = sym Clint::write_mtimecmp_naked,
  89. options(noreturn)
  90. )
  91. }
  92. /// machine soft 中断代理
  93. ///
  94. #[naked]
  95. pub unsafe extern "C" fn msoft() -> ! {
  96. asm!(
  97. ".align 2",
  98. "csrrw sp, mscratch, sp",
  99. "addi sp, sp, -32*8",
  100. "sd ra, 0*8(sp)
  101. sd gp, 2*8(sp)
  102. sd tp, 3*8(sp)
  103. sd t0, 4*8(sp)
  104. sd t1, 5*8(sp)
  105. sd t2, 6*8(sp)
  106. sd s0, 7*8(sp)
  107. sd s1, 8*8(sp)
  108. sd a0, 9*8(sp)
  109. sd a1, 10*8(sp)
  110. sd a2, 11*8(sp)
  111. sd a3, 12*8(sp)
  112. sd a4, 13*8(sp)
  113. sd a5, 14*8(sp)
  114. sd a6, 15*8(sp)
  115. sd a7, 16*8(sp)
  116. sd s2, 17*8(sp)
  117. sd s3, 18*8(sp)
  118. sd s4, 19*8(sp)
  119. sd s5, 20*8(sp)
  120. sd s6, 21*8(sp)
  121. sd s7, 22*8(sp)
  122. sd s8, 23*8(sp)
  123. sd s9, 24*8(sp)
  124. sd s10, 25*8(sp)
  125. sd s11, 26*8(sp)
  126. sd t3, 27*8(sp)
  127. sd t4, 28*8(sp)
  128. sd t5, 29*8(sp)
  129. sd t6, 30*8(sp)",
  130. "csrr t0, mepc
  131. sd t0, 31*8(sp)",
  132. "csrr t2, mscratch",
  133. "sd t2, 1*8(sp)",
  134. "mv a0, sp",
  135. "call {msoft_hanlder}",
  136. "ld t0, 31*8(sp)
  137. csrw mepc, t0",
  138. "ld ra, 0*8(sp)
  139. ld gp, 2*8(sp)
  140. ld tp, 3*8(sp)
  141. ld t0, 4*8(sp)
  142. ld t1, 5*8(sp)
  143. ld t2, 6*8(sp)
  144. ld s0, 7*8(sp)
  145. ld s1, 8*8(sp)
  146. ld a0, 9*8(sp)
  147. ld a1, 10*8(sp)
  148. ld a2, 11*8(sp)
  149. ld a3, 12*8(sp)
  150. ld a4, 13*8(sp)
  151. ld a5, 14*8(sp)
  152. ld a6, 15*8(sp)
  153. ld a7, 16*8(sp)
  154. ld s2, 17*8(sp)
  155. ld s3, 18*8(sp)
  156. ld s4, 19*8(sp)
  157. ld s5, 20*8(sp)
  158. ld s6, 21*8(sp)
  159. ld s7, 22*8(sp)
  160. ld s8, 23*8(sp)
  161. ld s9, 24*8(sp)
  162. ld s10, 25*8(sp)
  163. ld s11, 26*8(sp)
  164. ld t3, 27*8(sp)
  165. ld t4, 28*8(sp)
  166. ld t5, 29*8(sp)
  167. ld t6, 30*8(sp)",
  168. "addi sp, sp, 32*8",
  169. "csrrw sp, mscratch, sp",
  170. "mret",
  171. msoft_hanlder = sym msoft_hanlder,
  172. options(noreturn)
  173. );
  174. }
  175. pub extern "C" fn msoft_hanlder(ctx: &mut SupervisorContext) {
  176. #[inline(always)]
  177. fn boot(ctx: &mut SupervisorContext, start_addr: usize, opaque: usize) {
  178. unsafe {
  179. sstatus::clear_sie();
  180. satp::write(0);
  181. }
  182. ctx.a0 = current_hartid();
  183. ctx.a1 = opaque;
  184. ctx.mepc = start_addr;
  185. }
  186. match local_hsm().start() {
  187. // HSM Start
  188. Ok(next_stage) => {
  189. clint::clear_msip();
  190. unsafe {
  191. mstatus::set_mpie();
  192. mstatus::set_mpp(next_stage.next_mode);
  193. mie::set_msoft();
  194. mie::set_mtimer();
  195. }
  196. boot(ctx, next_stage.start_addr, next_stage.opaque);
  197. }
  198. Err(rustsbi::spec::hsm::HART_STOP) => {
  199. clint::clear_msip();
  200. unsafe { mie::set_msoft(); }
  201. riscv::asm::wfi();
  202. }
  203. // RFence
  204. _ => {
  205. msoft_rfence_handler();
  206. }
  207. }
  208. }
  209. pub fn msoft_rfence_handler() {
  210. let rfence_context = local_rfence().get();
  211. match rfence_context {
  212. Some(ctx) => match ctx.op {
  213. RFenceType::FenceI => unsafe {
  214. asm!("fence.i");
  215. local_rfence().clear();
  216. clint::clear_msip();
  217. },
  218. RFenceType::SFenceVma => {
  219. // If the flush size is greater than the maximum limit then simply flush all
  220. if (ctx.start_addr == 0 && ctx.size == 0)
  221. || (ctx.size == usize::MAX)
  222. || (ctx.size > TLB_FLUSH_LIMIT)
  223. {
  224. unsafe { asm!("sfence.vma"); }
  225. } else {
  226. for offset in (0..ctx.size).step_by(PAGE_SIZE) {
  227. let addr = ctx.start_addr + offset;
  228. unsafe { asm!("sfence.vma {}", in(reg) addr); }
  229. }
  230. }
  231. local_rfence().clear();
  232. clint::clear_msip();
  233. }
  234. RFenceType::SFenceVmaAsid => {
  235. let asid = ctx.asid;
  236. // If the flush size is greater than the maximum limit then simply flush all
  237. if (ctx.start_addr == 0 && ctx.size == 0)
  238. || (ctx.size == usize::MAX)
  239. || (ctx.size > TLB_FLUSH_LIMIT)
  240. {
  241. unsafe { asm!("sfence.vma {}, {}", in(reg) 0, in(reg) asid); }
  242. } else {
  243. for offset in (0..ctx.size).step_by(PAGE_SIZE) {
  244. let addr = ctx.start_addr + offset;
  245. unsafe { asm!("sfence.vma {}, {}", in(reg) addr, in(reg) asid); }
  246. }
  247. }
  248. local_rfence().clear();
  249. clint::clear_msip();
  250. }
  251. rfencetype => {
  252. error!("Unsupported RFence Type: {:?}!", rfencetype);
  253. local_rfence().clear();
  254. clint::clear_msip();
  255. }
  256. },
  257. None => {
  258. clint::clear_msip();
  259. unsafe {
  260. riscv::register::mip::set_ssoft();
  261. }
  262. }
  263. }
  264. }
  265. /// Fast trap
  266. pub extern "C" fn fast_handler(
  267. mut ctx: FastContext,
  268. a1: usize,
  269. a2: usize,
  270. a3: usize,
  271. a4: usize,
  272. a5: usize,
  273. a6: usize,
  274. a7: usize,
  275. ) -> FastResult {
  276. #[inline]
  277. fn resume(mut ctx: FastContext, start_addr: usize, opaque: usize) -> FastResult {
  278. unsafe {
  279. sstatus::clear_sie();
  280. satp::write(0);
  281. }
  282. ctx.regs().a[0] = current_hartid();
  283. ctx.regs().a[1] = opaque;
  284. ctx.regs().pc = start_addr;
  285. ctx.call(2)
  286. }
  287. match mcause::read().cause() {
  288. // SBI call
  289. T::Exception(E::SupervisorEnvCall) => {
  290. use sbi_spec::{base, hsm, legacy};
  291. let mut ret = unsafe { SBI.assume_init_ref() }.handle_ecall(
  292. a7,
  293. a6,
  294. [ctx.a0(), a1, a2, a3, a4, a5],
  295. );
  296. if ret.is_ok() {
  297. match (a7, a6) {
  298. // 不可恢复挂起
  299. (hsm::EID_HSM, hsm::HART_SUSPEND)
  300. if matches!(ctx.a0() as u32, hsm::suspend_type::NON_RETENTIVE) =>
  301. {
  302. return resume(ctx, a1, a2);
  303. }
  304. // legacy console 探测
  305. (base::EID_BASE, base::PROBE_EXTENSION)
  306. if matches!(
  307. ctx.a0(),
  308. legacy::LEGACY_CONSOLE_PUTCHAR | legacy::LEGACY_CONSOLE_GETCHAR
  309. ) =>
  310. {
  311. ret.value = 1;
  312. }
  313. _ => {}
  314. }
  315. } else {
  316. match a7 {
  317. legacy::LEGACY_CONSOLE_PUTCHAR => {
  318. ret.error = unsafe { SBI.assume_init_ref() }.uart16550.as_ref().unwrap().putchar(ctx.a0());
  319. ret.value = a1;
  320. }
  321. legacy::LEGACY_CONSOLE_GETCHAR => {
  322. ret.error = unsafe { SBI.assume_init_ref() }.uart16550.as_ref().unwrap().getchar();
  323. ret.value = a1;
  324. }
  325. _ => {}
  326. }
  327. }
  328. ctx.regs().a = [ret.error, ret.value, a2, a3, a4, a5, a6, a7];
  329. mepc::write(mepc::read() + 4);
  330. ctx.restore()
  331. }
  332. T::Exception(E::IllegalInstruction) => {
  333. if mstatus::read().mpp() == mstatus::MPP::Machine {
  334. panic!("Cannot handle illegal instruction exception from M-MODE");
  335. }
  336. ctx.regs().a = [ctx.a0(), a1, a2, a3, a4, a5, a6, a7];
  337. if !illegal_instruction_handler(&mut ctx) {
  338. delegate();
  339. }
  340. ctx.restore()
  341. }
  342. // 其他陷入
  343. trap => {
  344. println!(
  345. "
  346. -----------------------------
  347. > trap: {trap:?}
  348. > mepc: {:#018x}
  349. > mtval: {:#018x}
  350. -----------------------------
  351. ",
  352. mepc::read(),
  353. mtval::read()
  354. );
  355. panic!("Stopped with unsupported trap")
  356. }
  357. }
  358. }
  359. #[inline]
  360. fn delegate() {
  361. use riscv::register::{mcause, mepc, mtval, scause, sepc, sstatus, stval, stvec};
  362. unsafe {
  363. // TODO: 当支持中断嵌套时,需要从ctx里获取mpec。当前ctx.reg().pc与mepc不一致
  364. sepc::write(mepc::read());
  365. scause::write(mcause::read().bits());
  366. stval::write(mtval::read());
  367. sstatus::clear_sie();
  368. if mstatus::read().mpp() == mstatus::MPP::Supervisor {
  369. sstatus::set_spp(sstatus::SPP::Supervisor);
  370. } else {
  371. sstatus::set_spp(sstatus::SPP::User);
  372. }
  373. mepc::write(stvec::read().address());
  374. }
  375. }
  376. #[inline]
  377. fn illegal_instruction_handler(ctx: &mut FastContext) -> bool {
  378. use riscv::register::{mepc, mtval};
  379. use riscv_decode::{decode, Instruction};
  380. let inst = decode(mtval::read() as u32);
  381. match inst {
  382. Ok(Instruction::Csrrs(csr)) => match csr.csr() {
  383. CSR_TIME => {
  384. assert!(
  385. 10 <= csr.rd() && csr.rd() <= 17,
  386. "Unsupported CSR rd: {}",
  387. csr.rd()
  388. );
  389. ctx.regs().a[(csr.rd() - 10) as usize] = unsafe { SBI.assume_init_ref() }
  390. .clint
  391. .as_ref()
  392. .unwrap()
  393. .get_time();
  394. }
  395. CSR_TIMEH => {
  396. assert!(
  397. 10 <= csr.rd() && csr.rd() <= 17,
  398. "Unsupported CSR rd: {}",
  399. csr.rd()
  400. );
  401. ctx.regs().a[(csr.rd() - 10) as usize] = unsafe { SBI.assume_init_ref() }
  402. .clint
  403. .as_ref()
  404. .unwrap()
  405. .get_timeh();
  406. }
  407. _ => return false,
  408. },
  409. _ => return false,
  410. }
  411. mepc::write(mepc::read() + 4);
  412. true
  413. }
  414. #[derive(Debug)]
  415. #[repr(C)]
  416. pub struct SupervisorContext {
  417. pub ra: usize, // 0
  418. pub sp: usize,
  419. pub gp: usize,
  420. pub tp: usize,
  421. pub t0: usize,
  422. pub t1: usize,
  423. pub t2: usize,
  424. pub s0: usize,
  425. pub s1: usize,
  426. pub a0: usize,
  427. pub a1: usize,
  428. pub a2: usize,
  429. pub a3: usize,
  430. pub a4: usize,
  431. pub a5: usize,
  432. pub a6: usize,
  433. pub a7: usize,
  434. pub s2: usize,
  435. pub s3: usize,
  436. pub s4: usize,
  437. pub s5: usize,
  438. pub s6: usize,
  439. pub s7: usize,
  440. pub s8: usize,
  441. pub s9: usize,
  442. pub s10: usize,
  443. pub s11: usize,
  444. pub t3: usize,
  445. pub t4: usize,
  446. pub t5: usize,
  447. pub t6: usize, // 30
  448. pub mepc: usize, // 31
  449. }