Ver Fonte

Merge pull request #32 from woshiluo/ipi_error

Add invalid parma error for ipi ext
guttatus há 4 meses atrás
pai
commit
5494737a73

+ 13 - 13
Cargo.lock

@@ -28,9 +28,9 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
 
 [[package]]
 name = "critical-section"
-version = "1.1.3"
+version = "1.2.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f64009896348fc5af4222e9cf7d7d82a95a256c634ebcf61c53e4ea461422242"
+checksum = "790eea4361631c5e7d22598ecd5723ff611904e3344ce8720784c93e3d83d40b"
 
 [[package]]
 name = "dtb-walker"
@@ -95,9 +95,9 @@ checksum = "de96540e0ebde571dc55c73d60ef407c653844e6f9a1e2fdbd40c07b9252d812"
 
 [[package]]
 name = "proc-macro2"
-version = "1.0.87"
+version = "1.0.92"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b3e4daa0dcf6feba26f985457cdf104d4b4256fc5a09547140f3631bb076b19a"
+checksum = "37d3544b3f2748c54e147655edb5025752e2303145b5aefb3c3ea2c78b973bb0"
 dependencies = [
  "unicode-ident",
 ]
@@ -235,9 +235,9 @@ checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49"
 
 [[package]]
 name = "serde"
-version = "1.0.210"
+version = "1.0.215"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c8e3592472072e6e22e0a54d5904d9febf8508f65fb8552499a1abc7d1078c3a"
+checksum = "6513c1ad0b11a9376da888e3e0baa0077f1aed55c17f50e7b2397136129fb88f"
 dependencies = [
  "serde_derive",
 ]
