board.rs 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368
  1. use aclint::SifiveClint;
  2. use core::{
  3. cell::RefCell,
  4. fmt::{Display, Formatter, Result},
  5. ops::Range,
  6. sync::atomic::{AtomicBool, AtomicPtr, Ordering},
  7. };
  8. use serde_device_tree::Dtb;
  9. use sifive_test_device::SifiveTestDevice;
  10. use spin::Mutex;
  11. use uart16550::Uart16550;
  12. use uart_xilinx::uart_lite::uart::MmioUartAxiLite;
  13. use crate::fail;
  14. use crate::sbi::console::{ConsoleDevice, SbiConsole};
  15. use crate::sbi::extensions;
  16. use crate::sbi::hsm::SbiHsm;
  17. use crate::sbi::ipi::{IpiDevice, SbiIpi};
  18. use crate::sbi::logger;
  19. use crate::sbi::reset::{ResetDevice, SbiReset};
  20. use crate::sbi::trap_stack;
  21. use crate::sbi::trap_stack::NUM_HART_MAX;
  22. use crate::sbi::SBI;
  23. use crate::{dt, sbi::rfence::SbiRFence};
  24. pub(crate) const UART16650_COMPATIBLE: &str = "ns16550a";
  25. pub(crate) const UARTAXILITE_COMPATIBLE: &str = "xlnx,xps-uartlite-1.00.a";
  26. pub(crate) const SIFIVETEST_COMPATIBLE: &str = "sifive,test0";
  27. pub(crate) const SIFIVECLINT_COMPATIBLE: &str = "riscv,clint0";
  28. type BaseAddress = usize;
  29. /// Store finite-length string on the stack.
  30. pub(crate) struct StringInline<const N: usize>(usize, [u8; N]);
  31. impl<const N: usize> Display for StringInline<N> {
  32. fn fmt(&self, f: &mut Formatter<'_>) -> Result {
  33. write!(f, "{}", unsafe {
  34. core::str::from_utf8_unchecked(&self.1[..self.0])
  35. })
  36. }
  37. }
  38. type CpuEnableList = [bool; trap_stack::NUM_HART_MAX];
  39. pub struct BoardInfo {
  40. pub memory_range: Option<Range<usize>>,
  41. pub console: Option<(BaseAddress, MachineConsoleType)>,
  42. pub reset: Option<BaseAddress>,
  43. pub ipi: Option<BaseAddress>,
  44. pub cpu_num: Option<usize>,
  45. pub cpu_enabled: Option<CpuEnableList>,
  46. pub model: StringInline<128>,
  47. }
  48. impl BoardInfo {
  49. pub const fn new() -> Self {
  50. BoardInfo {
  51. memory_range: None,
  52. console: None,
  53. reset: None,
  54. ipi: None,
  55. cpu_enabled: None,
  56. cpu_num: None,
  57. model: StringInline(0, [0u8; 128]),
  58. }
  59. }
  60. }
  61. pub struct Board {
  62. pub info: BoardInfo,
  63. pub sbi: SBI<MachineConsole, SifiveClint, SifiveTestDevice>,
  64. pub ready: AtomicBool,
  65. }
  66. #[allow(unused)]
  67. impl Board {
  68. pub const fn new() -> Self {
  69. Board {
  70. info: BoardInfo::new(),
  71. sbi: SBI::new(),
  72. ready: AtomicBool::new(false),
  73. }
  74. }
  75. pub fn init(&mut self, dtb: &RefCell<Dtb>) {
  76. self.info_init(dtb);
  77. self.sbi_init();
  78. logger::Logger::init().unwrap();
  79. trap_stack::prepare_for_trap();
  80. self.ready.swap(true, Ordering::Release);
  81. }
  82. pub fn have_console(&self) -> bool {
  83. self.sbi.console.is_some()
  84. }
  85. pub fn have_reset(&self) -> bool {
  86. self.sbi.reset.is_some()
  87. }
  88. pub fn have_ipi(&self) -> bool {
  89. self.sbi.ipi.is_some()
  90. }
  91. pub fn have_hsm(&self) -> bool {
  92. self.sbi.hsm.is_some()
  93. }
  94. pub fn have_rfence(&self) -> bool {
  95. self.sbi.rfence.is_some()
  96. }
  97. pub fn ready(&self) -> bool {
  98. self.ready.load(Ordering::Acquire)
  99. }
  100. pub fn print_board_info(&self) {
  101. info!("RustSBI version {}", rustsbi::VERSION);
  102. rustsbi::LOGO.lines().for_each(|line| info!("{}", line));
  103. info!("Initializing RustSBI machine-mode environment.");
  104. info!("Number of CPU: {:?}", self.info.cpu_num);
  105. info!("Enabled hart: {:?}", self.info.cpu_enabled);
  106. info!("Model: {}", self.info.model);
  107. info!("Clint device: {:x?}", self.info.ipi);
  108. info!("Console device: {:x?}", self.info.console);
  109. }
  110. fn info_init(&mut self, dtb: &RefCell<Dtb>) {
  111. // TODO: should remove `fail:device_tree_deserialize`.
  112. let root: serde_device_tree::buildin::Node = serde_device_tree::from_raw_mut(&dtb)
  113. .unwrap_or_else(fail::device_tree_deserialize_root);
  114. let tree: dt::Tree = root.deserialize();
  115. // Get console device info
  116. for console_path in tree.chosen.stdout_path.iter() {
  117. if let Some(node) = root.find(console_path) {
  118. let info = dt::get_compatible_and_range(&node);
  119. let result = info.is_some_and(|info| {
  120. let (compatible, regs) = info;
  121. for device_id in compatible.iter() {
  122. if device_id == UART16650_COMPATIBLE {
  123. self.info.console = Some((regs.start, MachineConsoleType::Uart16550));
  124. return true;
  125. }
  126. if device_id == UARTAXILITE_COMPATIBLE {
  127. self.info.console = Some((regs.start, MachineConsoleType::UartAxiLite));
  128. return true;
  129. }
  130. }
  131. false
  132. });
  133. if result {
  134. break;
  135. }
  136. }
  137. }
  138. // Get ipi and reset device info
  139. let mut find_device = |node: &serde_device_tree::buildin::Node| {
  140. let info = dt::get_compatible_and_range(node);
  141. if let Some(info) = info {
  142. let (compatible, regs) = info;
  143. let base_address = regs.start;
  144. for device_id in compatible.iter() {
  145. // Initialize clint device.
  146. if device_id == SIFIVECLINT_COMPATIBLE {
  147. self.info.ipi = Some(base_address);
  148. }
  149. // Initialize reset device.
  150. if device_id == SIFIVETEST_COMPATIBLE {
  151. self.info.reset = Some(base_address);
  152. }
  153. }
  154. }
  155. };
  156. root.search(&mut find_device);
  157. // Get memory info
  158. // TODO: More than one memory node or range?
  159. let memory_reg = tree
  160. .memory
  161. .iter()
  162. .next()
  163. .unwrap()
  164. .deserialize::<dt::Memory>()
  165. .reg;
  166. let memory_range = memory_reg.iter().next().unwrap().0;
  167. self.info.memory_range = Some(memory_range);
  168. // Get cpu number info
  169. self.info.cpu_num = Some(tree.cpus.cpu.len());
  170. // Get model info
  171. if let Some(model) = tree.model {
  172. let model = model.iter().next().unwrap_or("<unspecified>");
  173. self.info.model.0 = model.as_bytes().len();
  174. self.info.model.1[..self.info.model.0].copy_from_slice(model.as_bytes());
  175. } else {
  176. let model = "<unspecified>";
  177. self.info.model.0 = model.as_bytes().len();
  178. self.info.model.1[..self.info.model.0].copy_from_slice(model.as_bytes());
  179. }
  180. // TODO: Need a better extension initialization method
  181. extensions::init(&tree.cpus.cpu);
  182. // Find which hart is enabled by fdt
  183. let mut cpu_list: CpuEnableList = [false; trap_stack::NUM_HART_MAX];
  184. for cpu_iter in tree.cpus.cpu.iter() {
  185. use dt::Cpu;
  186. let cpu = cpu_iter.deserialize::<Cpu>();
  187. let hart_id = cpu.reg.iter().next().unwrap().0.start;
  188. cpu_list.get_mut(hart_id).map(|x| *x = true);
  189. }
  190. self.info.cpu_enabled = Some(cpu_list);
  191. }
  192. fn sbi_init(&mut self) {
  193. self.sbi_console_init();
  194. self.sbi_ipi_init();
  195. self.sbi_hsm_init();
  196. self.sbi_reset_init();
  197. self.sbi_rfence_init();
  198. }
  199. fn sbi_console_init(&mut self) {
  200. if let Some((base, console_type)) = self.info.console {
  201. let new_console = match console_type {
  202. MachineConsoleType::Uart16550 => MachineConsole::Uart16550(base as _),
  203. MachineConsoleType::UartAxiLite => {
  204. MachineConsole::UartAxiLite(MmioUartAxiLite::new(base))
  205. }
  206. };
  207. self.sbi.console = Some(SbiConsole::new(Mutex::new(new_console)));
  208. } else {
  209. self.sbi.console = None;
  210. }
  211. }
  212. fn sbi_reset_init(&mut self) {
  213. if let Some(base) = self.info.reset {
  214. self.sbi.reset = Some(SbiReset::new(AtomicPtr::new(base as _)));
  215. } else {
  216. self.sbi.reset = None;
  217. }
  218. }
  219. fn sbi_ipi_init(&mut self) {
  220. if let Some(base) = self.info.ipi {
  221. self.sbi.ipi = Some(SbiIpi::new(
  222. AtomicPtr::new(base as _),
  223. self.info.cpu_num.unwrap_or(NUM_HART_MAX),
  224. ));
  225. } else {
  226. self.sbi.ipi = None;
  227. }
  228. }
  229. fn sbi_hsm_init(&mut self) {
  230. // TODO: Can HSM work properly when there is no ipi device?
  231. if self.info.ipi.is_some() {
  232. self.sbi.hsm = Some(SbiHsm);
  233. } else {
  234. self.sbi.hsm = None;
  235. }
  236. }
  237. fn sbi_rfence_init(&mut self) {
  238. // TODO: Can rfence work properly when there is no ipi device?
  239. if self.info.ipi.is_some() {
  240. self.sbi.rfence = Some(SbiRFence);
  241. } else {
  242. self.sbi.rfence = None;
  243. }
  244. }
  245. }
  246. pub(crate) static mut BOARD: Board = Board::new();
  247. /// Console Device: Uart16550
  248. #[doc(hidden)]
  249. #[allow(unused)]
  250. #[derive(Clone, Copy, Debug)]
  251. pub enum MachineConsoleType {
  252. Uart16550,
  253. UartAxiLite,
  254. }
  255. #[doc(hidden)]
  256. #[allow(unused)]
  257. pub enum MachineConsole {
  258. Uart16550(*const Uart16550<u8>),
  259. UartAxiLite(MmioUartAxiLite),
  260. }
  261. unsafe impl Send for MachineConsole {}
  262. unsafe impl Sync for MachineConsole {}
  263. impl ConsoleDevice for MachineConsole {
  264. fn read(&self, buf: &mut [u8]) -> usize {
  265. match self {
  266. Self::Uart16550(uart16550) => unsafe { (**uart16550).read(buf) },
  267. Self::UartAxiLite(axilite) => axilite.read(buf),
  268. }
  269. }
  270. fn write(&self, buf: &[u8]) -> usize {
  271. match self {
  272. MachineConsole::Uart16550(uart16550) => unsafe { (**uart16550).write(buf) },
  273. Self::UartAxiLite(axilite) => axilite.write(buf),
  274. }
  275. }
  276. }
  277. /// Ipi Device: Sifive Clint
  278. impl IpiDevice for SifiveClint {
  279. #[inline(always)]
  280. fn read_mtime(&self) -> u64 {
  281. self.read_mtime()
  282. }
  283. #[inline(always)]
  284. fn write_mtime(&self, val: u64) {
  285. self.write_mtime(val)
  286. }
  287. #[inline(always)]
  288. fn read_mtimecmp(&self, hart_idx: usize) -> u64 {
  289. self.read_mtimecmp(hart_idx)
  290. }
  291. #[inline(always)]
  292. fn write_mtimecmp(&self, hart_idx: usize, val: u64) {
  293. self.write_mtimecmp(hart_idx, val)
  294. }
  295. #[inline(always)]
  296. fn read_msip(&self, hart_idx: usize) -> bool {
  297. self.read_msip(hart_idx)
  298. }
  299. #[inline(always)]
  300. fn set_msip(&self, hart_idx: usize) {
  301. self.set_msip(hart_idx)
  302. }
  303. #[inline(always)]
  304. fn clear_msip(&self, hart_idx: usize) {
  305. self.clear_msip(hart_idx)
  306. }
  307. }
  308. /// Reset Device: SifiveTestDevice
  309. impl ResetDevice for SifiveTestDevice {
  310. #[inline]
  311. fn fail(&self, code: u16) -> ! {
  312. self.fail(code)
  313. }
  314. #[inline]
  315. fn pass(&self) -> ! {
  316. self.pass()
  317. }
  318. #[inline]
  319. fn reset(&self) -> ! {
  320. self.reset()
  321. }
  322. }