sbi_spec/
base.rs

1//! Chapter 4. Base Extension (EID #0x10).
2
3/// Extension ID for RISC-V SBI Base extension.
4pub const EID_BASE: usize = 0x10;
5pub use fid::*;
6
7/// Default probe value for the target SBI extension is unavailable.
8pub const UNAVAILABLE_EXTENSION: usize = 0;
9
10/// SBI specification version.
11///
12/// In RISC-V SBI specification, the bit 31 must be 0 and is reserved for future expansion.
13///
14/// Not to be confused with 'implementation version'.
15///
16/// Declared in §4.1.
17#[derive(Clone, Copy, Debug, PartialEq, Eq, Ord, Hash)]
18#[repr(transparent)]
19pub struct Version {
20    raw: usize,
21}
22
23impl Version {
24    /// Converts raw extension value into Version structure.
25    #[inline]
26    pub const fn from_raw(raw: usize) -> Self {
27        Self { raw }
28    }
29
30    /// Reads the major version of RISC-V SBI specification.
31    #[inline]
32    pub const fn major(self) -> usize {
33        (self.raw >> 24) & ((1 << 7) - 1)
34    }
35
36    /// Reads the minor version of RISC-V SBI specification.
37    #[inline]
38    pub const fn minor(self) -> usize {
39        self.raw & ((1 << 24) - 1)
40    }
41}
42
43impl core::fmt::Display for Version {
44    #[inline]
45    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
46        write!(f, "{}.{}", self.major(), self.minor())
47    }
48}
49
50impl core::cmp::PartialOrd for Version {
51    #[inline]
52    fn partial_cmp(&self, other: &Self) -> Option<core::cmp::Ordering> {
53        self.major()
54            .partial_cmp(&other.major())
55            .map(|ordering| ordering.then_with(|| self.minor().cmp(&other.minor())))
56    }
57}
58
59/// Declared in §4.8
60mod fid {
61    /// Function ID to get the current SBI specification version.
62    ///
63    /// Declared in §4.1.
64    pub const GET_SBI_SPEC_VERSION: usize = 0x0;
65    /// Function ID to get the current SBI implementation ID.
66    ///
67    /// Declared in §4.2.
68    pub const GET_SBI_IMPL_ID: usize = 0x1;
69    /// Function ID to get the current SBI implementation version.
70    ///
71    /// Declared in §4.3.
72    pub const GET_SBI_IMPL_VERSION: usize = 0x2;
73    /// Function ID to probe information about one SBI extension from the current environment.
74    ///
75    /// Declared in §4.4.
76    pub const PROBE_EXTENSION: usize = 0x3;
77    /// Function ID to get the value of `mvendorid` register in the current environment.
78    ///
79    /// Declared in §4.5.
80    pub const GET_MVENDORID: usize = 0x4;
81    /// Function ID to get the value of `marchid` register in the current environment.
82    ///
83    /// Declared in §4.6.
84    pub const GET_MARCHID: usize = 0x5;
85    /// Function ID to get the value of `mimpid` register in the current environment.
86    ///
87    /// Declared in §4.7.
88    pub const GET_MIMPID: usize = 0x6;
89}
90
91/// SBI Implementation IDs.
92///
93/// Declared in §4.9.
94pub mod impl_id {
95    /// Berkley Bootloader.
96    pub const BBL: usize = 0;
97    /// OpenSBI.
98    pub const OPEN_SBI: usize = 1;
99    /// Xvisor.
100    pub const XVISOR: usize = 2;
101    /// KVM.
102    pub const KVM: usize = 3;
103    /// RustSBI.
104    pub const RUST_SBI: usize = 4;
105    /// Diosix.
106    pub const DIOSIX: usize = 5;
107    /// Coffer.
108    pub const COFFER: usize = 6;
109    /// Xen Project.
110    pub const XEN: usize = 7;
111    /// PolarFire Hart Software Services.
112    pub const POLARFIRE_HSS: usize = 8;
113    /// Coreboot.
114    pub const COREBOOT: usize = 9;
115    /// Oreboot.
116    pub const OREBOOT: usize = 10;
117}
118
119#[cfg(test)]
120mod tests {
121    use super::Version;
122
123    #[test]
124    fn version_parse() {
125        let v1_0 = Version::from_raw(0x100_0000);
126        assert_eq!(v1_0.major(), 1);
127        assert_eq!(v1_0.minor(), 0);
128
129        let v2_0 = Version::from_raw(0x200_0000);
130        assert_eq!(v2_0.major(), 2);
131        assert_eq!(v2_0.minor(), 0);
132
133        let v2_1 = Version::from_raw(0x200_0001);
134        assert_eq!(v2_1.major(), 2);
135        assert_eq!(v2_1.minor(), 1);
136
137        let v2_max = Version::from_raw(0x2ff_ffff);
138        assert_eq!(v2_max.major(), 2);
139        assert_eq!(v2_max.minor(), 16777215);
140
141        let vmax_3 = Version::from_raw(0x7f00_0003);
142        assert_eq!(vmax_3.major(), 127);
143        assert_eq!(vmax_3.minor(), 3);
144
145        let vmax_max = Version::from_raw(0x7fff_ffff);
146        assert_eq!(vmax_max.major(), 127);
147        assert_eq!(vmax_max.minor(), 16777215);
148    }
149
150    #[test]
151    fn version_display() {
152        extern crate alloc;
153        use alloc::string::ToString;
154
155        assert_eq!("0.0", &Version::from_raw(0).to_string());
156        assert_eq!("0.1", &Version::from_raw(0x1).to_string());
157        assert_eq!("1.0", &Version::from_raw(0x100_0000).to_string());
158        assert_eq!("1.1", &Version::from_raw(0x100_0001).to_string());
159        assert_eq!("2.0", &Version::from_raw(0x200_0000).to_string());
160        assert_eq!("127.0", &Version::from_raw(0x7f00_0000).to_string());
161        assert_eq!("2.16777215", &Version::from_raw(0x2ff_ffff).to_string());
162        assert_eq!("127.16777215", &Version::from_raw(0x7fff_ffff).to_string());
163    }
164
165    #[test]
166    fn version_ordering() {
167        use core::cmp::Ordering;
168        let v0_0 = Version::from_raw(0x0);
169        let v0_3 = Version::from_raw(0x3);
170        let v1_0 = Version::from_raw(0x100_0000);
171        let v2_0 = Version::from_raw(0x200_0000);
172        let v2_1 = Version::from_raw(0x200_0001);
173        let v2_max = Version::from_raw(0x2ff_ffff);
174        let vmax_3 = Version::from_raw(0x7f00_0003);
175        let vmax_max = Version::from_raw(0x7fff_ffff);
176
177        assert!(v0_3 != v0_0);
178        assert!(!(v0_3 == v0_0));
179        assert!(v0_0 == v0_0);
180        assert!(vmax_max == vmax_max);
181
182        assert!(v0_3 > v0_0);
183        assert!(v0_3 >= v0_0);
184        assert!(v0_0 < v0_3);
185        assert!(v0_0 <= v0_3);
186        assert!(v0_0 >= v0_0);
187        assert!(v0_0 <= v0_0);
188
189        assert!(v0_3 > v0_0);
190        assert!(v1_0 > v0_3);
191        assert!(v2_0 > v1_0);
192        assert!(v2_1 > v2_0);
193        assert!(v2_max > v2_1);
194        assert!(vmax_3 > v2_max);
195        assert!(vmax_max > vmax_3);
196
197        assert_eq!(Version::partial_cmp(&v1_0, &v0_0), Some(Ordering::Greater));
198        assert_eq!(Version::partial_cmp(&v0_0, &v1_0), Some(Ordering::Less));
199        assert_eq!(Version::partial_cmp(&v0_0, &v0_0), Some(Ordering::Equal));
200
201        assert_eq!(Version::max(v0_0, v0_0), v0_0);
202        assert_eq!(Version::max(v1_0, v0_0), v1_0);
203        assert_eq!(Version::max(v0_0, v1_0), v1_0);
204        assert_eq!(Version::min(v0_0, v0_0), v0_0);
205        assert_eq!(Version::min(v1_0, v0_0), v0_0);
206        assert_eq!(Version::min(v0_0, v1_0), v0_0);
207
208        assert_eq!(v0_0.clamp(v0_3, v2_0), v0_3);
209        assert_eq!(v0_3.clamp(v0_3, v2_0), v0_3);
210        assert_eq!(v1_0.clamp(v0_3, v2_0), v1_0);
211        assert_eq!(v2_0.clamp(v0_3, v2_0), v2_0);
212        assert_eq!(v2_1.clamp(v0_3, v2_0), v2_0);
213    }
214}