Skip to main content

r_efi/
base.rs

1//! UEFI Base Environment
2//!
3//! This module defines the base environment for UEFI development. It provides types and macros as
4//! declared in the UEFI specification, as well as de-facto standard additions provided by the
5//! reference implementation by Intel.
6//!
7//! # Target Configuration
8//!
9//! Wherever possible, native rust types are used to represent their UEFI counter-parts. However,
10//! this means the ABI depends on the implementation of said rust types. Hence, native rust types
11//! are only used where rust supports a stable ABI of said types, and their ABI matches the ABI
12//! defined by the UEFI specification.
13//!
14//! Nevertheless, even if the ABI of a specific type is marked stable, this does not imply that it
15//! is the same across architectures. For instance, rust's `u64` type has the same binary
16//! representation as the `UINT64` type in UEFI. But this does not imply that it has the same
17//! binary representation on `x86_64` and on `ppc64be`. As a result of this, the compilation of
18//! this module is tied to the target-configuration you passed to the rust compiler. Wherever
19//! possible and reasonable, any architecture differences are abstracted, though. This means that
20//! in most cases you can use this module even though your target-configuration might not match
21//! the native UEFI target-configuration.
22//!
23//! The recommend way to compile your code, is to use the native target-configuration for UEFI.
24//! These configurations are not necessarily included in the upstream rust compiler. Hence, you
25//! might have to craft one yourself. For all systems that we can test on, we make sure to push
26//! the target configuration into upstream rust-lang.
27//!
28//! However, there are situations where you want to access UEFI data from a non-native host. For
29//! instance, a UEFI boot loader might store data in boot variables, formatted according to types
30//! declared in the UEFI specification. An OS booted thereafter might want to access these
31//! variables, but it might be compiled with a different target-configuration than the UEFI
32//! environment that it was booted from. A similar situation occurs when you call UEFI runtime
33//! functions from your OS. In all those cases, you should very likely be able to use this module
34//! to interact with UEFI as well. This is, because most bits of the target-configuration of UEFI
35//! and your OS very likely match. In fact, to figure out whether this is safe, you need to make
36//! sure that the rust ABI would match in both target-configurations. If it is, all other details
37//! are handled within this module just fine.
38//!
39//! In case of doubt, contact us!
40//!
41//! # Core Primitives
42//!
43//! Several of the UEFI primitives are represented by native Rust. These have no type aliases or
44//! other definitions here, but you are recommended to use native rust directly. These include:
45//!
46//!  * `NULL`, `void *`: Void pointers have a native rust implementation in
47//!                      [`c_void`](core::ffi::c_void). `NULL` is represented through
48//!                      [`null`](core::ptr::null) and [`is_null()`](core::ptr) for
49//!                      all pointer types.
50//!  * `uint8_t`..`uint64_t`,
51//!    `int8_t`..`int64_t`: Fixed-size integers are represented by their native rust equivalents
52//!                         (`u8`..`u64`, `i8`..`i64`).
53//!
54//!  * `UINTN`, `INTN`: Native-sized (or instruction-width sized) integers are represented by
55//!                     their native rust equivalents (`usize`, `isize`).
56//!
57//! # UEFI Details
58//!
59//! The UEFI Specification describes its target environments in detail. Each supported
60//! architecture has a separate section with details on calling conventions, CPU setup, and more.
61//! You are highly recommended to conduct the UEFI Specification for details on the programming
62//! environment. Following a summary of key parts relevant to rust developers:
63//!
64//!  * Similar to rust, integers are either fixed-size, or native size. This maps nicely to the
65//!    native rust types. The common `long`, `int`, `short` types known from ISO-C are not used.
66//!    Whenever you refer to memory (either pointing to it, or remember the size of a memory
67//!    block), the native size integers should be your tool of choice.
68//!
69//!  * Even though the CPU might run in any endianness, all stored data is little-endian. That
70//!    means, if you encounter integers split into byte-arrays (e.g.,
71//!    `CEfiDevicePathProtocol.length`), you must assume it is little-endian encoded. But if you
72//!    encounter native integers, you must assume they are encoded in native endianness.
73//!    For now the UEFI specification only defines little-endian architectures, hence this did not
74//!    pop up as actual issue. Future extensions might change this, though.
75//!
76//!  * The Microsoft calling-convention is used. That is, all external calls to UEFI functions
77//!    follow a calling convention that is very similar to that used on Microsoft Windows. All
78//!    such ABI functions must be marked with the right calling-convention. The UEFI Specification
79//!    defines some additional common rules for all its APIs, though. You will most likely not see
80//!    any of these mentioned in the individual API documentions. So here is a short reminder:
81//!
82//!     * Pointers must reference physical-memory locations (no I/O mappings, no
83//!       virtual addresses, etc.). Once ExitBootServices() was called, and the
84//!       virtual address mapping was set, you must provide virtual-memory
85//!       locations instead.
86//!     * Pointers must be correctly aligned.
87//!     * NULL is disallowed, unless explicitly mentioned otherwise.
88//!     * Data referenced by pointers is undefined on error-return from a
89//!       function.
90//!     * You must not pass data larger than native-size (sizeof(CEfiUSize)) on
91//!       the stack. You must pass them by reference.
92//!
93//!  * Stack size is at least 128KiB and 16-byte aligned. All stack space might be marked
94//!    non-executable! Once ExitBootServices() was called, you must guarantee at least 4KiB of
95//!    stack space, 16-byte aligned for all runtime services you call.
96//!    Details might differ depending on architectures. But the numbers here should serve as
97//!    ball-park figures.
98
99// Target Architecture
100//
101// The UEFI Specification explicitly lists all supported target architectures. While external
102// implementors are free to port UEFI to other targets, we need information on the target
103// architecture to successfully compile for it. This includes calling-conventions, register
104// layouts, endianness, and more. Most of these details are hidden in the rust-target-declaration.
105// However, some details are still left to the actual rust code.
106//
107// This initial check just makes sure the compilation is halted with a suitable error message if
108// the target architecture is not supported.
109//
110// We try to minimize conditional compilations as much as possible. A simple search for
111// `target_arch` should reveal all uses throughout the code-base. If you add your target to this
112// error-check, you must adjust all other uses as well.
113//
114// Similarly, UEFI only defines configurations for little-endian architectures so far. Several
115// bits of the specification are thus unclear how they would be applied on big-endian systems. We
116// therefore mark it as unsupported. If you override this, you are on your own.
117#[cfg(not(any(
118    target_arch = "arm",
119    target_arch = "aarch64",
120    target_arch = "riscv64",
121    target_arch = "x86",
122    target_arch = "x86_64"
123)))]
124compile_error!("The target architecture is not supported.");
125#[cfg(not(target_endian = "little"))]
126compile_error!("The target endianness is not supported.");
127
128// eficall_abi!()
129//
130// This macro is the architecture-dependent implementation of eficall!(). See the documentation of
131// the eficall!() macro for a description. Nowadays, this simply maps to `extern "efiapi"`, since
132// this has been stabilized with rust-1.68.
133
134#[macro_export]
135#[doc(hidden)]
136macro_rules! eficall_abi {
137    (($($prefix:tt)*),($($suffix:tt)*)) => { $($prefix)* extern "efiapi" $($suffix)* };
138}
139
140/// Annotate function with UEFI calling convention
141///
142/// Since rust-1.68 you can use `extern "efiapi"` as calling-convention to achieve the same
143/// behavior as this macro. This macro is kept for backwards-compatibility only, but will nowadays
144/// map to `extern "efiapi"`.
145///
146/// This macro takes a function-declaration as argument and produces the same function-declaration
147/// but annotated with the correct calling convention. Since the default `extern "C"` annotation
148/// depends on your compiler defaults, we cannot use it. Instead, this macro selects the default
149/// for your target platform.
150///
151/// Ideally, the macro would expand to `extern "<abi>"` so you would be able to write:
152///
153/// ```ignore
154/// // THIS DOES NOT WORK!
155/// pub fn eficall!{} foobar() {
156///     // ...
157/// }
158/// ```
159///
160/// However, macros are evaluated too late for this to work. Instead, the entire construct must be
161/// wrapped in a macro, which then expands to the same construct but with `extern "<abi>"`
162/// inserted at the correct place:
163///
164/// ```
165/// use r_efi::{eficall, eficall_abi};
166///
167/// eficall!{pub fn foobar() {
168///     // ...
169/// }}
170///
171/// type FooBar = eficall!{fn(u8) -> (u8)};
172/// ```
173///
174/// The `eficall!{}` macro takes either a function-type or function-definition as argument. It
175/// inserts `extern "<abi>"` after the function qualifiers, but before the `fn` keyword.
176///
177/// # Internals
178///
179/// The `eficall!{}` macro tries to parse the function header so it can insert `extern "<abi>"` at
180/// the right place. If, for whatever reason, this does not work with a particular syntax, you can
181/// use the internal `eficall_abi!{}` macro. This macro takes two token-streams as input and
182/// evaluates to the concatenation of both token-streams, but separated by the selected ABI.
183///
184/// For instance, the following 3 type definitions are equivalent, assuming the selected ABI
185/// is "C":
186///
187/// ```
188/// use r_efi::{eficall, eficall_abi};
189///
190/// type FooBar1 = unsafe extern "C" fn(u8) -> (u8);
191/// type FooBar2 = eficall!{unsafe fn(u8) -> (u8)};
192/// type FooBar3 = eficall_abi!{(unsafe), (fn(u8) -> (u8))};
193/// ```
194///
195/// # Calling Conventions
196///
197/// The UEFI specification defines the calling convention for each platform individually. It
198/// usually refers to other standards for details, but adds some restrictions on top. As of this
199/// writing, it mentions:
200///
201///  * aarch32 / arm: The `aapcs` calling-convention is used. It is native to aarch32 and described
202///                   in a document called
203///                   "Procedure Call Standard for the ARM Architecture". It is openly distributed
204///                   by ARM and widely known under the keyword `aapcs`.
205///  * aarch64: The `aapcs64` calling-convention is used. It is native to aarch64 and described in
206///             a document called
207///             "Procedure Call Standard for the ARM 64-bit Architecture (AArch64)". It is openly
208///             distributed by ARM and widely known under the keyword `aapcs64`.
209///  * ia-64: The "P64 C Calling Convention" as described in the
210///           "Itanium Software Conventions and Runtime Architecture Guide". It is also
211///           standardized in the "Intel Itanium SAL Specification".
212///  * RISC-V: The "Standard RISC-V C Calling Convention" is used. The UEFI specification
213///            describes it in detail, but also refers to the official RISC-V resources for
214///            detailed information.
215///  * x86 / ia-32: The `cdecl` C calling convention is used. Originated in the C Language and
216///                 originally tightly coupled to C specifics. Unclear whether a formal
217///                 specification exists (does anyone know?). Most compilers support it under the
218///                 `cdecl` keyword, and in nearly all situations it is the default on x86.
219///  * x86_64 / amd64 / x64: The `win64` calling-convention is used. It is similar to the `sysv64`
220///                          convention that is used on most non-windows x86_64 systems, but not
221///                          exactly the same. Microsoft provides open documentation on it. See
222///                          MSDN "x64 Software Conventions -> Calling Conventions".
223///                          The UEFI Specification does not directly refer to `win64`, but
224///                          contains a full specification of the calling convention itself.
225///
226/// Note that in most cases the UEFI Specification adds several more restrictions on top of the
227/// common calling-conventions. These restrictions usually do not affect how the compiler will lay
228/// out the function calls. Instead, it usually only restricts the set of APIs that are allowed in
229/// UEFI. Therefore, most compilers already support the calling conventions used on UEFI.
230///
231/// # Variadics
232///
233/// For some reason, the rust compiler allows variadics only in combination with the `"C"` calling
234/// convention, even if the selected calling-convention matches what `"C"` would select on the
235/// target platform. Hence, you will very likely be unable to use variadics with this macro.
236/// Luckily, all of the UEFI functions that use variadics are wrappers around more low-level
237/// accessors, so they are not necessarily required.
238#[macro_export]
239macro_rules! eficall {
240    // Muncher
241    //
242    // The `@munch()` rules are internal and should not be invoked directly. We walk through the
243    // input, moving one token after the other from the suffix into the prefix until we find the
244    // position where to insert `extern "<abi>"`. This muncher never drops any tokens, hence we
245    // can safely match invalid statements just fine, as the compiler will later print proper
246    // diagnostics when parsing the macro output.
247    // Once done, we invoke the `eficall_abi!{}` macro, which simply inserts the correct ABI.
248    (@munch(($($prefix:tt)*),(pub $($suffix:tt)*))) => { eficall!{@munch(($($prefix)* pub),($($suffix)*))} };
249    (@munch(($($prefix:tt)*),(unsafe $($suffix:tt)*))) => { eficall!{@munch(($($prefix)* unsafe),($($suffix)*))} };
250    (@munch(($($prefix:tt)*),($($suffix:tt)*))) => { eficall_abi!{($($prefix)*),($($suffix)*)} };
251
252    // Entry Point
253    //
254    // This captures the entire argument and invokes its own TT-muncher, but splits the input into
255    // prefix and suffix, so the TT-muncher can walk through it. Note that initially everything is
256    // in the suffix and the prefix is empty.
257    ($($arg:tt)*) => { eficall!{@munch((),($($arg)*))} };
258}
259
260/// Boolean Type
261///
262/// This boolean type works very similar to the rust primitive type of [`bool`]. However, the rust
263/// primitive type has no stable ABI, hence we provide this type to represent booleans on the FFI
264/// interface.
265///
266/// UEFI defines booleans to be 1-byte integers, which can only have the values of `0` or `1`.
267/// However, in practice anything non-zero is considered `true` by nearly all UEFI systems. Hence,
268/// this type implements a boolean over `u8` and maps `0` to `false`, everything else to `true`.
269///
270/// The binary representation of this type is ABI. That is, you are allowed to transmute from and
271/// to `u8`. Furthermore, this type never modifies its binary representation. If it was
272/// initialized as, or transmuted from, a specific integer value, this value will be retained.
273/// However, on the rust side you will never see the integer value. It instead behaves truly as a
274/// boolean. If you need access to the integer value, you have to transmute it back to `u8`.
275#[repr(C)]
276#[derive(Clone, Copy, Debug)]
277// Manual impls for: Default, Eq, Hash, Ord, PartialEq, PartialOrd
278pub struct Boolean(u8);
279
280/// Single-byte Character Type
281///
282/// The `Char8` type represents single-byte characters. UEFI defines them to be ASCII compatible,
283/// using the ISO-Latin-1 character set.
284pub type Char8 = u8;
285
286/// Dual-byte Character Type
287///
288/// The `Char16` type represents dual-byte characters. UEFI defines them to be UCS-2 encoded.
289pub type Char16 = u16;
290
291/// Status Codes
292///
293/// UEFI uses the `Status` type to represent all kinds of status codes. This includes return codes
294/// from functions, but also complex state of different devices and drivers. It is a simple
295/// `usize`, but wrapped in a rust-type to allow us to implement helpers on this type. Depending
296/// on the context, different state is stored in it. Note that it is always binary compatible to a
297/// usize!
298#[repr(C)]
299#[derive(Clone, Copy, Debug, Default)]
300#[derive(Eq, Hash, Ord, PartialEq, PartialOrd)]
301pub struct Status(usize);
302
303/// Object Handles
304///
305/// Handles represent access to an opaque object. Handles are untyped by default, but get a
306/// meaning when you combine them with an interface. Internally, they are simple void pointers. It
307/// is the UEFI driver model that applies meaning to them.
308pub type Handle = *mut core::ffi::c_void;
309
310/// Event Objects
311///
312/// Event objects represent hooks into the main-loop of a UEFI environment. They allow to register
313/// callbacks, to be invoked when a specific event happens. In most cases you use events to
314/// register timer-based callbacks, as well as chaining events together. Internally, they are
315/// simple void pointers. It is the UEFI task management that applies meaning to them.
316pub type Event = *mut core::ffi::c_void;
317
318/// Logical Block Addresses
319///
320/// The LBA type is used to denote logical block addresses of block devices. It is a simple 64-bit
321/// integer, that is used to denote addresses when working with block devices.
322pub type Lba = u64;
323
324/// Thread Priority Levels
325///
326/// The process model of UEFI systems is highly simplified. Priority levels are used to order
327/// execution of pending tasks. The TPL type denotes a priority level of a specific task. The
328/// higher the number, the higher the priority. It is a simple integer type, but its range is
329/// usually highly restricted. The UEFI task management provides constants and accessors for TPLs.
330pub type Tpl = usize;
331
332/// Physical Memory Address
333///
334/// A simple 64bit integer containing a physical memory address.
335pub type PhysicalAddress = u64;
336
337/// Virtual Memory Address
338///
339/// A simple 64bit integer containing a virtual memory address.
340pub type VirtualAddress = u64;
341
342/// Application Entry Point
343///
344/// This type defines the entry-point of UEFI applications. It is ABI and cannot be changed.
345/// Whenever you load UEFI images, the entry-point is called with this signature.
346///
347/// In most cases the UEFI image (or application) is unloaded when control returns from the entry
348/// point. In case of UEFI drivers, they can request to stay loaded until an explicit unload.
349///
350/// The system table is provided as mutable pointer. This is, because there is no guarantee that
351/// timer interrupts do not modify the table. Furthermore, exiting boot services causes several
352/// modifications on that table. And lastly, the system table lives longer than the function
353/// invocation, if invoked as an UEFI driver.
354/// In most cases it is perfectly fine to cast the pointer to a real rust reference. However, this
355/// should be an explicit decision by the caller.
356pub type ImageEntryPoint = unsafe extern "efiapi" fn(Handle, *mut crate::system::SystemTable) -> Status;
357
358/// Globally Unique Identifiers
359///
360/// The `Guid` type represents globally unique identifiers as defined by RFC-4122 (i.e., only the
361/// `10x` variant is used), with the caveat that LE is used instead of BE.
362///
363/// Note that only the binary representation of Guids is stable. You are highly recommended to
364/// interpret Guids as 128bit integers.
365///
366/// The UEFI specification requires the type to be 64-bit aligned, yet EDK2 uses a mere 32-bit
367/// alignment. Hence, for compatibility, a 32-bit alignment is used.
368///
369/// UEFI uses the Microsoft-style Guid format. Hence, a lot of documentation and code refers to
370/// these Guids. If you thusly cannot treat Guids as 128-bit integers, this Guid type allows you
371/// to access the individual fields of the Microsoft-style Guid. A reminder of the Guid encoding:
372///
373/// ```text
374///    0                   1                   2                   3
375///    0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
376///   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
377///   |                          time_low                             |
378///   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
379///   |       time_mid                |         time_hi_and_version   |
380///   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
381///   |clk_seq_hi_res |  clk_seq_low  |         node (0-1)            |
382///   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
383///   |                         node (2-5)                            |
384///   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
385/// ```
386///
387/// The individual fields are encoded as little-endian. Accessors are provided for the Guid
388/// structure allowing access to these fields in native endian byte order.
389#[repr(C, align(4))]
390#[derive(Clone, Copy, Debug)]
391#[derive(Eq, Hash, Ord, PartialEq, PartialOrd)]
392pub struct Guid {
393    time_low: [u8; 4],
394    time_mid: [u8; 2],
395    time_hi_and_version: [u8; 2],
396    clk_seq_hi_res: u8,
397    clk_seq_low: u8,
398    node: [u8; 6],
399}
400
401/// Network MAC Address
402///
403/// This type encapsulates a single networking media access control address
404/// (MAC). It is a simple 32 bytes buffer with no special alignment. Note that
405/// no comparison function are defined by default, since trailing bytes of the
406/// address might be random.
407///
408/// The interpretation of the content differs depending on the protocol it is
409/// used with. See each documentation for details. In most cases this contains
410/// an Ethernet address.
411#[repr(C)]
412#[derive(Clone, Copy, Debug)]
413#[derive(Eq, Hash, Ord, PartialEq, PartialOrd)]
414pub struct MacAddress {
415    pub addr: [u8; 32],
416}
417
418/// IPv4 Address
419///
420/// Binary representation of an IPv4 address. It is encoded in network byte
421/// order (i.e., big endian). Note that no special alignment restrictions are
422/// defined by the standard specification.
423#[repr(C)]
424#[derive(Clone, Copy, Debug, Default)]
425#[derive(Eq, Hash, Ord, PartialEq, PartialOrd)]
426pub struct Ipv4Address {
427    pub addr: [u8; 4],
428}
429
430/// IPv6 Address
431///
432/// Binary representation of an IPv6 address, encoded in network byte order
433/// (i.e., big endian). Similar to the IPv4 address, no special alignment
434/// restrictions are defined by the standard specification.
435#[repr(C)]
436#[derive(Clone, Copy, Debug)]
437#[derive(Eq, Hash, Ord, PartialEq, PartialOrd)]
438pub struct Ipv6Address {
439    pub addr: [u8; 16],
440}
441
442/// IP Address
443///
444/// A union type over the different IP addresses available. Alignment is always
445/// fixed to 4-bytes. Note that trailing bytes might be random, so no
446/// comparison functions are derived.
447#[repr(C, align(4))]
448#[derive(Clone, Copy)]
449pub union IpAddress {
450    pub addr: [u32; 4],
451    pub v4: Ipv4Address,
452    pub v6: Ipv6Address,
453}
454
455impl Boolean {
456    /// Literal False
457    ///
458    /// This constant represents the `false` value of the `Boolean` type.
459    pub const FALSE: Boolean = Boolean(0u8);
460
461    /// Literal True
462    ///
463    /// This constant represents the `true` value of the `Boolean` type.
464    pub const TRUE: Boolean = Boolean(1u8);
465}
466
467impl From<u8> for Boolean {
468    fn from(v: u8) -> Self {
469        Boolean(v)
470    }
471}
472
473impl From<bool> for Boolean {
474    fn from(v: bool) -> Self {
475        match v {
476            false => Boolean::FALSE,
477            true => Boolean::TRUE,
478        }
479    }
480}
481
482impl Default for Boolean {
483    fn default() -> Self {
484        Self::FALSE
485    }
486}
487
488impl From<Boolean> for u8 {
489    fn from(v: Boolean) -> Self {
490        match v.0 {
491            0 => 0,
492            _ => 1,
493        }
494    }
495}
496
497impl From<Boolean> for bool {
498    fn from(v: Boolean) -> Self {
499        match v.0 {
500            0 => false,
501            _ => true,
502        }
503    }
504}
505
506impl Eq for Boolean {}
507
508impl core::hash::Hash for Boolean {
509    fn hash<H: core::hash::Hasher>(&self, state: &mut H) {
510        bool::from(*self).hash(state)
511    }
512}
513
514impl Ord for Boolean {
515    fn cmp(&self, other: &Boolean) -> core::cmp::Ordering {
516        bool::from(*self).cmp(&(*other).into())
517    }
518}
519
520impl PartialEq for Boolean {
521    fn eq(&self, other: &Boolean) -> bool {
522        bool::from(*self).eq(&(*other).into())
523    }
524}
525
526impl PartialEq<bool> for Boolean {
527    fn eq(&self, other: &bool) -> bool {
528        bool::from(*self).eq(other)
529    }
530}
531
532impl PartialOrd for Boolean {
533    fn partial_cmp(&self, other: &Boolean) -> Option<core::cmp::Ordering> {
534        bool::from(*self).partial_cmp(&(*other).into())
535    }
536}
537
538impl PartialOrd<bool> for Boolean {
539    fn partial_cmp(&self, other: &bool) -> Option<core::cmp::Ordering> {
540        bool::from(*self).partial_cmp(other)
541    }
542}
543
544impl Status {
545    const WIDTH: usize = 8usize * core::mem::size_of::<Status>();
546    const MASK: usize = 0xc0 << (Status::WIDTH - 8);
547    const ERROR_MASK: usize = 0x80 << (Status::WIDTH - 8);
548    const WARNING_MASK: usize = 0x00 << (Status::WIDTH - 8);
549
550    /// Success Code
551    ///
552    /// This code represents a successfull function invocation. Its value is guaranteed to be 0.
553    /// However, note that warnings are considered success as well, so this is not the only code
554    /// that can be returned by UEFI functions on success. However, in nearly all situations
555    /// warnings are not allowed, so the effective result will be SUCCESS.
556    pub const SUCCESS: Status = Status::from_usize(0);
557
558    // List of predefined error codes
559    pub const LOAD_ERROR: Status = Status::from_usize(1 | Status::ERROR_MASK);
560    pub const INVALID_PARAMETER: Status = Status::from_usize(2 | Status::ERROR_MASK);
561    pub const UNSUPPORTED: Status = Status::from_usize(3 | Status::ERROR_MASK);
562    pub const BAD_BUFFER_SIZE: Status = Status::from_usize(4 | Status::ERROR_MASK);
563    pub const BUFFER_TOO_SMALL: Status = Status::from_usize(5 | Status::ERROR_MASK);
564    pub const NOT_READY: Status = Status::from_usize(6 | Status::ERROR_MASK);
565    pub const DEVICE_ERROR: Status = Status::from_usize(7 | Status::ERROR_MASK);
566    pub const WRITE_PROTECTED: Status = Status::from_usize(8 | Status::ERROR_MASK);
567    pub const OUT_OF_RESOURCES: Status = Status::from_usize(9 | Status::ERROR_MASK);
568    pub const VOLUME_CORRUPTED: Status = Status::from_usize(10 | Status::ERROR_MASK);
569    pub const VOLUME_FULL: Status = Status::from_usize(11 | Status::ERROR_MASK);
570    pub const NO_MEDIA: Status = Status::from_usize(12 | Status::ERROR_MASK);
571    pub const MEDIA_CHANGED: Status = Status::from_usize(13 | Status::ERROR_MASK);
572    pub const NOT_FOUND: Status = Status::from_usize(14 | Status::ERROR_MASK);
573    pub const ACCESS_DENIED: Status = Status::from_usize(15 | Status::ERROR_MASK);
574    pub const NO_RESPONSE: Status = Status::from_usize(16 | Status::ERROR_MASK);
575    pub const NO_MAPPING: Status = Status::from_usize(17 | Status::ERROR_MASK);
576    pub const TIMEOUT: Status = Status::from_usize(18 | Status::ERROR_MASK);
577    pub const NOT_STARTED: Status = Status::from_usize(19 | Status::ERROR_MASK);
578    pub const ALREADY_STARTED: Status = Status::from_usize(20 | Status::ERROR_MASK);
579    pub const ABORTED: Status = Status::from_usize(21 | Status::ERROR_MASK);
580    pub const ICMP_ERROR: Status = Status::from_usize(22 | Status::ERROR_MASK);
581    pub const TFTP_ERROR: Status = Status::from_usize(23 | Status::ERROR_MASK);
582    pub const PROTOCOL_ERROR: Status = Status::from_usize(24 | Status::ERROR_MASK);
583    pub const INCOMPATIBLE_VERSION: Status = Status::from_usize(25 | Status::ERROR_MASK);
584    pub const SECURITY_VIOLATION: Status = Status::from_usize(26 | Status::ERROR_MASK);
585    pub const CRC_ERROR: Status = Status::from_usize(27 | Status::ERROR_MASK);
586    pub const END_OF_MEDIA: Status = Status::from_usize(28 | Status::ERROR_MASK);
587    pub const END_OF_FILE: Status = Status::from_usize(31 | Status::ERROR_MASK);
588    pub const INVALID_LANGUAGE: Status = Status::from_usize(32 | Status::ERROR_MASK);
589    pub const COMPROMISED_DATA: Status = Status::from_usize(33 | Status::ERROR_MASK);
590    pub const IP_ADDRESS_CONFLICT: Status = Status::from_usize(34 | Status::ERROR_MASK);
591    pub const HTTP_ERROR: Status = Status::from_usize(35 | Status::ERROR_MASK);
592
593    // List of error codes from protocols
594    // UDP4
595    pub const NETWORK_UNREACHABLE: Status = Status::from_usize(100 | Status::ERROR_MASK);
596    pub const HOST_UNREACHABLE: Status = Status::from_usize(101 | Status::ERROR_MASK);
597    pub const PROTOCOL_UNREACHABLE: Status = Status::from_usize(102 | Status::ERROR_MASK);
598    pub const PORT_UNREACHABLE: Status = Status::from_usize(103 | Status::ERROR_MASK);
599    // TCP4
600    pub const CONNECTION_FIN: Status = Status::from_usize(104 | Status::ERROR_MASK);
601    pub const CONNECTION_RESET: Status = Status::from_usize(105 | Status::ERROR_MASK);
602    pub const CONNECTION_REFUSED: Status = Status::from_usize(106 | Status::ERROR_MASK);
603
604    // List of predefined warning codes
605    pub const WARN_UNKNOWN_GLYPH: Status = Status::from_usize(1 | Status::WARNING_MASK);
606    pub const WARN_DELETE_FAILURE: Status = Status::from_usize(2 | Status::WARNING_MASK);
607    pub const WARN_WRITE_FAILURE: Status = Status::from_usize(3 | Status::WARNING_MASK);
608    pub const WARN_BUFFER_TOO_SMALL: Status = Status::from_usize(4 | Status::WARNING_MASK);
609    pub const WARN_STALE_DATA: Status = Status::from_usize(5 | Status::WARNING_MASK);
610    pub const WARN_FILE_SYSTEM: Status = Status::from_usize(6 | Status::WARNING_MASK);
611    pub const WARN_RESET_REQUIRED: Status = Status::from_usize(7 | Status::WARNING_MASK);
612
613    /// Create Status Code from Integer
614    ///
615    /// This takes the literal value of a status code and turns it into a `Status` object. Note
616    /// that we want it as `const fn` so we cannot use `core::convert::From`.
617    pub const fn from_usize(v: usize) -> Status {
618        Status(v)
619    }
620
621    /// Return Underlying Integer Representation
622    ///
623    /// This takes the `Status` object and returns the underlying integer representation as
624    /// defined by the UEFI specification.
625    pub const fn as_usize(&self) -> usize {
626        self.0
627    }
628
629    fn value(&self) -> usize {
630        self.0
631    }
632
633    fn mask(&self) -> usize {
634        self.value() & Status::MASK
635    }
636
637    /// Check whether this is an error
638    ///
639    /// This returns true if the given status code is considered an error. Errors mean the
640    /// operation did not succeed, nor produce any valuable output. Output parameters must be
641    /// considered invalid if an error was returned. That is, its content is not well defined.
642    pub fn is_error(&self) -> bool {
643        self.mask() == Status::ERROR_MASK
644    }
645
646    /// Check whether this is a warning
647    ///
648    /// This returns true if the given status code is considered a warning. Warnings are to be
649    /// treated as success, but might indicate data loss or other device errors. However, if an
650    /// operation returns with a warning code, it must be considered successfull, and the output
651    /// parameters are valid.
652    pub fn is_warning(&self) -> bool {
653        self.value() != 0 && self.mask() == Status::WARNING_MASK
654    }
655
656    pub fn description(&self) -> Option<&str> {
657        match *self {
658            Status::SUCCESS => Some("Success"),
659            Status::LOAD_ERROR => Some("Load Error"),
660            Status::INVALID_PARAMETER => Some("Invalid Parameter"),
661            Status::UNSUPPORTED => Some("Unsupported"),
662            Status::BAD_BUFFER_SIZE => Some("Bad Buffer Size"),
663            Status::BUFFER_TOO_SMALL => Some("Buffer Too Small"),
664            Status::NOT_READY => Some("Not Ready"),
665            Status::DEVICE_ERROR => Some("Device Error"),
666            Status::WRITE_PROTECTED => Some("Write Protected"),
667            Status::OUT_OF_RESOURCES => Some("Out of Resources"),
668            Status::VOLUME_CORRUPTED => Some("Volume Corrupt"),
669            Status::VOLUME_FULL => Some("Volume Full"),
670            Status::NO_MEDIA => Some("No Media"),
671            Status::MEDIA_CHANGED => Some("Media Changed"),
672            Status::NOT_FOUND => Some("Not Found"),
673            Status::ACCESS_DENIED => Some("Access Denied"),
674            Status::NO_RESPONSE => Some("No Response"),
675            Status::NO_MAPPING => Some("No Mapping"),
676            Status::TIMEOUT => Some("Timeout"),
677            Status::NOT_STARTED => Some("Not Started"),
678            Status::ALREADY_STARTED => Some("Already Started"),
679            Status::ABORTED => Some("Aborted"),
680            Status::ICMP_ERROR => Some("ICMP Error"),
681            Status::TFTP_ERROR => Some("TFTP Error"),
682            Status::PROTOCOL_ERROR => Some("Protocol Error"),
683            Status::INCOMPATIBLE_VERSION => Some("Incompatible Version"),
684            Status::SECURITY_VIOLATION => Some("Security Violation"),
685            Status::CRC_ERROR => Some("CRC Error"),
686            Status::END_OF_MEDIA => Some("End of Media"),
687            Status::END_OF_FILE => Some("End of File"),
688            Status::INVALID_LANGUAGE => Some("Invalid Language"),
689            Status::COMPROMISED_DATA => Some("Compromised Data"),
690            Status::IP_ADDRESS_CONFLICT => Some("IP Address Conflict"),
691            Status::HTTP_ERROR => Some("HTTP Error"),
692            Status::NETWORK_UNREACHABLE => Some("Network Unreachable"),
693            Status::HOST_UNREACHABLE => Some("Host Unreachable"),
694            Status::PROTOCOL_UNREACHABLE => Some("Protocol Unreachable"),
695            Status::PORT_UNREACHABLE => Some("Port Unreachable"),
696            Status::CONNECTION_FIN => Some("Connection FIN"),
697            Status::CONNECTION_RESET => Some("Connection Reset"),
698            Status::CONNECTION_REFUSED => Some("Connection Refused"),
699            Status::WARN_UNKNOWN_GLYPH => Some("Warning Unknown Glyph"),
700            Status::WARN_DELETE_FAILURE => Some("Warning Delete Failure"),
701            Status::WARN_WRITE_FAILURE => Some("Warning Write Failure"),
702            Status::WARN_BUFFER_TOO_SMALL => Some("Warning Buffer Too Small"),
703            Status::WARN_STALE_DATA => Some("Warning Stale Data"),
704            Status::WARN_FILE_SYSTEM => Some("Warning File System"),
705            Status::WARN_RESET_REQUIRED => Some("Warning Reset Required"),
706            _ => None,
707        }
708    }
709}
710
711impl From<Status> for Result<Status, Status> {
712    fn from(status: Status) -> Self {
713        if status.is_error() {
714            Err(status)
715        } else {
716            Ok(status)
717        }
718    }
719}
720
721impl core::fmt::Display for Status {
722    fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
723        match self.description() {
724            None => write!(f, "{:08X}", self.value()),
725            Some(v) => v.fmt(f),
726        }
727    }
728}
729
730impl Guid {
731    const fn u32_to_bytes_le(num: u32) -> [u8; 4] {
732        [
733            num as u8,
734            (num >> 8) as u8,
735            (num >> 16) as u8,
736            (num >> 24) as u8,
737        ]
738    }
739
740    const fn u32_from_bytes_le(bytes: &[u8; 4]) -> u32 {
741        (bytes[0] as u32)
742            | ((bytes[1] as u32) << 8)
743            | ((bytes[2] as u32) << 16)
744            | ((bytes[3] as u32) << 24)
745    }
746
747    const fn u16_to_bytes_le(num: u16) -> [u8; 2] {
748        [num as u8, (num >> 8) as u8]
749    }
750
751    const fn u16_from_bytes_le(bytes: &[u8; 2]) -> u16 {
752        (bytes[0] as u16) | ((bytes[1] as u16) << 8)
753    }
754
755    /// Initialize a Guid from its individual fields
756    ///
757    /// This function initializes a Guid object given the individual fields as specified in the
758    /// UEFI specification. That is, if you simply copy the literals from the specification into
759    /// your code, this function will correctly initialize the Guid object.
760    ///
761    /// In other words, this takes the individual fields in native endian and converts them to the
762    /// correct endianness for a UEFI Guid.
763    ///
764    /// Due to the fact that UEFI Guids use variant 2 of the UUID specification in a little-endian
765    /// (or even mixed-endian) format, the following transformation is likely applied from text
766    /// representation to binary representation:
767    ///
768    ///   00112233-4455-6677-8899-aabbccddeeff
769    ///   =>
770    ///   33 22 11 00 55 44 77 66 88 99 aa bb cc dd ee ff
771    ///
772    /// (Note that UEFI protocols often use `88-99` instead of `8899`)
773    /// The first 3 parts use little-endian notation, the last 2 use big-endian.
774    pub const fn from_fields(
775        time_low: u32,
776        time_mid: u16,
777        time_hi_and_version: u16,
778        clk_seq_hi_res: u8,
779        clk_seq_low: u8,
780        node: &[u8; 6],
781    ) -> Guid {
782        Guid {
783            time_low: Self::u32_to_bytes_le(time_low),
784            time_mid: Self::u16_to_bytes_le(time_mid),
785            time_hi_and_version: Self::u16_to_bytes_le(time_hi_and_version),
786            clk_seq_hi_res: clk_seq_hi_res,
787            clk_seq_low: clk_seq_low,
788            node: *node,
789        }
790    }
791
792    /// Access a Guid as individual fields
793    ///
794    /// This decomposes a Guid back into the individual fields as given in the specification. The
795    /// individual fields are returned in native-endianness.
796    pub const fn as_fields(&self) -> (u32, u16, u16, u8, u8, &[u8; 6]) {
797        (
798            Self::u32_from_bytes_le(&self.time_low),
799            Self::u16_from_bytes_le(&self.time_mid),
800            Self::u16_from_bytes_le(&self.time_hi_and_version),
801            self.clk_seq_hi_res,
802            self.clk_seq_low,
803            &self.node,
804        )
805    }
806
807    /// Initialize a Guid from its byte representation
808    ///
809    /// Create a new Guid object from its byte representation. This
810    /// reinterprets the bytes as a Guid and copies them into a new Guid
811    /// instance. Note that you can safely transmute instead.
812    ///
813    /// See `as_bytes()` for the inverse operation.
814    pub const fn from_bytes(bytes: &[u8; 16]) -> Self {
815        unsafe { core::mem::transmute::<[u8; 16], Guid>(*bytes) }
816    }
817
818    /// Access a Guid as raw byte array
819    ///
820    /// This provides access to a Guid through a byte array. It is a simple re-interpretation of
821    /// the Guid value as a 128-bit byte array. No conversion is performed. This is a simple cast.
822    pub const fn as_bytes(&self) -> &[u8; 16] {
823        unsafe { core::mem::transmute::<&Guid, &[u8; 16]>(self) }
824    }
825}
826
827#[cfg(test)]
828mod tests {
829    use super::*;
830    use std::mem::{align_of, size_of};
831
832    // Helper to compute a hash of an object.
833    fn hash<T: core::hash::Hash>(v: &T) -> u64 {
834        let mut h = std::hash::DefaultHasher::new();
835        v.hash(&mut h);
836        core::hash::Hasher::finish(&h)
837    }
838
839    // Verify Type Size and Alignemnt
840    //
841    // Since UEFI defines explicitly the ABI of their types, we can verify that our implementation
842    // is correct by checking the size and alignment of the ABI types matches what the spec
843    // mandates.
844    #[test]
845    fn type_size_and_alignment() {
846        //
847        // Booleans
848        //
849
850        assert_eq!(size_of::<Boolean>(), 1);
851        assert_eq!(align_of::<Boolean>(), 1);
852
853        //
854        // Char8 / Char16
855        //
856
857        assert_eq!(size_of::<Char8>(), 1);
858        assert_eq!(align_of::<Char8>(), 1);
859        assert_eq!(size_of::<Char16>(), 2);
860        assert_eq!(align_of::<Char16>(), 2);
861
862        assert_eq!(size_of::<Char8>(), size_of::<u8>());
863        assert_eq!(align_of::<Char8>(), align_of::<u8>());
864        assert_eq!(size_of::<Char16>(), size_of::<u16>());
865        assert_eq!(align_of::<Char16>(), align_of::<u16>());
866
867        //
868        // Status
869        //
870
871        assert_eq!(size_of::<Status>(), size_of::<usize>());
872        assert_eq!(align_of::<Status>(), align_of::<usize>());
873
874        //
875        // Handles / Events
876        //
877
878        assert_eq!(size_of::<Handle>(), size_of::<usize>());
879        assert_eq!(align_of::<Handle>(), align_of::<usize>());
880        assert_eq!(size_of::<Event>(), size_of::<usize>());
881        assert_eq!(align_of::<Event>(), align_of::<usize>());
882
883        assert_eq!(size_of::<Handle>(), size_of::<*mut ()>());
884        assert_eq!(align_of::<Handle>(), align_of::<*mut ()>());
885        assert_eq!(size_of::<Event>(), size_of::<*mut ()>());
886        assert_eq!(align_of::<Event>(), align_of::<*mut ()>());
887
888        //
889        // Lba / Tpl
890        //
891
892        assert_eq!(size_of::<Lba>(), size_of::<u64>());
893        assert_eq!(align_of::<Lba>(), align_of::<u64>());
894        assert_eq!(size_of::<Tpl>(), size_of::<usize>());
895        assert_eq!(align_of::<Tpl>(), align_of::<usize>());
896
897        //
898        // PhysicalAddress / VirtualAddress
899        //
900
901        assert_eq!(size_of::<PhysicalAddress>(), size_of::<u64>());
902        assert_eq!(align_of::<PhysicalAddress>(), align_of::<u64>());
903        assert_eq!(size_of::<VirtualAddress>(), size_of::<u64>());
904        assert_eq!(align_of::<VirtualAddress>(), align_of::<u64>());
905
906        //
907        // ImageEntryPoint
908        //
909
910        assert_eq!(size_of::<ImageEntryPoint>(), size_of::<fn()>());
911        assert_eq!(align_of::<ImageEntryPoint>(), align_of::<fn()>());
912
913        //
914        // Guid
915        //
916
917        assert_eq!(size_of::<Guid>(), 16);
918        assert_eq!(align_of::<Guid>(), 4);
919
920        //
921        // Networking Types
922        //
923
924        assert_eq!(size_of::<MacAddress>(), 32);
925        assert_eq!(align_of::<MacAddress>(), 1);
926        assert_eq!(size_of::<Ipv4Address>(), 4);
927        assert_eq!(align_of::<Ipv4Address>(), 1);
928        assert_eq!(size_of::<Ipv6Address>(), 16);
929        assert_eq!(align_of::<Ipv6Address>(), 1);
930        assert_eq!(size_of::<IpAddress>(), 16);
931        assert_eq!(align_of::<IpAddress>(), 4);
932    }
933
934    #[test]
935    fn eficall() {
936        //
937        // Make sure the eficall!{} macro can deal with all kinds of function callbacks.
938        //
939
940        let _: eficall! {fn()};
941        let _: eficall! {unsafe fn()};
942        let _: eficall! {fn(i32)};
943        let _: eficall! {fn(i32) -> i32};
944        let _: eficall! {fn(i32, i32) -> (i32, i32)};
945
946        eficall! {fn _unused00() {}}
947        eficall! {unsafe fn _unused01() {}}
948        eficall! {pub unsafe fn _unused02() {}}
949    }
950
951    // Verify Boolean ABI
952    //
953    // Even though booleans are strictly 1-bit, and thus 0 or 1, in practice all UEFI systems
954    // treat it more like C does, and a boolean formatted as `u8` now allows any value other than
955    // 0 to represent `true`. Make sure we support the same.
956    #[test]
957    fn booleans() {
958        // Verify PartialEq works.
959        assert_ne!(Boolean::FALSE, Boolean::TRUE);
960
961        // Verify Boolean<->bool conversion and comparison works.
962        assert_eq!(Boolean::FALSE, false);
963        assert_eq!(Boolean::TRUE, true);
964
965        // Iterate all possible values for `u8` and verify 0 behaves as `false`, and everything
966        // else behaves as `true`. We verify both, the natural constructor through `From`, as well
967        // as a transmute.
968        for i in 0u8..=255u8 {
969            let v1: Boolean = i.into();
970            let v2: Boolean = unsafe { std::mem::transmute::<u8, Boolean>(i) };
971
972            assert_eq!(v1, v2);
973            assert_eq!(v1, v1);
974            assert_eq!(v2, v2);
975
976            match i {
977                0 => {
978                    assert_eq!(v1, Boolean::FALSE);
979                    assert_eq!(v1, false);
980                    assert_eq!(v2, Boolean::FALSE);
981                    assert_eq!(v2, false);
982
983                    assert_ne!(v1, Boolean::TRUE);
984                    assert_ne!(v1, true);
985                    assert_ne!(v2, Boolean::TRUE);
986                    assert_ne!(v2, true);
987
988                    assert!(v1 < Boolean::TRUE);
989                    assert!(v1 < true);
990                    assert!(v1 >= Boolean::FALSE);
991                    assert!(v1 >= false);
992                    assert!(v1 <= Boolean::FALSE);
993                    assert!(v1 <= false);
994                    assert_eq!(v1.cmp(&true.into()), core::cmp::Ordering::Less);
995                    assert_eq!(v1.cmp(&false.into()), core::cmp::Ordering::Equal);
996
997                    assert_eq!(hash(&v1), hash(&false));
998                }
999                _ => {
1000                    assert_eq!(v1, Boolean::TRUE);
1001                    assert_eq!(v1, true);
1002                    assert_eq!(v2, Boolean::TRUE);
1003                    assert_eq!(v2, true);
1004
1005                    assert_ne!(v1, Boolean::FALSE);
1006                    assert_ne!(v1, false);
1007                    assert_ne!(v2, Boolean::FALSE);
1008                    assert_ne!(v2, false);
1009
1010                    assert!(v1 <= Boolean::TRUE);
1011                    assert!(v1 <= true);
1012                    assert!(v1 >= Boolean::TRUE);
1013                    assert!(v1 >= true);
1014                    assert!(v1 > Boolean::FALSE);
1015                    assert!(v1 > false);
1016                    assert_eq!(v1.cmp(&true.into()), core::cmp::Ordering::Equal);
1017                    assert_eq!(v1.cmp(&false.into()), core::cmp::Ordering::Greater);
1018
1019                    assert_eq!(hash(&v1), hash(&true));
1020                }
1021            }
1022        }
1023    }
1024
1025    // Verify Status API
1026    //
1027    // Test the different methods and traits on `Status` and verify their
1028    // correctness.
1029    #[test]
1030    fn status() {
1031        assert_eq!(format!("{:}", &Status::SUCCESS), "Success");
1032        assert_eq!(format!("{:>16}", &Status::SUCCESS), "         Success");
1033
1034        // invalid status codes should be printed as hex
1035        let status = Status::from_usize(200);
1036        assert_eq!(status.description(), None);
1037        assert_eq!(format!("{}", &status), "000000C8");
1038    }
1039
1040    // Verify Guid Manipulations
1041    //
1042    // Test that creation of Guids from fields and bytes yields the expected
1043    // values, and conversions work as expected.
1044    #[test]
1045    fn guid() {
1046        let fields = (
1047            0x550e8400,
1048            0xe29b,
1049            0x41d4,
1050            0xa7,
1051            0x16,
1052            &[0x44, 0x66, 0x55, 0x44, 0x00, 0x00],
1053        );
1054        #[rustfmt::skip]
1055        let bytes = [
1056            0x00, 0x84, 0x0e, 0x55,
1057            0x9b, 0xe2,
1058            0xd4, 0x41,
1059            0xa7,
1060            0x16,
1061            0x44, 0x66, 0x55, 0x44, 0x00, 0x00,
1062        ];
1063        let (f0, f1, f2, f3, f4, f5) = fields;
1064        let g_fields = Guid::from_fields(f0, f1, f2, f3, f4, f5);
1065        let g_bytes = Guid::from_bytes(&bytes);
1066
1067        assert_eq!(g_fields, g_bytes);
1068        assert_eq!(g_fields.as_bytes(), &bytes);
1069        assert_eq!(g_bytes.as_fields(), fields);
1070    }
1071}