Rust UEFI开发库uefi-raw的使用:原生支持UEFI固件开发的底层接口和功能
Rust UEFI开发库uefi-raw的使用:原生支持UEFI固件开发的底层接口和功能
uefi-raw是一个Rust crate,它包含了与UEFI规范中定义紧密匹配的原始UEFI类型。
安装
在项目目录中运行以下Cargo命令:
cargo add uefi-raw
或者在Cargo.toml中添加以下行:
uefi-raw = "0.11.0"
使用示例
以下是一个使用uefi-raw进行UEFI开发的完整示例demo:
// 引入uefi-raw库
use uefi_raw::table::boot::{BootServices, SystemTable};
use uefi_raw::proto::console::gop::GraphicsOutput;
use uefi_raw::status::Status;
// UEFI入口点函数
#[no_mangle]
pub extern "efiapi" fn efi_main(
image_handle: uefi_raw::Handle,
system_table: *mut SystemTable,
) -> Status {
// 获取引导服务
let boot_services = unsafe { &mut *((*system_table).boot_services) };
// 获取图形输出协议
let mut gop: *mut GraphicsOutput = core::ptr::null_mut();
let status = unsafe {
boot_services.locate_protocol(
&GraphicsOutput::GUID,
core::ptr::null_mut(),
&mut gop as *mut _ as *mut *mut core::ffi::c_void,
)
};
if status != Status::SUCCESS {
return status;
}
// 设置屏幕背景色为蓝色
let gop = unsafe { &mut *gop };
let mode = unsafe { &mut *gop.mode };
let mut pixel = [0, 0, 255, 0]; // 蓝色
for y in 0..mode.info().resolution().1 {
for x in 0..mode.info().resolution().0 {
unsafe {
let buffer = mode.frame_buffer().as_mut_ptr();
let pixel_size = mode.info().pixel_format().bytes_per_pixel();
let offset = (y * mode.info().stride() + x) * pixel_size;
core::ptr::copy_nonoverlapping(
pixel.as_ptr(),
buffer.add(offset as usize),
pixel_size as usize,
);
}
}
}
Status::SUCCESS
}
功能特点
- 提供与UEFI规范紧密匹配的原始类型定义
- 支持UEFI引导服务、运行时服务和协议
- 可用于开发UEFI固件和UEFI应用程序
文档
更多详细文档可以在docs.rs上查看uefi-raw文档
许可证
uefi-raw采用MIT或Apache-2.0双重许可证。
1 回复
Rust UEFI开发库uefi-raw的使用指南
概述
uefi-raw
是一个Rust库,提供了对UEFI(统一可扩展固件接口)的底层原生支持,使开发者能够在Rust中直接与UEFI固件交互。这个库特别适合需要直接访问UEFI服务和协议的系统级开发。
主要特性
- 提供对UEFI规范定义的类型、常量和函数的原始绑定
- 支持UEFI启动服务、运行时服务和协议
- 允许直接内存操作和硬件访问
- 提供UEFI环境下的基本I/O功能
使用方法
添加依赖
首先在Cargo.toml
中添加依赖:
[dependencies]
uefi-raw = "0.1"
基本示例
use uefi_raw::table::{SystemTable, Boot, Runtime};
use uefi_raw::status::Status;
use uefi_raw::proto::console::gop::GraphicsOutput;
fn main() -> Status {
// 获取UEFI系统表
let system_table = SystemTable::<Boot>::current();
// 使用控制台输出服务
let stdout = system_table.stdout();
stdout.output_string("Hello, UEFI World!\r\n").unwrap();
// 获取图形输出协议
let gop = system_table.boot_services()
.locate_protocol::<GraphicsOutput>()
.unwrap();
// 设置图形模式
gop.set_mode(0).unwrap();
Status::SUCCESS
}
完整示例代码
以下是一个完整的UEFI应用程序示例,展示了如何使用uefi-raw库的基本功能:
//! 一个完整的UEFI应用程序示例
use uefi_raw::{
table::{SystemTable, Boot},
status::Status,
proto::console::{
gop::GraphicsOutput,
text::Output,
},
event::{Event, Timer, TPL, TimerTrigger},
table::boot::MemoryType,
memory::{PhysicalAddress, VirtAddr},
};
fn main() -> Status {
// 1. 获取系统表
let system_table = SystemTable::<Boot>::current();
let boot_services = system_table.boot_services();
// 2. 使用文本输出
let stdout = system_table.stdout();
stdout.output_string("UEFI应用程序启动...\r\n").unwrap();
// 3. 获取图形输出协议
let gop = boot_services.locate_protocol::<GraphicsOutput>()
.expect("无法获取图形输出协议");
// 设置图形模式
gop.set_mode(0).expect("设置图形模式失败");
// 4. 内存管理示例
let buffer = boot_services.allocate_pool(MemoryType::LoaderData, 1024)
.expect("内存分配失败");
// 使用分配的内存...
// 释放内存
boot_services.free_pool(buffer).expect("内存释放失败");
// 5. 事件处理示例
let event = Event::new(TPL::APPLICATION)
.expect("创建事件失败");
let timer = Timer::new(&event)
.expect("创建定时器失败");
timer.set_timer(TimerTrigger::Periodic, 1_000_000)
.expect("设置定时器失败");
// 6. 直接硬件访问示例
let phys_addr = PhysicalAddress::new(0xB8000);
let virt_addr = boot_services.map_memory(phys_addr, 4096)
.expect("内存映射失败");
unsafe {
let vga_buffer = virt_addr.as_mut_ptr::<u16>();
// 在屏幕左上角显示白色'A'
*vga_buffer.offset(0) = 0x0F41;
}
// 7. 自定义协议示例
#[repr(C)]
#[derive(uefi_raw::proto::Protocol)]
#[guid = "12345678-9abc-def0-1234-56789abcdef0"]
struct MyProtocol {
version: u32,
do_work: extern "efiapi" fn(this: &MyProtocol, param: u64) -> Status,
}
extern "efiapi" fn do_work_impl(_this: &MyProtocol, param: u64) -> Status {
stdout.output_string(&format!("执行工作,参数: {}\r\n", param)).unwrap();
Status::SUCCESS
}
let my_proto = MyProtocol {
version: 1,
do_work: do_work_impl,
};
// 使用自定义协议
(my_proto.do_work)(&my_proto, 42).expect("自定义协议执行失败");
stdout.output_string("UEFI应用程序执行完成\r\n").unwrap();
Status::SUCCESS
}
编译设置
在.cargo/config.toml
中添加:
[build]
target = "x86_64-unknown-uefi"
[target.x86_64-unknown-uefi]
rustflags = [
"-C", "link-arg=-nostdlib",
"-C", "link-arg=-Wl,-dll",
"-C", "link-arg=-shared",
"-C", "link-arg=-Wl,--subsystem,efi_application",
]
注意事项
- UEFI环境有特殊的内存管理要求,避免使用标准库的内存分配
- 大多数操作需要检查返回的
Status
值 - 运行时服务在ExitBootServices()后可能不可用
- 代码通常需要编译为
efi
目标 - 需要特殊的链接器脚本和编译参数
uefi-raw
为Rust开发者提供了直接访问UEFI服务的底层接口,适合开发固件、引导加载程序和其他系统级软件。使用时需特别注意UEFI环境的特殊性和安全性要求。