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}