main.rs 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443
  1. #![no_std]
  2. #![no_main]
  3. #![feature(alloc_error_handler)]
  4. #![feature(global_asm)]
  5. #![feature(llvm_asm)]
  6. use core::alloc::Layout;
  7. use core::panic::PanicInfo;
  8. use k210_hal::{clock::Clocks, fpioa, pac, prelude::*};
  9. use linked_list_allocator::LockedHeap;
  10. use rustsbi::{enter_privileged, print, println};
  11. use riscv::register::{
  12. mcause::{self, Exception, Interrupt, Trap},
  13. medeleg, mepc, mhartid, mideleg, mie, mip, misa::{self, MXL},
  14. mstatus::{self, MPP},
  15. mtval,
  16. mtvec::{self, TrapMode},
  17. satp,
  18. };
  19. #[global_allocator]
  20. static ALLOCATOR: LockedHeap = LockedHeap::empty();
  21. #[panic_handler]
  22. fn panic(info: &PanicInfo) -> ! {
  23. println!("[rustsbi] {}", info);
  24. loop {}
  25. }
  26. #[alloc_error_handler]
  27. fn oom(_layout: Layout) -> ! {
  28. loop {}
  29. }
  30. fn mp_hook() -> bool {
  31. use riscv::asm::wfi;
  32. use k210_hal::clint::msip;
  33. let hartid = mhartid::read();
  34. if hartid == 0 {
  35. true
  36. } else {
  37. unsafe {
  38. // Clear IPI
  39. msip::clear_ipi(hartid);
  40. // Start listening for software interrupts
  41. mie::set_msoft();
  42. loop {
  43. wfi();
  44. if mip::read().msoft() {
  45. break;
  46. }
  47. }
  48. // Stop listening for software interrupts
  49. mie::clear_msoft();
  50. // Clear IPI
  51. msip::clear_ipi(hartid);
  52. }
  53. false
  54. }
  55. }
  56. #[export_name = "_start"]
  57. #[link_section = ".text.entry"] // this is stable
  58. fn main() -> ! {
  59. unsafe {
  60. llvm_asm!(
  61. "
  62. csrr a2, mhartid
  63. lui t0, %hi(_max_hart_id)
  64. add t0, t0, %lo(_max_hart_id)
  65. bgtu a2, t0, _start_abort
  66. la sp, _stack_start
  67. lui t0, %hi(_hart_stack_size)
  68. add t0, t0, %lo(_hart_stack_size)
  69. .ifdef __riscv_mul
  70. mul t0, a2, t0
  71. .else
  72. beqz a2, 2f // Jump if single-hart
  73. mv t1, a2
  74. mv t2, t0
  75. 1:
  76. add t0, t0, t2
  77. addi t1, t1, -1
  78. bnez t1, 1b
  79. 2:
  80. .endif
  81. sub sp, sp, t0
  82. csrw mscratch, zero
  83. j _start_success
  84. _start_abort:
  85. wfi
  86. j _start_abort
  87. _start_success:
  88. "
  89. )
  90. };
  91. if mp_hook() {
  92. extern "C" {
  93. static mut _ebss: u32;
  94. static mut _sbss: u32;
  95. static mut _edata: u32;
  96. static mut _sdata: u32;
  97. static _sidata: u32;
  98. }
  99. unsafe {
  100. r0::zero_bss(&mut _sbss, &mut _ebss);
  101. r0::init_data(&mut _sdata, &mut _edata, &_sidata);
  102. }
  103. }
  104. extern "C" {
  105. fn _start_trap();
  106. }
  107. unsafe {
  108. mtvec::write(_start_trap as usize, TrapMode::Direct);
  109. }
  110. if mhartid::read() == 0 {
  111. extern "C" {
  112. fn _sheap();
  113. fn _heap_size();
  114. }
  115. let sheap = &mut _sheap as *mut _ as usize;
  116. let heap_size = &_heap_size as *const _ as usize;
  117. unsafe {
  118. ALLOCATOR.lock().init(sheap, heap_size);
  119. }
  120. let p = pac::Peripherals::take().unwrap();
  121. let mut sysctl = p.SYSCTL.constrain();
  122. let fpioa = p.FPIOA.split(&mut sysctl.apb0);
  123. let clocks = Clocks::new();
  124. let _uarths_tx = fpioa.io5.into_function(fpioa::UARTHS_TX);
  125. let _uarths_rx = fpioa.io4.into_function(fpioa::UARTHS_RX);
  126. // Configure UART
  127. let serial = p.UARTHS.configure(115_200.bps(), &clocks);
  128. let (tx, rx) = serial.split();
  129. use rustsbi::legacy_stdio::init_legacy_stdio_embedded_hal_fuse;
  130. init_legacy_stdio_embedded_hal_fuse(tx, rx);
  131. struct Ipi;
  132. impl rustsbi::Ipi for Ipi {
  133. fn max_hart_id(&self) -> usize {
  134. 1
  135. }
  136. fn send_ipi_many(&mut self, hart_mask: rustsbi::HartMask) {
  137. use k210_hal::clint::msip;
  138. for i in 0..=1 {
  139. if hart_mask.has_bit(i) {
  140. msip::set_ipi(i);
  141. msip::clear_ipi(i);
  142. }
  143. }
  144. }
  145. }
  146. use rustsbi::init_ipi;
  147. init_ipi(Ipi);
  148. struct Timer;
  149. impl rustsbi::Timer for Timer {
  150. fn set_timer(&mut self, stime_value: u64) {
  151. // This function must clear the pending timer interrupt bit as well.
  152. use k210_hal::clint::mtimecmp;
  153. mtimecmp::write(mhartid::read(), stime_value);
  154. unsafe { mip::clear_mtimer() };
  155. }
  156. }
  157. use rustsbi::init_timer;
  158. init_timer(Timer);
  159. }
  160. unsafe {
  161. mideleg::set_sext();
  162. mideleg::set_stimer();
  163. mideleg::set_ssoft();
  164. medeleg::set_instruction_misaligned();
  165. medeleg::set_breakpoint();
  166. medeleg::set_user_env_call();
  167. medeleg::set_instruction_page_fault();
  168. medeleg::set_load_page_fault();
  169. medeleg::set_store_page_fault();
  170. mie::set_mext();
  171. // 不打开mie::set_mtimer
  172. mie::set_msoft();
  173. }
  174. if mhartid::read() == 0 {
  175. println!("[rustsbi] Version 0.1.0");
  176. println!("{}", rustsbi::LOGO);
  177. println!("[rustsbi] Platform: K210");
  178. let isa = misa::read();
  179. if let Some(isa) = isa {
  180. let mxl_str = match isa.mxl() {
  181. MXL::XLEN32 => "RV32",
  182. MXL::XLEN64 => "RV64",
  183. MXL::XLEN128 => "RV128",
  184. };
  185. print!("[rustsbi] misa: {}", mxl_str);
  186. for ext in 'A'..='Z' {
  187. if isa.has_extension(ext) {
  188. print!("{}", ext);
  189. }
  190. }
  191. println!("");
  192. }
  193. println!("[rustsbi] mideleg: {:#x}", mideleg::read().bits());
  194. println!("[rustsbi] medeleg: {:#x}", medeleg::read().bits());
  195. println!("[rustsbi] Kernel entry: 0x80020000");
  196. }
  197. extern "C" {
  198. fn _s_mode_start();
  199. }
  200. unsafe {
  201. mepc::write(_s_mode_start as usize);
  202. mstatus::set_mpp(MPP::Supervisor);
  203. enter_privileged(mhartid::read(), 0x2333333366666666);
  204. }
  205. }
  206. global_asm!(
  207. "
  208. .section .text
  209. .globl _s_mode_start
  210. _s_mode_start:
  211. 1: auipc ra, %pcrel_hi(1f)
  212. ld ra, %pcrel_lo(1b)(ra)
  213. jr ra
  214. .align 3
  215. 1: .dword 0x80020000
  216. "
  217. );
  218. // todo: configurable target address
  219. global_asm!(
  220. "
  221. .equ REGBYTES, 8
  222. .macro STORE reg, offset
  223. sd \\reg, \\offset*REGBYTES(sp)
  224. .endm
  225. .macro LOAD reg, offset
  226. ld \\reg, \\offset*REGBYTES(sp)
  227. .endm
  228. .section .text
  229. .global _start_trap
  230. .p2align 2
  231. _start_trap:
  232. csrrw sp, mscratch, sp
  233. bnez sp, 1f
  234. /* from M level, load sp */
  235. csrrw sp, mscratch, zero
  236. 1:
  237. addi sp, sp, -16 * REGBYTES
  238. STORE ra, 0
  239. STORE t0, 1
  240. STORE t1, 2
  241. STORE t2, 3
  242. STORE t3, 4
  243. STORE t4, 5
  244. STORE t5, 6
  245. STORE t6, 7
  246. STORE a0, 8
  247. STORE a1, 9
  248. STORE a2, 10
  249. STORE a3, 11
  250. STORE a4, 12
  251. STORE a5, 13
  252. STORE a6, 14
  253. STORE a7, 15
  254. mv a0, sp
  255. call _start_trap_rust
  256. LOAD ra, 0
  257. LOAD t0, 1
  258. LOAD t1, 2
  259. LOAD t2, 3
  260. LOAD t3, 4
  261. LOAD t4, 5
  262. LOAD t5, 6
  263. LOAD t6, 7
  264. LOAD a0, 8
  265. LOAD a1, 9
  266. LOAD a2, 10
  267. LOAD a3, 11
  268. LOAD a4, 12
  269. LOAD a5, 13
  270. LOAD a6, 14
  271. LOAD a7, 15
  272. addi sp, sp, 16 * REGBYTES
  273. csrrw sp, mscratch, sp
  274. mret
  275. "
  276. );
  277. #[allow(unused)]
  278. struct TrapFrame {
  279. ra: usize,
  280. t0: usize,
  281. t1: usize,
  282. t2: usize,
  283. t3: usize,
  284. t4: usize,
  285. t5: usize,
  286. t6: usize,
  287. a0: usize,
  288. a1: usize,
  289. a2: usize,
  290. a3: usize,
  291. a4: usize,
  292. a5: usize,
  293. a6: usize,
  294. a7: usize,
  295. }
  296. #[export_name = "_start_trap_rust"]
  297. extern "C" fn start_trap_rust(trap_frame: &mut TrapFrame) {
  298. let cause = mcause::read().cause();
  299. match cause {
  300. Trap::Exception(Exception::SupervisorEnvCall) => {
  301. let params = [trap_frame.a0, trap_frame.a1, trap_frame.a2, trap_frame.a3];
  302. let ans = rustsbi::ecall(trap_frame.a7, trap_frame.a6, params);
  303. trap_frame.a0 = ans.error;
  304. trap_frame.a1 = ans.value;
  305. mepc::write(mepc::read().wrapping_add(4));
  306. }
  307. Trap::Interrupt(Interrupt::MachineSoft) => {
  308. unsafe {
  309. mip::set_ssoft();
  310. mie::clear_msoft();
  311. }
  312. }
  313. Trap::Interrupt(Interrupt::MachineTimer) => {
  314. unsafe {
  315. mip::set_stimer();
  316. mie::clear_mtimer();
  317. }
  318. }
  319. Trap::Exception(Exception::IllegalInstruction) => {
  320. let vaddr = mepc::read();
  321. println!("vaddr: {:016X}", vaddr);
  322. let ins = unsafe { get_vaddr_u32(vaddr) };
  323. println!("ins: {:08X}", ins);
  324. if ins & 0xFFFFF07F == 0xC0102073 { // rdtime instruction
  325. // rdtime is actually a csrrw instruction
  326. let rd = ((ins >> 7) & 0b1_1111) as u8;
  327. let mtime = k210_hal::clint::mtime::read();
  328. let time_usize = mtime as usize;
  329. set_rd(trap_frame, rd, time_usize);
  330. mepc::write(mepc::read().wrapping_add(4)); // skip current instruction
  331. } else if ins & 0xFE007FFF == 0x12000073 { // sfence.vma instruction
  332. println!("sfence.vma instruction");
  333. // sfence.vma: | 31..25 funct7=SFENCE.VMA(0001001) | 24..20 rs2/asid | 19..15 rs1/vaddr |
  334. // 14..12 funct3=PRIV(000) | 11..7 rd, =0 | 6..0 opcode=SYSTEM(1110011) |
  335. // sfence.vm(1.9): | 31..=20 SFENCE.VM(000100000100) | 19..15 rs1/vaddr |
  336. // 14..12 funct3=PRIV(000) | 11..7 rd, =0 | 6..0 opcode=SYSTEM(1110011) |
  337. // discard rs2 // let _rs2_asid = ((ins >> 20) & 0b1_1111) as u8;
  338. // let rs1_vaddr = ((ins >> 15) & 0b1_1111) as u8;
  339. // read paging mode from satp (sptbr)
  340. let satp_bits = satp::read().bits();
  341. let paging_mode = satp_bits >> 60; // 63..60 MODE WARL
  342. let asid = (satp_bits >> 44) & 0xFFFF; // 59..44 ASID WARL
  343. let ppn = satp_bits & 0xFFF_FFFF_FFFF; // 43..0 PPN WARL
  344. println!("satp bits: {:016X}", satp_bits);
  345. // write to sptbr
  346. let sptbr_bits = (asid << 38) | (ppn & 0x3F_FFFF_FFFF);
  347. println!("sptbr bits: {:016X}", satp_bits);
  348. unsafe { llvm_asm!("csrw 0x180, $0"::"r"(sptbr_bits)) }; // write to sptbr
  349. // enable paging (in v1.9.1, mstatus: | 28..24 VM[4:0] WARL | ... )
  350. let mut mstatus_bits: usize;
  351. unsafe { llvm_asm!("csrr $0, mstatus":"=r"(mstatus_bits)) };
  352. mstatus_bits &= !0x1F00_0000;
  353. mstatus_bits |= paging_mode << 24;
  354. println!(" bits: {:016X}", mstatus_bits);
  355. unsafe { llvm_asm!("csrw mstatus, $0"::"r"(mstatus_bits)) };
  356. println!("mstatus paging mode updated {:016X}",
  357. unsafe {
  358. let ans: usize;
  359. llvm_asm!("csrr $0, mstatus":"=r"(ans));
  360. ans
  361. });
  362. // emulate with sfence.vm (declared in privileged spec v1.9)
  363. unsafe { llvm_asm!(".word 0x10400073") }; // sfence.vm x0
  364. // ::"r"(rs1_vaddr)
  365. mepc::write(mepc::read().wrapping_add(4)); // skip current instruction
  366. } else {
  367. panic!("invalid instruction, mepc: {:016x?}, instruction: {:016x?}", mepc::read(), ins);
  368. }
  369. }
  370. cause => panic!(
  371. "Unhandled exception! mcause: {:?}, mepc: {:016x?}, mtval: {:016x?}",
  372. cause,
  373. mepc::read(),
  374. mtval::read()
  375. ),
  376. }
  377. }
  378. #[inline]
  379. unsafe fn get_vaddr_u32(vaddr: usize) -> u32 {
  380. // todo: comment
  381. get_vaddr_u16(vaddr) as u32 |
  382. ((get_vaddr_u16(vaddr.wrapping_add(2)) as u32) << 16)
  383. }
  384. #[inline]
  385. unsafe fn get_vaddr_u16(vaddr: usize) -> u16 {
  386. let mut ans: u16;
  387. llvm_asm!("
  388. li t0, (1 << 17)
  389. csrrs t0, mstatus, t0
  390. lhu $0, 0($1)
  391. csrw mstatus, t0
  392. "
  393. :"=r"(ans)
  394. :"r"(vaddr)
  395. :"t0", "t1");
  396. ans
  397. }
  398. #[inline]
  399. fn set_rd(trap_frame: &mut TrapFrame, rd: u8, value: usize) {
  400. match rd {
  401. 10 => trap_frame.a0 = value,
  402. 11 => trap_frame.a1 = value,
  403. 12 => trap_frame.a2 = value,
  404. 13 => trap_frame.a3 = value,
  405. 14 => trap_frame.a4 = value,
  406. 15 => trap_frame.a5 = value,
  407. 16 => trap_frame.a6 = value,
  408. 17 => trap_frame.a7 = value,
  409. 5 => trap_frame.t0 = value,
  410. 6 => trap_frame.t1 = value,
  411. 7 => trap_frame.t2 = value,
  412. 28 => trap_frame.t3 = value,
  413. 29 => trap_frame.t4 = value,
  414. 30 => trap_frame.t5 = value,
  415. 31 => trap_frame.t6 = value,
  416. _ => panic!("invalid target `rd`"),
  417. }
  418. }