Crate uefi

source ·
Expand description

Rusty wrapper for the Unified Extensible Firmware Interface.

This crate makes it easy to develop Rust software that leverages safe, convenient, and performant abstractions for UEFI functionality.

See the Rust UEFI Book for a tutorial, how-tos, and overviews of some important UEFI concepts. For more details of UEFI, see the latest UEFI Specification.

§Minimal Example

Minimal example for an UEFI application using functionality of the uefi crate:

#![no_main]
#![no_std]

use uefi::prelude::*;

#[entry]
fn main() -> Status {
    uefi::helpers::init().unwrap();

    Status::SUCCESS
}

Please find more info in our Rust UEFI Book.

§Value-add and Use Cases

uefi supports writing code for both pre- and post-exit boot services epochs, but its true strength shines when you create UEFI images that heavily interact with UEFI boot services. Still, you have the flexibility to just integrate selected types and abstractions into your project, for example to parse the UEFI memory map.

Note that for producing UEFI images, you also need to use a corresponding uefi compiler target of Rust, such as x86_64-unknown-uefi.

§Example Use Cases

This library significantly simplifies the process of creating UEFI images by abstracting away much of the UEFI API complexity and by providing convenient wrappers. When we mention UEFI images, we are talking about UEFI applications, UEFI boot service drivers, and EFI runtime service drivers, which typically have the .efi file extension. For instance, an UEFI application could be an OS-specific loader, similar to GRUB or Limine.

Additionally, you can use this crate in non-UEFI images (such as a kernel in ELF format) to perform tasks like parsing the UEFI memory map embedded in the boot information provided by a bootloader. It also enables access to UEFI runtime services from a non-UEFI image kernel.

§Supported Compiler Versions and Architectures

uefi works with stable Rust, but additional nightly-only features are gated behind the unstable Cargo feature. Please find more information about additional crate features below.

uefi is compatible with all platforms that both the Rust compiler and UEFI support, such as i686, x86_64, and aarch64. Please note that we can’t test all possible hardware/firmware/platform combinations in CI.

§MSRV

The minimum supported Rust version is currently 1.70. Our policy is to support at least the past two stable releases.

§API/User Documentation, Documentation Structure, and other Resources

Down below, you find typical technical documentation of all types, modules, and functions exported by uefi.

For a TL;DR quick start with an example on how to create your own EFI application, please check out the UEFI application template. The Rust UEFI Book is a more beginner-friendly tutorial with How-Tos, and overviews of some important UEFI concepts and the abstractions provided by this library.

For more details of UEFI itself, see the latest UEFI Specification.

§Library Structure & Tips

The top-level module contains some of the most used types and macros, including the Handle and Result types, the CStr16 and CString16 types for working with UCS-2 strings, and the entry and guid macros.

§UEFI Strings

Rust string literals are UTF-8 encoded and thus, not compatible with most UEFI interfaces. We provide CStr16 and CString16 for proper working with UCS-2 strings, including various transformation functions from standard Rust strings. You can use ctr16! to create UCS-2 string literals at compile time.

§Tables

Most UEFI functionality comes from the system, boot, and runtime tables. These can be accessed via the system, boot, and runtime modules.

§Protocols

When boot services are active, most functionality is provided via UEFI protocols. Protocols provide operations such as reading and writing files, drawing to the screen, sending and receiving network requests, and much more. The list of protocols that are actually available when running an application depends on the device. For example, a PC with no network card may not provide network protocols.

See the boot documentation for details of how to open a protocol, and see the proto module for protocol implementations. New protocols can be defined with the unsafe_protocol macro.

