Browse Source

macro: gate machine-mode information under `machine` feature

Signed-off-by: Zhouqi Jiang <[email protected]>
Zhouqi Jiang 1 year ago
parent
commit
579445ee0c
8 changed files with 134 additions and 891 deletions
  1. 2 1
      CHANGELOG.md
  2. 1 1
      Cargo.toml
  3. 25 9
      examples/derive.rs
  4. 5 0
      macros/Cargo.toml
  5. 36 16
      macros/src/lib.rs
  6. 0 845
      src/instance.rs
  7. 7 7
      src/lib.rs
  8. 58 12
      src/traits.rs

+ 2 - 1
CHANGELOG.md

@@ -14,6 +14,7 @@ to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
 - `new_uninit` and `uninit_with_machine_info` constructors for RustSBI instance
 - `handle_ecall` now only requires `&self` since RustSBI trait implementations are internally mutable
 - support NACL and STA extensions
+- macro based `#[derive(RustSBI)]` interface
 
 ### Modified
 
@@ -25,7 +26,7 @@ to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
 
 - `sbi_2_0` feature; RustSBI now supports SBI 2.0-rc1 by default
 - support for legacy SBI extensions
-- singleton based RustSBI interface; use struct `RustSBI` instead
+- singleton based RustSBI interface; use derive macro `#[derive(RustSBI)]` instead
 
 ## [0.3.2] - 2023-02-26
 

+ 1 - 1
Cargo.toml

@@ -23,7 +23,7 @@ rustsbi-macros = { path = "macros" }
 static_assertions = "1.1.0"
 
 [features]
-default = ["machine"]
+default = []
 # Run RustSBI on machine mode
 # This feature enables to use RISC-V primitives on current machine mode environment
 # If you are developing a cross-architecture virtual machine, consider disabling this feature

+ 25 - 9
examples/derive.rs

@@ -1,16 +1,17 @@
-use rustsbi::{HartMask, RustSBI};
+use rustsbi::{HartMask, MachineInfo, RustSBI};
 use sbi_spec::binary::SbiRet;
 
 #[derive(RustSBI)]
 struct MySBI {
     fence: MyFence,
+    info: MyMachineInfo,
 }
 
 struct MyFence;
 
 impl rustsbi::Fence for MyFence {
     fn remote_fence_i(&self, _: HartMask) -> SbiRet {
-        println!("remote fence i");
+        println!("remote fence i called");
         SbiRet::success(0)
     }
 
@@ -23,13 +24,28 @@ impl rustsbi::Fence for MyFence {
     }
 }
 
+struct MyMachineInfo;
+
+impl MachineInfo for MyMachineInfo {
+    fn mvendorid(&self) -> usize {
+        0x100
+    }
+
+    fn marchid(&self) -> usize {
+        0x200
+    }
+
+    fn mimpid(&self) -> usize {
+        0x300
+    }
+}
+
 fn main() {
-    let sbi = MySBI { fence: MyFence };
+    let sbi = MySBI {
+        fence: MyFence,
+        info: MyMachineInfo,
+    };
     sbi.handle_ecall(sbi_spec::rfnc::EID_RFNC, 0, [0; 6]);
-    let spec_version = sbi.handle_ecall(
-        sbi_spec::base::EID_BASE,
-        sbi_spec::base::GET_SBI_SPEC_VERSION,
-        [0; 6],
-    );
-    println!("spec version: {:x?}", spec_version.value);
+    let sbi_impl_id = sbi.handle_ecall(0x10, 0x1, [0; 6]);
+    println!("SBI implementation ID: {:x?}", sbi_impl_id.value);
 }

+ 5 - 0
macros/Cargo.toml

@@ -11,3 +11,8 @@ proc-macro = true
 [dependencies]
 quote = "1.0.33"
 syn = "2.0.39"
+
+[features]
+default = []
+# Run RustSBI macros on machine mode - See Cargo.toml in root project
+machine = []

+ 36 - 16
macros/src/lib.rs

@@ -15,6 +15,7 @@ struct RustSBIImp<'a> {
     cppc: Option<&'a Ident>,
     nacl: Option<&'a Ident>,
     sta: Option<&'a Ident>,
+    machine_info: Option<&'a Ident>,
 }
 
 /// Implement RustSBI trait for structure of each extensions.
@@ -55,6 +56,7 @@ pub fn derive_rustsbi(input: TokenStream) -> TokenStream {
                 "cppc" => imp.cppc = Some(name),
                 "nacl" => imp.nacl = Some(name),
                 "sta" => imp.sta = Some(name),
+                "info" | "machine_info" => imp.machine_info = Some(name),
                 _ => {}
             }
         }
