main.rs 14 KB

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