§Optional Cargo crate features

  • alloc: Enable functionality requiring the alloc crate from the Rust standard library. For example, methods that return a Vec rather than filling a statically-sized array. This requires a global allocator; you can use the global_allocator feature or provide your own. This is independent of internal direct usages of the UEFI boot service allocator which may happen anyway, where necessary.
  • global_allocator: Set allocator::Allocator as the global Rust allocator. This is a simple allocator that relies on the UEFI pool allocator. You can choose to provide your own allocator instead of using this feature, or no allocator at all if you don’t need to dynamically allocate any memory.
  • logger: Logging implementation for the standard log crate that prints output to the UEFI console. No buffering is done; this is not a high-performance logger.
  • panic_handler: Add a default panic handler that logs to stdout.
  • unstable: Enable functionality that depends on unstable features in the nightly compiler. As example, in conjunction with the alloc-feature, this gate allows the allocator_api on certain functions.
  • qemu: Enable some code paths to adapt their execution when executed in QEMU, such as using the special qemu-exit device when the panic handler is called.

Some of these features, such as the logger or panic_handler features, only unfold their potential when you invoke uefi::helpers::init as soon as possible in your application.

§Discuss and Contribute

For general discussions, feel free to join us in our Zulip and ask your questions there.

Further, you can submit bugs and also ask questions in our issue tracker. Contributions in the form of a PR are also highly welcome. Check our contributing guide for details.

§Comparison to other Projects in the Ecosystem

§Rust std implementation

There is an ongoing effort for a std implementation of the Rust standard library, which allows you to write UEFI programs that look very similar to normal Rust programs running on top of an OS.

It is still under development. You can track the progress in the corresponding tracking issue.

Using the std implementation simplifies the overall process of producing the binary. For example, our [#[entry]][entry-macro] macro won’t be required any longer. As the std implementation evolves over time, you’ll need fewer and fewer abstractions of this crate. For everything not covered by the std implementation, you can obtain relevant structures to work with our crate via:

  • std::os::uefi::env::boot_services()
  • std::os::uefi::env::get_system_handle()
  • std::os::uefi::env::get_system_table()

§r-efi

r-efi provides Raw UEFI bindings without high-level convenience similar to our uefi-raw crate, which is part of this project, but more feature-complete. It targets a lower-level than our uefi crate does.

§License

The code in this repository is licensed under the Mozilla Public License 2. This license allows you to use the crate in proprietary programs, but any modifications to the files must be open-sourced.

The full text of the license is available in the license file.

§Terminology

Both “EFI” and “UEFI” can be used interchangeably, such as “UEFI image” or “EFI image”. We prefer “UEFI” in our crate and its documentation.

Re-exports§

Modules§

  • This module implements Rust’s global allocator interface using UEFI’s memory allocation functions.
  • UEFI boot services.
  • Data type definitions
  • fsalloc
    A high-level file system API for UEFI applications close to the std::fs module from Rust’s standard library. The main export of this module is FileSystem.
  • This module provides miscellaneous opinionated but optional helpers to better integrate your application with the Rust runtime and the Rust ecosystem.
  • Types, functions, traits, and other helpers to work with memory in UEFI libraries and applications.
  • This module is used to simplify importing the most common UEFI types.
  • Protocol definitions.
  • UEFI runtime services.
  • Functions for accessing fields of the system table.
  • Standard UEFI tables.

Macros§

  • Encode a string literal as a &CStr8.
  • Encode a string literal as a &CStr16.
  • Create a Guid from a string at compile time.
  • Create an opaque struct suitable for use as an FFI pointer.
  • Prints to the standard output of the UEFI boot service console.
  • Prints to the standard output of the UEFI boot service console, but with a newline.

Structs§

  • An UEFI-related error with optionally additional payload data. The error kind is encoded in the status field (see Status). Additional payload may be inside the data field.
  • Globally-unique identifier.
  • UEFI uses status codes in order to report successes, errors, and warnings.

Traits§

  • Extension trait which provides some convenience methods for Result.
  • Extension trait which provides some convenience methods for Status.

Type Aliases§

  • Return type of most UEFI functions. Both success and error payloads are optional.

Attribute Macros§

  • Custom attribute for a UEFI executable entry point.