Rust ACPI解析库acpi的使用:实现高级配置与电源管理接口的硬件信息提取和系统控制
Rust ACPI解析库acpi的使用:实现高级配置与电源管理接口的硬件信息提取和系统控制
关于acpi库
acpi是一个用纯Rust编写的库,用于解析ACPI表和AML。它被设计为可以方便地在Rust引导程序和内核中使用。该库分为三个crate:
rsdp
:解析RSDP并可以在BIOS平台上定位它。它不依赖alloc
,因此适合在没有堆分配器的引导程序中使用acpi
:解析静态表(有用但功能还不完整)。可以在有分配器的环境中使用,也可以在没有分配器的环境中使用(但功能会减少)aml
:解析AML表(可能有用,但距离功能完整还很远)
还有一个acpi-dumper
实用程序可以轻松转储平台的ACPI表(目前仅适用于Linux)。
安装
在项目目录中运行以下Cargo命令:
cargo add acpi
或者在Cargo.toml中添加以下行:
acpi = "5.2.0"
使用示例
下面是一个使用acpi库解析ACPI表的完整示例:
use acpi::{AcpiHandler, PhysicalMapping, AcpiTables};
use core::ptr::NonNull;
// 定义一个简单的AcpiHandler实现
struct MyAcpiHandler;
impl AcpiHandler for MyAcpiHandler {
// 实现将物理地址映射到虚拟地址的方法
unsafe fn map_physical_region<T>(
&self,
physical_address: usize,
size: usize,
) -> PhysicalMapping<Self, T> {
// 在实际系统中,你需要在这里实现物理地址到虚拟地址的映射
// 这里只是一个示例实现
let virtual_ptr = NonNull::new(physical_address as *mut T).unwrap();
PhysicalMapping::new(
physical_address,
virtual_ptr,
size,
size,
MyAcpiHandler,
)
}
// 实现取消映射的方法
fn unmap_physical_region<T>(_region: &PhysicalMapping<Self, T>) {
// 在实际系统中,你需要在这里取消映射
}
}
fn main() {
// 获取RSDP地址 - 在实际系统中,你需要从正确的地址获取
let rsdp_address = 0x00000000; // 替换为实际的RSDP地址
// 创建我们的AcpiHandler
let handler = MyAcpiHandler;
// 解析ACPI表
let tables = unsafe { AcpiTables::from_rsdp(handler, rsdp_address) }.unwrap();
// 获取FADT (Fixed ACPI Description Table)
let fadt = tables.fadt().unwrap();
println!("FADT: {:?}", fadt);
// 获取MADT (Multiple APIC Description Table)
if let Ok(madt) = tables.madt() {
println!("MADT: {:?}", madt);
// 遍历MADT中的条目
for entry in madt.entries {
println!("MADT Entry: {:?}", entry);
}
}
// 获取HPET (High Precision Event Timer)表
if let Ok(hpet) = tables.hpet() {
println!("HPET: {:?}", hpet);
}
}
完整示例demo
以下是一个更完整的示例,展示了如何使用acpi库来获取系统电源管理信息:
use acpi::{AcpiHandler, PhysicalMapping, AcpiTables, PlatformInfo};
use core::ptr::NonNull;
// 实现自定义的AcpiHandler
struct KernelAcpiHandler;
impl AcpiHandler for KernelAcpiHandler {
unsafe fn map_physical_region<T>(
&self,
physical_address: usize,
size: usize,
) -> PhysicalMapping<Self, T> {
// 在实际内核中,这里应该实现物理地址到虚拟地址的映射
let virtual_ptr = NonNull::new(physical_address as *mut T).unwrap();
PhysicalMapping::new(
physical_address,
virtual_ptr,
size,
size,
KernelAcpiHandler,
)
}
fn unmap_physical_region<T>(_region: &PhysicalMapping<Self, T>) {
// 在实际内核中,这里应该取消映射
}
}
fn main() -> Result<(), acpi::AcpiError> {
// 在实际系统中,应该从正确的地址获取RSDP
let rsdp_address = 0x00000000;
let handler = KernelAcpiHandler;
// 解析ACPI表
let tables = unsafe { AcpiTables::from_rsdp(handler, rsdp_address)? };
// 获取平台信息
let platform_info = tables.platform_info()?;
println!("平台中断模型: {:?}", platform_info.interrupt_model);
// 获取FADT表
let fadt = tables.fadt()?;
println!("ACPI硬件信息:");
println!(" PM定时器块: 0x{:X}", fadt.pm_timer_block);
println!(" PM1a控制块: 0x{:X}", fadt.pm1a_control_block);
println!(" PM1b控制块: 0x{:X}", fadt.pm1b_control_block);
// 获取MADT表(APIC信息)
if let Ok(madt) = tables.madt() {
println!("发现 {} 个CPU核心", madt.processor_local_apics().count());
// 遍历处理器本地APIC
for lapic in madt.processor_local_apics() {
println!("处理器ID: {}, APIC ID: {}, 启用: {}",
lapic.processor_id,
lapic.local_apic_id,
lapic.enabled
);
}
}
// 获取电源管理定时器频率
if let Some(pm_timer_freq) = fadt.pm_timer_frequency() {
println!("PM定时器频率: {}Hz", pm_timer_freq);
}
Ok(())
}
贡献
欢迎贡献!你可以:
- 编写代码 - ACPI规范非常庞大,肯定有很多我们还不支持的功能!
- 改进我们的文档!
- 在内核中使用这些crate并提交错误报告和功能请求!
许可证
该项目采用双重许可:
- Apache许可证,版本2.0
- MIT许可证
除非你明确说明,否则根据Apache-2.0许可证提交的任何贡献都将按照上述方式双重许可,无需任何附加条款或条件。
1 回复
Rust ACPI解析库acpi的使用:实现高级配置与电源管理接口的硬件信息提取和系统控制
介绍
acpi
是一个Rust库,用于解析和操作ACPI(高级配置与电源管理接口)表。ACPI是操作系统用来发现和配置计算机硬件组件、执行电源管理(如睡眠、休眠)以及监控系统状态的开放标准。
这个库提供了:
- ACPI表结构的解析
- 系统描述表(SDT)的遍历
- 电源管理功能的访问
- 硬件信息的提取
使用方法
基本设置
首先在Cargo.toml
中添加依赖:
[dependencies]
acpi = "4.0"
初始化ACPI
use acpi::{AcpiTables, PlatformInfo};
fn main() {
// 获取ACPI表
let tables = unsafe { AcpiTables::from_rsdp(rsdp_address) };
// 或者让库自动查找RSDP
let tables = unsafe { AcpiTables::search_for_rsdp_bios() }.unwrap();
}
遍历ACPI表
use acpi::AcpiTables;
fn print_acpi_tables(tables: &AcpiTables) {
for table in tables.iter() {
println!("Found ACPI table: {:?}", table.signature);
}
}
解析特定表
use acpi::{AcpiTables, sdt::Sdt};
fn parse_fadt(tables: &AcpiTables) {
if let Some(fadt) = tables.find_table::<Sdt>(b"FACP") {
println!("FADT found at: {:?}", fadt);
}
}
电源管理功能
use acpi::{AcpiTables, fadt::Fadt};
fn check_sleep_states(tables: &AcpiTables) {
if let Some(fadt) = tables.find_table::<Fadt>(b"FACP") {
println!("Supported sleep states: S1: {}, S3: {}, S4: {}, S5: {}",
fadt.s1_supported(),
fadt.s3_supported(),
fadt.s4_supported(),
fadt.s5_supported()
);
}
}
访问DSDT
use acpi::{AcpiTables, fadt::Fadt};
fn parse_dsdt(tables: &AcpiTables) {
if let Some(fadt) = tables.find_table::<Fadt>(b"FACP") {
let dsdt = tables.load_table(fadt.dsdt_address()).unwrap();
println!("DSDT: {:?}", dsdt);
}
}
完整示例:列出所有ACPI表和电源状态
use acpi::{AcpiTables, fadt::Fadt, PlatformInfo};
fn main() {
// 获取ACPI表
let tables = unsafe { AcpiTables::search_for_rsdp_bios() }.unwrap();
// 打印所有表
println!("System ACPI Tables:");
for table in tables.iter() {
println!(" - {:?}", table.signature);
}
// 检查电源状态
if let Some(fadt) = tables.find_table::<Fadt>(b"FACP") {
println!("\nSupported Power States:");
println!("S1 (CPU停止): {}", fadt.s1_supported());
println!("S2 (CPU断电): {}", fadt.s2_supported());
println!("S3 (挂起到内存): {}", fadt.s3_supported());
println!("S4 (挂起到磁盘): {}", fadt.s4_supported());
println!("S5 (软关机): {}", fadt.s5_supported());
}
}
完整示例代码
以下是一个更完整的示例,展示了如何使用acpi
库提取系统硬件信息和电源管理功能:
use acpi::{AcpiTables, fadt::Fadt, PlatformInfo};
use acpi::madt::Madt;
use acpi::hpet::Hpet;
fn main() {
// 初始化ACPI表
let tables = unsafe { AcpiTables::search_for_rsdp_bios() }
.expect("Failed to find ACPI tables");
// 1. 打印所有ACPI表
println!("Detected ACPI Tables:");
for table in tables.iter() {
println!(" - {:?} ({} bytes)", table.signature, table.length);
}
// 2. 解析FADT获取电源管理信息
if let Some(fadt) = tables.find_table::<Fadt>(b"FACP") {
println!("\nPower Management Features:");
println!("S1 Sleep Supported: {}", fadt.s1_supported());
println!("S3 Sleep (Suspend-to-RAM): {}", fadt.s3_supported());
println!("S4 Sleep (Suspend-to-Disk): {}", fadt.s4_supported());
println!("S5 Soft Off: {}", fadt.s5_supported());
println!("Lid Present: {}", fadt.lid_present());
}
// 3. 解析MADT获取CPU和中断控制器信息
if let Some(madt) = tables.find_table::<Madt>(b"APIC") {
println!("\nCPU and Interrupt Controller Information:");
println!("Local APIC Address: {:#X}", madt.local_apic_address());
println!("Processor Count: {}", madt.processor_iter().count());
println!("IOAPIC Count: {}", madt.io_apic_iter().count());
}
// 4. 解析HPET表获取高精度定时器信息
if let Some(hpet) = tables.find_table::<Hpet>(b"HPET") {
println!("\nHigh Precision Event Timer:");
println!("Base Address: {:#X}", hpet.base_address());
println!("Minimum Clock Ticks: {}", hpet.minimum_clock_ticks());
println!("Legacy Replacement: {}", hpet.legacy_replacement());
}
// 5. 加载并解析DSDT
if let Some(fadt) = tables.find_table::<Fadt>(b"FACP") {
let dsdt = tables.load_table(fadt.dsdt_address())
.expect("Failed to load DSDT");
println!("\nDSDT Table:");
println!("Length: {} bytes", dsdt.length());
// 这里可以添加更详细的DSDT解析代码
}
}
注意事项
- 这个库需要unsafe操作来访问系统ACPI表
- 使用前确保了解ACPI规范和安全影响
- 某些功能需要特定的平台支持
- 在生产环境中使用前应进行充分测试
这个库为系统级开发者提供了强大的ACPI操作能力,特别适合操作系统开发、硬件监控工具和电源管理应用。