@@ -245,16 +245,16 @@ dependencies = [
 [[package]]
 name = "serde-device-tree"
 version = "0.0.1"
-source = "git+https://github.com/rustsbi/serde-device-tree#1c65f313c99ce73cfbfc954b1a58bcbcd885658c"
+source = "git+https://github.com/rustsbi/serde-device-tree#6d152e0160ff1dadd2f42638c3d85e0d6a2914bf"
 dependencies = [
  "serde",
 ]
 
 [[package]]
 name = "serde_derive"
-version = "1.0.210"
+version = "1.0.215"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "243902eda00fad750862fc144cea25caca5e20d615af0a81bee94ca738f1df1f"
+checksum = "ad1e866f866923f252f05c889987993144fb74e722403468a4ebd70c3cd756c0"
 dependencies = [
  "proc-macro2",
  "quote",
@@ -278,9 +278,9 @@ dependencies = [
 
 [[package]]
 name = "syn"
-version = "2.0.79"
+version = "2.0.89"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "89132cd0bf050864e1d38dc3bbc07a0eb8e7530af26344d3d2bbbef83499f590"
+checksum = "44d46482f1c1c87acd84dea20c1bf5ebff4c757009ed6bf19cfd36fb10e92c4e"
 dependencies = [
  "proc-macro2",
  "quote",
@@ -304,9 +304,9 @@ dependencies = [
 
 [[package]]
 name = "unicode-ident"
-version = "1.0.13"
+version = "1.0.14"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e91b56cd4cadaeb79bbf1a5645f6b4f8dc5bde8834ad5894a8db35fda9efa1fe"
+checksum = "adb9e6ca4f869e1180728b7950e35922a7fc6397f7b641499e8f3ef06e50dc83"
 
 [[package]]
 name = "vcell"

+ 2 - 1
Makefile.toml

@@ -7,7 +7,8 @@ args = ["clean"]
 
 [tasks.prototyper-nemu-build]
 command = "cargo"
-args = ["build", "-prustsbi-prototyper", "--release", "--features=nemu,payload"]
+args = ["build", "-prustsbi-prototyper", "--release", "--target", "riscv64imac-unknown-none-elf", "-Zbuild-std=core", "--features=nemu,payload"]
+env = {"RUSTFLAGS"="-C relocation-model=pie -C link-arg=-pie" }
 
 [tasks.prototyper-nemu]
 command = "rust-objcopy"

+ 6 - 47
prototyper/build.rs

@@ -11,11 +11,11 @@ fn main() {
     println!("cargo:rustc-link-search={}", out.display());
 }
 
-#[cfg(feature = "payload")]
 const LINKER_SCRIPT: &[u8] = b"OUTPUT_ARCH(riscv)
 ENTRY(_start) 
 SECTIONS {
     . = 0x80000000;
+    sbi_start = .;
     .text : ALIGN(8) { 
         *(.text.entry)
         *(.text .text.*)
@@ -34,6 +34,7 @@ SECTIONS {
         *(.rela*)
         __rel_dyn_end = .;
     }
+
     erodata = .;
     .data : ALIGN(8) { 
         sdata = .;
@@ -53,6 +54,10 @@ SECTIONS {
     /DISCARD/ : {
         *(.eh_frame)
     }
+
+    . = ALIGN(8);
+    sbi_end = .;
+
     .text 0x80100000 : ALIGN(8) {
         *(.fw_fdt)
     }
@@ -60,49 +65,3 @@ SECTIONS {
         *(.payload)
     }
 }";
-
-#[cfg(not(feature = "payload"))]
-const LINKER_SCRIPT: &[u8] = b"OUTPUT_ARCH(riscv)
-ENTRY(_start) 
-SECTIONS {
-    . = 0x80000000;
-    .text : ALIGN(8) { 
-        *(.text.entry)
-        *(.text .text.*)
-    }
-    .rodata : ALIGN(8) { 
-        srodata = .;
-        *(.rodata .rodata.*)
-        *(.srodata .srodata.*)
-        . = ALIGN(8);  
-    } 
-    .dynsym : ALIGN(8) {
-        *(.dynsym)
-    }
-    .rela.dyn : ALIGN(8) {
-        __rel_dyn_start = .;
-        *(.rela*)
-        __rel_dyn_end = .;
-    }
-
-    erodata = .;
-
-    .data : ALIGN(8) { 
-        sdata = .;
-        *(.data .data.*)
-        *(.sdata .sdata.*)
-        . = ALIGN(8); 
-        edata = .;
-    }
-    sidata = LOADADDR(.data);
-    .bss (NOLOAD) : ALIGN(8) {  
-        *(.bss.uninit)
-        sbss = .;
-        *(.bss .bss.*)
-        *(.sbss .sbss.*)
-        ebss = .;
-    } 
-    /DISCARD/ : {
-        *(.eh_frame)
-    }
-}";

+ 290 - 37
prototyper/src/board.rs

@@ -1,26 +1,307 @@
 use aclint::SifiveClint;
-use core::mem::MaybeUninit;
 use core::{
-    ptr::{null, null_mut},
-    sync::atomic::{AtomicPtr, Ordering::Release},
+    cell::RefCell,
+    fmt::{Display, Formatter, Result},
+    ops::Range,
+    sync::atomic::{AtomicBool, AtomicPtr, Ordering},
 };
+use serde_device_tree::Dtb;
 use sifive_test_device::SifiveTestDevice;
 use spin::Mutex;
 use uart16550::Uart16550;
 use uart_xilinx::uart_lite::uart::MmioUartAxiLite;
 
-use crate::sbi::console::ConsoleDevice;
-use crate::sbi::ipi::IpiDevice;
-use crate::sbi::reset::ResetDevice;
+use crate::fail;
+use crate::sbi::console::{ConsoleDevice, SbiConsole};
+use crate::sbi::extensions;
+use crate::sbi::hsm::SbiHsm;
+use crate::sbi::ipi::{IpiDevice, SbiIpi};
+use crate::sbi::logger;
+use crate::sbi::reset::{ResetDevice, SbiReset};
+use crate::sbi::trap_stack;
+use crate::sbi::trap_stack::NUM_HART_MAX;
 use crate::sbi::SBI;
+use crate::{dt, sbi::rfence::SbiRFence};
 
-pub(crate) static mut SBI_IMPL: MaybeUninit<
-    SBI<'static, MachineConsole, SifiveClint, SifiveTestDevice>,
-> = MaybeUninit::uninit();
+pub(crate) const UART16650_COMPATIBLE: &str = "ns16550a";
+pub(crate) const UARTAXILITE_COMPATIBLE: &str = "xlnx,xps-uartlite-1.00.a";
+pub(crate) const SIFIVETEST_COMPATIBLE: &str = "sifive,test0";
+pub(crate) const SIFIVECLINT_COMPATIBLE: &str = "riscv,clint0";
+
+type BaseAddress = usize;
+/// Store finite-length string on the stack.
+pub(crate) struct StringInline<const N: usize>(usize, [u8; N]);
+
+impl<const N: usize> Display for StringInline<N> {
+    fn fmt(&self, f: &mut Formatter<'_>) -> Result {
+        write!(f, "{}", unsafe {
+            core::str::from_utf8_unchecked(&self.1[..self.0])
+        })
+    }
+}
+
+type CpuEnableList = [bool; trap_stack::NUM_HART_MAX];
+
+pub struct BoardInfo {
+    pub memory_range: Option<Range<usize>>,
+    pub console: Option<(BaseAddress, MachineConsoleType)>,
+    pub reset: Option<BaseAddress>,
+    pub ipi: Option<BaseAddress>,
+    pub cpu_num: Option<usize>,
+    pub cpu_enabled: Option<CpuEnableList>,
+    pub model: StringInline<128>,
+}
+
+impl BoardInfo {
+    pub const fn new() -> Self {
+        BoardInfo {
+            memory_range: None,
+            console: None,
+            reset: None,
+            ipi: None,
+            cpu_enabled: None,
+            cpu_num: None,
+            model: StringInline(0, [0u8; 128]),
+        }
+    }
+}
+
+pub struct Board {
+    pub info: BoardInfo,
+    pub sbi: SBI<MachineConsole, SifiveClint, SifiveTestDevice>,
+    pub ready: AtomicBool,
+}
+
+#[allow(unused)]
+impl Board {
+    pub const fn new() -> Self {
+        Board {
+            info: BoardInfo::new(),
+            sbi: SBI::new(),
+            ready: AtomicBool::new(false),
+        }
+    }
+
+    pub fn init(&mut self, dtb: &RefCell<Dtb>) {
+        self.info_init(dtb);
+        self.sbi_init();
+        logger::Logger::init().unwrap();
+        trap_stack::prepare_for_trap();
+        self.ready.swap(true, Ordering::Release);
+    }
+
+    pub fn have_console(&self) -> bool {
+        match self.sbi.console {
+            None => false,
+            Some(_) => true,
+        }
+    }
+
+    pub fn have_reset(&self) -> bool {
+        match self.sbi.reset {
+            None => false,
+            Some(_) => true,
+        }
+    }
+
+    pub fn have_ipi(&self) -> bool {
+        match self.sbi.ipi {
+            None => false,
+            Some(_) => true,
+        }
+    }
+
+    pub fn have_hsm(&self) -> bool {
+        match self.sbi.hsm {
+            None => false,
+            Some(_) => true,
+        }
+    }
+
+    pub fn have_rfence(&self) -> bool {
+        match self.sbi.rfence {
+            None => false,
+            Some(_) => true,
+        }
+    }
+
+    pub fn ready(&self) -> bool {
+        self.ready.load(Ordering::Acquire)
+    }
+
+    pub fn print_board_info(&self) {
+        info!("RustSBI version {}", rustsbi::VERSION);
+        rustsbi::LOGO.lines().for_each(|line| info!("{}", line));
+        info!("Initializing RustSBI machine-mode environment.");
+        info!("Number of CPU: {:?}", self.info.cpu_num);
+        info!("Enabled hart: {:?}", self.info.cpu_enabled);
+        info!("Model: {}", self.info.model);
+        info!("Clint device: {:x?}", self.info.ipi);
+        info!("Console device: {:x?}", self.info.console);
+    }
+
+    fn info_init(&mut self, dtb: &RefCell<Dtb>) {
+        // TODO: should remove `fail:device_tree_deserialize`.
+        let root: serde_device_tree::buildin::Node = serde_device_tree::from_raw_mut(&dtb)
+            .unwrap_or_else(fail::device_tree_deserialize_root);
+        let tree: dt::Tree = root.deserialize();
+
+        //  Get console device info
+        for console_path in tree.chosen.stdout_path.iter() {
+            if let Some(node) = root.find(console_path) {
+                let info = dt::get_compatible_and_range(&node);
+                let result = info.is_some_and(|info| {
+                    let (compatible, regs) = info;
+                    for device_id in compatible.iter() {
+                        if device_id == UART16650_COMPATIBLE {
+                            self.info.console = Some((regs.start, MachineConsoleType::Uart16550));
+                            return true;
+                        }
+                        if device_id == UARTAXILITE_COMPATIBLE {
+                            self.info.console = Some((regs.start, MachineConsoleType::UartAxiLite));
+                            return true;
+                        }
+                    }
+                    false
+                });
+                if result {
+                    break;
+                }
+            }
+        }
+
+        // Get ipi and reset device info
+        let mut find_device = |node: &serde_device_tree::buildin::Node| {
+            let info = dt::get_compatible_and_range(node);
+            if let Some(info) = info {
+                let (compatible, regs) = info;
+                let base_address = regs.start;
+                for device_id in compatible.iter() {
+                    // Initialize clint device.
+                    if device_id == SIFIVECLINT_COMPATIBLE {
+                        self.info.ipi = Some(base_address);
+                    }
+                    // Initialize reset device.
+                    if device_id == SIFIVETEST_COMPATIBLE {
+                        self.info.reset = Some(base_address);
+                    }
+                }
+            }
+        };
+        root.search(&mut find_device);
+
+        // Get memory info
+        // TODO: More than one memory node or range?
+        let memory_reg = tree
+            .memory
+            .iter()
+            .next()
+            .unwrap()
+            .deserialize::<dt::Memory>()
+            .reg;
+        let memory_range = memory_reg.iter().next().unwrap().0;
+        self.info.memory_range = Some(memory_range);
+
+        // Get cpu number info
+        self.info.cpu_num = Some(tree.cpus.cpu.len());
+
+        // Get model info
+        if let Some(model) = tree.model {
+            let model = model.iter().next().unwrap_or("<unspecified>");
+            self.info.model.0 = model.as_bytes().len();
+            self.info.model.1[..self.info.model.0].copy_from_slice(model.as_bytes());
+        } else {
+            let model = "<unspecified>";
+            self.info.model.0 = model.as_bytes().len();
+            self.info.model.1[..self.info.model.0].copy_from_slice(model.as_bytes());
+        }
+
+        // TODO: Need a better extension initialization method
+        extensions::init(&tree.cpus.cpu);
+
+        // Find which hart is enabled by fdt
+        let mut cpu_list: CpuEnableList = [false; trap_stack::NUM_HART_MAX];
+        for cpu_iter in tree.cpus.cpu.iter() {
+            use dt::Cpu;
+            let cpu = cpu_iter.deserialize::<Cpu>();
+            let hart_id = cpu.reg.iter().next().unwrap().0.start;
+            cpu_list.get_mut(hart_id).map(|x| *x = true);
+        }
+        self.info.cpu_enabled = Some(cpu_list);
+    }
+
+    fn sbi_init(&mut self) {
+        self.sbi_console_init();
+        self.sbi_ipi_init();
+        self.sbi_hsm_init();
+        self.sbi_reset_init();
+        self.sbi_rfence_init();
+    }
+
+    fn sbi_console_init(&mut self) {
+        if let Some((base, console_type)) = self.info.console {
+            let new_console = match console_type {
+                MachineConsoleType::Uart16550 => MachineConsole::Uart16550(base as _),
+                MachineConsoleType::UartAxiLite => {
+                    MachineConsole::UartAxiLite(MmioUartAxiLite::new(base))
+                }
+            };
+            self.sbi.console = Some(SbiConsole::new(Mutex::new(new_console)));
+        } else {
+            self.sbi.console = None;
+        }
+    }
+
+    fn sbi_reset_init(&mut self) {
+        if let Some(base) = self.info.reset {
+            self.sbi.reset = Some(SbiReset::new(AtomicPtr::new(base as _)));
+        } else {
+            self.sbi.reset = None;
+        }
+    }
+
+    fn sbi_ipi_init(&mut self) {
+        if let Some(base) = self.info.ipi {
+            self.sbi.ipi = Some(SbiIpi::new(
+                AtomicPtr::new(base as _),
+                self.info.cpu_num.unwrap_or(NUM_HART_MAX),
+            ));
+        } else {
+            self.sbi.ipi = None;
+        }
+    }
+
+    fn sbi_hsm_init(&mut self) {
+        // TODO: Can HSM work properly when there is no ipi device?
+        if let Some(_) = self.info.ipi {
+            self.sbi.hsm = Some(SbiHsm);
+        } else {
+            self.sbi.hsm = None;
+        }
+    }
+
+    fn sbi_rfence_init(&mut self) {
+        // TODO: Can rfence work properly when there is no ipi device?
+        if let Some(_) = self.info.ipi {
+            self.sbi.rfence = Some(SbiRFence);
+        } else {
+            self.sbi.rfence = None;
+        }
+    }
+}
+
+pub(crate) static mut BOARD: Board = Board::new();
 
 /// Console Device: Uart16550
 #[doc(hidden)]
 #[allow(unused)]
+#[derive(Clone, Copy, Debug)]
+pub enum MachineConsoleType {
+    Uart16550,
+    UartAxiLite,
+}
+#[doc(hidden)]
+#[allow(unused)]
 pub enum MachineConsole {
     Uart16550(*const Uart16550<u8>),
     UartAxiLite(MmioUartAxiLite),
@@ -45,22 +326,6 @@ impl ConsoleDevice for MachineConsole {
     }
 }
 
-// TODO: select driver follow fdt
-
-#[doc(hidden)]
-#[cfg(feature = "nemu")]
-pub(crate) static UART: Mutex<MachineConsole> =
-    Mutex::new(MachineConsole::UartAxiLite(MmioUartAxiLite::new(0)));
-#[cfg(not(feature = "nemu"))]
-pub(crate) static UART: Mutex<MachineConsole> = Mutex::new(MachineConsole::Uart16550(null()));
-pub(crate) fn console_dev_init(base: usize) {
-    let new_console = match *UART.lock() {
-        MachineConsole::Uart16550(_) => MachineConsole::Uart16550(base as _),
-        MachineConsole::UartAxiLite(_) => MachineConsole::UartAxiLite(MmioUartAxiLite::new(base)),
-    };
-    *UART.lock() = new_console;
-}
-
 /// Ipi Device: Sifive Clint
 impl IpiDevice for SifiveClint {
     #[inline(always)]
@@ -99,12 +364,6 @@ impl IpiDevice for SifiveClint {
     }
 }
 
-#[doc(hidden)]
-pub(crate) static SIFIVECLINT: AtomicPtr<SifiveClint> = AtomicPtr::new(null_mut());
-pub(crate) fn ipi_dev_init(base: usize) {
-    SIFIVECLINT.store(base as _, Release);
-}
-
 /// Reset Device: SifiveTestDevice
 impl ResetDevice for SifiveTestDevice {
     #[inline]
@@ -122,9 +381,3 @@ impl ResetDevice for SifiveTestDevice {
         self.reset()
     }
 }
-
-#[doc(hidden)]
-pub(crate) static SIFIVETEST: AtomicPtr<SifiveTestDevice> = AtomicPtr::new(null_mut());
-pub fn reset_dev_init(base: usize) {
-    SIFIVETEST.store(base as _, Release);
-}

+ 37 - 14
prototyper/src/dt.rs

@@ -1,9 +1,11 @@
 use serde::Deserialize;
 use serde_device_tree::{
-    buildin::{NodeSeq, Reg, StrSeq},
+    buildin::{Node, NodeSeq, Reg, StrSeq},
     Dtb, DtbPtr,
 };
 
+use core::ops::Range;
+
 /// Root device tree structure containing system information.
 #[derive(Deserialize)]
 pub struct Tree<'a> {
@@ -11,10 +13,10 @@ pub struct Tree<'a> {
     pub model: Option<StrSeq<'a>>,
     /// Chosen node containing boot parameters.
     pub chosen: Chosen<'a>,
+    /// Memory information.
+    pub memory: NodeSeq<'a>,
     /// CPU information.
     pub cpus: Cpus<'a>,
-    /// System-on-chip components.
-    pub soc: Soc<'a>,
 }
 
 /// Chosen node containing boot parameters.
@@ -43,17 +45,6 @@ pub struct Cpu<'a> {
     pub reg: Reg<'a>,
 }
 
-/// System-on-chip components.
-#[derive(Deserialize, Debug)]
-pub struct Soc<'a> {
-    /// Serial (UART) device nodes.
-    pub serial: Option<NodeSeq<'a>>,
-    /// Test device nodes.
-    pub test: Option<NodeSeq<'a>>,
-    /// CLINT (Core Local Interruptor) nodes.
-    pub clint: Option<NodeSeq<'a>>,
-}
-
 /// Generic device node information.
 #[allow(unused)]
 #[derive(Deserialize, Debug)]
@@ -62,6 +53,13 @@ pub struct Device<'a> {
     pub reg: Reg<'a>,
 }
 
+/// Memory range.
+#[derive(Deserialize)]
+#[serde(rename_all = "kebab-case")]
+pub struct Memory<'a> {
+    pub reg: Reg<'a>,
+}
+
 /// Errors that can occur during device tree parsing.
 pub enum ParseDeviceTreeError {
     /// Invalid device tree format.
@@ -75,3 +73,28 @@ pub fn parse_device_tree(opaque: usize) -> Result<Dtb, ParseDeviceTreeError> {
     let dtb = Dtb::from(ptr);
     Ok(dtb)
 }
+
+pub fn get_compatible_and_range<'de>(node: &Node) -> Option<(StrSeq<'de>, Range<usize>)> {
+    let compatible = node
+        .get_prop("compatible")
+        .map(|prop_item| prop_item.deserialize::<StrSeq<'de>>());
+    let regs = node
+        .get_prop("reg")
+        .map(|prop_item| {
+            let reg = prop_item.deserialize::<serde_device_tree::buildin::Reg>();
+            if let Some(range) = reg.iter().next() {
+                return Some(range);
+            }
+            None
+        })
+        .map_or_else(|| None, |v| v);
+    if let Some(compatible) = compatible {
+        if let Some(regs) = regs {
+            Some((compatible, regs.0))
+        } else {
+            None
+        }
+    } else {
+        None
+    }
+}

+ 12 - 9
prototyper/src/fail.rs

@@ -1,6 +1,6 @@
 use serde_device_tree::Dtb;
 
-use crate::dt::{self, ParseDeviceTreeError, Tree};
+use crate::dt;
 use crate::sbi::reset;
 
 #[cfg(not(feature = "payload"))]
@@ -8,20 +8,23 @@ use crate::platform::dynamic;
 #[cfg(not(feature = "payload"))]
 use riscv::register::mstatus;
 
+// TODO: Need a better way to handle device tree parsing errors
+
 /// Handles device tree format parsing errors by logging and resetting.
 #[cold]
-pub fn device_tree_format(err: dt::ParseDeviceTreeError) -> Dtb {
-    match err {
-        ParseDeviceTreeError::Format => error!("- FDT format error"),
+pub fn device_tree_format(_err: dt::ParseDeviceTreeError) -> Dtb {
+    loop {
+        core::hint::spin_loop()
     }
-    reset::fail()
 }
 
-/// Handles device tree deserialization errors by logging and resetting.
 #[cold]
-pub fn device_tree_deserialize<'a>(err: serde_device_tree::error::Error) -> Tree<'a> {
-    error!("Device tree deserialization error: {:?}", err);
-    reset::fail()
+pub fn device_tree_deserialize_root<'a>(
+    _err: serde_device_tree::error::Error,
+) -> serde_device_tree::buildin::Node<'a> {
+    loop {
+        core::hint::spin_loop()
+    }
 }
 
 /// Handles invalid dynamic information data by logging details and resetting.

+ 10 - 6
prototyper/src/macros.rs

@@ -4,9 +4,11 @@
 macro_rules! print {
     ($($arg:tt)*) => {
         use core::fmt::Write;
-        let console = unsafe { $crate::board::SBI_IMPL.assume_init_mut() }.console.as_mut().unwrap();
-        console.write_fmt(core::format_args!($($arg)*)).unwrap();
-        drop(console);
+        if unsafe {$crate::board::BOARD.have_console()} {
+            let console = unsafe { $crate::board::BOARD.sbi.console.as_mut().unwrap() };
+            console.write_fmt(core::format_args!($($arg)*)).unwrap();
+            drop(console);
+        }
     }
 }
 
@@ -15,8 +17,10 @@ macro_rules! println {
     () => ($crate::print!("\n"));
     ($($arg:tt)*) => {{
         use core::fmt::Write;
-        let console = unsafe { $crate::board::SBI_IMPL.assume_init_mut() }.console.as_mut().unwrap();
-        console.write_fmt(core::format_args!($($arg)*)).unwrap();
-        console.write_char('\n').unwrap();
+        if unsafe {$crate::board::BOARD.have_console()} {
+            let console = unsafe { $crate::board::BOARD.sbi.console.as_mut().unwrap() };
+            console.write_fmt(core::format_args!($($arg)*)).unwrap();
+            console.write_char('\n').unwrap();
+        }
     }}
 }

+ 15 - 97
prototyper/src/main.rs

@@ -15,24 +15,16 @@ mod platform;
 mod riscv_spec;
 mod sbi;
 
-use core::sync::atomic::{AtomicBool, Ordering};
-use core::{arch::asm, mem::MaybeUninit};
+use core::arch::asm;
 
-use sbi::extensions;
-
-use crate::board::{SBI_IMPL, SIFIVECLINT, SIFIVETEST, UART};
+use crate::board::BOARD;
 use crate::riscv_spec::{current_hartid, menvcfg};
-use crate::sbi::console::SbiConsole;
 use crate::sbi::extensions::{hart_extension_probe, Extension};
 use crate::sbi::hart_context::NextStage;
-use crate::sbi::hsm::{local_remote_hsm, SbiHsm};
-use crate::sbi::ipi::{self, SbiIpi};
-use crate::sbi::logger;
-use crate::sbi::reset::SbiReset;
-use crate::sbi::rfence::SbiRFence;
+use crate::sbi::hsm::local_remote_hsm;
+use crate::sbi::ipi;
 use crate::sbi::trap::{self, trap_vec};
 use crate::sbi::trap_stack;
-use crate::sbi::SBI;
 
 pub const START_ADDRESS: usize = 0x80000000;
 pub const R_RISCV_RELATIVE: usize = 3;
@@ -40,88 +32,23 @@ pub const R_RISCV_RELATIVE: usize = 3;
 #[no_mangle]
 extern "C" fn rust_main(_hart_id: usize, opaque: usize, nonstandard_a2: usize) {
     // Track whether SBI is initialized and ready.
-    static SBI_READY: AtomicBool = AtomicBool::new(false);
 
     let boot_hart_info = platform::get_boot_hart(opaque, nonstandard_a2);
     // boot hart task entry.
     if boot_hart_info.is_boot_hart {
+        // parse the device tree
         let fdt_addr = boot_hart_info.fdt_address;
+        let dtb = dt::parse_device_tree(fdt_addr).unwrap_or_else(fail::device_tree_format);
+        let dtb = dtb.share();
 
         // 1. Init FDT
         // parse the device tree.
         // TODO: should remove `fail:device_tree_format`.
-        let dtb = dt::parse_device_tree(fdt_addr).unwrap_or_else(fail::device_tree_format);
-        let dtb = dtb.share();
-
-        // TODO: should remove `fail:device_tree_deserialize`.
-        let tree =
-            serde_device_tree::from_raw_mut(&dtb).unwrap_or_else(fail::device_tree_deserialize);
-
-        // 2. Init device
-        // TODO: The device base address should be find in a better way.
-        let console_base = tree.soc.serial.unwrap().iter().next().unwrap();
-        let clint_device = tree.soc.clint.unwrap().iter().next().unwrap();
-        let cpu_num = tree.cpus.cpu.len();
-        let console_base_address = console_base.at();
-        let ipi_base_address = clint_device.at();
-
-        // Initialize reset device if present.
-        if let Some(test) = tree.soc.test {
-            let reset_device = test.iter().next().unwrap();
-            let reset_base_address = reset_device.at();
-            board::reset_dev_init(usize::from_str_radix(reset_base_address, 16).unwrap());
-        }
-
-        // Initialize console and IPI devices.
-        board::console_dev_init(usize::from_str_radix(console_base_address, 16).unwrap());
-        board::ipi_dev_init(usize::from_str_radix(ipi_base_address, 16).unwrap());
-
-        // 3. Init the SBI implementation
         unsafe {
-            SBI_IMPL = MaybeUninit::new(SBI {
-                console: Some(SbiConsole::new(&UART)),
-                ipi: Some(SbiIpi::new(&SIFIVECLINT, cpu_num)),
-                hsm: Some(SbiHsm),
-                reset: Some(SbiReset::new(&SIFIVETEST)),
-                rfence: Some(SbiRFence),
-            });
-        }
-
-        // Setup trap handling.
-        trap_stack::prepare_for_trap();
-        extensions::init(&tree.cpus.cpu);
-        SBI_READY.swap(true, Ordering::AcqRel);
-
-        // 4. Init Logger
-        logger::Logger::init().unwrap();
-
-        info!("RustSBI version {}", rustsbi::VERSION);
-        rustsbi::LOGO.lines().for_each(|line| info!("{}", line));
-        info!("Initializing RustSBI machine-mode environment.");
-
-        info!("Number of CPU: {}", cpu_num);
-        if let Some(model) = tree.model {
-            info!("Model: {}", model.iter().next().unwrap_or("<unspecified>"));
-        }
-        info!("Clint device: {}", ipi_base_address);
-        info!("Console device: {}", console_base_address);
-        info!(
-            "Chosen stdout item: {}",
-            tree.chosen
-                .stdout_path
-                .iter()
-                .next()
-                .unwrap_or("<unspecified>")
-        );
-
-        // TODO: PMP configuration needs to be obtained through the memory range in the device tree
-        use riscv::register::*;
-        unsafe {
-            pmpcfg0::set_pmp(0, Range::OFF, Permission::NONE, false);
-            pmpaddr0::write(0);
-            pmpcfg0::set_pmp(1, Range::TOR, Permission::RWX, false);
-            pmpaddr1::write(usize::MAX >> 2);
+            BOARD.init(&dtb);
+            BOARD.print_board_info();
         }
+        platform::set_pmp(unsafe { BOARD.info.memory_range.as_ref().unwrap() });
 
         // Get boot information and prepare for kernel entry.
         let boot_info = platform::get_boot_info(nonstandard_a2);
@@ -141,24 +68,15 @@ extern "C" fn rust_main(_hart_id: usize, opaque: usize, nonstandard_a2: usize) {
             mpp
         );
     } else {
-        // Non-boot hart initialization path.
-
-        // TODO: PMP configuration needs to be obtained through the memory range in the device tree.
-        use riscv::register::*;
-        unsafe {
-            pmpcfg0::set_pmp(0, Range::OFF, Permission::NONE, false);
-            pmpaddr0::write(0);
-            pmpcfg0::set_pmp(1, Range::TOR, Permission::RWX, false);
-            pmpaddr1::write(usize::MAX >> 2);
-        }
-
-        // Setup trap handling.
+        // 设置陷入栈
         trap_stack::prepare_for_trap();
 
         // Wait for boot hart to complete SBI initialization.
-        while !SBI_READY.load(Ordering::Relaxed) {
+        while !unsafe { BOARD.ready() } {
             core::hint::spin_loop()
         }
+
+        platform::set_pmp(unsafe { BOARD.info.memory_range.as_ref().unwrap() });
     }
 
     // Clear all pending IPIs.
@@ -240,7 +158,7 @@ unsafe extern "C" fn relocation_update() {
     asm!(
         // Get load offset.
         "   li t0, {START_ADDRESS}",
-        "   lla t1, .text.entry",
+        "   lla t1, sbi_start",
         "   sub t2, t1, t0",
 
         // Foreach rela.dyn and update relocation.

+ 29 - 0
prototyper/src/platform/mod.rs

@@ -3,6 +3,8 @@ pub mod dynamic;
 #[cfg(feature = "payload")]
 pub mod payload;
 
+use core::arch::asm;
+use core::ops::Range;
 use riscv::register::mstatus;
 
 pub struct BootInfo {
@@ -19,3 +21,30 @@ pub struct BootHart {
 pub use dynamic::{get_boot_hart, get_boot_info};
 #[cfg(feature = "payload")]
 pub use payload::{get_boot_hart, get_boot_info};
+
+pub fn set_pmp(memory_range: &Range<usize>) {
+    unsafe {
+        // [0..memory_range.start] RW
+        // [memory_range.start..sbi_start] RWX
+        // [sbi_start..sbi_end] NONE
+        // [sbi_end..memory_range.end] RWX
+        // [memory_range.end..INF] RW
+        use riscv::register::*;
+        let mut sbi_start_address: usize;
+        let mut sbi_end_address: usize;
+        asm!("la {}, sbi_start", out(reg) sbi_start_address, options(nomem));
+        asm!("la {}, sbi_end", out(reg) sbi_end_address, options(nomem));
+        pmpcfg0::set_pmp(0, Range::OFF, Permission::NONE, false);
+        pmpaddr0::write(0);
+        pmpcfg0::set_pmp(1, Range::TOR, Permission::RW, false);
+        pmpaddr1::write(memory_range.start >> 2);
+        pmpcfg0::set_pmp(2, Range::TOR, Permission::RWX, false);
+        pmpaddr2::write(sbi_start_address >> 2);
+        pmpcfg0::set_pmp(3, Range::TOR, Permission::NONE, false);
+        pmpaddr3::write(sbi_end_address >> 2);
+        pmpcfg0::set_pmp(4, Range::TOR, Permission::RWX, false);
+        pmpaddr4::write(memory_range.end >> 2);
+        pmpcfg0::set_pmp(5, Range::TOR, Permission::RW, false);
+        pmpaddr5::write(usize::MAX >> 2);
+    }
+}

+ 9 - 17
prototyper/src/sbi/console.rs

@@ -1,4 +1,4 @@
-use crate::board::SBI_IMPL;
+use crate::board::BOARD;
 use core::fmt::{self, Write};
 use rustsbi::{Console, Physical, SbiRet};
 use spin::Mutex;
@@ -22,17 +22,17 @@ pub trait ConsoleDevice {
 ///
 /// This provides a safe interface for interacting with console hardware through the
 /// SBI specification.
-pub struct SbiConsole<'a, T: ConsoleDevice> {
-    inner: &'a Mutex<T>,
+pub struct SbiConsole<T: ConsoleDevice> {
+    inner: Mutex<T>,
 }
 
-impl<'a, T: ConsoleDevice> SbiConsole<'a, T> {
+impl<T: ConsoleDevice> SbiConsole<T> {
     /// Creates a new SBI console that wraps the provided locked console device.
     ///
     /// # Arguments
     /// * `inner` - A mutex containing the console device implementation
     #[inline]
-    pub fn new(inner: &'a Mutex<T>) -> Self {
+    pub fn new(inner: Mutex<T>) -> Self {
         Self { inner }
     }
 
@@ -67,7 +67,7 @@ impl<'a, T: ConsoleDevice> SbiConsole<'a, T> {
     }
 }
 
-impl<'a, T: ConsoleDevice> Console for SbiConsole<'a, T> {
+impl<T: ConsoleDevice> Console for SbiConsole<T> {
     /// Write a physical memory buffer to the console.
     #[inline]
     fn write(&self, bytes: Physical<&[u8]>) -> SbiRet {
@@ -96,7 +96,7 @@ impl<'a, T: ConsoleDevice> Console for SbiConsole<'a, T> {
     }
 }
 
-impl<'a, T: ConsoleDevice> fmt::Write for SbiConsole<'a, T> {
+impl<T: ConsoleDevice> fmt::Write for SbiConsole<T> {
     /// Implement Write trait for string formatting.
     #[inline]
     fn write_str(&mut self, s: &str) -> fmt::Result {
@@ -114,19 +114,11 @@ impl<'a, T: ConsoleDevice> fmt::Write for SbiConsole<'a, T> {
 /// Global function to write a character to the console.
 #[inline]
 pub fn putchar(c: usize) -> usize {
-    unsafe { SBI_IMPL.assume_init_mut() }
-        .console
-        .as_mut()
-        .unwrap()
-        .putchar(c)
+    unsafe { BOARD.sbi.console.as_mut().unwrap().putchar(c) }
 }
 
 /// Global function to read a character from the console.
 #[inline]
 pub fn getchar() -> usize {
-    unsafe { SBI_IMPL.assume_init_mut() }
-        .console
-        .as_mut()
-        .unwrap()
-        .getchar()
+    unsafe { BOARD.sbi.console.as_mut().unwrap().getchar() }
 }

+ 7 - 16
prototyper/src/sbi/hsm.rs

@@ -6,7 +6,7 @@ use core::{
 use riscv::register::mstatus::MPP;
 use rustsbi::{spec::hsm::hart_state, SbiRet};
 
-use crate::board::SBI_IMPL;
+use crate::board::BOARD;
 use crate::riscv_spec::current_hartid;
 use crate::sbi::hart_context::NextStage;
 use crate::sbi::trap_stack::ROOT_STACK;
@@ -195,11 +195,9 @@ impl rustsbi::Hsm for SbiHsm {
                     opaque,
                     next_mode: MPP::Supervisor,
                 }) {
-                    unsafe { SBI_IMPL.assume_init_ref() }
-                        .ipi
-                        .as_ref()
-                        .unwrap()
-                        .set_msip(hartid);
+                    unsafe {
+                        BOARD.sbi.ipi.as_ref().unwrap().set_msip(hartid);
+                    }
                     SbiRet::success(0)
                 } else {
                     SbiRet::already_started()
@@ -213,11 +211,6 @@ impl rustsbi::Hsm for SbiHsm {
     #[inline]
     fn hart_stop(&self) -> SbiRet {
         local_hsm().stop();
-        unsafe { SBI_IMPL.assume_init_ref() }
-            .ipi
-            .as_ref()
-            .unwrap()
-            .clear_msip(current_hartid());
         unsafe {
             riscv::register::mie::clear_msoft();
         }
@@ -239,11 +232,9 @@ impl rustsbi::Hsm for SbiHsm {
         use rustsbi::spec::hsm::suspend_type::{NON_RETENTIVE, RETENTIVE};
         if matches!(suspend_type, NON_RETENTIVE | RETENTIVE) {
             local_hsm().suspend();
-            unsafe { SBI_IMPL.assume_init_ref() }
-                .ipi
-                .as_ref()
-                .unwrap()
-                .clear_msip(current_hartid());
+            unsafe {
+                BOARD.sbi.ipi.as_ref().unwrap().clear_msip(current_hartid());
+            }
             unsafe {
                 riscv::register::mie::set_msoft();
             }

+ 69 - 14
prototyper/src/sbi/ipi.rs

@@ -1,7 +1,7 @@
 use core::sync::atomic::{AtomicPtr, Ordering::Relaxed};
-use rustsbi::SbiRet;
+use rustsbi::{HartMask, SbiRet};
 
-use crate::board::SBI_IMPL;
+use crate::board::BOARD;
 use crate::riscv_spec::{current_hartid, stimecmp};
 use crate::sbi::extensions::{hart_extension_probe, Extension};
 use crate::sbi::hsm::remote_hsm;
@@ -34,14 +34,14 @@ pub trait IpiDevice {
 }
 
 /// SBI IPI implementation.
-pub struct SbiIpi<'a, T: IpiDevice> {
+pub struct SbiIpi<T: IpiDevice> {
     /// Reference to atomic pointer to IPI device.
-    pub ipi_dev: &'a AtomicPtr<T>,
+    pub ipi_dev: AtomicPtr<T>,
     /// Maximum hart ID in the system
     pub max_hart_id: usize,
 }
 
-impl<'a, T: IpiDevice> rustsbi::Timer for SbiIpi<'a, T> {
+impl<T: IpiDevice> rustsbi::Timer for SbiIpi<T> {
     /// Set timer value for current hart.
     #[inline]
     fn set_timer(&self, stime_value: u64) {
@@ -64,22 +64,42 @@ impl<'a, T: IpiDevice> rustsbi::Timer for SbiIpi<'a, T> {
     }
 }
 
-impl<'a, T: IpiDevice> rustsbi::Ipi for SbiIpi<'a, T> {
+impl<T: IpiDevice> rustsbi::Ipi for SbiIpi<T> {
     /// Send IPI to specified harts.
     #[inline]
     fn send_ipi(&self, hart_mask: rustsbi::HartMask) -> SbiRet {
         let ipi_dev = unsafe { &*self.ipi_dev.load(Relaxed) };
+        let mut hart_mask = hart_mask;
 
         for hart_id in 0..=self.max_hart_id {
             if !hart_mask.has_bit(hart_id) {
                 continue;
             }
 
+            // There are 2 situation to return invalid_param:
+            // 1. We can not get hsm, which usually means this hart_id is bigger than MAX_HART_ID.
+            // 2. BOARD hasn't init or this hart_id is not enabled by device tree.
+            // In the next loop, we'll assume that all of above situation will not happend and
+            // directly send ipi.
             let Some(hsm) = remote_hsm(hart_id) else {
-                continue;
+                return SbiRet::invalid_param();
             };
 
+            if unsafe {
+                BOARD
+                    .info
+                    .cpu_enabled
+                    .is_none_or(|list| list.get(hart_id).is_none_or(|res| !(*res)))
+            } {
+                return SbiRet::invalid_param();
+            }
+
             if !hsm.allow_ipi() {
+                hart_mask = hart_mask_clear(hart_mask, hart_id);
+            }
+        }
+        for hart_id in 0..=self.max_hart_id {
+            if !hart_mask.has_bit(hart_id) {
                 continue;
             }
 
@@ -92,10 +112,10 @@ impl<'a, T: IpiDevice> rustsbi::Ipi for SbiIpi<'a, T> {
     }
 }
 
-impl<'a, T: IpiDevice> SbiIpi<'a, T> {
+impl<T: IpiDevice> SbiIpi<T> {
     /// Create new SBI IPI instance.
     #[inline]
-    pub fn new(ipi_dev: &'a AtomicPtr<T>, max_hart_id: usize) -> Self {
+    pub fn new(ipi_dev: AtomicPtr<T>, max_hart_id: usize) -> Self {
         Self {
             ipi_dev,
             max_hart_id,
@@ -110,18 +130,39 @@ impl<'a, T: IpiDevice> SbiIpi<'a, T> {
     ) -> SbiRet {
         let current_hart = current_hartid();
         let ipi_dev = unsafe { &*self.ipi_dev.load(Relaxed) };
+        let mut hart_mask = hart_mask;
 
-        // Send fence operations to target harts
         for hart_id in 0..=self.max_hart_id {
             if !hart_mask.has_bit(hart_id) {
                 continue;
             }
 
+            // There are 2 situation to return invalid_param:
+            // 1. We can not get hsm, which usually means this hart_id is bigger than MAX_HART_ID.
+            // 2. BOARD hasn't init or this hart_id is not enabled by device tree.
+            // In the next loop, we'll assume that all of above situation will not happend and
+            // directly send ipi.
             let Some(hsm) = remote_hsm(hart_id) else {
-                continue;
+                return SbiRet::invalid_param();
             };
 
+            if unsafe {
+                BOARD
+                    .info
+                    .cpu_enabled
+                    .is_none_or(|list| list.get(hart_id).is_none_or(|res| !(*res)))
+            } {
+                return SbiRet::invalid_param();
+            }
+
             if !hsm.allow_ipi() {
+                hart_mask = hart_mask_clear(hart_mask, hart_id);
+            }
+        }
+
+        // Send fence operations to target harts
+        for hart_id in 0..=self.max_hart_id {
+            if !hart_mask.has_bit(hart_id) {
                 continue;
             }
 
@@ -213,7 +254,7 @@ pub fn get_and_reset_ipi_type() -> u8 {
 /// Clear machine software interrupt pending for current hart.
 #[inline]
 pub fn clear_msip() {
-    match unsafe { SBI_IMPL.as_ptr().as_ref().and_then(|sbi| sbi.ipi.as_ref()) } {
+    match unsafe { BOARD.sbi.ipi.as_ref() } {
         Some(ipi) => ipi.clear_msip(current_hartid()),
         None => error!("SBI or IPI device not initialized"),
     }
@@ -222,7 +263,7 @@ pub fn clear_msip() {
 /// Clear machine timer interrupt for current hart.
 #[inline]
 pub fn clear_mtime() {
-    match unsafe { SBI_IMPL.as_ptr().as_ref().and_then(|sbi| sbi.ipi.as_ref()) } {
+    match unsafe { BOARD.sbi.ipi.as_ref() } {
         Some(ipi) => ipi.write_mtimecmp(current_hartid(), u64::MAX),
         None => error!("SBI or IPI device not initialized"),
     }
@@ -231,8 +272,22 @@ pub fn clear_mtime() {
 /// Clear all pending interrupts for current hart.
 #[inline]
 pub fn clear_all() {
-    match unsafe { SBI_IMPL.as_ptr().as_ref().and_then(|sbi| sbi.ipi.as_ref()) } {
+    match unsafe { BOARD.sbi.ipi.as_ref() } {
         Some(ipi) => ipi.clear(),
         None => error!("SBI or IPI device not initialized"),
     }
 }
+
+pub fn hart_mask_clear(hart_mask: HartMask, hart_id: usize) -> HartMask {
+    let (mask, mask_base) = hart_mask.into_inner();
+    if mask_base == usize::MAX {
+        return HartMask::from_mask_base(mask & (!(1 << hart_id)), 0);
+    }
+    let Some(idx) = hart_id.checked_sub(mask_base) else {
+        return hart_mask;
+    };
+    if idx >= usize::BITS as usize {
+        return hart_mask;
+    }
+    HartMask::from_mask_base(mask & (!(1 << hart_id)), mask_base)
+}

+ 16 - 4
prototyper/src/sbi/mod.rs

@@ -22,15 +22,27 @@ use rfence::SbiRFence;
 #[derive(RustSBI, Default)]
 #[rustsbi(dynamic)]
 #[allow(clippy::upper_case_acronyms)]
-pub struct SBI<'a, C: ConsoleDevice, I: IpiDevice, R: ResetDevice> {
+pub struct SBI<C: ConsoleDevice, I: IpiDevice, R: ResetDevice> {
     #[rustsbi(console)]
-    pub console: Option<SbiConsole<'a, C>>,
+    pub console: Option<SbiConsole<C>>,
     #[rustsbi(ipi, timer)]
-    pub ipi: Option<SbiIpi<'a, I>>,
+    pub ipi: Option<SbiIpi<I>>,
     #[rustsbi(hsm)]
     pub hsm: Option<SbiHsm>,
     #[rustsbi(reset)]
-    pub reset: Option<SbiReset<'a, R>>,
+    pub reset: Option<SbiReset<R>>,
     #[rustsbi(fence)]
     pub rfence: Option<SbiRFence>,
 }
+
+impl<C: ConsoleDevice, I: IpiDevice, R: ResetDevice> SBI<C, I, R> {
+    pub const fn new() -> Self {
+        SBI {
+            console: None,
+            ipi: None,
+            hsm: None,
+            reset: None,
+            rfence: None,
+        }
+    }
+}

+ 10 - 11
prototyper/src/sbi/reset.rs

@@ -1,7 +1,7 @@
 use core::sync::atomic::{AtomicPtr, Ordering::Relaxed};
 use rustsbi::SbiRet;
 
-use crate::board::SBI_IMPL;
+use crate::board::BOARD;
 
 pub trait ResetDevice {
     fn fail(&self, code: u16) -> !;
@@ -9,12 +9,12 @@ pub trait ResetDevice {
     fn reset(&self) -> !;
 }
 
-pub struct SbiReset<'a, T: ResetDevice> {
-    pub reset_dev: &'a AtomicPtr<T>,
+pub struct SbiReset<T: ResetDevice> {
+    pub reset_dev: AtomicPtr<T>,
 }
 
-impl<'a, T: ResetDevice> SbiReset<'a, T> {
-    pub fn new(reset_dev: &'a AtomicPtr<T>) -> Self {
+impl<'a, T: ResetDevice> SbiReset<T> {
+    pub fn new(reset_dev: AtomicPtr<T>) -> Self {
         Self { reset_dev }
     }
 
@@ -32,7 +32,7 @@ impl<'a, T: ResetDevice> SbiReset<'a, T> {
     }
 }
 
-impl<'a, T: ResetDevice> rustsbi::Reset for SbiReset<'a, T> {
+impl<T: ResetDevice> rustsbi::Reset for SbiReset<T> {
     #[inline]
     fn system_reset(&self, reset_type: u32, reset_reason: u32) -> SbiRet {
         use rustsbi::spec::srst::{
@@ -61,9 +61,8 @@ impl<'a, T: ResetDevice> rustsbi::Reset for SbiReset<'a, T> {
 }
 
 pub fn fail() -> ! {
-    unsafe { SBI_IMPL.assume_init_ref() }
-        .reset
-        .as_ref()
-        .unwrap()
-        .fail()
+    match unsafe { BOARD.sbi.reset.as_ref() } {
+        Some(reset) => reset.fail(),
+        None => panic!("SBI or IPI device not initialized"),
+    }
 }

+ 2 - 4
prototyper/src/sbi/rfence.rs

@@ -1,7 +1,7 @@
 use rustsbi::{HartMask, SbiRet};
 use spin::Mutex;
 
-use crate::board::SBI_IMPL;
+use crate::board::BOARD;
 use crate::riscv_spec::current_hartid;
 use crate::sbi::fifo::{Fifo, FifoError};
 use crate::sbi::trap;
@@ -187,9 +187,7 @@ fn validate_address_range(start_addr: usize, size: usize) -> Result<usize, SbiRe
 
 /// Processes a remote fence operation by sending IPI to target harts.
 fn remote_fence_process(rfence_ctx: RFenceContext, hart_mask: HartMask) -> SbiRet {
-    let sbi_ret = unsafe { SBI_IMPL.assume_init_mut() }
-        .ipi
-        .as_ref()
+    let sbi_ret = unsafe { BOARD.sbi.ipi.as_ref() }
         .unwrap()
         .send_ipi_by_fence(hart_mask, rfence_ctx);
 

+ 10 - 16
prototyper/src/sbi/trap.rs

@@ -6,7 +6,7 @@ use riscv::register::{
 };
 use rustsbi::RustSBI;
 
-use crate::board::SBI_IMPL;
+use crate::board::BOARD;
 use crate::riscv_spec::{current_hartid, CSR_TIME, CSR_TIMEH};
 use crate::sbi::console;
 use crate::sbi::hsm::local_hsm;
@@ -381,11 +381,11 @@ pub extern "C" fn fast_handler(
         // Handle SBI calls
         T::Exception(E::SupervisorEnvCall) => {
             use sbi_spec::{base, hsm, legacy};
-            let mut ret = unsafe { SBI_IMPL.assume_init_ref() }.handle_ecall(
-                a7,
-                a6,
-                [ctx.a0(), a1, a2, a3, a4, a5],
-            );
+            let mut ret = unsafe {
+                BOARD
+                    .sbi
+                    .handle_ecall(a7, a6, [ctx.a0(), a1, a2, a3, a4, a5])
+            };
             if ret.is_ok() {
                 match (a7, a6) {
                     // Handle non-retentive suspend
@@ -487,11 +487,8 @@ fn illegal_instruction_handler(ctx: &mut FastContext) -> bool {
                     "Unsupported CSR rd: {}",
                     csr.rd()
                 );
-                ctx.regs().a[(csr.rd() - 10) as usize] = unsafe { SBI_IMPL.assume_init_ref() }
-                    .ipi
-                    .as_ref()
-                    .unwrap()
-                    .get_time();
+                ctx.regs().a[(csr.rd() - 10) as usize] =
+                    unsafe { BOARD.sbi.ipi.as_ref() }.unwrap().get_time();
             }
             CSR_TIMEH => {
                 assert!(
@@ -499,11 +496,8 @@ fn illegal_instruction_handler(ctx: &mut FastContext) -> bool {
                     "Unsupported CSR rd: {}",
                     csr.rd()
                 );
-                ctx.regs().a[(csr.rd() - 10) as usize] = unsafe { SBI_IMPL.assume_init_ref() }
-                    .ipi
-                    .as_ref()
-                    .unwrap()
-                    .get_timeh();
+                ctx.regs().a[(csr.rd() - 10) as usize] =
+                    unsafe { BOARD.sbi.ipi.as_ref() }.unwrap().get_timeh();
             }
             _ => return false,
         },