#uefi #read-write #bindings #bootloader #tcp-socket #api-bindings #os-loader

nightly no-std efi

用于编写UEFI应用程序的Rust便捷绑定

7个版本

0.3.1 2023年10月18日
0.3.0 2023年10月6日
0.2.1 2019年11月13日
0.1.3 2018年12月3日
0.1.0 2018年3月14日

124操作系统类别中

每月下载量 26次

MIT许可证

500KB
9K SLoC

efi

Crates.io

Rust编写UEFI应用程序的框架。在UEFI平台上类似Rust标准库,支持诸如

  • 控制台I/O
  • 通过自定义分配器支持容器,如 VecString
  • 宏如 println!write!format!
  • Rust I/O 原语作为 ReadWrite 特性和相关类型
  • 类似于stdlib的UDP和TCP套接字
  • IpAddr 和其支持类型的实现
  • 域名解析,以便您可以使用主机名连接套接字

还提供用于UEFI特定功能的便捷API,例如

  • 加载和启动映像
  • DHCP
  • PXE
  • 设备路径

它使用 efi_ffi 包与UEFI平台进行接口交互。

限制

  • 仍在开发中。API表面可能会随时更改。
  • 目前仅支持 x64 架构。
  • 仅测试与Rust nightly版本 nightly-2023-01-12 编译。可能无法与其他版本编译。您必须使用 rust-toolchain 文件强制使用此版本(如下文所示)

编写UEFI应用程序

要使用此框架编写UEFI应用程序,请按照以下步骤操作

  1. 通过运行 cargo new my_efi_app 创建应用程序的新crate,其中 my_efi_app 是应用程序的名称
  2. Cargo.toml 中的 [dependencies] 下添加 efi = "0.3"
  3. 在crate的根目录下添加一个名为 rust-toolchain 的文件,其中包含文本 nightly-2023-01-12。这将确保crate总是使用nightly-2023-01-12版本构建。
  4. my_efi_app/src/main.rs 中添加以下代码。代码中的注释解释了每个部分
#![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 {}
}

构建

构建应用程序需要安装目标 x86_64-unknown-uefi 到您的机器上。要安装它

  1. 在crate的根目录下打开命令行(例如,本例中为 my_efi_app 文件夹)
  2. 运行命令 rustup target add x86_64-unknown-uefi

必须在crate的根目录下执行此操作,因为这样目标将为我们上面指定的带有 root-toolchain 文件的Rust工具链安装。

目标安装完成后,使用以下命令构建应用程序 cargo build --target x86_64-unknown-uefi。构建完成后,生成的EFI应用程序 my_efi_app.efi 将位于 target\x86_64-unknown-uefi\debug\

运行

按照以下步骤在qemu虚拟机中运行UEFI应用程序

  1. 下载并安装qemu
  2. 搜索 ovmf.fd 并下载该二进制文件(这是我们将运行应用程序的OVMF固件)
  3. 通过以下命令行启动qemu:<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
  4. Qemu将启动至 ovmf.fd 固件并启动EFI外壳
  5. 等待EFI外壳命令提示符出现。当它出现时,输入应用程序的名称 my_efi_app.efi 并按 ENTER
  6. 应用程序将运行,并在qemu屏幕上打印 "Welcome to UEFI"

示例应用程序

有关示例应用程序,请参阅 examples/sample_efi_app.rs。通过运行 cargo build --target x86_64-unknown-uefi --example sample_efi_app 来构建它。生成的二进制文件 sample_efi_app.efi 将位于 target/x86_64-unknown-uefi/debug/examples

应用程序在启动时执行DHCP以获取IP地址,然后向指定的服务器发送HTTP请求。因此,要运行它,您需要按照以下步骤操作

  1. 确保您的网络中运行着一个DHCP服务器,并且能够分配IP地址。
  2. 在您将要运行应用程序的机器上,安装一个您选择的TAP适配器,并记下其名称。
  3. 将TAP适配器连接到上面提到的DHCP服务器所在的同一局域网。如果它们不在同一个局域网中,应用程序将无法接收IP地址。
  4. 使用以下命令行运行qemu: <qemu安装路径>/qemu-system-x86_64 -pflash <您下载ovmf的位置.fd>/ovmf.fd -hda fat:rw:<您的uefi应用程序crate的路径>/target/x86_64-unknown-uefi/debug/examples -net tap,ifname=<您的TAP适配器名称> -net nic。末尾的两个-net选项告诉qemu使用您之前安装的TAP适配器。请确保您在ifname=之后指定的名称与您之前记录的TAP适配器名称一致。

应用程序将启动,执行DHCP,获取IP地址,提示您输入HTTP服务器的名称,然后对该服务器发起GET请求。

依赖项

~2MB
~43K SLoC