在Windows内核启动过程中,ACPI驱动负责枚举和管理所有基于ACPI规范的硬件设备。当系统执行ACPIRootIrpQueryBusRelations函数时,会触发完整的设备检测流程。这个函数的核心作用是查询总线关系(Bus Relations),即确定当前总线层级下存在的所有设备。
从调试器输出的调用栈可以看出完整的设备枚举流程:
code复制00 ACPI!ACPIDetectPdoDevices
01 ACPI!ACPIRootIrpQueryBusRelations
02 ACPI!ACPIRootIrpQueryDeviceRelations
03 ACPI!ACPIDispatchIrp
04 nt!IofCallDriver
...
0b nt!IopInitializeBootDrivers
0c nt!IoInitSystem
这个调用链揭示了几个关键点:
物理设备对象(PDO)是Windows设备栈的基础元素。在ACPI场景下,每个检测到的ACPI设备都会创建一个对应的PDO。从调试信息可见,本次枚举过程共创建了6个PDO:
code复制Device Object list:
89906258 899875e0 899c1cc0 899c5f18
899ae8b8 89981b98
这些PDO通过设备扩展(Device Extension)存储设备特定信息。以第一个PDO(89906258)为例,其设备扩展结构如下:
code复制+0x000 Flags : 0x0058a000`00360020
+0x010 DispatchTable : 0xf74382ac IRP_DISPATCH_TABLE
+0x130 DeviceObject : 0x89906258 _DEVICE_OBJECT
+0x138 PhysicalDeviceObject : 0x89906258 _DEVICE_OBJECT
+0x10c DeviceID : 0x89907188 "ACPI\FixedButton"
ACPIDetectPdoDevices是实际执行设备检测的核心函数。从反汇编代码可以看到关键执行点:
code复制ACPI!ACPIDetectPdoDevices+0x122:
f7400300 85c0 test eax,eax
这个测试指令通常在检查函数返回值时使用,表明此处可能在进行错误检查或状态判断。根据SRV03RTM版本的源代码路径(base\busdrv\acpi\driver\nt\detect.c),我们可以推断其基本逻辑:
从调试信息可见,创建的PDO设备ID遵循特定格式:
code复制ACPI\FixedButton
这是典型的ACPI设备ID格式,由三部分组成:
在设备对象目录中,这些设备还会被分配数字编号:
code复制89906258 Device 00000034
899875e0 Device 00000033
...
899c5f18 Device 00000031
这些编号由PnP管理器按枚举顺序分配,用于内部设备管理。
ACPI驱动的设备扩展(_Device_Extension)是一个联合体结构,根据设备类型不同会使用不同的子结构。关键字段包括:
code复制+0x000 Flags : 设备状态标志
+0x010 DispatchTable : IRP处理函数表
+0x058 WorkQueue : 工作队列相关结构
+0x10c DeviceID : 设备硬件ID
+0x130 DeviceObject : 指向关联的设备对象
+0x138 PhysicalDeviceObject : 物理设备对象指针
+0x13c ParentExtension : 父设备扩展
调试信息中显示的FixedButton设备是一个特殊案例:
code复制DeviceID: "ACPI\FixedButton"
Characteristics: 0x80 (FILE_AUTOGENERATED_DEVICE_NAME)
这表明:
在设备扩展中,Button相关字段会被初始化:
code复制+0x058 Button : BUTTON_EXTENSION
这个扩展结构存储按钮设备的特定信息,如触发类型、状态等。
ACPI驱动通过_LIST_ENTRY结构维护设备关系:
code复制+0x140 ChildDeviceList : 子设备链表
+0x148 SiblingDeviceList : 兄弟设备链表
+0x150 EjectDeviceHead : 可弹出设备链表头
这些链表在ACPIDetectPdoDevices执行过程中被填充。从调试信息可见:
code复制ChildDeviceList: [ 0x89906fe0 - 0x89906fe0 ] // 空链表
SiblingDeviceList: [ 0x89981b58 - 0x89906150 ] // 有有效节点
ACPI设备枚举遵循以下步骤:
显示设备对象:
code复制!devobj <address>
查看驱动对象:
code复制!drvobj <address>
列出设备目录:
code复制!object \device
查看设备扩展:
code复制dt acpi!_Device_Extension <address>
问题1:设备未正确枚举
问题2:PDO创建失败
问题3:设备关系不正确
在实际开发中,我们发现ACPI设备枚举耗时主要来自:
通过以下方法可显著提升性能: