sbi_rt/
base.rs

1//! Chapter 4. Base Extension (EID #0x10)
2
3use crate::binary::{sbi_call_0, sbi_call_1};
4
5use sbi_spec::base::{
6    Version, EID_BASE, GET_MARCHID, GET_MIMPID, GET_MVENDORID, GET_SBI_IMPL_ID,
7    GET_SBI_IMPL_VERSION, GET_SBI_SPEC_VERSION, PROBE_EXTENSION,
8};
9
10/// Return the current SBI specification version.
11///
12/// The minor number of the SBI specification is encoded in the low 24 bits,
13/// with the major number encoded in the next 7 bits.
14/// Bit 31 must be zero and is reserved for future expansion.
15///
16/// This function is defined in RISC-V SBI Specification chapter 4.1.
17/// According to the introduction of chapter 4, all base extension functions
18/// must success and return no error code.
19#[inline]
20pub fn get_spec_version() -> Version {
21    Version::from_raw(sbi_call_0(EID_BASE, GET_SBI_SPEC_VERSION).value)
22}
23
24/// Return the current SBI implementation ID.
25///
26/// Implementation ID is different for every SBI implementation.
27/// It is intended that this implementation ID allows software to probe
28/// for SBI implementation quirks.
29///
30/// This function is defined in RISC-V SBI Specification chapter 4.2.
31/// According to the introduction of chapter 4, all base extension functions
32/// must success and return no error code.
33#[inline]
34pub fn get_sbi_impl_id() -> usize {
35    sbi_call_0(EID_BASE, GET_SBI_IMPL_ID).value
36}
37
38/// Return the current SBI implementation version.
39///
40/// The encoding of this version number is specific to the SBI implementation.
41///
42/// This function is defined in RISC-V SBI Specification chapter 4.3.
43/// According to the introduction of chapter 4, all base extension functions
44/// must success and return no error code.
45#[inline]
46pub fn get_sbi_impl_version() -> usize {
47    sbi_call_0(EID_BASE, GET_SBI_IMPL_VERSION).value
48}
49
50/// Probe information about one SBI extension from the current environment.
51///
52/// Returns 0 if given SBI `extension_id` is not available, or typically
53/// 1 if it's available. Implementation would define further non-zero
54/// return values for information about this extension if it is available.
55///
56/// This function is defined in RISC-V SBI Specification chapter 4.4.
57/// According to the introduction of chapter 4, all base extension functions
58/// must success and return no error code.
59#[inline]
60pub fn probe_extension<E>(extension: E) -> ExtensionInfo
61where
62    E: Extension,
63{
64    let ans = sbi_call_1(EID_BASE, PROBE_EXTENSION, extension.extension_id());
65    ExtensionInfo { raw: ans.value }
66}
67
68/// Return the value of `mvendorid` register in the current environment.
69///
70/// This function returns a value that is legal for the `mvendorid` register,
71/// and 0 is always a legal value for this register.
72///
73/// This function is defined in RISC-V SBI Specification chapter 4.5.
74/// According to the introduction of chapter 4, all base extension functions
75/// must success and return no error code.
76#[inline]
77pub fn get_mvendorid() -> usize {
78    sbi_call_0(EID_BASE, GET_MVENDORID).value
79}
80
81/// Return value of `marchid` register in the current environment.
82///
83/// This function returns a value that is legal for the `marchid` register,
84/// and 0 is always a legal value for this register.
85///
86/// This function is defined in RISC-V SBI Specification chapter 4.6.
87/// According to the introduction of chapter 4, all base extension functions
88/// must success and return no error code.
89#[inline]
90pub fn get_marchid() -> usize {
91    sbi_call_0(EID_BASE, GET_MARCHID).value
92}
93
94/// Return value of `mimpid` register in the current environment.
95///
96/// This function returns a value that is legal for the `mimpid` register,
97/// and 0 is always a legal value for this register.
98///
99/// This function is defined in RISC-V SBI Specification chapter 4.7.
100/// According to the introduction of chapter 4, all base extension functions
101/// must success and return no error code.
102#[inline]
103pub fn get_mimpid() -> usize {
104    sbi_call_0(EID_BASE, GET_MIMPID).value
105}
106
107/// An SBI extension.
108pub trait Extension {
109    /// Get a raw `extension_id` value to pass to SBI environment.
110    fn extension_id(&self) -> usize;
111}
112
113macro_rules! define_extension {
114    ($($struct:ident($value:expr) #[$doc:meta])*) => {
115        $(
116            #[derive(Clone, Copy, Debug)]
117            #[$doc]
118            pub struct $struct;
119            impl Extension for $struct {
120                #[inline]
121                fn extension_id(&self) -> usize {
122                    $value
123                }
124            }
125        )*
126    };
127}
128
129define_extension! {
130    Base(sbi_spec::base::EID_BASE) /// RISC-V SBI Base extension.
131    Timer(sbi_spec::time::EID_TIME) /// Timer programmer extension.
132    Ipi(sbi_spec::spi::EID_SPI) /// Inter-processor Interrupt extension.
133    Fence(sbi_spec::rfnc::EID_RFNC) /// Remote Fence extension.
134    Hsm(sbi_spec::hsm::EID_HSM) /// Hart State Monitor extension.
135    Reset(sbi_spec::srst::EID_SRST) /// System Reset extension.
136    Pmu(sbi_spec::pmu::EID_PMU) /// Performance Monitoring Unit extension.
137    Console(sbi_spec::dbcn::EID_DBCN) /// Debug Console extension.
138    Suspend(sbi_spec::susp::SUSPEND) /// System Suspend extension.
139    Cppc(sbi_spec::cppc::EID_CPPC) /// SBI CPPC extension.
140    Nacl(sbi_spec::nacl::EID_NACL) /// Nested Acceleration extension.
141    Sta(sbi_spec::sta::EID_STA) /// Steal-time Accounting extension.
142}
143
144#[cfg(feature = "integer-impls")]
145impl Extension for usize {
146    #[inline]
147    fn extension_id(&self) -> usize {
148        *self
149    }
150}
151
152#[cfg(feature = "integer-impls")]
153impl Extension for isize {
154    #[inline]
155    fn extension_id(&self) -> usize {
156        usize::from_ne_bytes(isize::to_ne_bytes(*self))
157    }
158}
159
160/// Information about an SBI extension.
161#[derive(Clone, Copy, Debug)]
162pub struct ExtensionInfo {
163    pub raw: usize,
164}
165
166impl ExtensionInfo {
167    /// Is this extension available?
168    #[inline]
169    pub const fn is_available(&self) -> bool {
170        self.raw != 0
171    }
172
173    /// Is this extension not available?
174    #[inline]
175    pub const fn is_unavailable(&self) -> bool {
176        self.raw == 0
177    }
178}
179
180#[cfg(test)]
181mod tests {
182    #[test]
183    fn extension_id_defined() {
184        use crate::Extension;
185        assert_eq!(crate::Base.extension_id(), 0x10);
186        assert_eq!(crate::Timer.extension_id(), 0x54494D45);
187        assert_eq!(crate::Ipi.extension_id(), 0x735049);
188        assert_eq!(crate::Fence.extension_id(), 0x52464E43);
189        assert_eq!(crate::Hsm.extension_id(), 0x48534D);
190        assert_eq!(crate::Reset.extension_id(), 0x53525354);
191        assert_eq!(crate::Pmu.extension_id(), 0x504D55);
192        assert_eq!(crate::Console.extension_id(), 0x4442434E);
193        assert_eq!(crate::Suspend.extension_id(), 0x53555350);
194        assert_eq!(crate::Cppc.extension_id(), 0x43505043);
195        assert_eq!(crate::Nacl.extension_id(), 0x4E41434C);
196        assert_eq!(crate::Sta.extension_id(), 0x535441);
197    }
198}