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