Skip to main content

uefi_raw/
lib.rs

1// SPDX-License-Identifier: MIT OR Apache-2.0
2
3//! Raw interface for working with UEFI.
4//!
5//! This crate is intended for implementing UEFI services. It is also used for
6//! implementing the [`uefi`] crate, which provides a safe wrapper around UEFI.
7//!
8//! For creating UEFI applications and drivers, consider using the [`uefi`]
9//! crate instead of `uefi-raw`.
10//!
11//! [`uefi`]: https://crates.io/crates/uefi
12
13#![no_std]
14#![cfg_attr(docsrs, feature(doc_cfg))]
15#![deny(
16    clippy::all,
17    clippy::missing_const_for_fn,
18    clippy::missing_safety_doc,
19    clippy::must_use_candidate,
20    clippy::ptr_as_ptr,
21    clippy::undocumented_unsafe_blocks,
22    clippy::use_self,
23    missing_debug_implementations,
24    unused
25)]
26
27mod enums;
28
29pub mod capsule;
30pub mod firmware_storage;
31pub mod protocol;
32pub mod table;
33pub mod time;
34
35mod net;
36mod status;
37
38use core::cmp;
39pub use net::*;
40pub use status::Status;
41pub use uguid::{Guid, guid};
42
43use core::ffi::c_void;
44use core::hash::{Hash, Hasher};
45
46/// Handle to an event structure.
47pub type Event = *mut c_void;
48
49/// Handle to a UEFI entity (protocol, image, etc).
50pub type Handle = *mut c_void;
51
52/// One-byte character.
53///
54/// Most strings in UEFI use [`Char16`], but a few places use one-byte
55/// characters. Unless otherwise noted, these are encoded as 8-bit ASCII using
56/// the ISO-Latin-1 character set.
57pub type Char8 = u8;
58
59/// Two-byte character.
60///
61/// Unless otherwise noted, the encoding is UCS-2. The UCS-2 encoding was
62/// defined by Unicode 2.1 and ISO/IEC 10646 standards, but is no longer part of
63/// the modern Unicode standards. It is essentially UTF-16 without support for
64/// surrogate pairs.
65pub type Char16 = u16;
66
67/// Physical memory address. This is always a 64-bit value, regardless
68/// of target platform.
69pub type PhysicalAddress = u64;
70
71/// Virtual memory address. This is always a 64-bit value, regardless
72/// of target platform.
73pub type VirtualAddress = u64;
74
75/// ABI-compatible UEFI boolean.
76///
77/// This is similar to a `bool`, but allows values other than 0 or 1 to be
78/// stored without it being undefined behavior.
79///
80/// Any non-zero value is treated as logical `true`. The comparison, ordering,
81/// and hashing implementations follow that logical interpretation, so all
82/// non-zero values compare equal and hash the same way. The original byte is
83/// still preserved in the public field; compare the `.0` values directly when
84/// the exact raw bit pattern matters.
85#[derive(Copy, Clone, Debug, Default)]
86#[repr(transparent)]
87pub struct Boolean(pub u8);
88
89impl Boolean {
90    /// [`Boolean`] representing `true`.
91    ///
92    /// # Caution
93    ///
94    /// This is only one possible true bit pattern. In UEFI, every non-zero
95    /// bit pattern is treated as logical `true`.
96    pub const TRUE: Self = Self(1);
97
98    /// [`Boolean`] representing `false`.
99    pub const FALSE: Self = Self(0);
100}
101
102impl From<u8> for Boolean {
103    fn from(value: u8) -> Self {
104        Self(value)
105    }
106}
107
108impl From<bool> for Boolean {
109    fn from(value: bool) -> Self {
110        match value {
111            true => Self(1),
112            false => Self(0),
113        }
114    }
115}
116
117impl From<Boolean> for bool {
118    #[expect(clippy::match_like_matches_macro)]
119    fn from(value: Boolean) -> Self {
120        // We handle it as in C: Any bit-pattern != 0 equals true
121        match value.0 {
122            0 => false,
123            _ => true,
124        }
125    }
126}
127
128impl PartialEq for Boolean {
129    fn eq(&self, other: &Self) -> bool {
130        match (self.0, other.0) {
131            (0, 0) => true,
132            (0, _) => false,
133            (_, 0) => false,
134            // We handle it as in C: Any bit-pattern != 0 equals true
135            (_, _) => true,
136        }
137    }
138}
139
140impl Eq for Boolean {}
141
142impl PartialOrd for Boolean {
143    fn partial_cmp(&self, other: &Self) -> Option<cmp::Ordering> {
144        Some(self.cmp(other))
145    }
146}
147
148impl Ord for Boolean {
149    fn cmp(&self, other: &Self) -> cmp::Ordering {
150        match (self.0, other.0) {
151            (0, 0) => cmp::Ordering::Equal,
152            (0, _) => cmp::Ordering::Less,
153            (_, 0) => cmp::Ordering::Greater,
154            // We handle it as in C: Any bit-pattern != 0 equals true
155            (_, _) => cmp::Ordering::Equal,
156        }
157    }
158}
159
160impl Hash for Boolean {
161    fn hash<H: Hasher>(&self, state: &mut H) {
162        let seed = if self.0 == 0 { 0 } else { 1 };
163        state.write_u8(seed);
164    }
165}
166
167#[cfg(test)]
168mod tests {
169    use super::*;
170
171    #[test]
172    /// Test the properties promised in [0]. This also applies for the other
173    /// architectures.
174    ///
175    /// [0] https://github.com/tianocore/edk2/blob/b0f43dd3fdec2363e3548ec31eb455dc1c4ac761/MdePkg/Include/X64/ProcessorBind.h#L192
176    fn test_boolean_abi() {
177        assert_eq!(size_of::<Boolean>(), 1);
178        assert_eq!(Boolean::from(true).0, 1);
179        assert_eq!(Boolean::from(false).0, 0);
180        assert_eq!(Boolean::TRUE.0, 1);
181        assert_eq!(Boolean::FALSE.0, 0);
182        assert!(!bool::from(Boolean(0b0)));
183        assert!(bool::from(Boolean(0b1)));
184        // We do it as in C: Every bit pattern not 0 is equal to true.
185        assert!(bool::from(Boolean(0b11111110)));
186        assert!(bool::from(Boolean(0b11111111)));
187    }
188
189    #[test]
190    fn test_order() {
191        assert!(Boolean::FALSE < Boolean::TRUE);
192        assert!(Boolean::TRUE > Boolean::FALSE);
193    }
194
195    #[test]
196    fn test_equality() {
197        assert_eq!(Boolean(0), Boolean(0));
198        assert_ne!(Boolean(0), Boolean(3));
199        assert_ne!(Boolean(7), Boolean(0));
200        assert_eq!(Boolean(1), Boolean(1));
201        assert_eq!(Boolean(13), Boolean(7));
202    }
203
204    // Tests that hash impl matches equal impl
205    #[test]
206    fn test_hash() {
207        #[derive(Default)]
208        struct TestHasher(u64);
209
210        impl Hasher for TestHasher {
211            fn finish(&self) -> u64 {
212                self.0
213            }
214
215            fn write(&mut self, bytes: &[u8]) {
216                for byte in bytes {
217                    self.0 = self.0.wrapping_mul(257).wrapping_add(u64::from(*byte));
218                }
219            }
220        }
221
222        fn calculate_hash(value: Boolean) -> u64 {
223            let mut hasher = TestHasher::default();
224            value.hash(&mut hasher);
225            hasher.finish()
226        }
227
228        assert_eq!(calculate_hash(Boolean(1)), calculate_hash(Boolean(13)));
229        assert_eq!(calculate_hash(Boolean(13)), calculate_hash(Boolean(255)));
230        assert_ne!(calculate_hash(Boolean(0)), calculate_hash(Boolean(13)));
231    }
232}