main.rs 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498
  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. #[cfg(not(test))]
  24. #[panic_handler]
  25. fn panic(info: &PanicInfo) -> ! {
  26. println!("[rustsbi] {}", info);
  27. loop {}
  28. }
  29. #[cfg(not(test))]
  30. #[alloc_error_handler]
  31. fn oom(layout: Layout) -> ! {
  32. println!("[rustsbi] out of memory for layout {:?}", layout);
  33. loop {}
  34. }
  35. fn mp_hook() -> bool {
  36. use riscv::asm::wfi;
  37. use k210_hal::clint::msip;
  38. let hartid = mhartid::read();
  39. if hartid == 0 {
  40. true
  41. } else {
  42. //println!("[rustsbi] I know i am hart {} not hart 0, wfi", hartid);
  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. println!("[rustsbi] wakeup hart {}", mhartid::read());
  52. println!("[rustsbi] hart {} can go forward!", mhartid::read());
  53. break;
  54. }
  55. }
  56. println!("[rustsbi] hart {} exited the loop!", mhartid::read());
  57. // Stop listening for software interrupts
  58. mie::clear_msoft();
  59. println!("[rustsbi] mie::clear_msoft()");
  60. // Clear IPI
  61. msip::clear_ipi(hartid);
  62. println!("[rustsbi] msip::clear_ipi()");
  63. }
  64. false
  65. }
  66. }
  67. #[export_name = "_start"]
  68. #[link_section = ".text.entry"] // this is stable
  69. fn main() -> ! {
  70. unsafe {
  71. llvm_asm!(
  72. "
  73. csrr a2, mhartid
  74. lui t0, %hi(_max_hart_id)
  75. add t0, t0, %lo(_max_hart_id)
  76. bgt a2, t0, _start_abort
  77. la sp, _stack_start
  78. lui t0, %hi(_hart_stack_size)
  79. add t0, t0, %lo(_hart_stack_size)
  80. .ifdef __riscv_mul
  81. mul t0, a2, t0
  82. .else
  83. beqz a2, 2f // Jump if single-hart
  84. mv t1, a2
  85. mv t2, t0
  86. 1:
  87. add t0, t0, t2
  88. addi t1, t1, -1
  89. bnez t1, 1b
  90. 2:
  91. .endif
  92. sub sp, sp, t0
  93. csrw mscratch, zero
  94. j _start_success
  95. _start_abort:
  96. wfi
  97. j _start_abort
  98. _start_success:
  99. "
  100. )
  101. };
  102. let hart_boot = mp_hook();
  103. if hart_boot {
  104. extern "C" {
  105. static mut _ebss: u32;
  106. static mut _sbss: u32;
  107. static mut _edata: u32;
  108. static mut _sdata: u32;
  109. static _sidata: u32;
  110. }
  111. unsafe {
  112. r0::zero_bss(&mut _sbss, &mut _ebss);
  113. r0::init_data(&mut _sdata, &mut _edata, &_sidata);
  114. }
  115. }
  116. println!("after mp_hook hartid = {}", mhartid::read());
  117. extern "C" {
  118. fn _start_trap();
  119. }
  120. unsafe {
  121. mtvec::write(_start_trap as usize, TrapMode::Direct);
  122. }
  123. if mhartid::read() == 0 {
  124. extern "C" {
  125. fn _sheap();
  126. fn _heap_size();
  127. }
  128. let sheap = &mut _sheap as *mut _ as usize;
  129. let heap_size = &_heap_size as *const _ as usize;
  130. unsafe {
  131. ALLOCATOR.lock().init(sheap, heap_size);
  132. }
  133. let p = pac::Peripherals::take().unwrap();
  134. let mut sysctl = p.SYSCTL.constrain();
  135. let fpioa = p.FPIOA.split(&mut sysctl.apb0);
  136. let clocks = Clocks::new();
  137. let _uarths_tx = fpioa.io5.into_function(fpioa::UARTHS_TX);
  138. let _uarths_rx = fpioa.io4.into_function(fpioa::UARTHS_RX);
  139. // Configure UART
  140. let serial = p.UARTHS.configure(115_200.bps(), &clocks);
  141. let (tx, rx) = serial.split();
  142. use rustsbi::legacy_stdio::init_legacy_stdio_embedded_hal_fuse;
  143. init_legacy_stdio_embedded_hal_fuse(tx, rx);
  144. struct Ipi;
  145. impl rustsbi::Ipi for Ipi {
  146. fn max_hart_id(&self) -> usize {
  147. 1
  148. }
  149. fn send_ipi_many(&mut self, hart_mask: rustsbi::HartMask) {
  150. println!("[rustsbi] into send_ipi_many!");
  151. use k210_hal::clint::msip;
  152. for i in 0..=1 {
  153. println!("[rustsbi] i = {}", i);
  154. if hart_mask.has_bit(i) {
  155. println!("has bit, send ipi!");
  156. msip::set_ipi(i);
  157. /*
  158. use k210_hal::clint::mtime;
  159. let cur_time = mtime::read();
  160. loop {
  161. if mtime::read() > cur_time + 100 {
  162. break;
  163. }
  164. }
  165. */
  166. msip::clear_ipi(i);
  167. } else {
  168. println!("not bit, do not send ipi!");
  169. }
  170. }
  171. }
  172. }
  173. use rustsbi::init_ipi;
  174. init_ipi(Ipi);
  175. struct Timer;
  176. impl rustsbi::Timer for Timer {
  177. fn set_timer(&mut self, stime_value: u64) {
  178. // This function must clear the pending timer interrupt bit as well.
  179. use k210_hal::clint::mtimecmp;
  180. mtimecmp::write(mhartid::read(), stime_value);
  181. unsafe { mip::clear_mtimer() };
  182. }
  183. }
  184. use rustsbi::init_timer;
  185. init_timer(Timer);
  186. struct Reset;
  187. impl rustsbi::Reset for Reset {
  188. fn reset(&self) -> ! {
  189. println!("[rustsbi] todo: shutdown all harts on k210; program halt");
  190. loop {}
  191. }
  192. }
  193. use rustsbi::init_reset;
  194. init_reset(Reset);
  195. use k210_hal::plic::Priority;
  196. use k210_hal::pac::Interrupt;
  197. use k210_hal::gpiohs::Edge;
  198. unsafe {
  199. pac::PLIC::set_threshold(mhartid::read(), Priority::P0);
  200. }
  201. let gpiohs = p.GPIOHS.split();
  202. fpioa.io16.into_function(fpioa::GPIOHS0);
  203. let mut boot = gpiohs.gpiohs0.into_pull_up_input();
  204. boot.trigger_on_edge(Edge::RISING | Edge::FALLING);
  205. unsafe {
  206. pac::PLIC::set_priority(Interrupt::GPIOHS0, Priority::P1);
  207. pac::PLIC::unmask(mhartid::read(), Interrupt::GPIOHS0);
  208. }
  209. boot.clear_interrupt_pending_bits();
  210. } else {
  211. println!("[rustsbi] hart {} do not need initialize!", mhartid::read());
  212. }
  213. unsafe {
  214. println!("[rustsbi] hart {} now setting intr delegation!", mhartid::read());
  215. mideleg::set_sext();
  216. mideleg::set_stimer();
  217. mideleg::set_ssoft();
  218. medeleg::set_instruction_misaligned();
  219. medeleg::set_breakpoint();
  220. medeleg::set_user_env_call();
  221. medeleg::set_instruction_fault();
  222. medeleg::set_load_fault();
  223. medeleg::set_store_fault();
  224. mie::set_mext();
  225. // 不打开mie::set_mtimer
  226. mie::set_msoft();
  227. }
  228. if mhartid::read() == 0 {
  229. println!("[rustsbi] Version 0.1.0");
  230. println!("{}", rustsbi::LOGO);
  231. println!("[rustsbi] Platform: K210");
  232. let isa = misa::read();
  233. if let Some(isa) = isa {
  234. let mxl_str = match isa.mxl() {
  235. MXL::XLEN32 => "RV32",
  236. MXL::XLEN64 => "RV64",
  237. MXL::XLEN128 => "RV128",
  238. };
  239. print!("[rustsbi] misa: {}", mxl_str);
  240. for ext in 'A'..='Z' {
  241. if isa.has_extension(ext) {
  242. print!("{}", ext);
  243. }
  244. }
  245. println!("");
  246. }
  247. println!("[rustsbi] mideleg: {:#x}", mideleg::read().bits());
  248. println!("[rustsbi] medeleg: {:#x}", medeleg::read().bits());
  249. println!("[rustsbi] Kernel entry: 0x80020000");
  250. }
  251. extern "C" {
  252. fn _s_mode_start();
  253. }
  254. unsafe {
  255. println!("[rustsbi] hart {} is ready into S Mode!", mhartid::read());
  256. mepc::write(_s_mode_start as usize);
  257. mstatus::set_mpp(MPP::Supervisor);
  258. enter_privileged(mhartid::read(), 0x2333333366666666);
  259. }
  260. }
  261. global_asm!(
  262. "
  263. .section .text
  264. .globl _s_mode_start
  265. _s_mode_start:
  266. 1: auipc ra, %pcrel_hi(1f)
  267. ld ra, %pcrel_lo(1b)(ra)
  268. jr ra
  269. .align 3
  270. 1: .dword 0x80020000
  271. "
  272. );
  273. // todo: configurable target address
  274. global_asm!(
  275. "
  276. .equ REGBYTES, 8
  277. .macro STORE reg, offset
  278. sd \\reg, \\offset*REGBYTES(sp)
  279. .endm
  280. .macro LOAD reg, offset
  281. ld \\reg, \\offset*REGBYTES(sp)
  282. .endm
  283. .section .text
  284. .global _start_trap
  285. .p2align 2
  286. _start_trap:
  287. csrrw sp, mscratch, sp
  288. bnez sp, 1f
  289. /* from M level, load sp */
  290. csrrw sp, mscratch, zero
  291. 1:
  292. addi sp, sp, -16 * REGBYTES
  293. STORE ra, 0
  294. STORE t0, 1
  295. STORE t1, 2
  296. STORE t2, 3
  297. STORE t3, 4
  298. STORE t4, 5
  299. STORE t5, 6
  300. STORE t6, 7
  301. STORE a0, 8
  302. STORE a1, 9
  303. STORE a2, 10
  304. STORE a3, 11
  305. STORE a4, 12
  306. STORE a5, 13
  307. STORE a6, 14
  308. STORE a7, 15
  309. mv a0, sp
  310. call _start_trap_rust
  311. LOAD ra, 0
  312. LOAD t0, 1
  313. LOAD t1, 2
  314. LOAD t2, 3
  315. LOAD t3, 4
  316. LOAD t4, 5
  317. LOAD t5, 6
  318. LOAD t6, 7
  319. LOAD a0, 8
  320. LOAD a1, 9
  321. LOAD a2, 10
  322. LOAD a3, 11
  323. LOAD a4, 12
  324. LOAD a5, 13
  325. LOAD a6, 14
  326. LOAD a7, 15
  327. addi sp, sp, 16 * REGBYTES
  328. csrrw sp, mscratch, sp
  329. mret
  330. "
  331. );
  332. #[allow(unused)]
  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. let ans = rustsbi::ecall(trap_frame.a7, trap_frame.a6, params);
  358. trap_frame.a0 = ans.error;
  359. trap_frame.a1 = ans.value;
  360. mepc::write(mepc::read().wrapping_add(4));
  361. }
  362. Trap::Interrupt(Interrupt::MachineSoft) => {
  363. unsafe {
  364. mip::set_ssoft();
  365. mie::clear_msoft();
  366. }
  367. }
  368. Trap::Interrupt(Interrupt::MachineTimer) => {
  369. unsafe {
  370. mip::set_stimer();
  371. mie::clear_mtimer();
  372. }
  373. }
  374. Trap::Interrupt(Interrupt::MachineExternal) => {
  375. let irq_id = unsafe { (0x0c20_0004 as *const u32).read_volatile() };
  376. let ch: u8 = unsafe { (0x3800_0004 as *const u32).read_volatile() & 0xFF } as u8;
  377. print!("{}", 0 as char);
  378. unsafe { (0x0c20_0004 as *mut u32).write_volatile(irq_id); }
  379. unsafe { llvm_asm!("csrw stval, $0" :: "r"(ch as usize) :: "volatile"); }
  380. unsafe { mip::set_ssoft(); }
  381. }
  382. Trap::Exception(Exception::IllegalInstruction) => {
  383. let vaddr = mepc::read();
  384. let ins = unsafe { get_vaddr_u32(vaddr) };
  385. if ins & 0xFFFFF07F == 0xC0102073 { // rdtime instruction
  386. // rdtime is actually a csrrw instruction
  387. let rd = ((ins >> 7) & 0b1_1111) as u8;
  388. let mtime = k210_hal::clint::mtime::read();
  389. let time_usize = mtime as usize;
  390. set_rd(trap_frame, rd, time_usize);
  391. mepc::write(mepc::read().wrapping_add(4)); // skip current instruction
  392. } else if ins & 0xFE007FFF == 0x12000073 { // sfence.vma instruction
  393. // sfence.vma: | 31..25 funct7=SFENCE.VMA(0001001) | 24..20 rs2/asid | 19..15 rs1/vaddr |
  394. // 14..12 funct3=PRIV(000) | 11..7 rd, =0 | 6..0 opcode=SYSTEM(1110011) |
  395. // sfence.vm(1.9): | 31..=20 SFENCE.VM(000100000100) | 19..15 rs1/vaddr |
  396. // 14..12 funct3=PRIV(000) | 11..7 rd, =0 | 6..0 opcode=SYSTEM(1110011) |
  397. // discard rs2 // let _rs2_asid = ((ins >> 20) & 0b1_1111) as u8;
  398. // let rs1_vaddr = ((ins >> 15) & 0b1_1111) as u8;
  399. // read paging mode from satp (sptbr)
  400. let satp_bits = satp::read().bits();
  401. // bit 63..20 is not readable and writeable on K210, so we cannot
  402. // decide paging type from the 'satp' register.
  403. // that also means that the asid function is not usable on this chip.
  404. // we have to fix it to be Sv39.
  405. let ppn = satp_bits & 0xFFF_FFFF_FFFF; // 43..0 PPN WARL
  406. // write to sptbr
  407. let sptbr_bits = ppn & 0x3F_FFFF_FFFF;
  408. unsafe { llvm_asm!("csrw 0x180, $0"::"r"(sptbr_bits)) }; // write to sptbr
  409. // enable paging (in v1.9.1, mstatus: | 28..24 VM[4:0] WARL | ... )
  410. let mut mstatus_bits: usize;
  411. unsafe { llvm_asm!("csrr $0, mstatus":"=r"(mstatus_bits)) };
  412. mstatus_bits &= !0x1F00_0000;
  413. mstatus_bits |= 9 << 24;
  414. unsafe { llvm_asm!("csrw mstatus, $0"::"r"(mstatus_bits)) };
  415. // emulate with sfence.vm (declared in privileged spec v1.9)
  416. unsafe { llvm_asm!(".word 0x10400073") }; // sfence.vm x0
  417. // ::"r"(rs1_vaddr)
  418. mepc::write(mepc::read().wrapping_add(4)); // skip current instruction
  419. } else {
  420. panic!("invalid instruction, mepc: {:016x?}, instruction: {:08x?}", mepc::read(), ins);
  421. }
  422. }
  423. cause => panic!(
  424. "Unhandled trap! mcause: {:?}, mepc: {:016x?}, mtval: {:016x?}",
  425. cause,
  426. mepc::read(),
  427. mtval::read()
  428. ),
  429. }
  430. }
  431. #[inline]
  432. unsafe fn get_vaddr_u32(vaddr: usize) -> u32 {
  433. // todo: comment
  434. get_vaddr_u16(vaddr) as u32 |
  435. ((get_vaddr_u16(vaddr.wrapping_add(2)) as u32) << 16)
  436. }
  437. #[inline]
  438. unsafe fn get_vaddr_u16(vaddr: usize) -> u16 {
  439. let mut ans: u16;
  440. llvm_asm!("
  441. li t0, (1 << 17)
  442. csrrs t0, mstatus, t0
  443. lhu $0, 0($1)
  444. csrw mstatus, t0
  445. "
  446. :"=r"(ans)
  447. :"r"(vaddr)
  448. :"t0", "t1");
  449. ans
  450. }
  451. #[inline]
  452. fn set_rd(trap_frame: &mut TrapFrame, rd: u8, value: usize) {
  453. match rd {
  454. 10 => trap_frame.a0 = value,
  455. 11 => trap_frame.a1 = value,
  456. 12 => trap_frame.a2 = value,
  457. 13 => trap_frame.a3 = value,
  458. 14 => trap_frame.a4 = value,
  459. 15 => trap_frame.a5 = value,
  460. 16 => trap_frame.a6 = value,
  461. 17 => trap_frame.a7 = value,
  462. 5 => trap_frame.t0 = value,
  463. 6 => trap_frame.t1 = value,
  464. 7 => trap_frame.t2 = value,
  465. 28 => trap_frame.t3 = value,
  466. 29 => trap_frame.t4 = value,
  467. 30 => trap_frame.t5 = value,
  468. 31 => trap_frame.t6 = value,
  469. _ => panic!("invalid target `rd`"),
  470. }
  471. }