main.rs 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555
  1. #![no_std]
  2. #![no_main]
  3. #![feature(alloc_error_handler)]
  4. #![feature(global_asm)]
  5. #![feature(llvm_asm)]
  6. #[cfg(not(test))]
  7. use core::alloc::Layout;
  8. #[cfg(not(test))]
  9. use core::panic::PanicInfo;
  10. use k210_hal::{clock::Clocks, fpioa, pac, prelude::*};
  11. use linked_list_allocator::LockedHeap;
  12. use rustsbi::{enter_privileged, print, println};
  13. use riscv::register::{
  14. mcause::{self, Exception, Interrupt, Trap},
  15. medeleg, mepc, mhartid, mideleg, mie, mip, misa::{self, MXL},
  16. mstatus::{self, MPP},
  17. mtval,
  18. mtvec::{self, TrapMode},
  19. satp,
  20. };
  21. #[global_allocator]
  22. static ALLOCATOR: LockedHeap = LockedHeap::empty();
  23. static mut DEVINTRENTRY: usize = 0;
  24. #[cfg(not(test))]
  25. #[panic_handler]
  26. fn panic(info: &PanicInfo) -> ! {
  27. println!("[rustsbi] {}", info);
  28. loop {}
  29. }
  30. #[cfg(not(test))]
  31. #[alloc_error_handler]
  32. fn oom(layout: Layout) -> ! {
  33. println!("[rustsbi] out of memory for layout {:?}", layout);
  34. loop {}
  35. }
  36. fn mp_hook() -> bool {
  37. use riscv::asm::wfi;
  38. use k210_hal::clint::msip;
  39. let hartid = mhartid::read();
  40. if hartid == 0 {
  41. true
  42. } else {
  43. unsafe {
  44. // Clear IPI
  45. msip::clear_ipi(hartid);
  46. // Start listening for software interrupts
  47. mie::set_msoft();
  48. loop {
  49. wfi();
  50. if mip::read().msoft() {
  51. break;
  52. }
  53. }
  54. // Stop listening for software interrupts
  55. mie::clear_msoft();
  56. // Clear IPI
  57. msip::clear_ipi(hartid);
  58. }
  59. false
  60. }
  61. }
  62. #[export_name = "_start"]
  63. #[link_section = ".text.entry"] // this is stable
  64. fn main() -> ! {
  65. unsafe {
  66. llvm_asm!(
  67. "
  68. csrr a2, mhartid
  69. lui t0, %hi(_max_hart_id)
  70. add t0, t0, %lo(_max_hart_id)
  71. bgtu a2, t0, _start_abort
  72. la sp, _stack_start
  73. lui t0, %hi(_hart_stack_size)
  74. add t0, t0, %lo(_hart_stack_size)
  75. .ifdef __riscv_mul
  76. mul t0, a2, t0
  77. .else
  78. beqz a2, 2f // Jump if single-hart
  79. mv t1, a2
  80. mv t2, t0
  81. 1:
  82. add t0, t0, t2
  83. addi t1, t1, -1
  84. bnez t1, 1b
  85. 2:
  86. .endif
  87. sub sp, sp, t0
  88. csrw mscratch, zero
  89. j _start_success
  90. _start_abort:
  91. wfi
  92. j _start_abort
  93. _start_success:
  94. "
  95. )
  96. };
  97. if mp_hook() {
  98. extern "C" {
  99. static mut _ebss: u32;
  100. static mut _sbss: u32;
  101. static mut _edata: u32;
  102. static mut _sdata: u32;
  103. static _sidata: u32;
  104. }
  105. unsafe {
  106. r0::zero_bss(&mut _sbss, &mut _ebss);
  107. r0::init_data(&mut _sdata, &mut _edata, &_sidata);
  108. }
  109. }
  110. extern "C" {
  111. fn _start_trap();
  112. }
  113. unsafe {
  114. mtvec::write(_start_trap as usize, TrapMode::Direct);
  115. }
  116. if mhartid::read() == 0 {
  117. extern "C" {
  118. fn _sheap();
  119. fn _heap_size();
  120. }
  121. let sheap = &mut _sheap as *mut _ as usize;
  122. let heap_size = &_heap_size as *const _ as usize;
  123. unsafe {
  124. ALLOCATOR.lock().init(sheap, heap_size);
  125. }
  126. let p = pac::Peripherals::take().unwrap();
  127. let mut sysctl = p.SYSCTL.constrain();
  128. let fpioa = p.FPIOA.split(&mut sysctl.apb0);
  129. let clocks = Clocks::new();
  130. let _uarths_tx = fpioa.io5.into_function(fpioa::UARTHS_TX);
  131. let _uarths_rx = fpioa.io4.into_function(fpioa::UARTHS_RX);
  132. // Configure UART
  133. let serial = p.UARTHS.configure(115_200.bps(), &clocks);
  134. let (tx, rx) = serial.split();
  135. use rustsbi::legacy_stdio::init_legacy_stdio_embedded_hal_fuse;
  136. init_legacy_stdio_embedded_hal_fuse(tx, rx);
  137. struct Ipi;
  138. impl rustsbi::Ipi for Ipi {
  139. fn max_hart_id(&self) -> usize {
  140. 1
  141. }
  142. fn send_ipi_many(&mut self, hart_mask: rustsbi::HartMask) {
  143. use k210_hal::clint::msip;
  144. for i in 0..=1 {
  145. if hart_mask.has_bit(i) {
  146. msip::set_ipi(i);
  147. msip::clear_ipi(i);
  148. }
  149. }
  150. }
  151. }
  152. use rustsbi::init_ipi;
  153. init_ipi(Ipi);
  154. struct Timer;
  155. impl rustsbi::Timer for Timer {
  156. fn set_timer(&mut self, stime_value: u64) {
  157. // This function must clear the pending timer interrupt bit as well.
  158. use k210_hal::clint::mtimecmp;
  159. mtimecmp::write(mhartid::read(), stime_value);
  160. unsafe { mip::clear_mtimer() };
  161. }
  162. }
  163. use rustsbi::init_timer;
  164. init_timer(Timer);
  165. struct Reset;
  166. impl rustsbi::Reset for Reset {
  167. fn system_reset(&self, reset_type: usize, reset_reason: usize) -> rustsbi::SbiRet {
  168. println!("[rustsbi] reset triggered! todo: shutdown all harts on k210; program halt. Type: {}, reason: {}", reset_type, reset_reason);
  169. loop {}
  170. }
  171. }
  172. use rustsbi::init_reset;
  173. init_reset(Reset);
  174. use k210_hal::plic::Priority;
  175. use k210_hal::pac::Interrupt;
  176. use k210_hal::gpiohs::Edge;
  177. unsafe {
  178. pac::PLIC::set_threshold(mhartid::read(), Priority::P0);
  179. }
  180. let gpiohs = p.GPIOHS.split();
  181. fpioa.io16.into_function(fpioa::GPIOHS0);
  182. let mut boot = gpiohs.gpiohs0.into_pull_up_input();
  183. boot.trigger_on_edge(Edge::RISING | Edge::FALLING);
  184. unsafe {
  185. pac::PLIC::set_priority(Interrupt::GPIOHS0, Priority::P1);
  186. pac::PLIC::unmask(mhartid::read(), Interrupt::GPIOHS0);
  187. }
  188. boot.clear_interrupt_pending_bits();
  189. }
  190. unsafe {
  191. //mideleg::set_sext();
  192. mideleg::set_stimer();
  193. mideleg::set_ssoft();
  194. medeleg::set_instruction_misaligned();
  195. medeleg::set_breakpoint();
  196. medeleg::set_user_env_call();
  197. /* MMU Exception Delegation
  198. /* Page Faults are *Reserved* in 1.9.1 version */
  199. - medeleg::set_instruction_page_fault();
  200. - medeleg::set_load_page_fault();
  201. - medeleg::set_store_page_fault();
  202. /* Actually, in 1.9.1 they are merged into more general exceptions */
  203. + medeleg::set_instruction_fault();
  204. + medeleg::set_load_fault();
  205. + medeleg::set_store_fault(); */
  206. medeleg::set_instruction_fault();
  207. medeleg::set_load_fault();
  208. medeleg::set_store_fault();
  209. // 默认不打开mie::set_mext
  210. // 不打开mie::set_mtimer
  211. mie::set_msoft();
  212. }
  213. if mhartid::read() == 0 {
  214. println!("[rustsbi] Version 0.1.0");
  215. println!("{}", rustsbi::LOGO);
  216. println!("[rustsbi] Platform: K210");
  217. let isa = misa::read();
  218. if let Some(isa) = isa {
  219. let mxl_str = match isa.mxl() {
  220. MXL::XLEN32 => "RV32",
  221. MXL::XLEN64 => "RV64",
  222. MXL::XLEN128 => "RV128",
  223. };
  224. print!("[rustsbi] misa: {}", mxl_str);
  225. for ext in 'A'..='Z' {
  226. if isa.has_extension(ext) {
  227. print!("{}", ext);
  228. }
  229. }
  230. println!("");
  231. }
  232. println!("[rustsbi] mideleg: {:#x}", mideleg::read().bits());
  233. println!("[rustsbi] medeleg: {:#x}", medeleg::read().bits());
  234. println!("[rustsbi] Kernel entry: 0x80020000");
  235. }
  236. extern "C" {
  237. fn _s_mode_start();
  238. }
  239. unsafe {
  240. mepc::write(_s_mode_start as usize);
  241. mstatus::set_mpp(MPP::Supervisor);
  242. enter_privileged(mhartid::read(), 0x2333333366666666);
  243. }
  244. }
  245. global_asm!(
  246. "
  247. .section .text
  248. .globl _s_mode_start
  249. _s_mode_start:
  250. 1: auipc ra, %pcrel_hi(1f)
  251. ld ra, %pcrel_lo(1b)(ra)
  252. jr ra
  253. .align 3
  254. 1: .dword 0x80020000
  255. "
  256. );
  257. // todo: configurable target address
  258. global_asm!(
  259. "
  260. .equ REGBYTES, 8
  261. .macro STORE reg, offset
  262. sd \\reg, \\offset*REGBYTES(sp)
  263. .endm
  264. .macro LOAD reg, offset
  265. ld \\reg, \\offset*REGBYTES(sp)
  266. .endm
  267. .section .text
  268. .global _start_trap
  269. .p2align 2
  270. _start_trap:
  271. csrrw sp, mscratch, sp
  272. bnez sp, 1f
  273. /* from M level, load sp */
  274. csrrw sp, mscratch, zero
  275. 1:
  276. addi sp, sp, -16 * REGBYTES
  277. STORE ra, 0
  278. STORE t0, 1
  279. STORE t1, 2
  280. STORE t2, 3
  281. STORE t3, 4
  282. STORE t4, 5
  283. STORE t5, 6
  284. STORE t6, 7
  285. STORE a0, 8
  286. STORE a1, 9
  287. STORE a2, 10
  288. STORE a3, 11
  289. STORE a4, 12
  290. STORE a5, 13
  291. STORE a6, 14
  292. STORE a7, 15
  293. mv a0, sp
  294. call _start_trap_rust
  295. LOAD ra, 0
  296. LOAD t0, 1
  297. LOAD t1, 2
  298. LOAD t2, 3
  299. LOAD t3, 4
  300. LOAD t4, 5
  301. LOAD t5, 6
  302. LOAD t6, 7
  303. LOAD a0, 8
  304. LOAD a1, 9
  305. LOAD a2, 10
  306. LOAD a3, 11
  307. LOAD a4, 12
  308. LOAD a5, 13
  309. LOAD a6, 14
  310. LOAD a7, 15
  311. addi sp, sp, 16 * REGBYTES
  312. csrrw sp, mscratch, sp
  313. mret
  314. "
  315. );
  316. #[allow(unused)]
  317. struct TrapFrame {
  318. ra: usize,
  319. t0: usize,
  320. t1: usize,
  321. t2: usize,
  322. t3: usize,
  323. t4: usize,
  324. t5: usize,
  325. t6: usize,
  326. a0: usize,
  327. a1: usize,
  328. a2: usize,
  329. a3: usize,
  330. a4: usize,
  331. a5: usize,
  332. a6: usize,
  333. a7: usize,
  334. }
  335. #[export_name = "_start_trap_rust"]
  336. extern "C" fn start_trap_rust(trap_frame: &mut TrapFrame) {
  337. let cause = mcause::read().cause();
  338. match cause {
  339. Trap::Exception(Exception::SupervisorEnvCall) => {
  340. if trap_frame.a7 == 0x0A000004 && trap_frame.a6 == 0x210 {
  341. // We use implementation specific sbi_rustsbi_k210_sext function (extension
  342. // id: 0x0A000004, function id: 0x210) to register S-level interrupt handler
  343. // for K210 chip only. This chip uses 1.9.1 version of privileged spec,
  344. // which did not declare any S-level external interrupts.
  345. unsafe { DEVINTRENTRY = trap_frame.a0; }
  346. // enable mext
  347. unsafe { mie::set_mext(); }
  348. // return values
  349. trap_frame.a0 = 0; // SbiRet::error = SBI_SUCCESS
  350. trap_frame.a1 = 0; // SbiRet::value = 0
  351. } else {
  352. // Due to legacy 1.9.1 version of privileged spec, if we are in S-level
  353. // timer handler (delegated from M mode), and we call SBI's `set_timer`,
  354. // a M-level external interrupt may be triggered. This may try to obtain
  355. // data structures locked previously by S-level interrupt handler, which
  356. // results in a deadlock.
  357. // Ref: https://github.com/luojia65/rustsbi/pull/5
  358. if trap_frame.a7 == 0x0 {
  359. unsafe {
  360. let mtip = mip::read().mtimer();
  361. if mtip {
  362. if DEVINTRENTRY != 0 {
  363. mie::set_mext();
  364. }
  365. }
  366. }
  367. }
  368. // Actual ecall handler which is common for all RustSBI platforms
  369. let params = [trap_frame.a0, trap_frame.a1, trap_frame.a2, trap_frame.a3];
  370. let ans = rustsbi::ecall(trap_frame.a7, trap_frame.a6, params);
  371. trap_frame.a0 = ans.error;
  372. trap_frame.a1 = ans.value;
  373. }
  374. mepc::write(mepc::read().wrapping_add(4));
  375. }
  376. Trap::Interrupt(Interrupt::MachineSoft) => {
  377. // Forward to S-level software interrupt
  378. unsafe {
  379. mip::set_ssoft(); // set S-soft interrupt flag
  380. mie::clear_msoft(); // mask M-soft interrupt
  381. }
  382. }
  383. Trap::Interrupt(Interrupt::MachineTimer) => {
  384. // Forward to S-level timer interrupt
  385. unsafe {
  386. mip::set_stimer(); // set S-timer interrupt flag
  387. mie::clear_mext(); // Ref: Pull request #5
  388. mie::clear_mtimer(); // mask M-timer interrupt
  389. }
  390. }
  391. Trap::Interrupt(Interrupt::MachineExternal) => {
  392. /* legacy software delegation
  393. // to make UARTHS interrupt soft delegation work; ref: pull request #1
  394. // PLIC target0(Always Hart0-M-Interrupt) acquire
  395. let irq_id = unsafe { (0x0c20_0004 as *const u32).read_volatile() };
  396. // read from UARTHS RXFIFO
  397. let ch: u8 = unsafe { (0x3800_0004 as *const u32).read_volatile() & 0xFF } as u8;
  398. // black magic @_@, soft delegation won't success without it!
  399. print!("{}", 0 as char);
  400. // PLIC complete
  401. unsafe { (0x0c20_0004 as *mut u32).write_volatile(irq_id); }
  402. // communicate with delegated interrupt with stval CSR
  403. unsafe { llvm_asm!("csrw stval, $0" :: "r"(ch as usize) :: "volatile"); }
  404. // soft delegate to S Mode soft interrupt
  405. unsafe { mip::set_ssoft(); }
  406. */
  407. unsafe {
  408. let mut mstatus: usize;
  409. llvm_asm!("csrr $0, mstatus" : "=r"(mstatus) ::: "volatile");
  410. // set mstatus.mprv
  411. mstatus |= 1 << 17;
  412. // it may trap from U/S Mode
  413. // save mpp and set mstatus.mpp to S Mode
  414. let mpp = (mstatus >> 11) & 3;
  415. mstatus = mstatus & !(3 << 11);
  416. mstatus |= 1 << 11;
  417. // drop mstatus.mprv protection
  418. llvm_asm!("csrw mstatus, $0" :: "r"(mstatus) :: "volatile");
  419. fn devintr() {
  420. unsafe {
  421. // call devintr defined in application
  422. // we have to ask compiler save ra explicitly
  423. llvm_asm!("jalr 0($0)" :: "r"(DEVINTRENTRY) : "ra" : "volatile");
  424. }
  425. }
  426. // compiler helps us save/restore caller-saved registers
  427. devintr();
  428. // restore mstatus
  429. mstatus = mstatus &!(3 << 11);
  430. mstatus |= mpp << 11;
  431. mstatus -= 1 << 17;
  432. llvm_asm!("csrw mstatus, $0" :: "r"(mstatus) :: "volatile");
  433. }
  434. }
  435. Trap::Exception(Exception::IllegalInstruction) => {
  436. let vaddr = mepc::read();
  437. let ins = unsafe { get_vaddr_u32(vaddr) };
  438. if ins & 0xFFFFF07F == 0xC0102073 { // rdtime instruction
  439. // rdtime is actually a csrrw instruction
  440. let rd = ((ins >> 7) & 0b1_1111) as u8;
  441. let mtime = k210_hal::clint::mtime::read();
  442. let time_usize = mtime as usize;
  443. set_rd(trap_frame, rd, time_usize);
  444. mepc::write(mepc::read().wrapping_add(4)); // skip current instruction
  445. } else if ins & 0xFE007FFF == 0x12000073 { // sfence.vma instruction
  446. // There is no `sfence.vma` in 1.9.1 privileged spec; however there is a `sfence.vm`.
  447. // For backward compability, here we emulate the first instruction using the second one.
  448. // sfence.vma: | 31..25 funct7=SFENCE.VMA(0001001) | 24..20 rs2/asid | 19..15 rs1/vaddr |
  449. // 14..12 funct3=PRIV(000) | 11..7 rd, =0 | 6..0 opcode=SYSTEM(1110011) |
  450. // sfence.vm(1.9): | 31..=20 SFENCE.VM(000100000100) | 19..15 rs1/vaddr |
  451. // 14..12 funct3=PRIV(000) | 11..7 rd, =0 | 6..0 opcode=SYSTEM(1110011) |
  452. // discard rs2 // let _rs2_asid = ((ins >> 20) & 0b1_1111) as u8;
  453. // let rs1_vaddr = ((ins >> 15) & 0b1_1111) as u8;
  454. // read paging mode from satp (sptbr)
  455. let satp_bits = satp::read().bits();
  456. // bit 63..20 is not readable and writeable on K210, so we cannot
  457. // decide paging type from the 'satp' register.
  458. // that also means that the asid function is not usable on this chip.
  459. // we have to fix it to be Sv39.
  460. let ppn = satp_bits & 0xFFF_FFFF_FFFF; // 43..0 PPN WARL
  461. // write to sptbr
  462. let sptbr_bits = ppn & 0x3F_FFFF_FFFF;
  463. unsafe { llvm_asm!("csrw 0x180, $0"::"r"(sptbr_bits)) }; // write to sptbr
  464. // enable paging (in v1.9.1, mstatus: | 28..24 VM[4:0] WARL | ... )
  465. let mut mstatus_bits: usize;
  466. unsafe { llvm_asm!("csrr $0, mstatus":"=r"(mstatus_bits)) };
  467. mstatus_bits &= !0x1F00_0000;
  468. mstatus_bits |= 9 << 24;
  469. unsafe { llvm_asm!("csrw mstatus, $0"::"r"(mstatus_bits)) };
  470. // emulate with sfence.vm (declared in privileged spec v1.9)
  471. unsafe { llvm_asm!(".word 0x10400073") }; // sfence.vm x0
  472. // ::"r"(rs1_vaddr)
  473. mepc::write(mepc::read().wrapping_add(4)); // skip current instruction
  474. } else {
  475. panic!("invalid instruction! mepc: {:016x?}, instruction: {:08x?}", mepc::read(), ins);
  476. }
  477. }
  478. cause => panic!(
  479. "unhandled trap! mcause: {:?}, mepc: {:016x?}, mtval: {:016x?}",
  480. cause,
  481. mepc::read(),
  482. mtval::read(),
  483. ),
  484. }
  485. }
  486. #[inline]
  487. unsafe fn get_vaddr_u32(vaddr: usize) -> u32 {
  488. // todo: comment
  489. get_vaddr_u16(vaddr) as u32 |
  490. ((get_vaddr_u16(vaddr.wrapping_add(2)) as u32) << 16)
  491. }
  492. #[inline]
  493. unsafe fn get_vaddr_u16(vaddr: usize) -> u16 {
  494. let mut ans: u16;
  495. llvm_asm!("
  496. li t0, (1 << 17)
  497. csrrs t0, mstatus, t0
  498. lhu $0, 0($1)
  499. csrw mstatus, t0
  500. "
  501. :"=r"(ans)
  502. :"r"(vaddr)
  503. :"t0", "t1");
  504. ans
  505. }
  506. #[inline]
  507. fn set_rd(trap_frame: &mut TrapFrame, rd: u8, value: usize) {
  508. match rd {
  509. 10 => trap_frame.a0 = value,
  510. 11 => trap_frame.a1 = value,
  511. 12 => trap_frame.a2 = value,
  512. 13 => trap_frame.a3 = value,
  513. 14 => trap_frame.a4 = value,
  514. 15 => trap_frame.a5 = value,
  515. 16 => trap_frame.a6 = value,
  516. 17 => trap_frame.a7 = value,
  517. 5 => trap_frame.t0 = value,
  518. 6 => trap_frame.t1 = value,
  519. 7 => trap_frame.t2 = value,
  520. 28 => trap_frame.t3 = value,
  521. 29 => trap_frame.t4 = value,
  522. 30 => trap_frame.t5 = value,
  523. 31 => trap_frame.t6 = value,
  524. _ => panic!("invalid target `rd`"),
  525. }
  526. }