main.rs 7.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237
  1. #![feature(naked_functions)]
  2. #![no_std]
  3. #![no_main]
  4. #![allow(static_mut_refs)]
  5. #[macro_use]
  6. extern crate log;
  7. #[macro_use]
  8. mod macros;
  9. mod board;
  10. mod dt;
  11. mod dynamic;
  12. mod fail;
  13. mod riscv_spec;
  14. mod sbi;
  15. use core::sync::atomic::{AtomicBool, Ordering};
  16. use core::{arch::asm, mem::MaybeUninit};
  17. use crate::board::{SBI_IMPL, SIFIVECLINT, SIFIVETEST, UART};
  18. use crate::riscv_spec::{current_hartid, menvcfg};
  19. use crate::sbi::console::SbiConsole;
  20. use crate::sbi::hart_context::NextStage;
  21. use crate::sbi::hsm::{local_remote_hsm, SbiHsm};
  22. use crate::sbi::ipi::{self, SbiIpi};
  23. use crate::sbi::logger;
  24. use crate::sbi::reset::SbiReset;
  25. use crate::sbi::rfence::SbiRFence;
  26. use crate::sbi::trap::{self, trap_vec};
  27. use crate::sbi::trap_stack::{self, NUM_HART_MAX};
  28. use crate::sbi::SBI;
  29. #[no_mangle]
  30. extern "C" fn rust_main(_hart_id: usize, opaque: usize, nonstandard_a2: usize) {
  31. // parse dynamic information
  32. let info = dynamic::read_paddr(nonstandard_a2).unwrap_or_else(fail::use_lottery);
  33. static GENESIS: AtomicBool = AtomicBool::new(true);
  34. static SBI_READY: AtomicBool = AtomicBool::new(false);
  35. let is_boot_hart = if info.boot_hart == usize::MAX {
  36. GENESIS.swap(false, Ordering::AcqRel)
  37. } else {
  38. current_hartid() == info.boot_hart
  39. };
  40. if is_boot_hart {
  41. // 1. Init FDT
  42. let dtb = dt::parse_device_tree(opaque).unwrap_or_else(fail::device_tree_format);
  43. let dtb = dtb.share();
  44. let tree =
  45. serde_device_tree::from_raw_mut(&dtb).unwrap_or_else(fail::device_tree_deserialize);
  46. // 2. Init device
  47. // TODO: The device base address should be find in a better way
  48. let reset_device = tree.soc.test.unwrap().iter().next().unwrap();
  49. let console_base = tree.soc.serial.unwrap().iter().next().unwrap();
  50. let clint_device = tree.soc.clint.unwrap().iter().next().unwrap();
  51. let reset_base_address = reset_device.at();
  52. let console_base_address = console_base.at();
  53. let ipi_base_address = clint_device.at();
  54. board::reset_dev_init(usize::from_str_radix(reset_base_address, 16).unwrap());
  55. board::console_dev_init(usize::from_str_radix(console_base_address, 16).unwrap());
  56. board::ipi_dev_init(usize::from_str_radix(ipi_base_address, 16).unwrap());
  57. // Assume sstc is enabled only if all hart has sstc ext
  58. let sstc_support = tree
  59. .cpus
  60. .cpu
  61. .iter()
  62. .map(|cpu_iter| {
  63. use crate::dt::Cpu;
  64. let cpu = cpu_iter.deserialize::<Cpu>();
  65. let isa = match cpu.isa {
  66. Some(value) => value,
  67. None => return false,
  68. };
  69. isa.iter().find(|&x| x == "sstc").is_some()
  70. })
  71. .all(|x| x);
  72. // 3. Init SBI
  73. unsafe {
  74. SBI_IMPL = MaybeUninit::new(SBI {
  75. console: Some(SbiConsole::new(&UART)),
  76. ipi: Some(SbiIpi::new(&SIFIVECLINT, NUM_HART_MAX, sstc_support)),
  77. hsm: Some(SbiHsm),
  78. reset: Some(SbiReset::new(&SIFIVETEST)),
  79. rfence: Some(SbiRFence),
  80. });
  81. }
  82. SBI_READY.swap(true, Ordering::AcqRel);
  83. // 4. Init Logger
  84. logger::Logger::init();
  85. info!("RustSBI version {}", rustsbi::VERSION);
  86. rustsbi::LOGO.lines().for_each(|line| info!("{}", line));
  87. info!("Initializing RustSBI machine-mode environment.");
  88. if let Some(model) = tree.model {
  89. info!("Model: {}", model.iter().next().unwrap_or("<unspecified>"));
  90. }
  91. info!("Support sstc: {sstc_support}");
  92. info!("Clint device: {}", ipi_base_address);
  93. info!("Console deivce: {}", console_base_address);
  94. info!("Reset device: {}", reset_base_address);
  95. info!(
  96. "Chosen stdout item: {}",
  97. tree.chosen
  98. .stdout_path
  99. .iter()
  100. .next()
  101. .unwrap_or("<unspecified>")
  102. );
  103. // TODO: PMP configuration needs to be obtained through the memory range in the device tree
  104. use riscv::register::*;
  105. unsafe {
  106. pmpcfg0::set_pmp(0, Range::OFF, Permission::NONE, false);
  107. pmpaddr0::write(0);
  108. pmpcfg0::set_pmp(1, Range::TOR, Permission::RWX, false);
  109. pmpaddr1::write(usize::MAX >> 2);
  110. }
  111. // 设置陷入栈
  112. trap_stack::prepare_for_trap();
  113. let dynamic_info = dynamic::read_paddr(nonstandard_a2).unwrap_or_else(fail::no_dynamic_info_available);
  114. let (mpp, next_addr) =
  115. dynamic::mpp_next_addr(&dynamic_info).unwrap_or_else(fail::invalid_dynamic_data);
  116. // 设置内核入口
  117. local_remote_hsm().start(NextStage {
  118. start_addr: next_addr,
  119. next_mode: mpp,
  120. opaque,
  121. });
  122. info!(
  123. "Redirecting hart {} to 0x{:0>16x} in {:?} mode.",
  124. current_hartid(),
  125. next_addr,
  126. mpp
  127. );
  128. } else {
  129. // TODO: PMP configuration needs to be obtained through the memory range in the device tree
  130. use riscv::register::*;
  131. unsafe {
  132. pmpcfg0::set_pmp(0, Range::OFF, Permission::NONE, false);
  133. pmpaddr0::write(0);
  134. pmpcfg0::set_pmp(1, Range::TOR, Permission::RWX, false);
  135. pmpaddr1::write(usize::MAX >> 2);
  136. }
  137. // 设置陷入栈
  138. trap_stack::prepare_for_trap();
  139. // waiting for sbi ready
  140. while !SBI_READY.load(Ordering::Relaxed) {}
  141. }
  142. ipi::clear_all();
  143. unsafe {
  144. asm!("csrw mideleg, {}", in(reg) !0);
  145. asm!("csrw medeleg, {}", in(reg) !0);
  146. asm!("csrw mcounteren, {}", in(reg) !0);
  147. use riscv::register::{medeleg, mtvec};
  148. medeleg::clear_supervisor_env_call();
  149. medeleg::clear_illegal_instruction();
  150. if ipi::has_sstc() {
  151. menvcfg::set_bits(
  152. menvcfg::STCE | menvcfg::CBIE_INVALIDATE | menvcfg::CBCFE | menvcfg::CBZE,
  153. );
  154. } else {
  155. menvcfg::set_bits(menvcfg::CBIE_INVALIDATE | menvcfg::CBCFE | menvcfg::CBZE);
  156. }
  157. mtvec::write(trap_vec as _, mtvec::TrapMode::Vectored);
  158. }
  159. }
  160. #[naked]
  161. #[link_section = ".text.entry"]
  162. #[export_name = "_start"]
  163. unsafe extern "C" fn start() -> ! {
  164. core::arch::asm!(
  165. // 1. Turn off interrupt
  166. " csrw mie, zero",
  167. // 2. Initialize programming langauge runtime
  168. // only clear bss if hartid matches preferred boot hart id
  169. " csrr t0, mhartid",
  170. " ld t1, 0(a2)",
  171. " li t2, {magic}",
  172. " bne t1, t2, 3f",
  173. " ld t2, 40(a2)",
  174. " bne t0, t2, 2f",
  175. " j 4f",
  176. "3:",
  177. " j 3b", // TODO multi hart preempt for runtime init
  178. "4:",
  179. // 3. clear bss segment
  180. " la t0, sbss
  181. la t1, ebss
  182. 1: bgeu t0, t1, 2f
  183. sd zero, 0(t0)
  184. addi t0, t0, 8
  185. j 1b",
  186. "2:",
  187. // 4. Prepare stack for each hart
  188. " call {locate_stack}",
  189. " call {main}",
  190. " csrw mscratch, sp",
  191. " j {hart_boot}",
  192. magic = const dynamic::MAGIC,
  193. locate_stack = sym trap_stack::locate,
  194. main = sym rust_main,
  195. hart_boot = sym trap::msoft,
  196. options(noreturn)
  197. )
  198. }
  199. #[panic_handler]
  200. fn panic(info: &core::panic::PanicInfo) -> ! {
  201. use riscv::register::*;
  202. println!(
  203. "[rustsbi-panic] hart {} {info}",
  204. riscv::register::mhartid::read()
  205. );
  206. println!(
  207. "-----------------------------
  208. > mcause: {:?}
  209. > mepc: {:#018x}
  210. > mtval: {:#018x}
  211. -----------------------------",
  212. mcause::read().cause(),
  213. mepc::read(),
  214. mtval::read()
  215. );
  216. println!("[rustsbi-panic] system shutdown scheduled due to RustSBI panic");
  217. loop {}
  218. }