]> git.proxmox.com Git - rustc.git/blame - src/doc/rustc/src/platform-support/unknown-uefi.md
New upstream version 1.67.1+dfsg1
[rustc.git] / src / doc / rustc / src / platform-support / unknown-uefi.md
CommitLineData
064997fb
FG
1# `*-unknown-uefi`
2
487cf647 3**Tier: 2**
064997fb
FG
4
5Unified Extensible Firmware Interface (UEFI) targets for application, driver,
6and core UEFI binaries.
7
8Available targets:
9
10- `aarch64-unknown-uefi`
11- `i686-unknown-uefi`
12- `x86_64-unknown-uefi`
13
14## Target maintainers
15
16- David Rheinsberg ([@dvdhrm](https://github.com/dvdhrm))
17- Nicholas Bishop ([@nicholasbishop](https://github.com/nicholasbishop))
18
19## Requirements
20
21All UEFI targets can be used as `no-std` environments via cross-compilation.
22Support for `std` is missing, but actively worked on. `alloc` is supported if
23an allocator is provided by the user. No host tools are supported.
24
25The UEFI environment resembles the environment for Microsoft Windows, with some
26minor differences. Therefore, cross-compiling for UEFI works with the same
27tools as cross-compiling for Windows. The target binaries are PE32+ encoded,
28the calling convention is different for each architecture, but matches what
29Windows uses (if the architecture is supported by Windows). The special
30`efiapi` Rust calling-convention chooses the right ABI for the target platform
31(`extern "C"` is incorrect on Intel targets at least). The specification has an
32elaborate section on the different supported calling-conventions, if more
33details are desired.
34
35MMX, SSE, and other FP-units are disabled by default, to allow for compilation
36of core UEFI code that runs before they are set up. This can be overridden for
37individual compilations via rustc command-line flags. Not all firmwares
38correctly configure those units, though, so careful inspection is required.
39
40As native to PE32+, binaries are position-dependent, but can be relocated at
41runtime if their desired location is unavailable. The code must be statically
42linked. Dynamic linking is not supported. Code is shared via UEFI interfaces,
43rather than dynamic linking. Additionally, UEFI forbids running code on
44anything but the boot CPU/thread, nor is interrupt-usage allowed (apart from
45the timer interrupt). Device drivers are required to use polling methods.
46
47UEFI uses a single address-space to run all code in. Multiple applications can
48be loaded simultaneously and are dispatched via cooperative multitasking on a
49single stack.
50
51By default, the UEFI targets use the `link`-flavor of the LLVM linker `lld` to
52link binaries into the final PE32+ file suffixed with `*.efi`. The PE subsystem
53is set to `EFI_APPLICATION`, but can be modified by passing `/subsystem:<...>`
54to the linker. Similarly, the entry-point is to to `efi_main` but can be
55changed via `/entry:<...>`. The panic-strategy is set to `abort`,
56
57The UEFI specification is available online for free:
58[UEFI Specification Directory](https://uefi.org/specifications)
59
60## Building rust for UEFI targets
61
62Rust can be built for the UEFI targets by enabling them in the `rustc` build
63configuration. Note that you can only build the standard libraries. The
64compiler and host tools currently cannot be compiled for UEFI targets. A sample
65configuration would be:
66
67```toml
68[build]
69build-stage = 1
70target = ["x86_64-unknown-uefi"]
71```
72
73## Building Rust programs
74
487cf647
FG
75Starting with Rust 1.67, precompiled artifacts are provided via
76`rustup`. For example, to use `x86_64-unknown-uefi`:
064997fb
FG
77
78```sh
487cf647
FG
79# install cross-compile toolchain
80rustup target add x86_64-unknown-uefi
81# target flag may be used with any cargo or rustc command
82cargo build --target x86_64-unknown-uefi
064997fb
FG
83```
84
85## Testing
86
87UEFI applications can be copied into the ESP on any UEFI system and executed
88via the firmware boot menu. The qemu suite allows emulating UEFI systems and
89executing UEFI applications as well. See its documentation for details.
90
91The [uefi-run](https://github.com/Richard-W/uefi-run) rust tool is a simple
92wrapper around `qemu` that can spawn UEFI applications in qemu. You can install
93it via `cargo install uefi-run` and execute qemu applications as
94`uefi-run ./application.efi`.
95
96## Cross-compilation toolchains and C code
97
98There are 3 common ways to compile native C code for UEFI targets:
99
100- Use the official SDK by Intel:
101 [Tianocore/EDK2](https://github.com/tianocore/edk2). This supports a
102 multitude of platforms, comes with the full specification transposed into C,
103 lots of examples and build-system integrations. This is also the only
104 officially supported platform by Intel, and is used by many major firmware
105 implementations. Any code compiled via the SDK is compatible to rust binaries
106 compiled for the UEFI targets. You can link them directly into your rust
107 binaries, or call into each other via UEFI protocols.
108- Use the **GNU-EFI** suite. This approach is used by many UEFI applications
109 in the Linux/OSS ecosystem. The GCC compiler is used to compile ELF binaries,
110 and linked with a pre-loader that converts the ELF binary to PE32+
111 **at runtime**. You can combine such binaries with the rust UEFI targets only
112 via UEFI protocols. Linking both into the same executable will fail, since
113 one is an ELF executable, and one a PE32+. If linking to **GNU-EFI**
114 executables is desired, you must compile your rust code natively for the same
115 GNU target as **GNU-EFI** and use their pre-loader. This requires careful
116 consideration about which calling-convention to use when calling into native
117 UEFI protocols, or calling into linked **GNU-EFI** code (similar to how these
118 differences need to be accounted for when writing **GNU-EFI** C code).
119- Use native Windows targets. This means compiling your C code for the Windows
120 platform as if it was the UEFI platform. This works for static libraries, but
121 needs adjustments when linking into an UEFI executable. You can, however,
f2b60f7d 122 link such static libraries seamlessly into rust code compiled for UEFI
064997fb
FG
123 targets. Be wary of any includes that are not specifically suitable for UEFI
124 targets (especially the C standard library includes are not always
125 compatible). Freestanding compilations are recommended to avoid
126 incompatibilites.
127
128## Ecosystem
129
130The rust language has a long history of supporting UEFI targets. Many crates
131have been developed to provide access to UEFI protocols and make UEFI
132programming more ergonomic in rust. The following list is a short overview (in
133alphabetical ordering):
134
135- **efi**: *Ergonomic Rust bindings for writing UEFI applications*. Provides
136 _rustified_ access to UEFI protocols, implements allocators and a safe
137 environment to write UEFI applications.
138- **r-efi**: *UEFI Reference Specification Protocol Constants and Definitions*.
139 A pure transpose of the UEFI specification into rust. This provides the raw
140 definitions from the specification, without any extended helpers or
141 _rustification_. It serves as baseline to implement any more elaborate rust
142 UEFI layers.
143- **uefi-rs**: *Safe and easy-to-use wrapper for building UEFI apps*. An
144 elaborate library providing safe abstractions for UEFI protocols and
145 features. It implements allocators and provides an execution environment to
146 UEFI applications written in rust.
147- **uefi-run**: *Run UEFI applications*. A small wrapper around _qemu_ to spawn
148 UEFI applications in an emulated `x86_64` machine.
149
150## Example: Freestanding
151
152The following code is a valid UEFI application returning immediately upon
153execution with an exit code of 0. A panic handler is provided. This is executed
154by rust on panic. For simplicity, we simply end up in an infinite loop.
155
064997fb
FG
156This example can be compiled as binary crate via `cargo`:
157
158```sh
487cf647 159cargo build --target x86_64-unknown-uefi
064997fb
FG
160```
161
162```rust,ignore (platform-specific,eh-personality-is-unstable)
163#![no_main]
164#![no_std]
165
166#[panic_handler]
167fn panic_handler(_info: &core::panic::PanicInfo) -> ! {
168 loop {}
169}
170
171#[export_name = "efi_main"]
172pub extern "C" fn main(_h: *mut core::ffi::c_void, _st: *mut core::ffi::c_void) -> usize {
173 0
174}
175```
176
177## Example: Hello World
178
179This is an example UEFI application that prints "Hello World!", then waits for
180key input before it exits. It serves as base example how to write UEFI
181applications without any helper modules other than the standalone UEFI protocol
182definitions provided by the `r-efi` crate.
183
184This extends the "Freestanding" example and builds upon its setup. See there
185for instruction how to compile this as binary crate.
186
187Note that UEFI uses UTF-16 strings. Since rust literals are UTF-8, we have to
188use an open-coded, zero-terminated, UTF-16 array as argument to
189`output_string()`. Similarly to the panic handler, real applications should
190rather use UTF-16 modules.
191
192```rust,ignore (platform-specific,eh-personality-is-unstable)
193#![no_main]
194#![no_std]
195
196use r_efi::efi;
197
198#[panic_handler]
199fn panic_handler(_info: &core::panic::PanicInfo) -> ! {
200 loop {}
201}
202
203#[export_name = "efi_main"]
204pub extern "C" fn main(_h: efi::Handle, st: *mut efi::SystemTable) -> efi::Status {
205 let s = [
206 0x0048u16, 0x0065u16, 0x006cu16, 0x006cu16, 0x006fu16, // "Hello"
207 0x0020u16, // " "
208 0x0057u16, 0x006fu16, 0x0072u16, 0x006cu16, 0x0064u16, // "World"
209 0x0021u16, // "!"
210 0x000au16, // "\n"
211 0x0000u16, // NUL
212 ];
213
214 // Print "Hello World!".
215 let r =
216 unsafe { ((*(*st).con_out).output_string)((*st).con_out, s.as_ptr() as *mut efi::Char16) };
217 if r.is_error() {
218 return r;
219 }
220
221 // Wait for key input, by waiting on the `wait_for_key` event hook.
222 let r = unsafe {
223 let mut x: usize = 0;
224 ((*(*st).boot_services).wait_for_event)(1, &mut (*(*st).con_in).wait_for_key, &mut x)
225 };
226 if r.is_error() {
227 return r;
228 }
229
230 efi::Status::SUCCESS
231}
232```