1pub const EID_BASE: usize = 0x10;
5pub use fid::*;
6
7pub const UNAVAILABLE_EXTENSION: usize = 0;
9
10#[derive(Clone, Copy, Debug, PartialEq, Eq, Ord, Hash)]
18#[repr(transparent)]
19pub struct Version {
20 raw: usize,
21}
22
23impl Version {
24 #[inline]
26 pub const fn from_raw(raw: usize) -> Self {
27 Self { raw }
28 }
29
30 #[inline]
32 pub const fn major(self) -> usize {
33 (self.raw >> 24) & ((1 << 7) - 1)
34 }
35
36 #[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
59mod fid {
61 pub const GET_SBI_SPEC_VERSION: usize = 0x0;
65 pub const GET_SBI_IMPL_ID: usize = 0x1;
69 pub const GET_SBI_IMPL_VERSION: usize = 0x2;
73 pub const PROBE_EXTENSION: usize = 0x3;
77 pub const GET_MVENDORID: usize = 0x4;
81 pub const GET_MARCHID: usize = 0x5;
85 pub const GET_MIMPID: usize = 0x6;
89}
90
91pub mod impl_id {
95 pub const BBL: usize = 0;
97 pub const OPEN_SBI: usize = 1;
99 pub const XVISOR: usize = 2;
101 pub const KVM: usize = 3;
103 pub const RUST_SBI: usize = 4;
105 pub const DIOSIX: usize = 5;
107 pub const COFFER: usize = 6;
109 pub const XEN: usize = 7;
111 pub const POLARFIRE_HSS: usize = 8;
113 pub const COREBOOT: usize = 9;
115 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}