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