Skip to content

Commit ab9c7c6

Browse files
committed
repo: init uefi-std-example
This is a minimal template to build Rust apps with Rust's std support for UEFI and our additional `uefi` functionality. It isn't build in CI yet, but might serve as a base for now.
1 parent 890ae99 commit ab9c7c6

File tree

9 files changed

+145
-0
lines changed

9 files changed

+145
-0
lines changed

Cargo.lock

+7
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

+1
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ members = [
55
"uefi",
66
"uefi-macros",
77
"uefi-raw",
8+
"uefi-std-example",
89
"uefi-test-runner",
910
"xtask",
1011
]

README.md

+2
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,8 @@ This project contains multiple sub-crates:
7777
Specification. Safe wrappers for these types are provided by the `uefi`
7878
crate. The raw types are suitable for implementing UEFI firmware.
7979

80+
- `uefi-std-example`: Example UEFI app but as Rust standard binary.
81+
8082
- `uefi-test-runner`: a UEFI application that runs unit / integration tests.
8183

8284
[log]: https://github.com/rust-lang-nursery/log

book/src/SUMMARY.md

+1
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
- [Introduction](introduction.md)
44
- [Tutorial](tutorial/introduction.md)
55
- [Creating a UEFI Application](tutorial/app.md)
6+
- [Combining Rust `std` with `uefi`](tutorial/rust-std.md)
67
- [Building](tutorial/building.md)
78
- [Running in a VM](tutorial/vm.md)
89
- [Running on Hardware](tutorial/hardware.md)

book/src/tutorial/rust-std.md

+73
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
# Combining Rust `std` with `uefi`
2+
3+
## TL;DR
4+
5+
In Mid-2024, we recommend to stick to our normal guide. Use this document as
6+
guide and outlook for the future of UEFI and Rust.
7+
8+
## About
9+
10+
In the `uefi` crate, we provide tooling to create a `no_std` + `no_main`
11+
binary, i.e., an UEFI image, in a convenient way. However, there is also the
12+
option to create a "standard" binary with Rust. The result is the same, but the
13+
build process and the overall programming is much more similar to regular
14+
Rust binaries written for Operating Systems, such as Linux, Windows, or macOS.
15+
16+
## Standard binary vs `no_std` binary
17+
18+
A Rust standard binary is a binary that uses the Rust standard library. This
19+
means that the Rust standard library (_`std` implementation_) is implemented for
20+
the given platform. A `no_std` (strictly speaking, `no_std` + `no_main`) on the
21+
other hand can only use the `core` library, but not `std`. Thus, you need to
22+
write more functionality on your own or use libraries, such as the `uefi` crate.
23+
24+
## About `std` for `uefi`
25+
26+
Using `std` is always the recommended and standard way. However, the `std`
27+
implementation is not feature-complete and work in progress
28+
(Mid-2024, Rust stable 1.80), and will also be it in the coming months and
29+
probably years. Over time, you will need less and less specific features of
30+
`uefi` and can utilize standard and well-known OS-independent APIs in `std`
31+
instead. Just as you would to in the typical Linux application, for example.
32+
33+
The `uefi` crate is suited to extend the functionality of these "standard
34+
binaries".
35+
36+
## Code Example
37+
38+
Please refer to [`<repo>/uefi-std-example`](/uefi-std-example/README.md) to
39+
see a specific example. The relevant `main.rs` looks as follows:
40+
41+
```rust
42+
// Note: In Rust 1.82.0-nightly and before, the `uefi_std` feature is
43+
// required for accessing `std::os::uefi::env::*`. The other default
44+
// functionality doesn't need a nightly toolchain (with Rust 1.80 and later),
45+
// but with that limited functionality you - currently - also can't integrate
46+
// the `uefi` crate.
47+
#![feature(uefi_std)]
48+
49+
use std::os::uefi as uefi_std;
50+
use uefi::runtime::ResetType;
51+
use uefi::{Handle, Status};
52+
53+
/// Performs the necessary setup code for the `uefi` crate.
54+
fn setup_uefi_crate() {
55+
let st = uefi_std::env::system_table();
56+
let ih = uefi_std::env::image_handle();
57+
58+
// Mandatory setup code for `uefi` crate.
59+
unsafe {
60+
uefi::table::set_system_table(st.as_ptr().cast());
61+
62+
let ih = Handle::from_ptr(ih.as_ptr().cast()).unwrap();
63+
uefi::boot::set_image_handle(ih);
64+
}
65+
}
66+
67+
fn main() {
68+
println!("Hello World from uefi_std");
69+
setup_uefi_crate();
70+
println!("UEFI-Version is {}", uefi::system::uefi_revision());
71+
uefi::runtime::reset(ResetType::SHUTDOWN, Status::SUCCESS, None);
72+
}
73+
```

shell.nix

+1
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ pkgs.mkShell {
2121
rustToolchain
2222

2323
# Other
24+
mdbook
2425
yamlfmt
2526
which # used by "cargo xtask fmt"
2627
];

uefi-std-example/Cargo.toml

+11
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
[package]
2+
name = "uefi-std-example"
3+
version = "0.1.0"
4+
authors = ["The Rust OSDev team"]
5+
publish = false
6+
edition = "2021"
7+
8+
[dependencies]
9+
# Attention: Don't activate the panic_handler feature, as it will clash with
10+
# the one coming from `std`.
11+
uefi = { path = "../uefi", features = ["alloc"], default-features = false }

uefi-std-example/README.md

+18
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
# Minimal Rust App using `std` and `uefi`
2+
3+
Minimal example of a "standard Rust application" that showcases how `uefi` can
4+
be utilized and enhance the developers experience, when `std` is available.
5+
6+
For simplicity, this example is minimal and the documentation is focused on
7+
`x86_64-unknown-uefi`. However, it works similar for other supported UEFI
8+
platforms.
9+
10+
## Build
11+
12+
Build the app using
13+
`$ cargo +nightly build --target x86_64-unknown-uefi`. To build it from the root
14+
directory (the Cargo workspace), append `-p uefi-std-example`.
15+
16+
## Run
17+
18+
The resulting `.efi` file can be found in `target/x86_64-unknown-uefi/<debug|release>/uefi-std-example.efi`.

uefi-std-example/src/main.rs

+31
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
// Note: In Rust 1.82.0-nightly and before, the `uefi_std` feature is
2+
// required for accessing `std::os::uefi::env::*`. The other default
3+
// functionality doesn't need a nightly toolchain (with Rust 1.80 and later),
4+
// but with that limited functionality you - currently - also can't integrate
5+
// the `uefi` crate.
6+
#![feature(uefi_std)]
7+
8+
use std::os::uefi as uefi_std;
9+
use uefi::runtime::ResetType;
10+
use uefi::{Handle, Status};
11+
12+
/// Performs the necessary setup code for the `uefi` crate.
13+
fn setup_uefi_crate() {
14+
let st = uefi_std::env::system_table();
15+
let ih = uefi_std::env::image_handle();
16+
17+
// Mandatory setup code for `uefi` crate.
18+
unsafe {
19+
uefi::table::set_system_table(st.as_ptr().cast());
20+
21+
let ih = Handle::from_ptr(ih.as_ptr().cast()).unwrap();
22+
uefi::boot::set_image_handle(ih);
23+
}
24+
}
25+
26+
fn main() {
27+
println!("Hello World from uefi_std");
28+
setup_uefi_crate();
29+
println!("UEFI-Version is {}", uefi::system::uefi_revision());
30+
uefi::runtime::reset(ResetType::SHUTDOWN, Status::SUCCESS, None);
31+
}

0 commit comments

Comments
 (0)