Coverage Report

Created: 2025-10-13 06:48

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/rust/registry/src/index.crates.io-1949cf8c6b5b557f/r-efi-3.2.0/src/base.rs
Line
Count
Source
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 = "x86",
121
    target_arch = "x86_64"
122
)))]
123
compile_error!("The target architecture is not supported.");
124
#[cfg(not(any(target_endian = "little")))]
125
compile_error!("The target endianness is not supported.");
126
127
// eficall_abi!()
128
//
129
// This macro is the architecture-dependent implementation of eficall!(). See the documentation of
130
// the eficall!() macro for a description.
131
132
#[cfg(target_arch = "arm")]
133
#[macro_export]
134
#[doc(hidden)]
135
macro_rules! eficall_abi {
136
    (($($prefix:tt)*),($($suffix:tt)*)) => { $($prefix)* extern "aapcs" $($suffix)* };
137
}
138
139
// XXX: Rust does not define aapcs64, yet. Once it does, we should switch to it, rather than
140
//      referring to the system default.
141
#[cfg(target_arch = "aarch64")]
142
#[macro_export]
143
#[doc(hidden)]
144
macro_rules! eficall_abi {
145
    (($($prefix:tt)*),($($suffix:tt)*)) => { $($prefix)* extern "C" $($suffix)* };
146
}
147
148
#[cfg(target_arch = "x86")]
149
#[macro_export]
150
#[doc(hidden)]
151
macro_rules! eficall_abi {
152
    (($($prefix:tt)*),($($suffix:tt)*)) => { $($prefix)* extern "cdecl" $($suffix)* };
153
}
154
155
#[cfg(target_arch = "x86_64")]
156
#[macro_export]
157
#[doc(hidden)]
158
macro_rules! eficall_abi {
159
    (($($prefix:tt)*),($($suffix:tt)*)) => { $($prefix)* extern "win64" $($suffix)* };
160
}
161
162
#[cfg(not(any(
163
    target_arch = "arm",
164
    target_arch = "aarch64",
165
    target_arch = "x86",
166
    target_arch = "x86_64"
