Combining Rust std with uefi

TL;DR

In Mid-2024, we recommend to stick to our normal guide. Use this document as guide and outlook for the future of UEFI and Rust.

About

Programs created with the uefi crate are typically created with #![no_std] and #![no_main]. A #![no_std] crate can use the core and alloc parts of Rust's standard library, but not std. A #![no_main] executable does not use the standard main entry point, and must define its own entry point; uefi provides the #[entry] macro for this purpose.

Rust has added partial support for building UEFI executables without #![no_std] and #![no_main], thus, the standard way. Some functionality requires a nightly toolchain, they are gated by the uefi_std feature (Rust language feature, not uefi crate feature). Follow the tracking issue for details.

Code Example

Please refer to <repo>/uefi-std-example to see a specific example. The relevant main.rs looks as follows:

// Note: In Rust 1.82.0-nightly and before, the `uefi_std` feature is
// required for accessing `std::os::uefi::env::*`. The other default
// functionality doesn't need a nightly toolchain (with Rust 1.80 and later),
// but with that limited functionality you - currently - also can't integrate
// the `uefi` crate.
#![feature(uefi_std)]

use std::os::uefi as uefi_std;
use uefi::runtime::ResetType;
use uefi::{Handle, Status};

/// Performs the necessary setup code for the `uefi` crate.
fn setup_uefi_crate() {
    let st = uefi_std::env::system_table();
    let ih = uefi_std::env::image_handle();

    // Mandatory setup code for `uefi` crate.
    unsafe {
        uefi::table::set_system_table(st.as_ptr().cast());

        let ih = Handle::from_ptr(ih.as_ptr().cast()).unwrap();
        uefi::boot::set_image_handle(ih);
    }
}

fn main() {
    println!("Hello World from uefi_std");
    setup_uefi_crate();
    println!("UEFI-Version is {}", uefi::system::uefi_revision());
    uefi::runtime::reset(ResetType::SHUTDOWN, Status::SUCCESS, None);
}