@@ -78,22 +80,40 @@ fn impl_derive_rustsbi(name: &Ident, imp: RustSBIImp) -> TokenStream {
     let cppc_probe: usize = if imp.cppc.is_some() { 1 } else { 0 };
     let nacl_probe: usize = if imp.nacl.is_some() { 1 } else { 0 };
     let sta_probe: usize = if imp.sta.is_some() { 1 } else { 0 };
-    let base_procedure = quote! {
-        ::rustsbi::spec::base::EID_BASE => ::rustsbi::_rustsbi_base_machine(param, function,
-            ::rustsbi::_StandardExtensionProbe {
-                base: #base_probe,
-                fence: #fence_probe,
-                hsm: #hsm_probe,
-                ipi: #ipi_probe,
-                reset: #reset_probe,
-                timer: #timer_probe,
-                pmu: #pmu_probe,
-                console: #console_probe,
-                susp: #susp_probe,
-                cppc: #cppc_probe,
-                nacl: #nacl_probe,
-                sta: #sta_probe,
-            }),
+    let probe = quote! {
+        ::rustsbi::_StandardExtensionProbe {
+            base: #base_probe,
+            fence: #fence_probe,
+            hsm: #hsm_probe,
+            ipi: #ipi_probe,
+            reset: #reset_probe,
+            timer: #timer_probe,
+            pmu: #pmu_probe,
+            console: #console_probe,
+            susp: #susp_probe,
+            cppc: #cppc_probe,
+            nacl: #nacl_probe,
+            sta: #sta_probe,
+        }
+    };
+    let base_procedure = if let Some(machine_info) = imp.machine_info {
+        quote! {
+            ::rustsbi::spec::base::EID_BASE => ::rustsbi::_rustsbi_base_machine_info(param, function, &self.#machine_info, #probe),
+        }
+    } else {
+        match () {
+            #[cfg(not(feature = "machine"))]
+            () => quote! {
+                ::rustsbi::spec::base::EID_BASE => compile_error!(
+                    "can't derive RustSBI: #[cfg(feature = \"machine\")] is needed to derive RustSBI with no extra MachineInfo provided; \
+            consider adding an `info` parameter to provide machine information if RustSBI is not run on machine mode."
+                ),
+            },
+            #[cfg(feature = "machine")]
+            () => quote! {
+                ::rustsbi::spec::base::EID_BASE => ::rustsbi::_rustsbi_base_bare(param, function, #probe),
+            },
+        }
     };
     let fence_procedure = if let Some(fence) = &imp.fence {
         quote! {

+ 0 - 845
src/instance.rs

@@ -1,845 +0,0 @@
-use crate::{
-    spec::binary::SbiRet, Console, Cppc, Fence, HartMask, Hsm, Ipi, Pmu, Reset, Susp, Timer,
-    IMPL_ID_RUSTSBI, RUSTSBI_VERSION, SBI_SPEC_MAJOR, SBI_SPEC_MINOR,
-};
-use core::convert::Infallible;
-#[cfg(feature = "machine")]
-use riscv::register::{marchid, mimpid, mvendorid};
-use spec::binary::Physical;
-
-/// RustSBI instance including standard extensions
-///
-/// By now RustSBI supports to run instance based interface on systems has environment pointer width
-/// that is the same as supervisor pointer width.
-#[derive(Clone, Debug)]
-pub struct RustSBI<T, I, R, H, S, P, C, SU, CP> {
-    timer: Option<T>,
-    ipi: Option<I>,
-    rfnc: Option<R>,
-    hsm: Option<H>,
-    srst: Option<S>,
-    pmu: Option<P>,
-    dbcn: Option<C>,
-    susp: Option<SU>,
-    cppc: Option<CP>,
-    #[cfg(not(feature = "machine"))]
-    info: MachineInfo,
-}
-
-/// Machine information for SBI environment
-///
-/// This structure is useful to build an SBI environment when RustSBI is not run directly on RISC-V machine mode.
-#[cfg(not(feature = "machine"))]
-#[derive(Clone, Copy, Debug)]
-pub struct MachineInfo {
-    /// Register `mvendorid` for supervisor environment
-    pub mvendorid: usize,
-    /// Register `marchid` for supervisor environment
-    pub marchid: usize,
-    /// Register `mimpid` for supervisor environment
-    pub mimpid: usize,
-}
-
-impl<T: Timer, I: Ipi, R: Fence, H: Hsm, S: Reset, P: Pmu, C: Console, SU: Susp, CP: Cppc>
-    RustSBI<T, I, R, H, S, P, C, SU, CP>
-{
-    /// Create RustSBI instance on current machine environment for all the SBI extensions
-    #[cfg(feature = "machine")]
-    #[inline]
-    pub const fn new_machine(
-        timer: T,
-        ipi: I,
-        rfnc: R,
-        hsm: H,
-        srst: S,
-        pmu: P,
-        dbcn: C,
-        susp: SU,
-        cppc: CP,
-    ) -> Self {
-        Self {
-            timer: Some(timer),
-            ipi: Some(ipi),
-            rfnc: Some(rfnc),
-            hsm: Some(hsm),
-            srst: Some(srst),
-            pmu: Some(pmu),
-            dbcn: Some(dbcn),
-            susp: Some(susp),
-            cppc: Some(cppc),
-        }
-    }
-
-    /// Create an uninitialized RustSBI instance on current machine environment.
-    #[cfg(feature = "machine")]
-    #[inline]
-    pub const fn new_uninit_machine() -> Self {
-        Self {
-            timer: None,
-            ipi: None,
-            rfnc: None,
-            hsm: None,
-            srst: None,
-            pmu: None,
-            dbcn: None,
-            susp: None,
-            cppc: None,
-        }
-    }
-
-    /// Create RustSBI instance on given machine information for all the SBI extensions
-    #[cfg(not(feature = "machine"))]
-    #[allow(clippy::too_many_arguments)] // fixme: is it possible to have a better design here?
-    #[inline]
-    pub const fn with_machine_info(
-        timer: T,
-        ipi: I,
-        rfnc: R,
-        hsm: H,
-        srst: S,
-        pmu: P,
-        dbcn: C,
-        susp: SU,
-        cppc: CP,
-        info: MachineInfo,
-    ) -> Self {
-        Self {
-            timer: Some(timer),
-            ipi: Some(ipi),
-            rfnc: Some(rfnc),
-            hsm: Some(hsm),
-            srst: Some(srst),
-            pmu: Some(pmu),
-            dbcn: Some(dbcn),
-            susp: Some(susp),
-            cppc: Some(cppc),
-            info,
-        }
-    }
-
-    /// Create an uninitialized RustSBI instance on current machine environment.
-    #[cfg(not(feature = "machine"))]
-    #[inline]
-    pub const fn uninit_with_machine_info(info: MachineInfo) -> Self {
-        Self {
-            timer: None,
-            ipi: None,
-            rfnc: None,
-            hsm: None,
-            srst: None,
-            pmu: None,
-            dbcn: None,
-            susp: None,
-            cppc: None,
-            info,
-        }
-    }
-
-    /// Handle supervisor environment call with given parameters and return the `SbiRet` result.
-    #[inline]
-    pub fn handle_ecall(&self, extension: usize, function: usize, param: [usize; 6]) -> SbiRet {
-        match extension {
-            spec::rfnc::EID_RFNC => {
-                let Some(rfnc) = &self.rfnc else {
-                    return SbiRet::not_supported();
-                };
-                let [param0, param1, param2, param3, param4] =
-                    [param[0], param[1], param[2], param[3], param[4]];
-                let hart_mask = crate::HartMask::from_mask_base(param0, param1);
-                match function {
-                    spec::rfnc::REMOTE_FENCE_I => rfnc.remote_fence_i(hart_mask),
-                    spec::rfnc::REMOTE_SFENCE_VMA => {
-                        rfnc.remote_sfence_vma(hart_mask, param2, param3)
-                    }
-                    spec::rfnc::REMOTE_SFENCE_VMA_ASID => {
-                        rfnc.remote_sfence_vma_asid(hart_mask, param2, param3, param4)
-                    }
-                    spec::rfnc::REMOTE_HFENCE_GVMA_VMID => {
-                        rfnc.remote_hfence_gvma_vmid(hart_mask, param2, param3, param4)
-                    }
-                    spec::rfnc::REMOTE_HFENCE_GVMA => {
-                        rfnc.remote_hfence_gvma(hart_mask, param2, param3)
-                    }
-                    spec::rfnc::REMOTE_HFENCE_VVMA_ASID => {
-                        rfnc.remote_hfence_vvma_asid(hart_mask, param2, param3, param4)
-                    }
-                    spec::rfnc::REMOTE_HFENCE_VVMA => {
-                        rfnc.remote_hfence_vvma(hart_mask, param2, param3)
-                    }
-                    _ => SbiRet::not_supported(),
-                }
-            }
-            spec::time::EID_TIME => match () {
-                #[cfg(target_pointer_width = "64")]
-                () => {
-                    let Some(timer) = &self.timer else {
-                        return SbiRet::not_supported();
-                    };
-                    let [param0] = [param[0]];
-                    match function {
-                        spec::time::SET_TIMER => {
-                            timer.set_timer(param0 as _);
-                            SbiRet::success(0)
-                        }
-                        _ => SbiRet::not_supported(),
-                    }
-                }
-                #[cfg(target_pointer_width = "32")]
-                () => {
-                    let Some(timer) = &self.timer else {
-                        return SbiRet::not_supported();
-                    };
-                    let [param0, param1] = [param[0], param[1]];
-                    match function {
-                        spec::time::SET_TIMER => {
-                            timer.set_timer(concat_u32(param1, param0));
-                            SbiRet::success(0)
-                        }
-                        _ => SbiRet::not_supported(),
-                    }
-                }
-            },
-            spec::spi::EID_SPI => {
-                let Some(ipi) = &self.ipi else {
-                    return SbiRet::not_supported();
-                };
-                let [param0, param1] = [param[0], param[1]];
-                match function {
-                    spec::spi::SEND_IPI => ipi.send_ipi(HartMask::from_mask_base(param0, param1)),
-                    _ => SbiRet::not_supported(),
-                }
-            }
-            spec::base::EID_BASE => {
-                let [param0] = [param[0]];
-                let value = match function {
-                    spec::base::GET_SBI_SPEC_VERSION => (SBI_SPEC_MAJOR << 24) | (SBI_SPEC_MINOR),
-                    spec::base::GET_SBI_IMPL_ID => IMPL_ID_RUSTSBI,
-                    spec::base::GET_SBI_IMPL_VERSION => RUSTSBI_VERSION,
-                    spec::base::PROBE_EXTENSION => {
-                        // only provides probes to standard extensions. If you have customized extensions to be probed,
-                        // run it even before this `handle_ecall` function.
-                        self.probe_extension(param0)
-                    }
-                    spec::base::GET_MVENDORID => match () {
-                        #[cfg(feature = "machine")]
-                        () => mvendorid::read().map(|r| r.bits()).unwrap_or(0),
-                        #[cfg(not(feature = "machine"))]
-                        () => self.info.mvendorid,
-                    },
-                    spec::base::GET_MARCHID => match () {
-                        #[cfg(feature = "machine")]
-                        () => marchid::read().map(|r| r.bits()).unwrap_or(0),
-                        #[cfg(not(feature = "machine"))]
-                        () => self.info.marchid,
-                    },
-                    spec::base::GET_MIMPID => match () {
-                        #[cfg(feature = "machine")]
-                        () => mimpid::read().map(|r| r.bits()).unwrap_or(0),
-                        #[cfg(not(feature = "machine"))]
-                        () => self.info.mimpid,
-                    },
-                    _ => return SbiRet::not_supported(),
-                };
-                SbiRet::success(value)
-            }
-            spec::hsm::EID_HSM => {
-                let Some(hsm) = &self.hsm else {
-                    return SbiRet::not_supported();
-                };
-                let [param0, param1, param2] = [param[0], param[1], param[2]];
-                match function {
-                    spec::hsm::HART_START => hsm.hart_start(param0, param1, param2),
-                    spec::hsm::HART_STOP => hsm.hart_stop(),
-                    spec::hsm::HART_GET_STATUS => hsm.hart_get_status(param0),
-                    spec::hsm::HART_SUSPEND => {
-                        if let Ok(suspend_type) = u32::try_from(param0) {
-                            hsm.hart_suspend(suspend_type, param1, param2)
-                        } else {
-                            SbiRet::invalid_param()
-                        }
-                    }
-                    _ => SbiRet::not_supported(),
-                }
-            }
-            spec::srst::EID_SRST => {
-                let Some(srst) = &self.srst else {
-                    return SbiRet::not_supported();
-                };
-                let [param0, param1] = [param[0], param[1]];
-                match function {
-                    spec::srst::SYSTEM_RESET => {
-                        match (u32::try_from(param0), u32::try_from(param1)) {
-                            (Ok(reset_type), Ok(reset_reason)) => {
-                                srst.system_reset(reset_type, reset_reason)
-                            }
-                            (_, _) => SbiRet::invalid_param(),
-                        }
-                    }
-                    _ => SbiRet::not_supported(),
-                }
-            }
-            spec::pmu::EID_PMU => match () {
-                #[cfg(target_pointer_width = "64")]
-                () => {
-                    let Some(pmu) = &self.pmu else {
-                        return SbiRet::not_supported();
-                    };
-                    let [param0, param1, param2, param3, param4] =
-                        [param[0], param[1], param[2], param[3], param[4]];
-                    match function {
-                        spec::pmu::NUM_COUNTERS => SbiRet::success(pmu.num_counters()),
-                        spec::pmu::COUNTER_GET_INFO => pmu.counter_get_info(param0),
-                        spec::pmu::COUNTER_CONFIG_MATCHING => {
-                            pmu.counter_config_matching(param0, param1, param2, param3, param4 as _)
-                        }
-                        spec::pmu::COUNTER_START => {
-                            pmu.counter_start(param0, param1, param2, param3 as _)
-                        }
-                        spec::pmu::COUNTER_STOP => pmu.counter_stop(param0, param1, param2),
-                        spec::pmu::COUNTER_FW_READ => pmu.counter_fw_read(param0),
-                        spec::pmu::COUNTER_FW_READ_HI => pmu.counter_fw_read_hi(param0),
-                        _ => SbiRet::not_supported(),
-                    }
-                }
-                #[cfg(target_pointer_width = "32")]
-                () => {
-                    let Some(pmu) = &self.pmu else {
-                        return SbiRet::not_supported();
-                    };
-                    let [param0, param1, param2, param3, param4, param5] =
-                        [param[0], param[1], param[2], param[3], param[4], param[5]];
-                    match function {
-                        spec::pmu::NUM_COUNTERS => SbiRet::success(pmu.num_counters()),
-                        spec::pmu::COUNTER_GET_INFO => pmu.counter_get_info(param0),
-                        spec::pmu::COUNTER_CONFIG_MATCHING => pmu.counter_config_matching(
-                            param0,
-                            param1,
-                            param2,
-                            param3,
-                            concat_u32(param5, param4),
-                        ),
-                        spec::pmu::COUNTER_START => {
-                            pmu.counter_start(param0, param1, param2, concat_u32(param4, param3))
-                        }
-                        spec::pmu::COUNTER_STOP => pmu.counter_stop(param0, param1, param2),
-                        spec::pmu::COUNTER_FW_READ => pmu.counter_fw_read(param0),
-                        spec::pmu::COUNTER_FW_READ_HI => pmu.counter_fw_read_hi(param0),
-                        _ => SbiRet::not_supported(),
-                    }
-                }
-            },
-            spec::dbcn::EID_DBCN => {
-                let Some(dbcn) = &self.dbcn else {
-                    return SbiRet::not_supported();
-                };
-                let [param0, param1, param2] = [param[0], param[1], param[2]];
-                match function {
-                    spec::dbcn::CONSOLE_WRITE => {
-                        let bytes = Physical::new(param0, param1, param2);
-                        dbcn.write(bytes)
-                    }
-                    spec::dbcn::CONSOLE_READ => {
-                        let bytes = Physical::new(param0, param1, param2);
-                        dbcn.read(bytes)
-                    }
-                    spec::dbcn::CONSOLE_WRITE_BYTE => dbcn.write_byte((param0 & 0xFF) as u8),
-                    _ => SbiRet::not_supported(),
-                }
-            }
-            spec::susp::EID_SUSP => {
-                let Some(susp) = &self.susp else {
-                    return SbiRet::not_supported();
-                };
-                let [param0, param1, param2] = [param[0], param[1], param[2]];
-                match function {
-                    spec::susp::SUSPEND => match u32::try_from(param0) {
-                        Ok(sleep_type) => susp.system_suspend(sleep_type, param1, param2),
-                        _ => SbiRet::invalid_param(),
-                    },
-                    _ => SbiRet::not_supported(),
-                }
-            }
-            spec::cppc::EID_CPPC => match () {
-                #[cfg(target_pointer_width = "64")]
-                () => {
-                    let Some(cppc) = &self.cppc else {
-                        return SbiRet::not_supported();
-                    };
-                    let [param0, param1] = [param[0], param[1]];
-                    match function {
-                        spec::cppc::PROBE => match u32::try_from(param0) {
-                            Ok(reg_id) => cppc.probe(reg_id),
-                            _ => SbiRet::invalid_param(),
-                        },
-                        spec::cppc::READ => match u32::try_from(param0) {
-                            Ok(reg_id) => cppc.read(reg_id),
-                            _ => SbiRet::invalid_param(),
-                        },
-                        spec::cppc::READ_HI => match u32::try_from(param0) {
-                            Ok(reg_id) => cppc.read_hi(reg_id),
-                            _ => SbiRet::invalid_param(),
-                        },
-                        spec::cppc::WRITE => match u32::try_from(param0) {
-                            Ok(reg_id) => cppc.write(reg_id, param1 as _),
-                            _ => SbiRet::invalid_param(),
-                        },
-                        _ => SbiRet::not_supported(),
-                    }
-                }
-                #[cfg(target_pointer_width = "32")]
-                () => {
-                    let Some(cppc) = &self.cppc else {
-                        return SbiRet::not_supported();
-                    };
-                    let [param0, param1, param2] = [param[0], param[1], param[2]];
-                    match function {
-                        spec::cppc::PROBE => cppc.probe(param0 as _),
-                        spec::cppc::READ => cppc.read(param0 as _),
-                        spec::cppc::READ_HI => cppc.read_hi(param0 as _),
-                        spec::cppc::WRITE => cppc.write(param0 as _, concat_u32(param2, param1)),
-                        _ => SbiRet::not_supported(),
-                    }
-                }
-            },
-            _ => SbiRet::not_supported(),
-        }
-    }
-
-    #[inline]
-    fn probe_extension(&self, extension: usize) -> usize {
-        let ans = match extension {
-            spec::base::EID_BASE => true,
-            spec::time::EID_TIME => self.timer.is_some(),
-            spec::spi::EID_SPI => self.ipi.is_some(),
-            spec::rfnc::EID_RFNC => self.rfnc.is_some(),
-            spec::srst::EID_SRST => self.srst.is_some(),
-            spec::hsm::EID_HSM => self.hsm.is_some(),
-            spec::pmu::EID_PMU => self.pmu.is_some(),
-            spec::dbcn::EID_DBCN => self.dbcn.is_some(),
-            spec::susp::EID_SUSP => self.susp.is_some(),
-            spec::cppc::EID_CPPC => self.cppc.is_some(),
-            _ => false,
-        };
-        if ans {
-            spec::base::UNAVAILABLE_EXTENSION.wrapping_add(1)
-        } else {
-            spec::base::UNAVAILABLE_EXTENSION
-        }
-    }
-}
-
-#[cfg(target_pointer_width = "32")]
-#[inline]
-const fn concat_u32(h: usize, l: usize) -> u64 {
-    ((h as u64) << 32) | (l as u64)
-}
-
-/// Structure to build a RustSBI instance
-pub struct Builder<T, I, R, H, S, P, C, SU, CP> {
-    inner: RustSBI<T, I, R, H, S, P, C, SU, CP>,
-}
-
-impl
-    Builder<
-        Infallible,
-        Infallible,
-        Infallible,
-        Infallible,
-        Infallible,
-        Infallible,
-        Infallible,
-        Infallible,
-        Infallible,
-    >
-{
-    /// Create a new `Builder` from current machine environment
-    #[inline]
-    #[cfg(feature = "machine")]
-    pub const fn new_machine() -> Builder<
-        Infallible,
-        Infallible,
-        Infallible,
-        Infallible,
-        Infallible,
-        Infallible,
-        Infallible,
-        Infallible,
-        Infallible,
-    > {
-        Builder {
-            inner: RustSBI {
-                timer: None,
-                ipi: None,
-                rfnc: None,
-                hsm: None,
-                srst: None,
-                pmu: None,
-                dbcn: None,
-                susp: None,
-                cppc: None,
-            },
-        }
-    }
-
-    /// Create a new `Builder` from machine information
-    #[inline]
-    #[cfg(not(feature = "machine"))]
-    pub const fn with_machine_info(
-        info: MachineInfo,
-    ) -> Builder<
-        Infallible,
-        Infallible,
-        Infallible,
-        Infallible,
-        Infallible,
-        Infallible,
-        Infallible,
-        Infallible,
-        Infallible,
-    > {
-        Builder {
-            inner: RustSBI {
-                timer: None,
-                ipi: None,
-                rfnc: None,
-                hsm: None,
-                srst: None,
-                pmu: None,
-                dbcn: None,
-                susp: None,
-                cppc: None,
-                info,
-            },
-        }
-    }
-}
-
-// fixme: in future releases we may use type-changing struct update syntax like:
-// Builder { inner: RustSBI { timer: None, ..self.inner } }
-// https://github.com/rust-lang/rust/issues/86555
-
-// fixme: struct `Infallible` should be replaced to never type once it's stablized
-
-impl<T, I, R, H, S, P, C, SU, CP> Builder<T, I, R, H, S, P, C, SU, CP> {
-    /// Add Timer programmer extension to RustSBI
-    #[inline]
-    pub fn with_timer<T2: Timer>(self, timer: T2) -> Builder<T2, I, R, H, S, P, C, SU, CP> {
-        Builder {
-            inner: RustSBI {
-                timer: Some(timer),
-                ipi: self.inner.ipi,
-                rfnc: self.inner.rfnc,
-                hsm: self.inner.hsm,
-                srst: self.inner.srst,
-                pmu: self.inner.pmu,
-                dbcn: self.inner.dbcn,
-                susp: self.inner.susp,
-                cppc: self.inner.cppc,
-                #[cfg(not(feature = "machine"))]
-                info: self.inner.info,
-            },
-        }
-    }
-
-    /// Add Inter-processor Interrupt extension to RustSBI
-    #[inline]
-    pub fn with_ipi<I2: Ipi>(self, ipi: I2) -> Builder<T, I2, R, H, S, P, C, SU, CP> {
-        Builder {
-            inner: RustSBI {
-                timer: self.inner.timer,
-                ipi: Some(ipi),
-                rfnc: self.inner.rfnc,
-                hsm: self.inner.hsm,
-                srst: self.inner.srst,
-                pmu: self.inner.pmu,
-                dbcn: self.inner.dbcn,
-                susp: self.inner.susp,
-                cppc: self.inner.cppc,
-                #[cfg(not(feature = "machine"))]
-                info: self.inner.info,
-            },
-        }
-    }
-
-    /// Add Remote Fence extension to RustSBI
-    #[inline]
-    pub fn with_fence<R2: Fence>(self, fence: R2) -> Builder<T, I, R2, H, S, P, C, SU, CP> {
-        Builder {
-            inner: RustSBI {
-                timer: self.inner.timer,
-                ipi: self.inner.ipi,
-                rfnc: Some(fence),
-                hsm: self.inner.hsm,
-                srst: self.inner.srst,
-                pmu: self.inner.pmu,
-                dbcn: self.inner.dbcn,
-                susp: self.inner.susp,
-                cppc: self.inner.cppc,
-                #[cfg(not(feature = "machine"))]
-                info: self.inner.info,
-            },
-        }
-    }
-
-    /// Add Hart State Monitor extension to RustSBI
-    #[inline]
-    pub fn with_hsm<H2: Hsm>(self, hsm: H2) -> Builder<T, I, R, H2, S, P, C, SU, CP> {
-        Builder {
-            inner: RustSBI {
-                timer: self.inner.timer,
-                ipi: self.inner.ipi,
-                rfnc: self.inner.rfnc,
-                hsm: Some(hsm),
-                srst: self.inner.srst,
-                pmu: self.inner.pmu,
-                dbcn: self.inner.dbcn,
-                susp: self.inner.susp,
-                cppc: self.inner.cppc,
-                #[cfg(not(feature = "machine"))]
-                info: self.inner.info,
-            },
-        }
-    }
-
-    /// Add System Reset extension to RustSBI
-    #[inline]
-    pub fn with_reset<S2: Reset>(self, reset: S2) -> Builder<T, I, R, H, S2, P, C, SU, CP> {
-        Builder {
-            inner: RustSBI {
-                timer: self.inner.timer,
-                ipi: self.inner.ipi,
-                rfnc: self.inner.rfnc,
-                hsm: self.inner.hsm,
-                srst: Some(reset),
-                pmu: self.inner.pmu,
-                dbcn: self.inner.dbcn,
-                susp: self.inner.susp,
-                cppc: self.inner.cppc,
-                #[cfg(not(feature = "machine"))]
-                info: self.inner.info,
-            },
-        }
-    }
-
-    /// Add Performance Monitor Unit extension to RustSBI
-    #[inline]
-    pub fn with_pmu<P2: Pmu>(self, pmu: P2) -> Builder<T, I, R, H, S, P2, C, SU, CP> {
-        Builder {
-            inner: RustSBI {
-                timer: self.inner.timer,
-                ipi: self.inner.ipi,
-                rfnc: self.inner.rfnc,
-                hsm: self.inner.hsm,
-                srst: self.inner.srst,
-                pmu: Some(pmu),
-                dbcn: self.inner.dbcn,
-                susp: self.inner.susp,
-                cppc: self.inner.cppc,
-                #[cfg(not(feature = "machine"))]
-                info: self.inner.info,
-            },
-        }
-    }
-    /// Add Debug Console extension to RustSBI
-    #[inline]
-    pub fn with_console<C2: Console>(self, console: C2) -> Builder<T, I, R, H, S, P, C2, SU, CP> {
-        Builder {
-            inner: RustSBI {
-                timer: self.inner.timer,
-                ipi: self.inner.ipi,
-                rfnc: self.inner.rfnc,
-                hsm: self.inner.hsm,
-                srst: self.inner.srst,
-                pmu: self.inner.pmu,
-                dbcn: Some(console),
-                susp: self.inner.susp,
-                cppc: self.inner.cppc,
-                #[cfg(not(feature = "machine"))]
-                info: self.inner.info,
-            },
-        }
-    }
-    /// Add System Suspend extension to RustSBI
-    #[inline]
-    pub fn with_susp<SU2: Susp>(self, susp: SU2) -> Builder<T, I, R, H, S, P, C, SU2, CP> {
-        Builder {
-            inner: RustSBI {
-                timer: self.inner.timer,
-                ipi: self.inner.ipi,
-                rfnc: self.inner.rfnc,
-                hsm: self.inner.hsm,
-                srst: self.inner.srst,
-                pmu: self.inner.pmu,
-                dbcn: self.inner.dbcn,
-                susp: Some(susp),
-                cppc: self.inner.cppc,
-                #[cfg(not(feature = "machine"))]
-                info: self.inner.info,
-            },
-        }
-    }
-    /// Add CPPC extension to RustSBI
-    #[inline]
-    pub fn with_cppc<CP2: Cppc>(self, cppc: CP2) -> Builder<T, I, R, H, S, P, C, SU, CP2> {
-        Builder {
-            inner: RustSBI {
-                timer: self.inner.timer,
-                ipi: self.inner.ipi,
-                rfnc: self.inner.rfnc,
-                hsm: self.inner.hsm,
-                srst: self.inner.srst,
-                pmu: self.inner.pmu,
-                dbcn: self.inner.dbcn,
-                susp: self.inner.susp,
-                cppc: Some(cppc),
-                #[cfg(not(feature = "machine"))]
-                info: self.inner.info,
-            },
-        }
-    }
-
-    /// Build the target RustSBI instance
-    #[inline]
-    pub fn build(self) -> RustSBI<T, I, R, H, S, P, C, SU, CP> {
-        self.inner
-    }
-}
-
-// Placeholder for a structure that implements all RustSBI traits but is never accessed
-
-// fixme: Should be replaced to never type `!` once it's stablized
-// https://github.com/rust-lang/rust/issues/35121
-
-// fixme: should be replaced to impl SomeTrait for ! once never type is stablized
-
-impl crate::Timer for Infallible {
-    fn set_timer(&self, _: u64) {
-        unreachable!()
-    }
-}
-
-impl crate::Ipi for Infallible {
-    fn send_ipi(&self, _: HartMask) -> SbiRet {
-        unreachable!()
-    }
-}
-
-impl crate::Fence for Infallible {
-    #[inline]
-    fn remote_fence_i(&self, _: HartMask) -> SbiRet {
-        unreachable!()
-    }
-    #[inline]
-    fn remote_sfence_vma(&self, _: HartMask, _: usize, _: usize) -> SbiRet {
-        unreachable!()
-    }
-    #[inline]
-    fn remote_sfence_vma_asid(&self, _: HartMask, _: usize, _: usize, _: usize) -> SbiRet {
-        unreachable!()
-    }
-    #[inline]
-    fn remote_hfence_gvma_vmid(&self, _: HartMask, _: usize, _: usize, _: usize) -> SbiRet {
-        unreachable!()
-    }
-    #[inline]
-    fn remote_hfence_gvma(&self, _: HartMask, _: usize, _: usize) -> SbiRet {
-        unreachable!()
-    }
-    #[inline]
-    fn remote_hfence_vvma_asid(&self, _: HartMask, _: usize, _: usize, _: usize) -> SbiRet {
-        unreachable!()
-    }
-    #[inline]
-    fn remote_hfence_vvma(&self, _: HartMask, _: usize, _: usize) -> SbiRet {
-        unreachable!()
-    }
-}
-
-impl crate::Hsm for Infallible {
-    fn hart_start(&self, _: usize, _: usize, _: usize) -> SbiRet {
-        unreachable!()
-    }
-
-    fn hart_stop(&self) -> SbiRet {
-        unreachable!()
-    }
-
-    fn hart_get_status(&self, _: usize) -> SbiRet {
-        unreachable!()
-    }
-
-    fn hart_suspend(&self, _: u32, _: usize, _: usize) -> SbiRet {
-        unreachable!()
-    }
-}
-
-impl crate::Reset for Infallible {
-    fn system_reset(&self, _: u32, _: u32) -> SbiRet {
-        unreachable!()
-    }
-}
-
-impl crate::Pmu for Infallible {
-    fn num_counters(&self) -> usize {
-        unreachable!()
-    }
-
-    fn counter_get_info(&self, _: usize) -> SbiRet {
-        unreachable!()
-    }
-
-    fn counter_config_matching(&self, _: usize, _: usize, _: usize, _: usize, _: u64) -> SbiRet {
-        unreachable!()
-    }
-
-    fn counter_start(&self, _: usize, _: usize, _: usize, _: u64) -> SbiRet {
-        unreachable!()
-    }
-
-    fn counter_stop(&self, _: usize, _: usize, _: usize) -> SbiRet {
-        unreachable!()
-    }
-
-    fn counter_fw_read(&self, _: usize) -> SbiRet {
-        unreachable!()
-    }
-
-    fn counter_fw_read_hi(&self, _: usize) -> SbiRet {
-        unreachable!()
-    }
-}
-
-impl crate::Console for Infallible {
-    fn write(&self, _: Physical<&[u8]>) -> SbiRet {
-        unreachable!()
-    }
-
-    fn read(&self, _: Physical<&mut [u8]>) -> SbiRet {
-        unreachable!()
-    }
-
-    fn write_byte(&self, _: u8) -> SbiRet {
-        unreachable!()
-    }
-}
-
-impl crate::Susp for Infallible {
-    fn system_suspend(&self, _: u32, _: usize, _: usize) -> SbiRet {
-        unreachable!()
-    }
-}
-
-impl crate::Cppc for Infallible {
-    fn probe(&self, _: u32) -> SbiRet {
-        unreachable!()
-    }
-    fn read(&self, _: u32) -> SbiRet {
-        unreachable!()
-    }
-    fn read_hi(&self, _: u32) -> SbiRet {
-        unreachable!()
-    }
-    fn write(&self, _: u32, _: u64) -> SbiRet {
-        unreachable!()
-    }
-}

+ 7 - 7
src/lib.rs

@@ -552,7 +552,6 @@ pub use console::Console;
 pub use cppc::Cppc;
 pub use hart_mask::HartMask;
 pub use hsm::Hsm;
-// pub use instance::{Builder, RustSBI};
 pub use ipi::Ipi;
 pub use nacl::Nacl;
 pub use pmu::Pmu;
@@ -561,15 +560,16 @@ pub use rfence::Rfence as Fence;
 pub use sta::Sta;
 pub use susp::Susp;
 pub use timer::Timer;
-pub use traits::RustSBI;
+pub use traits::{MachineInfo, RustSBI};
 
-// macro internal functions and structures
+// Macro internal functions and structures
+
+#[cfg(feature = "machine")]
+#[doc(hidden)]
+pub use traits::_rustsbi_base_bare;
 #[doc(hidden)]
 pub use traits::{
-    _StandardExtensionProbe, _rustsbi_base_machine, _rustsbi_console, _rustsbi_cppc,
+    _StandardExtensionProbe, _rustsbi_base_machine_info, _rustsbi_console, _rustsbi_cppc,
     _rustsbi_fence, _rustsbi_hsm, _rustsbi_ipi, _rustsbi_nacl, _rustsbi_pmu, _rustsbi_reset,
     _rustsbi_sta, _rustsbi_susp, _rustsbi_timer,
 };
-
-// #[cfg(not(feature = "machine"))]
-// pub use instance::MachineInfo;

+ 58 - 12
src/traits.rs

@@ -1,4 +1,5 @@
 use crate::HartMask;
+#[cfg(feature = "machine")]
 use riscv::register::{marchid, mimpid, mvendorid};
 use spec::binary::{Physical, SbiRet, SharedPtr};
 
@@ -8,6 +9,24 @@ pub trait RustSBI {
     fn handle_ecall(&self, extension: usize, function: usize, param: [usize; 6]) -> SbiRet;
 }
 
+/// Machine information for SBI environment.
+///
+/// This trait is useful to build an SBI environment when RustSBI is not run directly on RISC-V machine mode.
+pub trait MachineInfo {
+    /// Vendor ID for the supervisor environment.
+    ///
+    /// Provides JEDEC manufacturer ID of the provider of the core.
+    fn mvendorid(&self) -> usize;
+    /// Architecture ID for the supervisor environment.
+    ///
+    /// Encodes the base micro-architecture of the hart.
+    fn marchid(&self) -> usize;
+    /// Implementation ID for the supervisor environment.
+    ///
+    /// Provides a unique encoding of the version of the processor implementation.
+    fn mimpid(&self) -> usize;
+}
+
 /* macro internal structures and functions */
 
 #[doc(hidden)]
@@ -27,9 +46,10 @@ pub struct _StandardExtensionProbe {
     // NOTE: don't forget to add to `fn probe_extension` as well
 }
 
+#[cfg(feature = "machine")]
 #[doc(hidden)]
 #[inline(always)]
-pub fn _rustsbi_base_machine(
+pub fn _rustsbi_base_bare(
     param: [usize; 6],
     function: usize,
     probe: _StandardExtensionProbe,
@@ -52,6 +72,32 @@ pub fn _rustsbi_base_machine(
     SbiRet::success(value)
 }
 
+#[doc(hidden)]
+#[inline(always)]
+pub fn _rustsbi_base_machine_info<T: MachineInfo>(
+    param: [usize; 6],
+    function: usize,
+    machine_info: &T,
+    probe: _StandardExtensionProbe,
+) -> SbiRet {
+    let [param0] = [param[0]];
+    let value = match function {
+        spec::base::GET_SBI_SPEC_VERSION => (crate::SBI_SPEC_MAJOR << 24) | (crate::SBI_SPEC_MINOR),
+        spec::base::GET_SBI_IMPL_ID => crate::IMPL_ID_RUSTSBI,
+        spec::base::GET_SBI_IMPL_VERSION => crate::RUSTSBI_VERSION,
+        spec::base::PROBE_EXTENSION => {
+            // only provides probes to standard extensions. If you have customized extensions to be probed,
+            // run it even before this `handle_ecall` function.
+            probe_extension(param0, probe)
+        }
+        spec::base::GET_MVENDORID => machine_info.mvendorid(),
+        spec::base::GET_MARCHID => machine_info.marchid(),
+        spec::base::GET_MIMPID => machine_info.mimpid(),
+        _ => return SbiRet::not_supported(),
+    };
+    SbiRet::success(value)
+}
+
 #[inline(always)]
 fn probe_extension(extension: usize, probe: _StandardExtensionProbe) -> usize {
     match extension {
@@ -73,7 +119,7 @@ fn probe_extension(extension: usize, probe: _StandardExtensionProbe) -> usize {
 
 #[doc(hidden)]
 #[inline(always)]
-pub fn _rustsbi_fence<T: crate::Fence>(fence: T, param: [usize; 6], function: usize) -> SbiRet {
+pub fn _rustsbi_fence<T: crate::Fence>(fence: &T, param: [usize; 6], function: usize) -> SbiRet {
     let [param0, param1, param2, param3, param4] =
         [param[0], param[1], param[2], param[3], param[4]];
     let hart_mask = HartMask::from_mask_base(param0, param1);
@@ -97,7 +143,7 @@ pub fn _rustsbi_fence<T: crate::Fence>(fence: T, param: [usize; 6], function: us
 
 #[doc(hidden)]
 #[inline(always)]
-pub fn _rustsbi_timer<T: crate::Timer>(timer: T, param: [usize; 6], function: usize) -> SbiRet {
+pub fn _rustsbi_timer<T: crate::Timer>(timer: &T, param: [usize; 6], function: usize) -> SbiRet {
     match () {
         #[cfg(target_pointer_width = "64")]
         () => {
@@ -126,7 +172,7 @@ pub fn _rustsbi_timer<T: crate::Timer>(timer: T, param: [usize; 6], function: us
 
 #[doc(hidden)]
 #[inline(always)]
-pub fn _rustsbi_ipi<T: crate::Ipi>(ipi: T, param: [usize; 6], function: usize) -> SbiRet {
+pub fn _rustsbi_ipi<T: crate::Ipi>(ipi: &T, param: [usize; 6], function: usize) -> SbiRet {
     let [param0, param1] = [param[0], param[1]];
     match function {
         spec::spi::SEND_IPI => ipi.send_ipi(HartMask::from_mask_base(param0, param1)),
@@ -136,7 +182,7 @@ pub fn _rustsbi_ipi<T: crate::Ipi>(ipi: T, param: [usize; 6], function: usize) -
 
 #[doc(hidden)]
 #[inline(always)]
-pub fn _rustsbi_hsm<T: crate::Hsm>(hsm: T, param: [usize; 6], function: usize) -> SbiRet {
+pub fn _rustsbi_hsm<T: crate::Hsm>(hsm: &T, param: [usize; 6], function: usize) -> SbiRet {
     let [param0, param1, param2] = [param[0], param[1], param[2]];
     match function {
         spec::hsm::HART_START => hsm.hart_start(param0, param1, param2),
@@ -155,7 +201,7 @@ pub fn _rustsbi_hsm<T: crate::Hsm>(hsm: T, param: [usize; 6], function: usize) -
 
 #[doc(hidden)]
 #[inline(always)]
-pub fn _rustsbi_reset<T: crate::Reset>(reset: T, param: [usize; 6], function: usize) -> SbiRet {
+pub fn _rustsbi_reset<T: crate::Reset>(reset: &T, param: [usize; 6], function: usize) -> SbiRet {
     let [param0, param1] = [param[0], param[1]];
     match function {
         spec::srst::SYSTEM_RESET => match (u32::try_from(param0), u32::try_from(param1)) {
@@ -168,7 +214,7 @@ pub fn _rustsbi_reset<T: crate::Reset>(reset: T, param: [usize; 6], function: us
 
 #[doc(hidden)]
 #[inline(always)]
-pub fn _rustsbi_pmu<T: crate::Pmu>(pmu: T, param: [usize; 6], function: usize) -> SbiRet {
+pub fn _rustsbi_pmu<T: crate::Pmu>(pmu: &T, param: [usize; 6], function: usize) -> SbiRet {
     match () {
         #[cfg(target_pointer_width = "64")]
         () => {
@@ -216,7 +262,7 @@ pub fn _rustsbi_pmu<T: crate::Pmu>(pmu: T, param: [usize; 6], function: usize) -
 #[doc(hidden)]
 #[inline(always)]
 pub fn _rustsbi_console<T: crate::Console>(
-    console: T,
+    console: &T,
     param: [usize; 6],
     function: usize,
 ) -> SbiRet {
@@ -237,7 +283,7 @@ pub fn _rustsbi_console<T: crate::Console>(
 
 #[doc(hidden)]
 #[inline(always)]
-pub fn _rustsbi_susp<T: crate::Susp>(susp: T, param: [usize; 6], function: usize) -> SbiRet {
+pub fn _rustsbi_susp<T: crate::Susp>(susp: &T, param: [usize; 6], function: usize) -> SbiRet {
     let [param0, param1, param2] = [param[0], param[1], param[2]];
     match function {
         spec::susp::SUSPEND => match u32::try_from(param0) {
@@ -250,7 +296,7 @@ pub fn _rustsbi_susp<T: crate::Susp>(susp: T, param: [usize; 6], function: usize
 
 #[doc(hidden)]
 #[inline(always)]
-pub fn _rustsbi_cppc<T: crate::Cppc>(cppc: T, param: [usize; 6], function: usize) -> SbiRet {
+pub fn _rustsbi_cppc<T: crate::Cppc>(cppc: &T, param: [usize; 6], function: usize) -> SbiRet {
     match () {
         #[cfg(target_pointer_width = "64")]
         () => {
@@ -291,7 +337,7 @@ pub fn _rustsbi_cppc<T: crate::Cppc>(cppc: T, param: [usize; 6], function: usize
 
 #[doc(hidden)]
 #[inline(always)]
-pub fn _rustsbi_nacl<T: crate::Nacl>(nacl: T, param: [usize; 6], function: usize) -> SbiRet {
+pub fn _rustsbi_nacl<T: crate::Nacl>(nacl: &T, param: [usize; 6], function: usize) -> SbiRet {
     let [param0, param1, param2] = [param[0], param[1], param[2]];
     match function {
         spec::nacl::PROBE_FEATURE => match u32::try_from(param0) {
@@ -308,7 +354,7 @@ pub fn _rustsbi_nacl<T: crate::Nacl>(nacl: T, param: [usize; 6], function: usize
 
 #[doc(hidden)]
 #[inline(always)]
-pub fn _rustsbi_sta<T: crate::Sta>(sta: T, param: [usize; 6], function: usize) -> SbiRet {
+pub fn _rustsbi_sta<T: crate::Sta>(sta: &T, param: [usize; 6], function: usize) -> SbiRet {
     let [param0, param1, param2] = [param[0], param[1], param[2]];
     match function {
         spec::sta::SET_SHMEM => sta.set_shmem(SharedPtr::new(param0, param1), param2),