Crates.io | efi |
lib.rs | efi |
version | 0.3.1 |
source | src |
created_at | 2018-03-14 06:10:16.943367 |
updated_at | 2023-10-18 07:42:30.631042 |
description | Ergonomic Rust bindings for writing UEFI applications |
homepage | |
repository | https://github.com/gurry/efi |
max_upload_size | |
id | 55492 |
size | 510,495 |
A framework for writing UEFI applications in Rust. Acts like the Rust standard library on the UEFI platform with support for things like:
Vec
and String
via a custom allocatorprintln!
, write!
, format!
etc.Read
and Write
traits and the related typesIpAddr
and its supporting typesAlso offers an ergonomic API for UEFI-specific functionality such as:
It uses the efi_ffi
crate to interface with the UEFI platform.
x64
architecture is supported.nightly-2023-01-12
. May not compile with others. You must force this version using a rust-toolchain
file (as shown in the following section)To write a UEFI application using this framework follow the below steps:
cargo new my_efi_app
, where my_efi_app
is the name of the applicationefi = "0.3"
under [dependencies]
in Cargo.toml
rust-toolchain
containing the text nightly-2023-01-12
at the root of the crate. This will ensure that the crate is always built with nightly-2023-01-12.my_efi_app/src/main.rs
. Comments in the code explain each part:#![no_std] // Indicates to the Rust compiler that the app does not depend on the standard library but is a 'standalone' application.
#![no_main] // Indicates that this application does not have a "main" function typically found in a Linux or Windows application (although it does have its own "main" function "efi_main" as declared below)
// Externs for efi and alloc crates (alloc crate is the one that contains definitions of String and Vec etc.)
#[macro_use] extern crate efi;
extern crate alloc;
// EFI entrypoint or main function. UEFI firmware will call this function to start the application.
// The signature and the name of this function must be exactly as below.
#[no_mangle]
pub extern "win64" fn efi_main(image_handle: efi::ffi::EFI_HANDLE, sys_table : *const efi::ffi::EFI_SYSTEM_TABLE) -> isize {
efi::init_env(image_handle, sys_table); // Call to init_env must be the first thing in efi_main. Without it things like println!() won't work
println!("Welcome to UEFI");
// Your business logic here
0
}
// A handler to respond to panics in the code. Required by the Rust compiler
#[panic_handler]
fn panic(_: &core::panic::PanicInfo) -> ! {
loop {}
}
Building the application requires the target x86_64-unknown-uefi
to be installed on your machine. To install it:
my_efi_app
folder in this case)rustup target add x86_64-unknown-uefi
This must be done in the root of the crate because then the target will be installed for the Rust toolchain we specified above with the root-toolchain
file.
After the target is installed, build the application with the command cargo build --target x86_64-unknown-uefi
. When the build completes the resulting EFI application my_efi_app.efi
will be found in target\x86_64-unknown-uefi\debug\
Run the UEFI appliction in a qemu virtual machine by following the below steps:
ovmf.fd
and download that binary (This is the OVMF firmware under which we will run the application)<path where qemu is installed>/qemu-system-x86_64 -pflash <path where you downloaded ovmf.fd>/ovmf.fd -hda fat:rw:<path to your uefi application crate>/target/x86_64-unknown-uefi/debug
ovmf.fd
firmware and start the EFI shellmy_efi_app.efi
and press ENTER
For a sample application see examples/sample_efi_app.rs
. Build it by running cargo build --target x86_64-unknown-uefi --example sample_efi_app
. The resulting binary sample_efi_app.efi
will be found in target/x86_64-unknown-uefi/debug/examples
.
The application performs DHCP at the start to obtain an IP address and then makes an HTTP request to a specified server. So to run it you need to follow the below steps:
<path where qemu is installed>/qemu-system-x86_64 -pflash <path where you downloaded ovmf.fd>/ovmf.fd -hda fat:rw:<path to your uefi application crate>/target/x86_64-unknown-uefi/debug/examples -net tap,ifname=<name of your TAP adapter> -net nic
. With the two -net
options at the end this commandline tells qemu to use the TAP adapter you installed above. Ensure that the name you specify after ifname=
is that of the TAP adapter which you noted above.The application will start, perform DHCP, get an IP address, prompt you for the name of an HTTP server and then make a GET request to that server.