Selaa lähdekoodia

Merge pull request #55 from guttatus/heap

Add heap and rewrite driver interface using `dyn trait`
guttatus 2 kuukautta sitten
vanhempi
commit
9c6f1493eb

+ 10 - 0
Cargo.lock

@@ -75,6 +75,15 @@ version = "2.6.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "b048fb63fd8b5923fc5aa7b340d8e156aec7ec02f0c78fa8a6ddc2613f6f71de"
 
+[[package]]
+name = "buddy_system_allocator"
+version = "0.11.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a1a0108968a3a2dab95b089c0fc3f1afa7759aa5ebe6f1d86d206d6f7ba726eb"
+dependencies = [
+ "spin",
+]
+
 [[package]]
 name = "cfg-if"
 version = "1.0.0"
@@ -332,6 +341,7 @@ name = "rustsbi-prototyper"
 version = "0.0.0"
 dependencies = [
  "aclint",
+ "buddy_system_allocator",
  "cfg-if",
  "fast-trap",
  "log",

+ 3 - 2
prototyper/Cargo.toml

@@ -16,15 +16,16 @@ riscv = "0.11.1"
 rustsbi = { version = "0.4.0", features = ["machine"] }
 sbi-spec = { version = "0.0.8", features = ["legacy"] }
 serde = { version = "1.0.202", default-features = false, features = ["derive"] }
-serde-device-tree = { git = "https://github.com/rustsbi/serde-device-tree", default-features = false }
 sifive-test-device = "0.0.0"
 spin = "0.9.8"
 uart16550 = "0.0.1"
 riscv-decode = "0.2.1"
+cfg-if = "1.0.0"
+buddy_system_allocator = "0.11.0"
 fast-trap = { version = "0.0.1", features = ["riscv-m"] }
+serde-device-tree = { git = "https://github.com/rustsbi/serde-device-tree", default-features = false }
 uart_xilinx = { git = "https://github.com/duskmoon314/uart-rs/" }
 xuantie-riscv = { git= "https://github.com/rustsbi/xuantie" }
-cfg-if = "1.0.0"
 
 [[bin]]
 name = "rustsbi-prototyper"

+ 4 - 1
prototyper/build.rs

@@ -60,7 +60,10 @@ SECTIONS {
     sidata = LOADADDR(.data);
 
     .bss (NOLOAD) : ALIGN(0x1000) {  
-        *(.bss.uninit)
+        *(.bss.stack)
+        sbi_heap_start = .;
+        *(.bss.heap)
+        sbi_heap_end = .;
         sbi_bss_start = .;
         *(.bss .bss.*)
         *(.sbss .sbss.*)

+ 3 - 2
prototyper/src/cfg.rs

@@ -2,12 +2,13 @@
 pub const NUM_HART_MAX: usize = 8;
 /// Stack size per hart (hardware thread) in bytes.
 pub const LEN_STACK_PER_HART: usize = 16 * 1024;
+/// Heap Size of SBI firmware
+pub const HEAP_SIZE: usize = 32 * 1024;
 /// Page size
 pub const PAGE_SIZE: usize = 4096;
-/// TLB_FLUSH_LIMIT defines the TLB refresh range limit. 
+/// TLB_FLUSH_LIMIT defines the TLB refresh range limit.
 /// If the TLB refresh range is greater than TLB_FLUSH_LIMIT, the entire TLB is refreshed.
 pub const TLB_FLUSH_LIMIT: usize = 4 * PAGE_SIZE;
 
-
 #[cfg(feature = "jump")]
 pub const JUMP_ADDRESS: usize = 0x80200000;

+ 13 - 0
prototyper/src/fail.rs

@@ -1,3 +1,4 @@
+use crate::riscv::current_hartid;
 use serde_device_tree::Dtb;
 
 use crate::devicetree;
@@ -5,6 +6,18 @@ use crate::devicetree;
 #[cfg(all(feature = "payload", feature = "jump"))]
 compile_error!("feature \"payload\" and feature \"jump\" cannot be enabled at the same time");
 
+#[panic_handler]
+fn panic(info: &core::panic::PanicInfo) -> ! {
+    use ::riscv::register::*;
+    error!("Hart {} {info}", current_hartid());
+    error!("-----------------------------");
+    error!("mcause:  {:?}", mcause::read().cause());
+    error!("mepc:    {:#018x}", mepc::read());
+    error!("mtval:   {:#018x}", mtval::read());
+    error!("-----------------------------");
+    error!("System shutdown scheduled due to RustSBI panic");
+    loop {}
+}
 
 /// Handles device tree format parsing errors by logging and resetting.
 #[cold]

+ 0 - 1
prototyper/src/firmware/mod.rs

@@ -42,7 +42,6 @@ fn get_fdt_address() -> usize {
     raw_fdt as usize
 }
 
-
 /// Gets boot hart information based on opaque and nonstandard_a2 parameters.
 ///
 /// Returns a BootHart struct containing FDT address and whether this is the boot hart.

+ 6 - 13
prototyper/src/main.rs

@@ -1,9 +1,11 @@
+#![feature(alloc_error_handler)]
 #![feature(naked_functions)]
 #![feature(fn_align)]
 #![no_std]
 #![no_main]
 #![allow(static_mut_refs)]
 
+extern crate alloc;
 #[macro_use]
 extern crate log;
 #[macro_use]
@@ -27,6 +29,7 @@ use crate::sbi::extensions::{
     PrivilegedVersion,
 };
 use crate::sbi::hart_context::NextStage;
+use crate::sbi::heap::sbi_heap_init;
 use crate::sbi::hsm::local_remote_hsm;
 use crate::sbi::ipi;
 use crate::sbi::trap::{self, trap_vec};
@@ -42,6 +45,9 @@ extern "C" fn rust_main(_hart_id: usize, opaque: usize, nonstandard_a2: usize) {
     let boot_hart_info = firmware::get_boot_hart(opaque, nonstandard_a2);
     // boot hart task entry.
     if boot_hart_info.is_boot_hart {
+        // Initialize the sbi heap
+        sbi_heap_init();
+
         // parse the device tree
         let fdt_address = boot_hart_info.fdt_address;
 
@@ -198,16 +204,3 @@ unsafe extern "C" fn relocation_update() {
         options(noreturn)
     )
 }
-
-#[panic_handler]
-fn panic(info: &core::panic::PanicInfo) -> ! {
-    use ::riscv::register::*;
-    error!("Hart {} {info}", current_hartid());
-    error!("-----------------------------");
-    error!("mcause:  {:?}", mcause::read().cause());
-    error!("mepc:    {:#018x}", mepc::read());
-    error!("mtval:   {:#018x}", mtval::read());
-    error!("-----------------------------");
-    error!("System shutdown scheduled due to RustSBI panic");
-    loop {}
-}

+ 75 - 43
prototyper/src/platform/clint.rs

@@ -13,77 +13,109 @@ pub enum MachineClintType {
     TheadClint,
 }
 
-#[doc(hidden)]
-#[allow(unused)]
-pub enum MachineClint {
-    SiFive(*const SifiveClint),
-    THead(*const THeadClint),
+/// For SiFive Clint
+pub struct SifiveClintWrap {
+    inner: *const SifiveClint,
+}
+
+impl SifiveClintWrap {
+    pub fn new(base: usize) -> Self {
+        Self {
+            inner: base as *const SifiveClint,
+        }
+    }
 }
 
-/// Ipi Device: Sifive Clint
-impl IpiDevice for MachineClint {
+impl IpiDevice for SifiveClintWrap {
     #[inline(always)]
     fn read_mtime(&self) -> u64 {
-        match self {
-            Self::SiFive(sifive_clint) => unsafe { (**sifive_clint).read_mtime() },
-            Self::THead(_) => unsafe {
-                let mut mtime: u64 = 0;
-                asm!(
-                    "rdtime {}",
-                    inout(reg) mtime,
-                );
-                mtime
-            },
-        }
+        unsafe { (*self.inner).read_mtime() }
     }
 
     #[inline(always)]
     fn write_mtime(&self, val: u64) {
-        match self {
-            Self::SiFive(sifive_clint) => unsafe { (**sifive_clint).write_mtime(val) },
-            Self::THead(_) => {
-                unimplemented!()
-            }
-        }
+        unsafe { (*self.inner).write_mtime(val) }
     }
 
     #[inline(always)]
     fn read_mtimecmp(&self, hart_idx: usize) -> u64 {
-        match self {
-            Self::SiFive(sifive_clint) => unsafe { (**sifive_clint).read_mtimecmp(hart_idx) },
-            Self::THead(thead_clint) => unsafe { (**thead_clint).read_mtimecmp(hart_idx) },
-        }
+        unsafe { (*self.inner).read_mtimecmp(hart_idx) }
     }
 
     #[inline(always)]
     fn write_mtimecmp(&self, hart_idx: usize, val: u64) {
-        match self {
-            Self::SiFive(sifive_clint) => unsafe { (**sifive_clint).write_mtimecmp(hart_idx, val) },
-            Self::THead(thead_clint) => unsafe { (**thead_clint).write_mtimecmp(hart_idx, val) },
-        }
+        unsafe { (*self.inner).write_mtimecmp(hart_idx, val) }
     }
 
     #[inline(always)]
     fn read_msip(&self, hart_idx: usize) -> bool {
-        match self {
-            Self::SiFive(sifive_clint) => unsafe { (**sifive_clint).read_msip(hart_idx) },
-            Self::THead(thead_clint) => unsafe { (**thead_clint).read_msip(hart_idx) },
-        }
+        unsafe { (*self.inner).read_msip(hart_idx) }
     }
 
     #[inline(always)]
     fn set_msip(&self, hart_idx: usize) {
-        match self {
-            Self::SiFive(sifive_clint) => unsafe { (**sifive_clint).set_msip(hart_idx) },
-            Self::THead(thead_clint) => unsafe { (**thead_clint).set_msip(hart_idx) },
-        }
+        unsafe { (*self.inner).set_msip(hart_idx) }
     }
 
     #[inline(always)]
     fn clear_msip(&self, hart_idx: usize) {
-        match self {
-            Self::SiFive(sifive_clint) => unsafe { (**sifive_clint).clear_msip(hart_idx) },
-            Self::THead(thead_clint) => unsafe { (**thead_clint).clear_msip(hart_idx) },
+        unsafe { (*self.inner).clear_msip(hart_idx) }
+    }
+}
+
+/// For T-Head Clint
+pub struct THeadClintWrap {
+    inner: *const THeadClint,
+}
+
+impl THeadClintWrap {
+    pub fn new(base: usize) -> Self {
+        Self {
+            inner: base as *const THeadClint,
+        }
+    }
+}
+
+impl IpiDevice for THeadClintWrap {
+    #[inline(always)]
+    fn read_mtime(&self) -> u64 {
+        unsafe {
+            let mut mtime: u64 = 0;
+            asm!(
+                "rdtime {}",
+                inout(reg) mtime,
+            );
+            mtime
         }
     }
+
+    #[inline(always)]
+    fn write_mtime(&self, _val: u64) {
+        unimplemented!()
+    }
+
+    #[inline(always)]
+    fn read_mtimecmp(&self, hart_idx: usize) -> u64 {
+        unsafe { (*self.inner).read_mtimecmp(hart_idx) }
+    }
+
+    #[inline(always)]
+    fn write_mtimecmp(&self, hart_idx: usize, val: u64) {
+        unsafe { (*self.inner).write_mtimecmp(hart_idx, val) }
+    }
+
+    #[inline(always)]
+    fn read_msip(&self, hart_idx: usize) -> bool {
+        unsafe { (*self.inner).read_msip(hart_idx) }
+    }
+
+    #[inline(always)]
+    fn set_msip(&self, hart_idx: usize) {
+        unsafe { (*self.inner).set_msip(hart_idx) }
+    }
+
+    #[inline(always)]
+    fn clear_msip(&self, hart_idx: usize) {
+        unsafe { (*self.inner).clear_msip(hart_idx) }
+    }
 }

+ 24 - 20
prototyper/src/platform/console.rs

@@ -1,4 +1,4 @@
-use uart16550::Uart16550;
+use uart16550::{Register, Uart16550};
 use uart_xilinx::MmioUartAxiLite;
 
 use crate::sbi::console::ConsoleDevice;
@@ -14,31 +14,35 @@ pub enum MachineConsoleType {
     Uart16550U32,
     UartAxiLite,
 }
-#[doc(hidden)]
-#[allow(unused)]
-pub enum MachineConsole {
-    Uart16550U8(*const Uart16550<u8>),
-    Uart16550U32(*const Uart16550<u32>),
-    UartAxiLite(MmioUartAxiLite),
+
+pub struct Uart16550Wrap<R: Register> {
+    inner: *const Uart16550<R>,
 }
 
-unsafe impl Send for MachineConsole {}
-unsafe impl Sync for MachineConsole {}
+impl<R: Register> Uart16550Wrap<R> {
+    pub fn new(base: usize) -> Self {
+        Self {
+            inner: base as *const Uart16550<R>,
+        }
+    }
+}
 
-impl ConsoleDevice for MachineConsole {
+impl<R: Register> ConsoleDevice for Uart16550Wrap<R> {
     fn read(&self, buf: &mut [u8]) -> usize {
-        match self {
-            Self::Uart16550U8(uart16550) => unsafe { (**uart16550).read(buf) },
-            Self::Uart16550U32(uart16550) => unsafe { (**uart16550).read(buf) },
-            Self::UartAxiLite(axilite) => axilite.read(buf),
-        }
+        unsafe { (*self.inner).read(buf) }
     }
 
     fn write(&self, buf: &[u8]) -> usize {
-        match self {
-            MachineConsole::Uart16550U8(uart16550) => unsafe { (**uart16550).write(buf) },
-            MachineConsole::Uart16550U32(uart16550) => unsafe { (**uart16550).write(buf) },
-            Self::UartAxiLite(axilite) => axilite.write(buf),
-        }
+        unsafe { (*self.inner).write(buf) }
+    }
+}
+
+impl ConsoleDevice for MmioUartAxiLite {
+    fn read(&self, buf: &mut [u8]) -> usize {
+        self.read(buf)
+    }
+
+    fn write(&self, buf: &[u8]) -> usize {
+        self.write(buf)
     }
 }

+ 37 - 27
prototyper/src/platform/mod.rs

@@ -1,10 +1,21 @@
+use alloc::boxed::Box;
+use clint::{SifiveClintWrap, THeadClintWrap};
+use core::{
+    fmt::{Display, Formatter, Result},
+    ops::Range,
+    sync::atomic::{AtomicBool, Ordering},
+};
+use reset::SifiveTestDeviceWrap;
+use spin::Mutex;
+use uart_xilinx::MmioUartAxiLite;
+
 use crate::cfg::NUM_HART_MAX;
 use crate::devicetree::*;
 use crate::fail;
-use crate::platform::clint::{MachineClint, MachineClintType, CLINT_COMPATIBLE};
+use crate::platform::clint::{MachineClintType, CLINT_COMPATIBLE};
+use crate::platform::console::Uart16550Wrap;
 use crate::platform::console::{
-    MachineConsole, MachineConsoleType, UART16650U32_COMPATIBLE, UART16650U8_COMPATIBLE,
-    UARTAXILITE_COMPATIBLE,
+    MachineConsoleType, UART16650U32_COMPATIBLE, UART16650U8_COMPATIBLE, UARTAXILITE_COMPATIBLE,
 };
 use crate::platform::reset::SIFIVETEST_COMPATIBLE;
 use crate::sbi::console::SbiConsole;
@@ -16,14 +27,6 @@ use crate::sbi::reset::SbiReset;
 use crate::sbi::rfence::SbiRFence;
 use crate::sbi::trap_stack;
 use crate::sbi::SBI;
-use core::{
-    fmt::{Display, Formatter, Result},
-    ops::Range,
-    sync::atomic::{AtomicBool, AtomicPtr, Ordering},
-};
-use sifive_test_device::SifiveTestDevice;
-use spin::Mutex;
-use uart_xilinx::MmioUartAxiLite;
 
 mod clint;
 mod console;
@@ -69,7 +72,7 @@ impl BoardInfo {
 
 pub struct Platform {
     pub info: BoardInfo,
-    pub sbi: SBI<MachineConsole, MachineClint, SifiveTestDevice>,
+    pub sbi: SBI,
     pub ready: AtomicBool,
 }
 
@@ -202,14 +205,17 @@ impl Platform {
 
     fn sbi_console_init(&mut self) {
         if let Some((base, console_type)) = self.info.console {
-            let new_console = match console_type {
-                MachineConsoleType::Uart16550U8 => MachineConsole::Uart16550U8(base as _),
-                MachineConsoleType::Uart16550U32 => MachineConsole::Uart16550U32(base as _),
-                MachineConsoleType::UartAxiLite => {
-                    MachineConsole::UartAxiLite(MmioUartAxiLite::new(base))
-                }
+            self.sbi.console = match console_type {
+                MachineConsoleType::Uart16550U8 => Some(SbiConsole::new(Mutex::new(Box::new(
+                    Uart16550Wrap::<u8>::new(base),
+                )))),
+                MachineConsoleType::Uart16550U32 => Some(SbiConsole::new(Mutex::new(Box::new(
+                    Uart16550Wrap::<u32>::new(base),
+                )))),
+                MachineConsoleType::UartAxiLite => Some(SbiConsole::new(Mutex::new(Box::new(
+                    MmioUartAxiLite::new(base),
+                )))),
             };
-            self.sbi.console = Some(SbiConsole::new(Mutex::new(new_console)));
         } else {
             self.sbi.console = None;
         }
@@ -217,7 +223,9 @@ impl Platform {
 
     fn sbi_reset_init(&mut self) {
         if let Some(base) = self.info.reset {
-            self.sbi.reset = Some(SbiReset::new(AtomicPtr::new(base as _)));
+            self.sbi.reset = Some(SbiReset::new(Mutex::new(Box::new(
+                SifiveTestDeviceWrap::new(base),
+            ))));
         } else {
             self.sbi.reset = None;
         }
@@ -225,14 +233,16 @@ impl Platform {
 
     fn sbi_ipi_init(&mut self) {
         if let Some((base, clint_type)) = self.info.ipi {
-            let new_clint = match clint_type {
-                MachineClintType::SiFiveClint => MachineClint::SiFive(base as _),
-                MachineClintType::TheadClint => MachineClint::THead(base as _),
+            self.sbi.ipi = match clint_type {
+                MachineClintType::SiFiveClint => Some(SbiIpi::new(
+                    Mutex::new(Box::new(SifiveClintWrap::new(base))),
+                    self.info.cpu_num.unwrap_or(NUM_HART_MAX),
+                )),
+                MachineClintType::TheadClint => Some(SbiIpi::new(
+                    Mutex::new(Box::new(THeadClintWrap::new(base))),
+                    self.info.cpu_num.unwrap_or(NUM_HART_MAX),
+                )),
             };
-            self.sbi.ipi = Some(SbiIpi::new(
-                Mutex::new(new_clint),
-                self.info.cpu_num.unwrap_or(NUM_HART_MAX),
-            ));
         } else {
             self.sbi.ipi = None;
         }

+ 16 - 4
prototyper/src/platform/reset.rs

@@ -3,20 +3,32 @@ use sifive_test_device::SifiveTestDevice;
 use crate::sbi::reset::ResetDevice;
 pub(crate) const SIFIVETEST_COMPATIBLE: [&str; 1] = ["sifive,test0"];
 
+pub struct SifiveTestDeviceWrap {
+    inner: *const SifiveTestDevice,
+}
+
+impl SifiveTestDeviceWrap {
+    pub fn new(base: usize) -> Self {
+        Self {
+            inner: base as *const SifiveTestDevice,
+        }
+    }
+}
+
 /// Reset Device: SifiveTestDevice
-impl ResetDevice for SifiveTestDevice {
+impl ResetDevice for SifiveTestDeviceWrap {
     #[inline]
     fn fail(&self, code: u16) -> ! {
-        self.fail(code)
+        unsafe { (*self.inner).fail(code) }
     }
 
     #[inline]
     fn pass(&self) -> ! {
-        self.pass()
+        unsafe { (*self.inner).pass() }
     }
 
     #[inline]
     fn reset(&self) -> ! {
-        self.reset()
+        unsafe { (*self.inner).reset() }
     }
 }

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

@@ -1,8 +1,10 @@
-use crate::platform::PLATFORM;
+use alloc::boxed::Box;
 use core::fmt::{self, Write};
 use rustsbi::{Console, Physical, SbiRet};
 use spin::Mutex;
 
+use crate::platform::PLATFORM;
+
 /// A trait that must be implemented by console devices to provide basic I/O functionality.
 pub trait ConsoleDevice {
     /// Reads bytes from the console into the provided buffer.
@@ -22,17 +24,17 @@ pub trait ConsoleDevice {
 ///
 /// This provides a safe interface for interacting with console hardware through the
 /// SBI specification.
-pub struct SbiConsole<T: ConsoleDevice> {
-    inner: Mutex<T>,
+pub struct SbiConsole {
+    inner: Mutex<Box<dyn ConsoleDevice>>,
 }
 
-impl<T: ConsoleDevice> SbiConsole<T> {
+impl SbiConsole {
     /// 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: Mutex<T>) -> Self {
+    pub fn new(inner: Mutex<Box<dyn ConsoleDevice>>) -> Self {
         Self { inner }
     }
 
@@ -67,7 +69,7 @@ impl<T: ConsoleDevice> SbiConsole<T> {
     }
 }
 
-impl<T: ConsoleDevice> Console for SbiConsole<T> {
+impl Console for SbiConsole {
     /// Write a physical memory buffer to the console.
     #[inline]
     fn write(&self, bytes: Physical<&[u8]>) -> SbiRet {
@@ -96,7 +98,7 @@ impl<T: ConsoleDevice> Console for SbiConsole<T> {
     }
 }
 
-impl<T: ConsoleDevice> fmt::Write for SbiConsole<T> {
+impl fmt::Write for SbiConsole {
     /// Implement Write trait for string formatting.
     #[inline]
     fn write_str(&mut self, s: &str) -> fmt::Result {

+ 21 - 0
prototyper/src/sbi/heap.rs

@@ -0,0 +1,21 @@
+use crate::cfg::HEAP_SIZE;
+use buddy_system_allocator::LockedHeap;
+
+#[link_section = ".bss.heap"]
+static mut HEAP: [u8; HEAP_SIZE] = [0; HEAP_SIZE];
+
+#[global_allocator]
+static HEAP_ALLOCATOR: LockedHeap<15> = LockedHeap::<15>::empty();
+
+pub fn sbi_heap_init() {
+    unsafe {
+        HEAP_ALLOCATOR
+            .lock()
+            .init(HEAP.as_ptr() as usize, HEAP_SIZE);
+    }
+}
+
+#[alloc_error_handler]
+pub fn handle_alloc_error(layout: core::alloc::Layout) -> ! {
+    panic!("Heap allocation error, layout = {:?}", layout);
+}

+ 7 - 6
prototyper/src/sbi/ipi.rs

@@ -6,6 +6,7 @@ use crate::sbi::hsm::remote_hsm;
 use crate::sbi::rfence;
 use crate::sbi::trap;
 use crate::sbi::trap_stack::ROOT_STACK;
+use alloc::boxed::Box;
 use core::sync::atomic::Ordering::Relaxed;
 use rustsbi::{HartMask, SbiRet};
 use spin::Mutex;
@@ -35,14 +36,14 @@ pub trait IpiDevice {
 }
 
 /// SBI IPI implementation.
-pub struct SbiIpi<T: IpiDevice> {
+pub struct SbiIpi {
     /// Reference to atomic pointer to IPI device.
-    pub ipi_dev: Mutex<T>,
+    pub ipi_dev: Mutex<Box<dyn IpiDevice>>,
     /// Maximum hart ID in the system
     pub max_hart_id: usize,
 }
 
-impl<T: IpiDevice> rustsbi::Timer for SbiIpi<T> {
+impl rustsbi::Timer for SbiIpi {
     /// Set timer value for current hart.
     #[inline]
     fn set_timer(&self, stime_value: u64) {
@@ -65,7 +66,7 @@ impl<T: IpiDevice> rustsbi::Timer for SbiIpi<T> {
     }
 }
 
-impl<T: IpiDevice> rustsbi::Ipi for SbiIpi<T> {
+impl rustsbi::Ipi for SbiIpi {
     /// Send IPI to specified harts.
     #[inline]
     fn send_ipi(&self, hart_mask: rustsbi::HartMask) -> SbiRet {
@@ -112,10 +113,10 @@ impl<T: IpiDevice> rustsbi::Ipi for SbiIpi<T> {
     }
 }
 
-impl<T: IpiDevice> SbiIpi<T> {
+impl SbiIpi {
     /// Create new SBI IPI instance.
     #[inline]
-    pub fn new(ipi_dev: Mutex<T>, max_hart_id: usize) -> Self {
+    pub fn new(ipi_dev: Mutex<Box<dyn IpiDevice>>, max_hart_id: usize) -> Self {
         Self {
             ipi_dev,
             max_hart_id,

+ 9 - 8
prototyper/src/sbi/mod.rs

@@ -10,33 +10,34 @@ pub mod early_trap;
 pub mod extensions;
 pub mod fifo;
 pub mod hart_context;
+pub mod heap;
 pub mod logger;
 pub mod trap;
 pub mod trap_stack;
 
-use console::{ConsoleDevice, SbiConsole};
+use console::SbiConsole;
 use hsm::SbiHsm;
-use ipi::{IpiDevice, SbiIpi};
-use reset::{ResetDevice, SbiReset};
+use ipi::SbiIpi;
+use reset::SbiReset;
 use rfence::SbiRFence;
 
 #[derive(RustSBI, Default)]
 #[rustsbi(dynamic)]
 #[allow(clippy::upper_case_acronyms)]
-pub struct SBI<C: ConsoleDevice, I: IpiDevice, R: ResetDevice> {
+pub struct SBI {
     #[rustsbi(console)]
-    pub console: Option<SbiConsole<C>>,
+    pub console: Option<SbiConsole>,
     #[rustsbi(ipi, timer)]
-    pub ipi: Option<SbiIpi<I>>,
+    pub ipi: Option<SbiIpi>,
     #[rustsbi(hsm)]
     pub hsm: Option<SbiHsm>,
     #[rustsbi(reset)]
-    pub reset: Option<SbiReset<R>>,
+    pub reset: Option<SbiReset>,
     #[rustsbi(fence)]
     pub rfence: Option<SbiRFence>,
 }
 
-impl<C: ConsoleDevice, I: IpiDevice, R: ResetDevice> SBI<C, I, R> {
+impl SBI {
     pub const fn new() -> Self {
         SBI {
             console: None,

+ 19 - 29
prototyper/src/sbi/reset.rs

@@ -1,5 +1,6 @@
-use core::sync::atomic::{AtomicPtr, Ordering::Relaxed};
+use alloc::boxed::Box;
 use rustsbi::SbiRet;
+use spin::Mutex;
 
 use crate::platform::PLATFORM;
 
@@ -9,31 +10,23 @@ pub trait ResetDevice {
     fn reset(&self) -> !;
 }
 
-pub struct SbiReset<T: ResetDevice> {
-    pub reset_dev: AtomicPtr<T>,
+pub struct SbiReset {
+    pub reset_dev: Mutex<Box<dyn ResetDevice>>,
 }
 
-impl<T: ResetDevice> SbiReset<T> {
-    pub fn new(reset_dev: AtomicPtr<T>) -> Self {
+impl SbiReset {
+    pub fn new(reset_dev: Mutex<Box<dyn ResetDevice>>) -> Self {
         Self { reset_dev }
     }
 
     #[allow(unused)]
     pub fn fail(&self) -> ! {
-        let reset_dev = self.reset_dev.load(Relaxed);
-        if reset_dev.is_null() {
-            trace!("test fail, begin dead loop");
-            loop {
-                core::hint::spin_loop()
-            }
-        } else {
-            trace!("Test fail, invoke process exit procedure on Reset device");
-            unsafe { (*reset_dev).fail(0) }
-        }
+        trace!("Test fail, invoke process exit procedure on Reset device");
+        self.reset_dev.lock().fail(0);
     }
 }
 
-impl<T: ResetDevice> rustsbi::Reset for SbiReset<T> {
+impl rustsbi::Reset for SbiReset {
     #[inline]
     fn system_reset(&self, reset_type: u32, reset_reason: u32) -> SbiRet {
         use rustsbi::spec::srst::{
@@ -42,19 +35,11 @@ impl<T: ResetDevice> rustsbi::Reset for SbiReset<T> {
         };
         match reset_type {
             RESET_TYPE_SHUTDOWN => match reset_reason {
-                RESET_REASON_NO_REASON => unsafe {
-                    (*self.reset_dev.load(Relaxed)).pass();
-                },
-                RESET_REASON_SYSTEM_FAILURE => unsafe {
-                    (*self.reset_dev.load(Relaxed)).fail(u16::MAX);
-                },
-                value => unsafe {
-                    (*self.reset_dev.load(Relaxed)).fail(value as _);
-                },
-            },
-            RESET_TYPE_COLD_REBOOT | RESET_TYPE_WARM_REBOOT => unsafe {
-                (*self.reset_dev.load(Relaxed)).reset();
+                RESET_REASON_NO_REASON => self.reset_dev.lock().pass(),
+                RESET_REASON_SYSTEM_FAILURE => self.reset_dev.lock().fail(u16::MAX),
+                value => self.reset_dev.lock().fail(value as _),
             },
+            RESET_TYPE_COLD_REBOOT | RESET_TYPE_WARM_REBOOT => self.reset_dev.lock().reset(),
 
             _ => SbiRet::invalid_param(),
         }
@@ -65,6 +50,11 @@ impl<T: ResetDevice> rustsbi::Reset for SbiReset<T> {
 pub fn fail() -> ! {
     match unsafe { PLATFORM.sbi.reset.as_ref() } {
         Some(reset) => reset.fail(),
-        None => panic!("SBI or IPI device not initialized"),
+        None => {
+            trace!("test fail, begin dead loop");
+            loop {
+                core::hint::spin_loop()
+            }
+        }
     }
 }

+ 3 - 3
prototyper/src/sbi/trap_stack.rs

@@ -1,12 +1,12 @@
+use crate::cfg::{LEN_STACK_PER_HART, NUM_HART_MAX};
 use crate::riscv::current_hartid;
 use crate::sbi::hart_context::HartContext;
 use crate::sbi::trap::fast_handler;
 use core::mem::forget;
 use fast_trap::FreeTrapStack;
-use crate::cfg::{NUM_HART_MAX, LEN_STACK_PER_HART};
 
-/// Root stack array for all harts, placed in uninitialized BSS section.
-#[link_section = ".bss.uninit"]
+/// Root stack array for all harts, placed in BSS Stack section.
+#[link_section = ".bss.stack"]
 pub(crate) static mut ROOT_STACK: [Stack; NUM_HART_MAX] = [Stack::ZERO; NUM_HART_MAX];
 
 /// Locates and initializes stack for each hart.

+ 1 - 1
xtask/src/prototyper.rs

@@ -45,7 +45,7 @@ pub fn run(arg: &PrototyperArg) -> Option<ExitStatus> {
     cargo::Cargo::new("build")
         .package("rustsbi-prototyper")
         .target(arch)
-        .unstable("build-std", ["core"])
+        .unstable("build-std", ["core","alloc"])
         .env("RUSTFLAGS", "-C relocation-model=pie -C link-arg=-pie")
         .features(&arg.features)
         .optional(arg.fdt.is_some(), |cargo| {