167
)))]
168
#[macro_export]
169
#[doc(hidden)]
170
macro_rules! eficall_abi {
171
    (($($prefix:tt)*),($($suffix:tt)*)) => { $($prefix)* extern "C" $($suffix)* };
172
}
173
174
/// Annotate function with UEFI calling convention
175
///
176
/// This macro takes a function-declaration as argument and produces the same function-declaration
177
/// but annotated with the correct calling convention. Since the default `extern "C"` annotation
178
/// depends on your compiler defaults, we cannot use it. Instead, this macro selects the default
179
/// for your target platform.
180
///
181
/// Ideally, the macro would expand to `extern "<abi>"` so you would be able to write:
182
///
183
/// ```ignore
184
/// // THIS DOES NOT WORK!
185
/// pub fn eficall!{} foobar() {
186
///     // ...
187
/// }
188
/// ```
189
///
190
/// However, macros are evaluated too late for this to work. Instead, the entire construct must be
191
/// wrapped in a macro, which then expands to the same construct but with `extern "<abi>"`
192
/// inserted at the correct place:
193
///
194
/// ```
195
/// use r_efi::{eficall, eficall_abi};
196
///
197
/// eficall!{pub fn foobar() {
198
///     // ...
199
/// }}
200
///
201
/// type FooBar = eficall!{fn(u8) -> (u8)};
202
/// ```
203
///
204
/// The `eficall!{}` macro takes either a function-type or function-definition as argument. It
205
/// inserts `extern "<abi>"` after the function qualifiers, but before the `fn` keyword.
206
///
207
/// # Internals
208
///
209
/// The `eficall!{}` macro tries to parse the function header so it can insert `extern "<abi>"` at
210
/// the right place. If, for whatever reason, this does not work with a particular syntax, you can
211
/// use the internal `eficall_abi!{}` macro. This macro takes two token-streams as input and
212
/// evaluates to the concatenation of both token-streams, but separated by the selected ABI.
213
///
214
/// For instance, the following 3 type definitions are equivalent, assuming the selected ABI
215
/// is "C":
216
///
217
/// ```
218
/// use r_efi::{eficall, eficall_abi};
219
///
220
/// type FooBar1 = unsafe extern "C" fn(u8) -> (u8);
221
/// type FooBar2 = eficall!{unsafe fn(u8) -> (u8)};
222
/// type FooBar3 = eficall_abi!{(unsafe), (fn(u8) -> (u8))};
223
/// ```
224
///
225
/// # Calling Conventions
226
///
227
/// The UEFI specification defines the calling convention for each platform individually. It
228
/// usually refers to other standards for details, but adds some restrictions on top. As of this
229
/// writing, it mentions:
230
///
231
///  * aarch32 / arm: The `aapcs` calling-convention is used. It is native to aarch32 and described
232
///                   in a document called
233
///                   "Procedure Call Standard for the ARM Architecture". It is openly distributed
234
///                   by ARM and widely known under the keyword `aapcs`.
235
///  * aarch64: The `aapcs64` calling-convention is used. It is native to aarch64 and described in
236
///             a document called
237
///             "Procedure Call Standard for the ARM 64-bit Architecture (AArch64)". It is openly
238
///             distributed by ARM and widely known under the keyword `aapcs64`.
239
///  * ia-64: The "P64 C Calling Convention" as described in the
240
///           "Itanium Software Conventions and Runtime Architecture Guide". It is also
241
///           standardized in the "Intel Itanium SAL Specification".
242
///  * RISC-V: The "Standard RISC-V C Calling Convention" is used. The UEFI specification
243
///            describes it in detail, but also refers to the official RISC-V resources for
244
///            detailed information.
245
///  * x86 / ia-32: The `cdecl` C calling convention is used. Originated in the C Language and
246
///                 originally tightly coupled to C specifics. Unclear whether a formal
247
///                 specification exists (does anyone know?). Most compilers support it under the
248
///                 `cdecl` keyword, and in nearly all situations it is the default on x86.
249
///  * x86_64 / amd64 / x64: The `win64` calling-convention is used. It is similar to the `sysv64`
250
///                          convention that is used on most non-windows x86_64 systems, but not
251
///                          exactly the same. Microsoft provides open documentation on it. See
252
///                          MSDN "x64 Software Conventions -> Calling Conventions".
253
///                          The UEFI Specification does not directly refer to `win64`, but
254
///                          contains a full specification of the calling convention itself.
255
///
256
/// Note that in most cases the UEFI Specification adds several more restrictions on top of the
257
/// common calling-conventions. These restrictions usually do not affect how the compiler will lay
258
/// out the function calls. Instead, it usually only restricts the set of APIs that are allowed in
259
/// UEFI. Therefore, most compilers already support the calling conventions used on UEFI.
260
///
261
/// # Variadics
262
///
263
/// For some reason, the rust compiler allows variadics only in combination with the `"C"` calling
264
/// convention, even if the selected calling-convention matches what `"C"` would select on the
265
/// target platform. Hence, you will very likely be unable to use variadics with this macro.
266
/// Luckily, all of the UEFI functions that use variadics are wrappers around more low-level
267
/// accessors, so they are not necessarily required.
268
#[macro_export]
269
macro_rules! eficall {
270
    // Muncher
271
    //
272
    // The `@munch()` rules are internal and should not be invoked directly. We walk through the
273
    // input, moving one token after the other from the suffix into the prefix until we find the
274
    // position where to insert `extern "<abi>"`. This muncher never drops any tokens, hence we
275
    // can safely match invalid statements just fine, as the compiler will later print proper
276
    // diagnostics when parsing the macro output.
277
    // Once done, we invoke the `eficall_abi!{}` macro, which simply inserts the correct ABI.
278
    (@munch(($($prefix:tt)*),(pub $($suffix:tt)*))) => { eficall!{@munch(($($prefix)* pub),($($suffix)*))} };
279
    (@munch(($($prefix:tt)*),(unsafe $($suffix:tt)*))) => { eficall!{@munch(($($prefix)* unsafe),($($suffix)*))} };
280
    (@munch(($($prefix:tt)*),($($suffix:tt)*))) => { eficall_abi!{($($prefix)*),($($suffix)*)} };
281
282
    // Entry Point
283
    //
284
    // This captures the entire argument and invokes its own TT-muncher, but splits the input into
285
    // prefix and suffix, so the TT-muncher can walk through it. Note that initially everything is
286
    // in the suffix and the prefix is empty.
287
    ($($arg:tt)*) => { eficall!{@munch((),($($arg)*))} };
288
}
289
290
/// Boolean Type
291
///
292
/// This boolean type works very similar to the rust primitive type of [`bool`]. However, the rust
293
/// primitive type has no stable ABI, hence we provide this type to represent booleans on the FFI
294
/// interface.
295
///
296
/// UEFI defines booleans to be 1-byte integers, which can only have the values of `0` or `1`.
297
/// However, in practice anything non-zero is considered `true` by nearly all UEFI systems. Hence,
298
/// this type implements a boolean over `u8` and maps `0` to `false`, everything else to `true`.
299
///
300
/// The binary representation of this type is ABI. That is, you are allowed to transmute from and
301
/// to `u8`. Furthermore, this type never modifies its binary representation. If it was
302
/// initialized as, or transmuted from, a specific integer value, this value will be retained.
303
/// However, on the rust side you will never see the integer value. It instead behaves truly as a
304
/// boolean. If you need access to the integer value, you have to transmute it back to `u8`.
305
#[repr(C)]
306
#[derive(Copy, Clone, Debug, Eq)]
307
pub struct Boolean(u8);
308
309
/// Single-byte Character Type
310
///
311
/// The `Char8` type represents single-byte characters. UEFI defines them to be ASCII compatible,
312
/// using the ISO-Latin-1 character set.
313
pub type Char8 = u8;
314
315
/// Dual-byte Character Type
316
///
317
/// The `Char16` type represents dual-byte characters. UEFI defines them to be UCS-2 encoded.
318
pub type Char16 = u16;
319
320
/// Status Codes
321
///
322
/// UEFI uses the `Status` type to represent all kinds of status codes. This includes return codes
323
/// from functions, but also complex state of different devices and drivers. It is a simple
324
/// `usize`, but wrapped in a rust-type to allow us to implement helpers on this type. Depending
325
/// on the context, different state is stored in it. Note that it is always binary compatible to a
326
/// usize!
327
#[repr(C)]
328
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
329
pub struct Status(usize);
330
331
/// Object Handles
332
///
333
/// Handles represent access to an opaque object. Handles are untyped by default, but get a
334
/// meaning when you combine them with an interface. Internally, they are simple void pointers. It
335
/// is the UEFI driver model that applies meaning to them.
336
pub type Handle = *mut core::ffi::c_void;
337
338
/// Event Objects
339
///
340
/// Event objects represent hooks into the main-loop of a UEFI environment. They allow to register
341
/// callbacks, to be invoked when a specific event happens. In most cases you use events to
342
/// register timer-based callbacks, as well as chaining events together. Internally, they are
343
/// simple void pointers. It is the UEFI task management that applies meaning to them.
344
pub type Event = *mut core::ffi::c_void;
345
346
/// Logical Block Addresses
347
///
348
/// The LBA type is used to denote logical block addresses of block devices. It is a simple 64-bit
349
/// integer, that is used to denote addresses when working with block devices.
350
pub type Lba = u64;
351
352
/// Thread Priority Levels
353
///
354
/// The process model of UEFI systems is highly simplified. Priority levels are used to order
355
/// execution of pending tasks. The TPL type denotes a priority level of a specific task. The
356
/// higher the number, the higher the priority. It is a simple integer type, but its range is
357
/// usually highly restricted. The UEFI task management provides constants and accessors for TPLs.
358
pub type Tpl = usize;
359
360
/// Physical Memory Address
361
///
362
/// A simple 64bit integer containing a physical memory address.
363
pub type PhysicalAddress = u64;
364
365
/// Virtual Memory Address
366
///
367
/// A simple 64bit integer containing a virtual memory address.
368
pub type VirtualAddress = u64;
369
370
/// Application Entry Point
371
///
372
/// This type defines the entry-point of UEFI applications. It is ABI and cannot be changed.
373
/// Whenever you load UEFI images, the entry-point is called with this signature.
374
///
375
/// In most cases the UEFI image (or application) is unloaded when control returns from the entry
376
/// point. In case of UEFI drivers, they can request to stay loaded until an explicit unload.
377
///
378
/// The system table is provided as mutable pointer. This is, because there is no guarantee that
379
/// timer interrupts do not modify the table. Furthermore, exiting boot services causes several
380
/// modifications on that table. And lastly, the system table lives longer than the function
381
/// invocation, if invoked as an UEFI driver.
382
/// In most cases it is perfectly fine to cast the pointer to a real rust reference. However, this
383
/// should be an explicit decision by the caller.
384
pub type ImageEntryPoint = fn(Handle, *mut crate::system::SystemTable) -> Status;
385
386
/// Globally Unique Identifiers
387
///
388
/// The `Guid` type represents globally unique identifiers as defined by RFC-4122 (i.e., only the
389
/// `10x` variant is used), with the caveat that LE is used instead of BE. The type must be 64-bit
390
/// aligned.
391
///
392
/// Note that only the binary representation of Guids is stable. You are highly recommended to
393
/// interpret Guids as 128bit integers.
394
///
395
/// UEFI uses the Microsoft-style Guid format. Hence, a lot of documentation and code refers to
396
/// these Guids. If you thusly cannot treat Guids as 128-bit integers, this Guid type allows you
397
/// to access the individual fields of the Microsoft-style Guid. A reminder of the Guid encoding:
398
///
399
/// ```text
400
///    0                   1                   2                   3
401
///    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
402
///   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
403
///   |                          time_low                             |
404
///   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
405
///   |       time_mid                |         time_hi_and_version   |
406
///   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
407
///   |clk_seq_hi_res |  clk_seq_low  |         node (0-1)            |
408
///   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
409
///   |                         node (2-5)                            |
410
///   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
411
/// ```
412
///
413
/// The individual fields are encoded as little-endian. Accessors are provided for the Guid
414
/// structure allowing access to these fields in native endian byte order.
415
#[repr(C, align(8))]
416
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
417
pub struct Guid {
418
    time_low: [u8; 4],
419
    time_mid: [u8; 2],
420
    time_hi_and_version: [u8; 2],
421
    clk_seq_hi_res: u8,
422
    clk_seq_low: u8,
423
    node: [u8; 6],
424
}
425
426
/// Network MAC Address
427
///
428
/// This type encapsulates a single networking media access control address
429
/// (MAC). It is a simple 32 bytes buffer with no special alignment. Note that
430
/// no comparison function are defined by default, since trailing bytes of the
431
/// address might be random.
432
///
433
/// The interpretation of the content differs depending on the protocol it is
434
/// used with. See each documentation for details. In most cases this contains
435
/// an Ethernet address.
436
#[repr(C)]
437
#[derive(Copy, Clone, Debug)]
438
pub struct MacAddress {
439
    pub addr: [u8; 32],
440
}
441
442
/// IPv4 Address
443
///
444
/// Binary representation of an IPv4 address. It is encoded in network byte
445
/// order (i.e., big endian). Note that no special alignment restrictions are
446
/// defined by the standard specification.
447
#[repr(C)]
448
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
449
pub struct Ipv4Address {
450
    pub addr: [u8; 4],
451
}
452
453
/// IPv6 Address
454
///
455
/// Binary representation of an IPv6 address, encoded in network byte order
456
/// (i.e., big endian). Similar to the IPv4 address, no special alignment
457
/// restrictions are defined by the standard specification.
458
#[repr(C)]
459
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
460
pub struct Ipv6Address {
461
    pub addr: [u8; 16],
462
}
463
464
/// IP Address
465
///
466
/// A union type over the different IP addresses available. Alignment is always
467
/// fixed to 4-bytes. Note that trailing bytes might be random, so no
468
/// comparison functions are derived.
469
#[repr(C, align(4))]
470
#[derive(Copy, Clone)]
471
pub union IpAddress {
472
    pub addr: [u32; 4],
473
    pub v4: Ipv4Address,
474
    pub v6: Ipv6Address,
475
}
476
477
impl Boolean {
478
    /// Literal False
479
    ///
480
    /// This constant represents the `false` value of the `Boolean` type.
481
    pub const FALSE: Boolean = Boolean(0u8);
482
483
    /// Literal True
484
    ///
485
    /// This constant represents the `true` value of the `Boolean` type.
486
    pub const TRUE: Boolean = Boolean(1u8);
487
}
488
489
impl From<u8> for Boolean {
490
0
    fn from(v: u8) -> Self {
491
0
        Boolean(v)
492
0
    }
493
}
494
495
impl From<bool> for Boolean {
496
0
    fn from(v: bool) -> Self {
497
0
        match v {
498
0
            false => Boolean::FALSE,
499
0
            true => Boolean::TRUE,
500
        }
501
0
    }
502
}
503
504
impl From<Boolean> for bool {
505
0
    fn from(v: Boolean) -> Self {
506
0
        match v.0 {
507
0
            0 => false,
508
0
            _ => true,
509
        }
510
0
    }
511
}
512
513
impl PartialEq for Boolean {
514
0
    fn eq(&self, other: &Boolean) -> bool {
515
0
        <bool as From<Boolean>>::from(*self) == (*other).into()
516
0
    }
517
}
518
519
impl PartialEq<bool> for Boolean {
520
0
    fn eq(&self, other: &bool) -> bool {
521
0
        *other == (*self).into()
522
0
    }
523
}
524
525
impl Status {
526
    const WIDTH: usize = 8usize * core::mem::size_of::<Status>();
527
    const MASK: usize = 0xc0 << (Status::WIDTH - 8);
528
    const ERROR_MASK: usize = 0x80 << (Status::WIDTH - 8);
529
    const WARNING_MASK: usize = 0x00 << (Status::WIDTH - 8);
530
531
    /// Success Code
532
    ///
533
    /// This code represents a successfull function invocation. Its value is guaranteed to be 0.
534
    /// However, note that warnings are considered success as well, so this is not the only code
535
    /// that can be returned by UEFI functions on success. However, in nearly all situations
536
    /// warnings are not allowed, so the effective result will be SUCCESS.
537
    pub const SUCCESS: Status = Status::from_usize(0);
538
539
    // List of predefined error codes
540
    pub const LOAD_ERROR: Status = Status::from_usize(1 | Status::ERROR_MASK);
541
    pub const INVALID_PARAMETER: Status = Status::from_usize(2 | Status::ERROR_MASK);
542
    pub const UNSUPPORTED: Status = Status::from_usize(3 | Status::ERROR_MASK);
543
    pub const BAD_BUFFER_SIZE: Status = Status::from_usize(4 | Status::ERROR_MASK);
544
    pub const BUFFER_TOO_SMALL: Status = Status::from_usize(5 | Status::ERROR_MASK);
545
    pub const NOT_READY: Status = Status::from_usize(6 | Status::ERROR_MASK);
546
    pub const DEVICE_ERROR: Status = Status::from_usize(7 | Status::ERROR_MASK);
547
    pub const WRITE_PROTECTED: Status = Status::from_usize(8 | Status::ERROR_MASK);
548
    pub const OUT_OF_RESOURCES: Status = Status::from_usize(9 | Status::ERROR_MASK);
549
    pub const VOLUME_CORRUPTED: Status = Status::from_usize(10 | Status::ERROR_MASK);
550
    pub const VOLUME_FULL: Status = Status::from_usize(11 | Status::ERROR_MASK);
551
    pub const NO_MEDIA: Status = Status::from_usize(12 | Status::ERROR_MASK);
552
    pub const MEDIA_CHANGED: Status = Status::from_usize(13 | Status::ERROR_MASK);
553
    pub const NOT_FOUND: Status = Status::from_usize(14 | Status::ERROR_MASK);
554
    pub const ACCESS_DENIED: Status = Status::from_usize(15 | Status::ERROR_MASK);
555
    pub const NO_RESPONSE: Status = Status::from_usize(16 | Status::ERROR_MASK);
556
    pub const NO_MAPPING: Status = Status::from_usize(17 | Status::ERROR_MASK);
557
    pub const TIMEOUT: Status = Status::from_usize(18 | Status::ERROR_MASK);
558
    pub const NOT_STARTED: Status = Status::from_usize(19 | Status::ERROR_MASK);
559
    pub const ALREADY_STARTED: Status = Status::from_usize(20 | Status::ERROR_MASK);
560
    pub const ABORTED: Status = Status::from_usize(21 | Status::ERROR_MASK);
561
    pub const ICMP_ERROR: Status = Status::from_usize(22 | Status::ERROR_MASK);
562
    pub const TFTP_ERROR: Status = Status::from_usize(23 | Status::ERROR_MASK);
563
    pub const PROTOCOL_ERROR: Status = Status::from_usize(24 | Status::ERROR_MASK);
564
    pub const INCOMPATIBLE_VERSION: Status = Status::from_usize(25 | Status::ERROR_MASK);
565
    pub const SECURITY_VIOLATION: Status = Status::from_usize(26 | Status::ERROR_MASK);
566
    pub const CRC_ERROR: Status = Status::from_usize(27 | Status::ERROR_MASK);
567
    pub const END_OF_MEDIA: Status = Status::from_usize(28 | Status::ERROR_MASK);
568
    pub const END_OF_FILE: Status = Status::from_usize(31 | Status::ERROR_MASK);
569
    pub const INVALID_LANGUAGE: Status = Status::from_usize(32 | Status::ERROR_MASK);
570
    pub const COMPROMISED_DATA: Status = Status::from_usize(33 | Status::ERROR_MASK);
571
    pub const IP_ADDRESS_CONFLICT: Status = Status::from_usize(34 | Status::ERROR_MASK);
572
    pub const HTTP_ERROR: Status = Status::from_usize(35 | Status::ERROR_MASK);
573
574
    // List of predefined warning codes
575
    pub const WARN_UNKNOWN_GLYPH: Status = Status::from_usize(1 | Status::WARNING_MASK);
576
    pub const WARN_DELETE_FAILURE: Status = Status::from_usize(2 | Status::WARNING_MASK);
577
    pub const WARN_WRITE_FAILURE: Status = Status::from_usize(3 | Status::WARNING_MASK);
578
    pub const WARN_BUFFER_TOO_SMALL: Status = Status::from_usize(4 | Status::WARNING_MASK);
579
    pub const WARN_STALE_DATA: Status = Status::from_usize(5 | Status::WARNING_MASK);
580
    pub const WARN_FILE_SYSTEM: Status = Status::from_usize(6 | Status::WARNING_MASK);
581
    pub const WARN_RESET_REQUIRED: Status = Status::from_usize(7 | Status::WARNING_MASK);
582
583
    /// Create Status Code from Integer
584
    ///
585
    /// This takes the literal value of a status code and turns it into a `Status` object. Note
586
    /// that we want it as `const fn` so we cannot use `core::convert::From`.
587
0
    pub const fn from_usize(v: usize) -> Status {
588
0
        Status(v)
589
0
    }
590
591
    /// Return Underlying Integer Representation
592
    ///
593
    /// This takes the `Status` object and returns the underlying integer representation as
594
    /// defined by the UEFI specification.
595
0
    pub const fn as_usize(&self) -> usize {
596
0
        self.0
597
0
    }
598
599
0
    fn value(&self) -> usize {
600
0
        self.0
601
0
    }
602
603
0
    fn mask(&self) -> usize {
604
0
        self.value() & Status::MASK
605
0
    }
606
607
    /// Check whether this is an error
608
    ///
609
    /// This returns true if the given status code is considered an error. Errors mean the
610
    /// operation did not succeed, nor produce any valuable output. Output parameters must be
611
    /// considered invalid if an error was returned. That is, its content is not well defined.
612
0
    pub fn is_error(&self) -> bool {
613
0
        self.mask() == Status::ERROR_MASK
614
0
    }
615
616
    /// Check whether this is a warning
617
    ///
618
    /// This returns true if the given status code is considered a warning. Warnings are to be
619
    /// treated as success, but might indicate data loss or other device errors. However, if an
620
    /// operation returns with a warning code, it must be considered successfull, and the output
621
    /// parameters are valid.
622
0
    pub fn is_warning(&self) -> bool {
623
0
        self.value() != 0 && self.mask() == Status::WARNING_MASK
624
0
    }
625
}
626
627
impl From<Status> for Result<Status, Status> {
628
0
    fn from(status: Status) -> Self {
629
0
        if status.is_error() {
630
0
            Err(status)
631
        } else {
632
0
            Ok(status)
633
        }
634
0
    }
635
}
636
637
impl Guid {
638
0
    const fn u32_to_bytes_le(num: u32) -> [u8; 4] {
639
0
        [
640
0
            num as u8,
641
0
            (num >> 8) as u8,
642
0
            (num >> 16) as u8,
643
0
            (num >> 24) as u8,
644
0
        ]
645
0
    }
646
647
0
    const fn u32_from_bytes_le(bytes: &[u8; 4]) -> u32 {
648
0
        (bytes[0] as u32)
649
0
            | ((bytes[1] as u32) << 8)
650
0
            | ((bytes[2] as u32) << 16)
651
0
            | ((bytes[3] as u32) << 24)
652
0
    }
653
654
0
    const fn u16_to_bytes_le(num: u16) -> [u8; 2] {
655
0
        [num as u8, (num >> 8) as u8]
656
0
    }
657
658
0
    const fn u16_from_bytes_le(bytes: &[u8; 2]) -> u16 {
659
0
        (bytes[0] as u16) | ((bytes[1] as u16) << 8)
660
0
    }
661
662
    /// Initialize a Guid from its individual fields
663
    ///
664
    /// This function initializes a Guid object given the individual fields as specified in the
665
    /// UEFI specification. That is, if you simply copy the literals from the specification into
666
    /// your code, this function will correctly initialize the Guid object.
667
    ///
668
    /// In other words, this takes the individual fields in native endian and converts them to the
669
    /// correct endianness for a UEFI Guid.
670
0
    pub const fn from_fields(
671
0
        time_low: u32,
672
0
        time_mid: u16,
673
0
        time_hi_and_version: u16,
674
0
        clk_seq_hi_res: u8,
675
0
        clk_seq_low: u8,
676
0
        node: &[u8; 6],
677
0
    ) -> Guid {
678
0
        Guid {
679
0
            time_low: Self::u32_to_bytes_le(time_low),
680
0
            time_mid: Self::u16_to_bytes_le(time_mid),
681
0
            time_hi_and_version: Self::u16_to_bytes_le(time_hi_and_version),
682
0
            clk_seq_hi_res: clk_seq_hi_res,
683
0
            clk_seq_low: clk_seq_low,
684
0
            node: *node,
685
0
        }
686
0
    }
687
688
    /// Access a Guid as individual fields
689
    ///
690
    /// This decomposes a Guid back into the individual fields as given in the specification. The
691
    /// individual fields are returned in native-endianness.
692
0
    pub const fn as_fields(&self) -> (u32, u16, u16, u8, u8, &[u8; 6]) {
693
0
        (
694
0
            Self::u32_from_bytes_le(&self.time_low),
695
0
            Self::u16_from_bytes_le(&self.time_mid),
696
0
            Self::u16_from_bytes_le(&self.time_hi_and_version),
697
0
            self.clk_seq_hi_res,
698
0
            self.clk_seq_low,
699
0
            &self.node,
700
0
        )
701
0
    }
702
703
    /// Access a Guid as raw byte array
704
    ///
705
    /// This provides access to a Guid through a byte array. It is a simple re-interpretation of
706
    /// the Guid value as a 128-bit byte array. No conversion is performed. This is a simple cast.
707
11.2k
    pub fn as_bytes(&self) -> &[u8; 16] {
708
11.2k
        unsafe { core::mem::transmute::<&Guid, &[u8; 16]>(self) }
709
11.2k
    }
710
}
711
712
#[cfg(test)]
713
mod tests {
714
    use super::*;
715
    use std::mem::{align_of, size_of};
716
717
    // Verify Type Size and Alignemnt
718
    //
719
    // Since UEFI defines explicitly the ABI of their types, we can verify that our implementation
720
    // is correct by checking the size and alignment of the ABI types matches what the spec
721
    // mandates.
722
    #[test]
723
    fn type_size_and_alignment() {
724
        //
725
        // Booleans
726
        //
727
728
        assert_eq!(size_of::<Boolean>(), 1);
729
        assert_eq!(align_of::<Boolean>(), 1);
730
731
        //
732
        // Char8 / Char16
733
        //
734
735
        assert_eq!(size_of::<Char8>(), 1);
736
        assert_eq!(align_of::<Char8>(), 1);
737
        assert_eq!(size_of::<Char16>(), 2);
738
        assert_eq!(align_of::<Char16>(), 2);
739
740
        assert_eq!(size_of::<Char8>(), size_of::<u8>());
741
        assert_eq!(align_of::<Char8>(), align_of::<u8>());
742
        assert_eq!(size_of::<Char16>(), size_of::<u16>());
743
        assert_eq!(align_of::<Char16>(), align_of::<u16>());
744
745
        //
746
        // Status
747
        //
748
749
        assert_eq!(size_of::<Status>(), size_of::<usize>());
750
        assert_eq!(align_of::<Status>(), align_of::<usize>());
751
752
        //
753
        // Handles / Events
754
        //
755
756
        assert_eq!(size_of::<Handle>(), size_of::<usize>());
757
        assert_eq!(align_of::<Handle>(), align_of::<usize>());
758
        assert_eq!(size_of::<Event>(), size_of::<usize>());
759
        assert_eq!(align_of::<Event>(), align_of::<usize>());
760
761
        assert_eq!(size_of::<Handle>(), size_of::<*mut ()>());
762
        assert_eq!(align_of::<Handle>(), align_of::<*mut ()>());
763
        assert_eq!(size_of::<Event>(), size_of::<*mut ()>());
764
        assert_eq!(align_of::<Event>(), align_of::<*mut ()>());
765
766
        //
767
        // Lba / Tpl
768
        //
769
770
        assert_eq!(size_of::<Lba>(), size_of::<u64>());
771
        assert_eq!(align_of::<Lba>(), align_of::<u64>());
772
        assert_eq!(size_of::<Tpl>(), size_of::<usize>());
773
        assert_eq!(align_of::<Tpl>(), align_of::<usize>());
774
775
        //
776
        // PhysicalAddress / VirtualAddress
777
        //
778
779
        assert_eq!(size_of::<PhysicalAddress>(), size_of::<u64>());
780
        assert_eq!(align_of::<PhysicalAddress>(), align_of::<u64>());
781
        assert_eq!(size_of::<VirtualAddress>(), size_of::<u64>());
782
        assert_eq!(align_of::<VirtualAddress>(), align_of::<u64>());
783
784
        //
785
        // ImageEntryPoint
786
        //
787
788
        assert_eq!(size_of::<ImageEntryPoint>(), size_of::<fn()>());
789
        assert_eq!(align_of::<ImageEntryPoint>(), align_of::<fn()>());
790
791
        //
792
        // Guid
793
        //
794
795
        assert_eq!(size_of::<Guid>(), 16);
796
        assert_eq!(align_of::<Guid>(), 8);
797
798
        //
799
        // Networking Types
800
        //
801
802
        assert_eq!(size_of::<MacAddress>(), 32);
803
        assert_eq!(align_of::<MacAddress>(), 1);
804
        assert_eq!(size_of::<Ipv4Address>(), 4);
805
        assert_eq!(align_of::<Ipv4Address>(), 1);
806
        assert_eq!(size_of::<Ipv6Address>(), 16);
807
        assert_eq!(align_of::<Ipv6Address>(), 1);
808
        assert_eq!(size_of::<IpAddress>(), 16);
809
        assert_eq!(align_of::<IpAddress>(), 4);
810
    }
811
812
    #[test]
813
    fn eficall() {
814
        //
815
        // Make sure the eficall!{} macro can deal with all kinds of function callbacks.
816
        //
817
818
        let _: eficall! {fn()};
819
        let _: eficall! {unsafe fn()};
820
        let _: eficall! {fn(i32)};
821
        let _: eficall! {fn(i32) -> i32};
822
        let _: eficall! {fn(i32, i32) -> (i32, i32)};
823
824
        eficall! {fn _unused00() {}}
825
        eficall! {unsafe fn _unused01() {}}
826
        eficall! {pub unsafe fn _unused02() {}}
827
    }
828
829
    // Verify Boolean ABI
830
    //
831
    // Even though booleans are strictly 1-bit, and thus 0 or 1, in practice all UEFI systems
832
    // treat it more like C does, and a boolean formatted as `u8` now allows any value other than
833
    // 0 to represent `true`. Make sure we support the same.
834
    #[test]
835
    fn booleans() {
836
        // Verify PartialEq works.
837
        assert_ne!(Boolean::FALSE, Boolean::TRUE);
838
839
        // Verify Boolean<->bool conversion and comparison works.
840
        assert_eq!(Boolean::FALSE, false);
841
        assert_eq!(Boolean::TRUE, true);
842
843
        // Iterate all possible values for `u8` and verify 0 behaves as `false`, and everything
844
        // else behaves as `true`. We verify both, the natural constructor through `From`, as well
845
        // as a transmute.
846
        for i in 0u8..=255u8 {
847
            let v1: Boolean = i.into();
848
            let v2: Boolean = unsafe { std::mem::transmute::<u8, Boolean>(i) };
849
850
            assert_eq!(v1, v2);
851
            assert_eq!(v1, v1);
852
            assert_eq!(v2, v2);
853
854
            match i {
855
                0 => {
856
                    assert_eq!(v1, Boolean::FALSE);
857
                    assert_eq!(v1, false);
858
                    assert_eq!(v2, Boolean::FALSE);
859
                    assert_eq!(v2, false);
860
861
                    assert_ne!(v1, Boolean::TRUE);
862
                    assert_ne!(v1, true);
863
                    assert_ne!(v2, Boolean::TRUE);
864
                    assert_ne!(v2, true);
865
                }
866
                _ => {
867
                    assert_eq!(v1, Boolean::TRUE);
868
                    assert_eq!(v1, true);
869
                    assert_eq!(v2, Boolean::TRUE);
870
                    assert_eq!(v2, true);
871
872
                    assert_ne!(v1, Boolean::FALSE);
873
                    assert_ne!(v1, false);
874
                    assert_ne!(v2, Boolean::FALSE);
875
                    assert_ne!(v2, false);
876
                }
877
            }
878
        }
879
    }
880
}