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