main.rs 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505
  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, SPP},
  19. mtval,
  20. mtvec::{self, TrapMode},
  21. stvec, scause, stval, sepc,
  22. };
  23. #[global_allocator]
  24. static ALLOCATOR: LockedHeap = LockedHeap::empty();
  25. #[cfg(not(test))]
  26. #[panic_handler]
  27. fn panic(info: &PanicInfo) -> ! {
  28. let hart_id = mhartid::read();
  29. // 输出的信息大概是“[rustsbi-panic] hart 0 panicked at ...”
  30. println!("[rustsbi-panic] hart {} {}", hart_id, info);
  31. println!("[rustsbi-panic] system shutdown scheduled due to RustSBI panic");
  32. use rustsbi::Reset;
  33. hal::Reset.system_reset(
  34. rustsbi::reset::RESET_TYPE_SHUTDOWN,
  35. rustsbi::reset::RESET_REASON_SYSTEM_FAILURE
  36. );
  37. loop { }
  38. }
  39. #[cfg(not(test))]
  40. #[alloc_error_handler]
  41. fn oom(_layout: Layout) -> ! {
  42. loop {}
  43. }
  44. lazy_static::lazy_static! {
  45. // 最大的硬件线程编号;只在启动时写入,跨核软中断发生时读取
  46. pub static ref MAX_HART_ID: spin::Mutex<usize> =
  47. spin::Mutex::new(compiled_max_hartid());
  48. }
  49. // #[export_name = "_mp_hook"]
  50. pub extern "C" fn mp_hook() -> bool {
  51. let hartid = mhartid::read();
  52. if hartid == 0 {
  53. true
  54. } else {
  55. use riscv::asm::wfi;
  56. use hal::Clint;
  57. unsafe {
  58. let mut clint = Clint::new(0x200_0000 as *mut u8);
  59. // Clear IPI
  60. clint.clear_soft(hartid);
  61. // Start listening for software interrupts
  62. mie::set_msoft();
  63. loop {
  64. wfi();
  65. if mip::read().msoft() {
  66. break;
  67. }
  68. }
  69. // Stop listening for software interrupts
  70. mie::clear_msoft();
  71. // Clear IPI
  72. clint.clear_soft(hartid);
  73. }
  74. false
  75. }
  76. }
  77. #[export_name = "_start"]
  78. #[link_section = ".text.entry"] // this is stable
  79. #[naked]
  80. // extern "C" for Rust ABI is by now unsupported for naked functions
  81. unsafe extern "C" fn start() -> ! {
  82. asm!(
  83. "
  84. csrr a2, mhartid
  85. lui t0, %hi(_max_hart_id)
  86. add t0, t0, %lo(_max_hart_id)
  87. bgtu a2, t0, _start_abort
  88. la sp, _stack_start
  89. lui t0, %hi(_hart_stack_size)
  90. add t0, t0, %lo(_hart_stack_size)
  91. .ifdef __riscv_mul
  92. mul t0, a2, t0
  93. .else
  94. beqz a2, 2f // Jump if single-hart
  95. mv t1, a2
  96. mv t2, t0
  97. 1:
  98. add t0, t0, t2
  99. addi t1, t1, -1
  100. bnez t1, 1b
  101. 2:
  102. .endif
  103. sub sp, sp, t0
  104. csrw mscratch, zero
  105. j main
  106. _start_abort:
  107. wfi
  108. j _start_abort
  109. ", options(noreturn))
  110. }
  111. #[export_name = "main"]
  112. extern "C" fn main(_mhartid: usize, dtb_pa: usize) -> ! {
  113. // dtb_pa is put into a1 register on qemu boot
  114. // Ref: https://github.com/qemu/qemu/blob/aeb07b5f6e69ce93afea71027325e3e7a22d2149/hw/riscv/boot.c#L243
  115. if mp_hook() {
  116. // init
  117. }
  118. /* setup trap */
  119. extern "C" {
  120. fn _start_trap();
  121. }
  122. unsafe {
  123. mtvec::write(_start_trap as usize, TrapMode::Direct);
  124. }
  125. /* main function start */
  126. extern "C" {
  127. static mut _sheap: u8;
  128. static _heap_size: u8;
  129. }
  130. if mhartid::read() == 0 {
  131. let sheap = unsafe { &mut _sheap } as *mut _ as usize;
  132. let heap_size = unsafe { &_heap_size } as *const u8 as usize;
  133. unsafe {
  134. ALLOCATOR.lock().init(sheap, heap_size);
  135. }
  136. // 其实这些参数不用提供,直接通过pac库生成
  137. let serial = hal::Ns16550a::new(0x10000000, 0, 11_059_200, 115200);
  138. // use through macro
  139. use rustsbi::legacy_stdio::init_legacy_stdio_embedded_hal;
  140. init_legacy_stdio_embedded_hal(serial);
  141. let clint = hal::Clint::new(0x2000000 as *mut u8);
  142. use rustsbi::init_ipi;
  143. init_ipi(clint);
  144. // todo: do not create two instances
  145. let clint = hal::Clint::new(0x2000000 as *mut u8);
  146. use rustsbi::init_timer;
  147. init_timer(clint);
  148. use rustsbi::init_reset;
  149. init_reset(hal::Reset);
  150. }
  151. // 把S的中断全部委托给S层
  152. unsafe {
  153. mideleg::set_sext();
  154. mideleg::set_stimer();
  155. mideleg::set_ssoft();
  156. medeleg::set_instruction_misaligned();
  157. medeleg::set_breakpoint();
  158. medeleg::set_user_env_call();
  159. medeleg::set_instruction_page_fault();
  160. medeleg::set_load_page_fault();
  161. medeleg::set_store_page_fault();
  162. medeleg::set_instruction_fault();
  163. medeleg::set_load_fault();
  164. medeleg::set_store_fault();
  165. mie::set_mext();
  166. // 不打开mie::set_mtimer
  167. mie::set_msoft();
  168. }
  169. if mhartid::read() == 0 {
  170. println!("[rustsbi] RustSBI version {}", rustsbi::VERSION);
  171. println!("{}", rustsbi::LOGO);
  172. println!("[rustsbi] Platform: QEMU (Version {})", env!("CARGO_PKG_VERSION"));
  173. let isa = misa::read();
  174. if let Some(isa) = isa {
  175. let mxl_str = match isa.mxl() {
  176. MXL::XLEN32 => "RV32",
  177. MXL::XLEN64 => "RV64",
  178. MXL::XLEN128 => "RV128",
  179. };
  180. print!("[rustsbi] misa: {}", mxl_str);
  181. for ext in 'A'..='Z' {
  182. if isa.has_extension(ext) {
  183. print!("{}", ext);
  184. }
  185. }
  186. println!("");
  187. }
  188. println!("[rustsbi] mideleg: {:#x}", mideleg::read().bits());
  189. println!("[rustsbi] medeleg: {:#x}", medeleg::read().bits());
  190. let mut guard = MAX_HART_ID.lock();
  191. *guard = unsafe { count_harts(dtb_pa) };
  192. drop(guard);
  193. println!("[rustsbi] Kernel entry: 0x80200000");
  194. }
  195. unsafe {
  196. mepc::write(s_mode_start as usize);
  197. mstatus::set_mpp(MPP::Supervisor);
  198. rustsbi::enter_privileged(mhartid::read(), dtb_pa)
  199. }
  200. }
  201. #[naked]
  202. #[link_section = ".text"] // must add link section for all naked functions
  203. unsafe extern "C" fn s_mode_start() -> ! {
  204. asm!("
  205. 1: auipc ra, %pcrel_hi(1f)
  206. ld ra, %pcrel_lo(1b)(ra)
  207. jr ra
  208. .align 3
  209. 1: .dword 0x80200000
  210. ", options(noreturn))
  211. }
  212. unsafe fn count_harts(dtb_pa: usize) -> usize {
  213. use device_tree::{DeviceTree, Node};
  214. const DEVICE_TREE_MAGIC: u32 = 0xD00DFEED;
  215. // 遍历“cpu_map”结构
  216. // 这个结构的子结构是“处理核簇”(cluster)
  217. // 每个“处理核簇”的子结构分别表示一个处理器核
  218. fn enumerate_cpu_map(cpu_map_node: &Node) -> usize {
  219. let mut tot = 0;
  220. for cluster_node in cpu_map_node.children.iter() {
  221. let name = &cluster_node.name;
  222. let count = cluster_node.children.iter().count();
  223. // 会输出:Hart count: cluster0 with 2 cores
  224. // 在justfile的“threads := "2"”处更改
  225. println!("[rustsbi-dtb] Hart count: {} with {} cores", name, count);
  226. tot += count;
  227. }
  228. tot
  229. }
  230. #[repr(C)]
  231. struct DtbHeader { magic: u32, size: u32 }
  232. let header = &*(dtb_pa as *const DtbHeader);
  233. // from_be 是大小端序的转换(from big endian)
  234. let magic = u32::from_be(header.magic);
  235. if magic == DEVICE_TREE_MAGIC {
  236. let size = u32::from_be(header.size);
  237. // 拷贝数据,加载并遍历
  238. let data = core::slice::from_raw_parts(dtb_pa as *const u8, size as usize);
  239. if let Ok(dt) = DeviceTree::load(data) {
  240. if let Some(cpu_map) = dt.find("/cpus/cpu-map") {
  241. return enumerate_cpu_map(cpu_map)
  242. }
  243. }
  244. }
  245. // 如果DTB的结构不对(读不到/cpus/cpu-map),返回默认的8个核
  246. let ans = compiled_max_hartid();
  247. println!("[rustsbi-dtb] Could not read '/cpus/cpu-map' from 'dtb_pa' device tree root; assuming {} cores", ans);
  248. ans
  249. }
  250. #[inline]
  251. fn compiled_max_hartid() -> usize {
  252. let ans;
  253. unsafe { asm!("
  254. lui {ans}, %hi(_max_hart_id)
  255. add {ans}, {ans}, %lo(_max_hart_id)
  256. ", ans = out(reg) ans) };
  257. ans
  258. }
  259. global_asm!(
  260. "
  261. .equ REGBYTES, 8
  262. .macro STORE reg, offset
  263. sd \\reg, \\offset*REGBYTES(sp)
  264. .endm
  265. .macro LOAD reg, offset
  266. ld \\reg, \\offset*REGBYTES(sp)
  267. .endm
  268. .section .text
  269. .global _start_trap
  270. .p2align 2
  271. _start_trap:
  272. csrrw sp, mscratch, sp
  273. bnez sp, 1f
  274. /* from M level, load sp */
  275. csrrw sp, mscratch, zero
  276. 1:
  277. addi sp, sp, -16 * REGBYTES
  278. STORE ra, 0
  279. STORE t0, 1
  280. STORE t1, 2
  281. STORE t2, 3
  282. STORE t3, 4
  283. STORE t4, 5
  284. STORE t5, 6
  285. STORE t6, 7
  286. STORE a0, 8
  287. STORE a1, 9
  288. STORE a2, 10
  289. STORE a3, 11
  290. STORE a4, 12
  291. STORE a5, 13
  292. STORE a6, 14
  293. STORE a7, 15
  294. mv a0, sp
  295. call _start_trap_rust
  296. LOAD ra, 0
  297. LOAD t0, 1
  298. LOAD t1, 2
  299. LOAD t2, 3
  300. LOAD t3, 4
  301. LOAD t4, 5
  302. LOAD t5, 6
  303. LOAD t6, 7
  304. LOAD a0, 8
  305. LOAD a1, 9
  306. LOAD a2, 10
  307. LOAD a3, 11
  308. LOAD a4, 12
  309. LOAD a5, 13
  310. LOAD a6, 14
  311. LOAD a7, 15
  312. addi sp, sp, 16 * REGBYTES
  313. csrrw sp, mscratch, sp
  314. mret
  315. "
  316. );
  317. // #[doc(hidden)]
  318. // #[export_name = "_mp_hook"]
  319. // pub extern "Rust" fn _mp_hook() -> bool {
  320. // match mhartid::read() {
  321. // 0 => true,
  322. // _ => loop {
  323. // unsafe { riscv::asm::wfi() }
  324. // },
  325. // }
  326. // }
  327. #[allow(unused)]
  328. #[derive(Debug)]
  329. struct TrapFrame {
  330. ra: usize,
  331. t0: usize,
  332. t1: usize,
  333. t2: usize,
  334. t3: usize,
  335. t4: usize,
  336. t5: usize,
  337. t6: usize,
  338. a0: usize,
  339. a1: usize,
  340. a2: usize,
  341. a3: usize,
  342. a4: usize,
  343. a5: usize,
  344. a6: usize,
  345. a7: usize,
  346. }
  347. impl TrapFrame {
  348. #[inline]
  349. fn set_register_xi(&mut self, i: u8, data: usize) {
  350. match i {
  351. 10 => self.a0 = data,
  352. 11 => self.a1 = data,
  353. 12 => self.a2 = data,
  354. 13 => self.a3 = data,
  355. 14 => self.a4 = data,
  356. 15 => self.a5 = data,
  357. 16 => self.a6 = data,
  358. 17 => self.a7 = data,
  359. 5 => self.t0 = data,
  360. 6 => self.t1 = data,
  361. 7 => self.t2 = data,
  362. 28 => self.t3 = data,
  363. 29 => self.t4 = data,
  364. 30 => self.t5 = data,
  365. 31 => self.t6 = data,
  366. _ => panic!("invalid target"),
  367. }
  368. }
  369. }
  370. #[export_name = "_start_trap_rust"]
  371. extern "C" fn start_trap_rust(trap_frame: &mut TrapFrame) {
  372. let cause = mcause::read().cause();
  373. match cause {
  374. Trap::Exception(Exception::SupervisorEnvCall) => {
  375. let params = [trap_frame.a0, trap_frame.a1, trap_frame.a2, trap_frame.a3, trap_frame.a4];
  376. // Call RustSBI procedure
  377. let ans = rustsbi::ecall(trap_frame.a7, trap_frame.a6, params);
  378. // Return the return value to TrapFrame
  379. trap_frame.a0 = ans.error;
  380. trap_frame.a1 = ans.value;
  381. // Skip ecall instruction
  382. mepc::write(mepc::read().wrapping_add(4));
  383. }
  384. Trap::Interrupt(Interrupt::MachineSoft) => {
  385. // 机器软件中断返回给S层
  386. unsafe {
  387. mip::set_ssoft();
  388. mie::clear_msoft();
  389. }
  390. }
  391. Trap::Interrupt(Interrupt::MachineTimer) => {
  392. // 机器时间中断返回给S层
  393. unsafe {
  394. mip::set_stimer();
  395. mie::clear_mtimer();
  396. }
  397. }
  398. Trap::Exception(Exception::IllegalInstruction) => {
  399. #[inline]
  400. unsafe fn get_vaddr_u32(vaddr: usize) -> u32 {
  401. let mut ans: u32;
  402. asm!("
  403. li {tmp}, (1 << 17)
  404. csrrs {tmp}, mstatus, {tmp}
  405. lwu {ans}, 0({vaddr})
  406. csrw mstatus, {tmp}
  407. ",
  408. tmp = out(reg) _,
  409. vaddr = in(reg) vaddr,
  410. ans = lateout(reg) ans
  411. );
  412. ans
  413. }
  414. let vaddr = mepc::read();
  415. let ins = unsafe { get_vaddr_u32(vaddr) };
  416. if ins & 0xFFFFF07F == 0xC0102073 {
  417. // rdtime
  418. let rd = ((ins >> 7) & 0b1_1111) as u8;
  419. // todo: one instance only
  420. let clint = hal::Clint::new(0x2000000 as *mut u8);
  421. let time_usize = clint.get_mtime() as usize;
  422. trap_frame.set_register_xi(rd, time_usize);
  423. mepc::write(mepc::read().wrapping_add(4)); // 跳过指令
  424. } else if mstatus::read().mpp() != MPP::Machine { // invalid instruction, can't emulate, raise to supervisor
  425. // 出现非法指令异常,转发到S特权层
  426. unsafe {
  427. // 设置S层异常原因为:非法指令
  428. scause::set(scause::Trap::Exception(scause::Exception::IllegalInstruction));
  429. // 填写异常指令的指令内容
  430. stval::write(mtval::read());
  431. // 填写S层需要返回到的地址,这里的mepc会被随后的代码覆盖掉
  432. sepc::write(mepc::read());
  433. // 设置中断位
  434. mstatus::set_mpp(MPP::Supervisor);
  435. mstatus::set_spp(SPP::Supervisor);
  436. if mstatus::read().sie() {
  437. mstatus::set_spie()
  438. }
  439. mstatus::clear_sie();
  440. // 设置返回地址,返回到S层
  441. // 注意,无论是Direct还是Vectored模式,所有异常的向量偏移都是0,不需要处理中断向量,跳转到入口地址即可
  442. mepc::write(stvec::read().address());
  443. };
  444. } else {
  445. // 真·非法指令异常,是M层出现的
  446. #[cfg(target_pointer_width = "64")]
  447. panic!("invalid instruction, mepc: {:016x?}, instruction: {:016x?}", mepc::read(), ins);
  448. #[cfg(target_pointer_width = "32")]
  449. panic!("invalid instruction, mepc: {:08x?}, instruction: {:08x?}", mepc::read(), ins);
  450. }
  451. }
  452. #[cfg(target_pointer_width = "64")]
  453. cause => panic!(
  454. "Unhandled exception! mcause: {:?}, mepc: {:016x?}, mtval: {:016x?}, trap frame: {:p}, {:x?}",
  455. cause,
  456. mepc::read(),
  457. mtval::read(),
  458. &trap_frame as *const _,
  459. trap_frame
  460. ),
  461. #[cfg(target_pointer_width = "32")]
  462. cause => panic!(
  463. "Unhandled exception! mcause: {:?}, mepc: {:08x?}, mtval: {:08x?}, trap frame: {:x?}",
  464. cause,
  465. mepc::read(),
  466. mtval::read(),
  467. trap_frame
  468. ),
  469. }
  470. }