main.rs 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433
  1. #![no_std]
  2. #![no_main]
  3. #![feature(naked_functions)]
  4. #![feature(alloc_error_handler)]
  5. #![feature(llvm_asm)]
  6. #![feature(asm)]
  7. #![feature(global_asm)]
  8. mod hal;
  9. #[cfg(not(test))]
  10. use core::alloc::Layout;
  11. #[cfg(not(test))]
  12. use core::panic::PanicInfo;
  13. use linked_list_allocator::LockedHeap;
  14. use rustsbi::{print, println};
  15. use riscv::register::{
  16. mcause::{self, Exception, Interrupt, Trap},
  17. medeleg, mepc, mhartid, mideleg, mie, mip, misa::{self, MXL},
  18. mstatus::{self, MPP},
  19. mtval,
  20. mtvec::{self, TrapMode},
  21. };
  22. #[global_allocator]
  23. static ALLOCATOR: LockedHeap = LockedHeap::empty();
  24. #[cfg(not(test))]
  25. #[panic_handler]
  26. fn panic(info: &PanicInfo) -> ! {
  27. println!("[rustsbi-panic] {}", info);
  28. println!("[rustsbi-panic] system shutdown scheduled due to RustSBI panic");
  29. use rustsbi::Reset;
  30. hal::Reset.system_reset(
  31. rustsbi::reset::RESET_TYPE_SHUTDOWN,
  32. rustsbi::reset::RESET_REASON_SYSTEM_FAILURE
  33. );
  34. loop { }
  35. }
  36. #[cfg(not(test))]
  37. #[alloc_error_handler]
  38. fn oom(_layout: Layout) -> ! {
  39. loop {}
  40. }
  41. // #[export_name = "_mp_hook"]
  42. pub extern "C" fn mp_hook() -> bool {
  43. let hartid = mhartid::read();
  44. if hartid == 0 {
  45. true
  46. } else {
  47. use riscv::asm::wfi;
  48. use hal::Clint;
  49. unsafe {
  50. let mut clint = Clint::new(0x200_0000 as *mut u8);
  51. // Clear IPI
  52. clint.clear_soft(hartid);
  53. // Start listening for software interrupts
  54. mie::set_msoft();
  55. loop {
  56. wfi();
  57. if mip::read().msoft() {
  58. break;
  59. }
  60. }
  61. // Stop listening for software interrupts
  62. mie::clear_msoft();
  63. // Clear IPI
  64. clint.clear_soft(hartid);
  65. }
  66. false
  67. }
  68. }
  69. #[export_name = "_start"]
  70. #[link_section = ".text.entry"]
  71. #[naked]
  72. unsafe extern "C" fn start() -> ! {
  73. asm!(
  74. "
  75. csrr a2, mhartid
  76. lui t0, %hi(_max_hart_id)
  77. add t0, t0, %lo(_max_hart_id)
  78. bgtu a2, t0, _start_abort
  79. la sp, _stack_start
  80. lui t0, %hi(_hart_stack_size)
  81. add t0, t0, %lo(_hart_stack_size)
  82. .ifdef __riscv_mul
  83. mul t0, a2, t0
  84. .else
  85. beqz a2, 2f // Jump if single-hart
  86. mv t1, a2
  87. mv t2, t0
  88. 1:
  89. add t0, t0, t2
  90. addi t1, t1, -1
  91. bnez t1, 1b
  92. 2:
  93. .endif
  94. sub sp, sp, t0
  95. csrw mscratch, zero
  96. j main
  97. _start_abort:
  98. wfi
  99. j _start_abort
  100. ", options(noreturn))
  101. }
  102. #[export_name = "main"]
  103. #[link_section = ".text"]
  104. fn main() {
  105. // Ref: https://github.com/qemu/qemu/blob/aeb07b5f6e69ce93afea71027325e3e7a22d2149/hw/riscv/boot.c#L243
  106. #[cfg(riscv)]
  107. let dtb_pa = unsafe {
  108. let dtb_pa: usize;
  109. asm!("", in("a1") dtb_pa);
  110. dtb_pa
  111. };
  112. if mp_hook() {
  113. // init
  114. }
  115. /* setup trap */
  116. extern "C" {
  117. fn _start_trap_asm();
  118. }
  119. unsafe {
  120. mtvec::write(_start_trap_asm as usize, TrapMode::Direct);
  121. }
  122. /* main function start */
  123. extern "C" {
  124. static mut _sheap: u8;
  125. static _heap_size: u8;
  126. }
  127. if mhartid::read() == 0 {
  128. let sheap = unsafe { &mut _sheap } as *mut _ as usize;
  129. let heap_size = unsafe { &_heap_size } as *const u8 as usize;
  130. unsafe {
  131. ALLOCATOR.lock().init(sheap, heap_size);
  132. }
  133. // 其实这些参数不用提供,直接通过pac库生成
  134. let serial = hal::Ns16550a::new(0x10000000, 0, 11_059_200, 115200);
  135. // use through macro
  136. use rustsbi::legacy_stdio::init_legacy_stdio_embedded_hal;
  137. init_legacy_stdio_embedded_hal(serial);
  138. let clint = hal::Clint::new(0x2000000 as *mut u8);
  139. use rustsbi::init_ipi;
  140. init_ipi(clint);
  141. // todo: do not create two instances
  142. let clint = hal::Clint::new(0x2000000 as *mut u8);
  143. use rustsbi::init_timer;
  144. init_timer(clint);
  145. use rustsbi::init_reset;
  146. init_reset(hal::Reset);
  147. }
  148. // 把S的中断全部委托给S层
  149. unsafe {
  150. mideleg::set_sext();
  151. mideleg::set_stimer();
  152. mideleg::set_ssoft();
  153. medeleg::set_instruction_misaligned();
  154. medeleg::set_breakpoint();
  155. medeleg::set_user_env_call();
  156. medeleg::set_instruction_page_fault();
  157. medeleg::set_load_page_fault();
  158. medeleg::set_store_page_fault();
  159. medeleg::set_instruction_fault();
  160. medeleg::set_load_fault();
  161. medeleg::set_store_fault();
  162. mie::set_mext();
  163. // 不打开mie::set_mtimer
  164. mie::set_msoft();
  165. }
  166. if mhartid::read() == 0 {
  167. println!("[rustsbi] RustSBI version {}", rustsbi::VERSION);
  168. println!("{}", rustsbi::LOGO);
  169. println!("[rustsbi] Platform: QEMU (Version {})", env!("CARGO_PKG_VERSION"));
  170. let isa = misa::read();
  171. if let Some(isa) = isa {
  172. let mxl_str = match isa.mxl() {
  173. MXL::XLEN32 => "RV32",
  174. MXL::XLEN64 => "RV64",
  175. MXL::XLEN128 => "RV128",
  176. };
  177. print!("[rustsbi] misa: {}", mxl_str);
  178. for ext in 'A'..='Z' {
  179. if isa.has_extension(ext) {
  180. print!("{}", ext);
  181. }
  182. }
  183. println!("");
  184. }
  185. println!("[rustsbi] mideleg: {:#x}", mideleg::read().bits());
  186. println!("[rustsbi] medeleg: {:#x}", medeleg::read().bits());
  187. println!("[rustsbi] Kernel entry: 0x80200000");
  188. }
  189. unsafe {
  190. mepc::write(s_mode_start as usize);
  191. mstatus::set_mpp(MPP::Supervisor);
  192. #[cfg(riscv)]
  193. rustsbi::enter_privileged(mhartid::read(), dtb_pa)
  194. }
  195. }
  196. #[naked]
  197. #[link_section = ".text"]
  198. unsafe extern "C" fn s_mode_start() -> ! {
  199. asm!(
  200. "
  201. .option push
  202. .option norelax
  203. 1:
  204. auipc ra, %pcrel_hi(1f)
  205. ld ra, %pcrel_lo(1b)(ra)
  206. jr ra
  207. .align 3
  208. 1:
  209. .dword 0x80200000
  210. .option pop
  211. ", options(noreturn))
  212. }
  213. #[naked]
  214. pub unsafe extern "C" fn start_trap() {
  215. asm!(
  216. "
  217. .equ REGBYTES, 8
  218. .macro STORE reg, offset
  219. sd \\reg, \\offset*REGBYTES(sp)
  220. .endm
  221. .macro LOAD reg, offset
  222. ld \\reg, \\offset*REGBYTES(sp)
  223. .endm
  224. .pushsection .text
  225. .global _start_trap
  226. .p2align 2
  227. _start_trap:
  228. csrrw sp, mscratch, sp
  229. bnez sp, 1f
  230. /* from M level, load sp */
  231. csrrw sp, mscratch, zero
  232. 1:
  233. addi sp, sp, -16 * REGBYTES
  234. STORE ra, 0
  235. STORE t0, 1
  236. STORE t1, 2
  237. STORE t2, 3
  238. STORE t3, 4
  239. STORE t4, 5
  240. STORE t5, 6
  241. STORE t6, 7
  242. STORE a0, 8
  243. STORE a1, 9
  244. STORE a2, 10
  245. STORE a3, 11
  246. STORE a4, 12
  247. STORE a5, 13
  248. STORE a6, 14
  249. STORE a7, 15
  250. mv a0, sp
  251. call _start_trap_rust
  252. LOAD ra, 0
  253. LOAD t0, 1
  254. LOAD t1, 2
  255. LOAD t2, 3
  256. LOAD t3, 4
  257. LOAD t4, 5
  258. LOAD t5, 6
  259. LOAD t6, 7
  260. LOAD a0, 8
  261. LOAD a1, 9
  262. LOAD a2, 10
  263. LOAD a3, 11
  264. LOAD a4, 12
  265. LOAD a5, 13
  266. LOAD a6, 14
  267. LOAD a7, 15
  268. addi sp, sp, 16 * REGBYTES
  269. csrrw sp, mscratch, sp
  270. mret
  271. .popsection
  272. ", options(noreturn));
  273. }
  274. // #[doc(hidden)]
  275. // #[export_name = "_mp_hook"]
  276. // pub extern "Rust" fn _mp_hook() -> bool {
  277. // match mhartid::read() {
  278. // 0 => true,
  279. // _ => loop {
  280. // unsafe { riscv::asm::wfi() }
  281. // },
  282. // }
  283. // }
  284. #[allow(unused)]
  285. #[derive(Debug)]
  286. struct TrapFrame {
  287. ra: usize,
  288. t0: usize,
  289. t1: usize,
  290. t2: usize,
  291. t3: usize,
  292. t4: usize,
  293. t5: usize,
  294. t6: usize,
  295. a0: usize,
  296. a1: usize,
  297. a2: usize,
  298. a3: usize,
  299. a4: usize,
  300. a5: usize,
  301. a6: usize,
  302. a7: usize,
  303. }
  304. #[export_name = "_start_trap_rust"]
  305. extern "C" fn start_trap_rust(trap_frame: &mut TrapFrame) {
  306. let cause = mcause::read().cause();
  307. match cause {
  308. Trap::Exception(Exception::SupervisorEnvCall) => {
  309. let params = [trap_frame.a0, trap_frame.a1, trap_frame.a2, trap_frame.a3];
  310. // Call RustSBI procedure
  311. let ans = rustsbi::ecall(trap_frame.a7, trap_frame.a6, params);
  312. // Return the return value to TrapFrame
  313. trap_frame.a0 = ans.error;
  314. trap_frame.a1 = ans.value;
  315. // Skip ecall instruction
  316. mepc::write(mepc::read().wrapping_add(4));
  317. }
  318. Trap::Interrupt(Interrupt::MachineSoft) => {
  319. // 机器软件中断返回给S层
  320. unsafe {
  321. mip::set_ssoft();
  322. mie::clear_msoft();
  323. }
  324. }
  325. Trap::Interrupt(Interrupt::MachineTimer) => {
  326. // 机器时间中断返回给S层
  327. unsafe {
  328. mip::set_stimer();
  329. mie::clear_mtimer();
  330. }
  331. }
  332. Trap::Exception(Exception::IllegalInstruction) => {
  333. #[inline]
  334. unsafe fn get_vaddr_u32(vaddr: usize) -> u32 {
  335. let mut ans: u32;
  336. llvm_asm!("
  337. li t0, (1 << 17)
  338. mv t1, $1
  339. csrrs t0, mstatus, t0
  340. lwu t1, 0(t1)
  341. csrw mstatus, t0
  342. mv $0, t1
  343. "
  344. :"=r"(ans)
  345. :"r"(vaddr)
  346. :"t0", "t1");
  347. ans
  348. }
  349. let vaddr = mepc::read();
  350. let ins = unsafe { get_vaddr_u32(vaddr) };
  351. if ins & 0xFFFFF07F == 0xC0102073 {
  352. // rdtime
  353. let rd = ((ins >> 7) & 0b1_1111) as u8;
  354. // todo: one instance only
  355. let clint = hal::Clint::new(0x2000000 as *mut u8);
  356. let time_usize = clint.get_mtime() as usize;
  357. match rd {
  358. 10 => trap_frame.a0 = time_usize,
  359. 11 => trap_frame.a1 = time_usize,
  360. 12 => trap_frame.a2 = time_usize,
  361. 13 => trap_frame.a3 = time_usize,
  362. 14 => trap_frame.a4 = time_usize,
  363. 15 => trap_frame.a5 = time_usize,
  364. 16 => trap_frame.a6 = time_usize,
  365. 17 => trap_frame.a7 = time_usize,
  366. 5 => trap_frame.t0 = time_usize,
  367. 6 => trap_frame.t1 = time_usize,
  368. 7 => trap_frame.t2 = time_usize,
  369. 28 => trap_frame.t3 = time_usize,
  370. 29 => trap_frame.t4 = time_usize,
  371. 30 => trap_frame.t5 = time_usize,
  372. 31 => trap_frame.t6 = time_usize,
  373. _ => panic!("invalid target"),
  374. }
  375. mepc::write(mepc::read().wrapping_add(4)); // 跳过指令
  376. } else {
  377. #[cfg(target_pointer_width = "64")]
  378. panic!("invalid instruction, mepc: {:016x?}, instruction: {:016x?}", mepc::read(), ins);
  379. #[cfg(target_pointer_width = "32")]
  380. panic!("invalid instruction, mepc: {:08x?}, instruction: {:08x?}", mepc::read(), ins);
  381. }
  382. }
  383. #[cfg(target_pointer_width = "64")]
  384. cause => panic!(
  385. "Unhandled exception! mcause: {:?}, mepc: {:016x?}, mtval: {:016x?}, trap frame: {:p}, {:x?}",
  386. cause,
  387. mepc::read(),
  388. mtval::read(),
  389. &trap_frame as *const _,
  390. trap_frame
  391. ),
  392. #[cfg(target_pointer_width = "32")]
  393. cause => panic!(
  394. "Unhandled exception! mcause: {:?}, mepc: {:08x?}, mtval: {:08x?}, trap frame: {:x?}",
  395. cause,
  396. mepc::read(),
  397. mtval::read(),
  398. trap_frame
  399. ),
  400. }
  401. }