1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
//! UEFI Reference Specification Protocol Constants and Definitions
//!
//! This project provides protocol constants and definitions as defined in the UEFI Reference
//! Specification. The aim is to provide all these constants as C-ABI compatible imports to rust.
//! Safe rust abstractions over the UEFI API are out of scope of this project. That is, the
//! purpose is really just to extract all the bits and pieces from the specification and provide
//! them as rust types and constants.
//!
//! While we strongly recommend using safe abstractions to interact with UEFI systems, this
//! project serves both as base to write those abstractions, but also as last resort if you have
//! to deal with quirks and peculiarities of UEFI systems directly. Therefore, several examples
//! are included, which show how to interact with UEFI systems from rust. These serve both as
//! documentation for anyone interested in how the system works, but also as base for anyone
//! implementing safe abstractions on top.
//!
//! # Target Configuration
//!
//! Rust code can be compiled natively for UEFI systems. However, you are quite unlikely to have a
//! rust compiler running in an UEFI environment. Therefore, you will most likely want to cross
//! compile your rust code for UEFI systems. To do this, you need a target-configuration for UEFI
//! systems. As of rust-1.61, upstream rust includes the following UEFI targets:
//!
//!  * `aarch64-unknown-uefi`: A native UEFI target for aarch64 systems (64bit ARM).
//!  * `i686-unknown-uefi`: A native UEFI target for i686 systems (32bit Intel x86).
//!  * `x86_64-unknown-uefi`: A native UEFI target for x86-64 systems (64bit Intel x86).
//!
//! If none of these targets match your architecture, you have to create the target specification
//! yourself. Feel free to contact the `r-efi` project for help.
//!
//! # Transpose Guidelines
//!
//! The UEFI specification provides C language symbols and definitions of all
//! its protocols and features. Those are integral parts of the specification
//! and UEFI programming is often tightly coupled with the C language. For
//! better compatibility to existing UEFI documentation, all the rust symbols
//! are transposed from C following strict rules, aiming for close similarity
//! to specification. This section gives a rationale on some of the less
//! obvious choices and tries to describe as many of those rules as possible.
//!
//!  * `no enums`: Rust enums do not allow random discriminant values. However,
//!    many UEFI enumerations use reserved ranges for vendor defined values.
//!    These cannot be represented with rust enums in an efficient manner.
//!    Hence, any enumerations are turned into rust constants with an
//!    accompanying type alias.
//!
//!    A detailed discussion can be found in:
//!
//!    ```gitlog
//!        commit 401a91901e860a5c0cd0f92b75dda0a72cf65322
//!        Author: David Rheinsberg <david.rheinsberg@gmail.com>
//!        Date:   Wed Apr 21 12:07:07 2021 +0200
//!
//!            r-efi: convert enums to constants
//!    ```
//!
//!  * `no incomplete types`: Several structures use incomplete structure types
//!    by using an unbound array as last member. While rust can easily
//!    represent those within its type-system, such structures become DSTs,
//!    hence even raw pointers to them become fat-pointers, and would thus
//!    violate the UEFI ABI.
//!
//!    Instead, we use const-generics to allow compile-time adjustment of the
//!    variable-sized structures, with a default value of 0. This allows
//!    computing different sizes of the structures without any runtime overhead.
//!
//!  * `nullable callbacks as Option`: Rust has no raw function pointers, but
//!    just normal Rust function pointers. Those, however, have no valid null
//!    value. The Rust ABI guarantees that `Option<fn ...>` is an C-ABI
//!    compatible replacement for nullable function pointers, with `None` being
//!    mapped to `NULL`. Hence, whenever UEFI APIs require nullable function
//!    pointers, we use `Option<fn ...>`.
//!
//!  * `prefer *mut over *const`: Whenever we transpose pointers from the
//!    specification into Rust, we prefer `*mut` in almost all cases. `*const`
//!    should only be used if the underlying value is known not to be accessible
//!    via any other mutable pointer type. Since this is rarely the case in
//!    UEFI, we avoid it.
//!
//!    The reasoning is that Rust allows coercing immutable types into `*const`
//!    pointers, without any explicit casting required. However, immutable Rust
//!    references require that no other mutable reference exists simultaneously.
//!    This is not a guarantee of `const`-pointers in C / UEFI, hence this
//!    coercion is usually ill-advised or even wrong.
//!
//!    Lastly, note that `*mut` and `*const` and be `as`-casted in both
//!    directions without violating any Rust guarantees. Any UB concerns always
//!    stem from the safety guarantees of the surrounding code, not of the
//!    raw-pointer handling.
//!
//! # Examples
//!
//! To write free-standing UEFI applications, you need to disable the entry-point provided by rust
//! and instead provide your own. Most target-configurations look for a function called `efi_main`
//! during linking and set it as entry point. If you use the target-configurations provided with
//! upstream rust, they will pick the function called `efi_main` as entry-point.
//!
//! The following example shows a minimal UEFI application, which simply returns success upon
//! invocation. Note that you must provide your own panic-handler when running without `libstd`.
//! In our case, we use a trivial implementation that simply loops forever.
//!
//! ```ignore
//! #![no_main]
//! #![no_std]
//!
//! use r_efi::efi;
//!
//! #[panic_handler]
//! fn panic_handler(_info: &core::panic::PanicInfo) -> ! {
//!     loop {}
//! }
//!
//! #[export_name = "efi_main"]
//! pub extern fn main(_h: efi::Handle, _st: *mut efi::SystemTable) -> efi::Status {
//!     efi::Status::SUCCESS
//! }
//! ```

// Mark this crate as `no_std`. We have no std::* dependencies (and we better don't have them),
// so no reason to require it. This does not mean that you cannot use std::* with UEFI. You have
// to port it to UEFI first, though.
//
// In case of unit-test compilation, we pull in `std` and drop the `no_std` marker. This allows
// basic unit-tests on the compilation host. For integration tests, we have separate compilation
// units, so they will be unaffected by this.
#![cfg_attr(not(test), no_std)]

// Import the different core modules. We separate them into different modules to make it easier to
// work on them and describe what each part implements. This is different to the reference
// implementation, which uses a flat namespace due to its origins in the C language. For
// compatibility, we provide this flat namespace as well. See the `efi` submodule.
#[macro_use]
pub mod base;
#[macro_use]
pub mod hii;
#[macro_use]
pub mod system;

// Import the protocols. Each protocol is separated into its own module, readily imported by the
// meta `protocols` module. Note that this puts all symbols into their respective protocol
// namespace, thus clearly separating them (unlike the UEFI Specification, which more often than
// not violates its own namespacing).
pub mod protocols;

// Import vendor protocols. They are just like protocols in `protocols`, but
// separated for better namespacing.
pub mod vendor;

/// Flat EFI Namespace
///
/// The EFI namespace re-exports all symbols in a single, flat namespace. This allows mirroring
/// the entire EFI namespace as given in the specification and makes it easier to refer to them
/// with the same names as the reference C implementation.
///
/// Note that the individual protocols are put into submodules. The specification does this in
/// most parts as well (by prefixing all symbols). This is not true in all cases, as the
/// specification suffers from lack of namespaces in the reference C language. However, we decided
/// to namespace the remaining bits as well, for better consistency throughout the API. This
/// should be self-explanatory in nearly all cases.
pub mod efi {
    pub use crate::base::*;
    pub use crate::system::*;

    pub use crate::hii;
    pub use crate::protocols;
    pub use crate::vendor;
}