ACPI 与设备树:固件接口建模
概述
Hypervisor 需要把“虚拟硬件拓扑”准确告诉 guest 内核:
- 在 x86_64 上,通常通过 ACPI 表
- 在 aarch64 上,通常通过 Device Tree(DT)
你可以把它理解为“启动时硬件说明书”。说明书不对,guest 就会出现“设备看不见、IRQ 不工作、热插拔失败”等问题。
代码定位
| 目录/文件 | 角色 |
|---|---|
vmm/src/acpi.rs | ACPI 表构建与拼装入口 |
arch/src/x86_64/ | x86_64 启动布局、ACPI 相关逻辑 |
arch/src/aarch64/ | aarch64 启动参数与 DT 相关逻辑 |
vmm/src/device_manager.rs | 设备拓扑变化触发表/树更新 |
ACPI:x86_64 的主路径
ACPI 关注三类信息:
- 资源拓扑:CPU、内存、NUMA
- 设备拓扑:PCI 总线、设备地址、热插拔槽位
- 中断与电源:IRQ 路由、电源状态模型
构建流程(概念)
热插拔关联
当 CPU/内存/PCI 设备支持热插拔时,ACPI 不仅要描述“当前状态”,还要描述“可变化能力”。
典型要求:
- 预留插槽信息
- 正确触发通知事件
- guest 侧可识别并完成驱动重探测
Device Tree:aarch64 的主路径
在 ARM 场景里,DT(FDT blob)通常描述:
- CPU 节点与拓扑
- 内存区间
- 中断控制器
- MMIO 设备与 IRQ 号
最小可用节点集合(概念)
| 节点 | 作用 |
|---|---|
/cpus | 描述 vCPU 核心信息 |
/memory | 描述可用内存区间 |
/chosen | 启动参数与内核入口上下文 |
/soc/* | 平台设备、MMIO 与 IRQ 映射 |
x86_64 与 aarch64 的实现差异
| 维度 | x86_64 | aarch64 |
|---|---|---|
| 固件描述主机制 | ACPI | Device Tree |
| 中断控制器模型 | APIC/IOAPIC | GIC |
| 启动参数注入 | ACPI 指针与引导参数 | FDT 地址传递 |
| 热插拔信息承载 | ACPI table/AML | DT 更新机制(受限) |
中断建模与设备可见性
无论 ACPI 还是 DT,最终都要回答两个问题:
- 这个设备“在哪儿”(MMIO/PCI 地址)
- 这个设备“怎么中断”(IRQ 路由)
如果任何一项错误,常见表现是:
- 设备能枚举但不工作
- 驱动 probe 失败
- 中断风暴或完全无中断
设备热插拔时的文档更新策略
建议采用“显式更新 + 事件通知”策略:
- 更新内核可见的拓扑描述
- 通知 guest 触发重探测
- 校验 guest 侧枚举结果
对于不支持动态更新的路径,明确标注“需重启生效”。
常见故障排查
1) guest 识别不到设备
- 检查 ACPI 表/DT 节点是否生成
- 检查设备地址与总线号是否冲突
- 检查驱动是否启用对应 feature
2) 中断异常
- 检查 IRQ 路由和控制器类型是否匹配
- 检查中断触发模式(电平/边沿)
- 检查 guest 内核日志中的 irq init 信息
3) 热插拔失败
- 检查是否更新了可热插拔描述
- 检查通知事件是否发出并被 guest 接收
- 检查 guest udev/驱动重探测链路
阅读顺序建议
vmm/src/acpi.rs(理解描述生成)arch/src/x86_64/(看 ACPI 接入启动流程)arch/src/aarch64/(对照 DT 模型)vmm/src/device_manager.rs(看设备变化如何反映到固件描述)
小结
ACPI/DT 是“虚拟硬件契约”。契约正确,guest 启动与设备管理才能稳定;契约错误,问题往往表现为“看似随机”的设备或中断故障。源码学习时,建议把拓扑描述与设备创建、中断注册三条线一起看。