Rust UEFI开发库的使用:在Rust中实现统一可扩展固件接口的嵌入式系统开发

Rust UEFI开发库的使用:在Rust中实现统一可扩展固件接口的嵌入式系统开发

uefi

统一可扩展固件接口的Rust包装器。

这个crate使得开发Rust软件变得容易,该软件利用安全方便高性能的抽象来实现UEFI功能。

Crates.io Docs.rs License Build status Stars

价值增加和使用案例

uefi支持为退出引导服务前后的时期编写代码,但其真正的优势在于创建与UEFI引导服务大量交互的UEFI映像时。尽管如此,您仍然有灵活性将选定的类型和抽象集成到您的项目中,例如解析UEFI内存映射。

请注意,为了生成UEFI映像,您还需要使用Rust的相应uefi编译器目标,例如x86_64-unknown-uefi

API和用户文档

请参考docs.rs以获取最新稳定版本的全面文档。尚未发布的最新文档可以在src/lib.rs中找到,也可以通过运行$ cargo xtask doc --open在本地查看。

有关uefi-rs项目和此存储库的介绍,请参考我们的主要README。

完整示例demo

以下是一个完整的Rust UEFI应用程序示例,演示如何使用uefi库:

//! 一个简单的UEFI应用程序示例

#![no_std]
#![no_main]
#![feature(abi_efiapi)]

use uefi::prelude::*;
use uefi::proto::console::gop::GraphicsOutput;
use uefi::table::boot::{OpenProtocolAttributes, OpenProtocolParams};

// UEFI入口点
#[entry]
fn efi_main(image: Handle, st: SystemTable<Boot>) -> Status {
    // 初始化UEFI服务
    uefi_services::init(&st).expect("Failed to initialize UEFI services");
    
    // 获取系统表
    let boot_services = st.boot_services();
    
    // 打印欢迎消息
    st.stdout()
        .output_string("Hello from Rust UEFI Application!\r\n")
        .expect("Failed to output string");
    
    // 尝试获取图形输出协议
    if let Ok(gop) = boot_services.locate_protocol::<GraphicsOutput>() {
        let gop = unsafe { &mut *gop.get() };
        
        // 设置图形模式(如果支持)
        if let Ok(modes) = gop.modes().collect::<Result<Vec<_>, _>>() {
            if !modes.is_empty() {
                // 使用第一个可用模式
                let _ = gop.set_mode(&modes[0]);
            }
        }
        
        // 清屏为蓝色
        let blue_pixel = 0xFF0000FF; // ARGB格式
        gop.clear(blue_pixel);
    }
    
    // 等待用户按键
    st.stdout()
        .output_string("Press any key to exit...\r\n")
        .expect("Failed to output string");
    
    wait_for_keypress(&st);
    
    Status::SUCCESS
}

// 等待按键函数
fn wait_for_keypress(st: &SystemTable<Boot>) {
    use uefi::proto::console::text::Input;
    
    let boot_services = st.boot_services();
    
    // 获取输入协议
    if let Ok(input) = boot_services.locate_protocol::<Input>() {
        let input = unsafe { &mut *input.get() };
        
        // 等待按键
        let mut key = uefi::proto::console::text::Key::default();
        while input.read_key(&mut key).is_err() {
            // 在等待输入时让出CPU
            boot_services.stall(10_000); // 10ms延迟
        }
    }
}

// 恐慌处理程序
#[panic_handler]
fn panic(info: &core::panic::PanicInfo) -> ! {
    if let Some(st) = uefi_services::system_table() {
        let _ = st.stdout().output_string("UEFI application panicked!\r\n");
        if let Some(location) = info.location() {
            let _ = st.stdout().output_fmt(format_args!(
                "Panic at {}:{}:{}\r\n",
                location.file(),
                location.line(),
                location.column()
            ));
        }
        if let Some(message) = info.message() {
            let _ = st.stdout().output_fmt(format_args!("Message: {}\r\n", message));
        }
    }
    
    loop {
        // 在恐慌时无限循环
        if let Some(st) = uefi_services::system_table() {
            st.boot_services().stall(10_000);
        }
    }
}

对应的Cargo.toml配置:

[package]
name = "uefi-demo"
version = "0.1.0"
edition = "2021"

