efi

A framework for writing UEFI applications in Rust. It is intended to act like the Rust standard library on the UEFI platform with support for things like:

In addition, it offers an ergonomic API for UEFI-specific functionality such as:

Thirdly it exposes an API for doing raw FFI with the UEFI platform. It's the same FFI API that is used to implement the above functionality.

WARNING: this crate is still a work in progress and the API surface can change without notice. Currently only x64 architecture is supported

Writing a UEFI Application

To write a UEFI application using this framework follow the below steps:

  1. Install cargo-xbuild by running cargo install cargo-xbuild
  2. Switch to nightly Rust by running rustup default nightly
  3. Create a new crate for your application by running cargo new my_efi_app, where "myefiapp" is the name of the application
  4. Add efi = "0.2" under [dependencies] in Cargo.toml
  5. Add the below code in my_efi_app/src/main.rs. Comments in the code explain each part:

```rust

![no_std] // Indicates to the Rust compiler that the app does not depend on the standard library but is a 'standalone' application.

![nomain] // 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 "efimain" as declared below)

![feature(allocerrorhandler)] // Needed for the alloc error handler function declared below since this feature is unstable.

// Externs for efi and alloc crates (alloc crate is the one that contains definitions of String and Vec etc.)

[macro_use] extern crate efi;

[macro_use] 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 efimain(imagehandle: efi::ffi::EFIHANDLE, systable : *const efi::ffi::EFISYSTEMTABLE) -> isize { efi::initenv(imagehandle, systable); // Call to initenv 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 {} }

// A handler to respond to allocation failures. Required by the Rust compiler

[allocerrorhandler]

fn allocerror(: core::alloc::Layout) -> ! { loop {} } ```

  1. Build the application by running cargo xbuild --target x86_64-unknown-uefi
  2. When the build complete the resulting EFI application my_efi_app.efi will be found in target\x86_64-unknown-uefi\debug\

Load the applicationin qemu and run it via EFI shell. You will need the OVMF firmware for this. Google using ovmf in qemufor details.

Example

For a sample application see examples/sample_efi_app.rs. Build it by running cargo xbuild --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\.