[lib]
crate-type = ["cdylib"]

[dependencies]
uefi = "0.35.0"
uefi-services = "0.22"

[package.metadata.uefi]
volume-type = "fat32"  # 输出磁盘映像的文件系统类型
main = "efi_main"      # 入口点函数名

[build-dependencies]
uefi-build = "0.5.0"

构建脚本build.rs

use uefi_build::build;

fn main() {
    // 构建UEFI目标
    build::build_uefi("x86_64-unknown-uefi", "uefi-demo");
}

1 回复

Rust UEFI开发库的使用指南

介绍

Rust UEFI开发库是一个专门用于在Rust语言中实现统一可扩展固件接口(UEFI)嵌入式系统开发的工具包。该库提供了与UEFI固件交互的底层接口,支持开发UEFI应用程序、驱动程序和系统工具。通过Rust的内存安全特性和高性能,开发者可以构建可靠且高效的嵌入式系统组件。

主要特性

  • 安全的UEFI协议绑定
  • 内存管理和错误处理支持
  • 硬件抽象层(HAL)集成
  • 跨平台编译支持(x86、ARM等架构)
  • 与标准Rust工具链(如Cargo)无缝集成

安装与设置

  1. 确保已安装Rust工具链(rustc、cargo)。
  2. 添加UEFI目标支持(例如,针对x86_64架构):
    rustup target add x86_64-unknown-uefi
    
  3. 在Cargo.toml中添加依赖:
    [dependencies]
    uefi = "0.20.0"
    uefi-services = "0.20.0"
    

基本使用方法

以下是一个简单的UEFI应用程序示例,演示如何初始化和输出"Hello, UEFI!"。

示例代码

#![no_std]
#![no_main]
#![feature(abi_efiapi)]

use uefi::prelude::*;
use uefi_services::init;

#[entry]
fn main(_handle: Handle, mut system_table: SystemTable<Boot>) -> Status {
    // 初始化UEFI服务
    init(&mut system_table).unwrap();
    
    // 获取标准输出协议
    let stdout = system_table.stdout();
    
    // 输出消息
    stdout.output_string("Hello, UEFI!\n").unwrap();
    
    // 等待用户按键(可选)
    let _ = system_table.boot_services().wait_for_event(0, &[]);
    
    Status::SUCCESS
}

编译与运行

  1. 使用Cargo编译为UEFI目标:
    cargo build --target x86_64-unknown-uefi
    
  2. 将生成的EFI文件(位于target/x86_64-unknown-uefi/debug/your_app.efi)复制到UEFI可引导介质(如USB驱动器或虚拟机镜像)。
  3. 通过UEFI Shell或启动菜单运行应用程序。

完整示例代码

// 禁用标准库,因为UEFI环境没有标准库支持
#![no_std]
// 禁用主函数,使用UEFI的入口点
#![no_main]
// 启用EFI API特性
#![feature(abi_efiapi)]

// 导入UEFI预导入模块
use uefi::prelude::*;
// 导入UEFI服务初始化函数
use uefi_services::init;

// UEFI应用程序入口点
#[entry]
fn main(_handle: Handle, mut system_table: SystemTable<Boot>) -> Status {
    // 初始化UEFI服务,提供日志和panic处理
    init(&mut system_table).unwrap();
    
    // 从系统表中获取标准输出协议
    let stdout = system_table.stdout();
    
    // 使用标准输出协议输出字符串
    stdout.output_string("Hello, UEFI!\n").unwrap();
    
    // 可选:等待用户按键事件,防止程序立即退出
    let _ = system_table.boot_services().wait_for_event(0, &[]);
    
    // 返回成功状态码
    Status::SUCCESS
}

高级功能

  • 协议使用:访问UEFI协议(如文件系统、网络、图形输出)。
  • 内存管理:使用UEFI的内存分配服务。
  • 错误处理:利用Rust的Result类型处理UEFI错误。

注意事项

  • 确保目标硬件支持UEFI启动。
  • 调试可能需要QEMU等虚拟化工具。
  • 遵循UEFI规范的安全最佳实践。

通过Rust UEFI库,开发者可以高效地构建嵌入式系统组件,同时享受Rust的语言优势。

回到顶部