在Windows内核启动过程中,ACPI驱动的初始化是一个关键环节。让我们深入分析ACPI!ACPIDispatchAddDevice函数的首次调用场景,此时系统中尚未建立\Driver\ACPI对应的设备对象。
从调试器输出的调用栈可以看出完整的执行路径:
code复制00 ACPI!ACPIDispatchAddDevice
01 nt!PpvUtilCallAddDevice
02 nt!PipCallDriverAddDevice
03 nt!PiProcessAddBootDevices
04 nt!PipDeviceActionWorker
05 nt!PipRequestDeviceAction
06 nt!PipAddDevicesToBootDriverWorker
07 nt!PipApplyFunctionToServiceInstances
08 nt!PipAddDevicesToBootDriver
09 nt!IopInitializeBootDrivers
0a nt!IoInitSystem
0b nt!Phase1Initialization
0c nt!PspSystemThreadStartup
0d nt!KiThreadStartup
这个调用链展示了Windows内核如何初始化启动驱动程序的过程。特别值得注意的是PipAddDevicesToBootDriver函数,它负责为启动驱动程序创建设备对象。
在分析函数执行前,我们先查看相关数据结构:
cpp复制typedef struct _DEVICE_EXTENSION {
ULONG64 Flags;
union {
// 各种设备扩展类型
};
ULONG Signature;
ULONG DebugFlags;
PIRP_DISPATCH_TABLE DispatchTable;
// ...其他字段...
PDEVICE_OBJECT DeviceObject;
PDEVICE_OBJECT TargetDeviceObject;
PDEVICE_OBJECT PhysicalDeviceObject;
// ...更多字段...
} DEVICE_EXTENSION, *PDEVICE_EXTENSION;
当ACPIDispatchAddDevice首次被调用时,调试信息显示:
code复制DriverObject = 0x89db5530 Driver "\Driver\ACPI"
PhysicalDeviceObject = 0x89db5cb8 Device for "\Driver\ACPI_HAL"
此时!drvobj 89db5530命令显示ACPI驱动对象下还没有任何设备对象:
code复制Device Object list:
[空]
函数首先调用IoCreateDevice创建新的设备对象:
cpp复制status = IoCreateDevice(
DriverObject,
0, // DeviceExtensionSize
NULL, // DeviceName
0x32, // DeviceType
0, // DeviceCharacteristics
FALSE, // Exclusive
&newDeviceObject
);
创建成功后,设备对象的状态如下:
code复制+0x008 DriverObject : 0x89db5530 _DRIVER_OBJECT
+0x00c NextDevice : (null)
+0x010 AttachedDevice : (null)
+0x02c DeviceType : 0x32
函数随后初始化设备扩展:
cpp复制deviceExtension->DeviceObject = newDeviceObject;
deviceExtension->PhysicalDeviceObject = PhysicalDeviceObject;
deviceExtension->TargetDeviceObject = tempDeviceObject;
关键字段设置:
code复制[+0x130] DeviceObject : 0x89db4020
[+0x134] TargetDeviceObject : 0x89db5cb8
[+0x138] PhysicalDeviceObject : 0x89db5cb8
函数为设备生成标识信息:
cpp复制deviceID = ExAllocatePoolWithTag(NonPagedPool, 14, ACPI_STRING_POOLTAG);
strcpy(deviceID, "ACPI\\PNP0C08");
instanceID = ExAllocatePoolWithTag(NonPagedPool, 11, ACPI_STRING_POOLTAG);
strcpy(instanceID, "0x5F534750");
这些ID最终存储在设备扩展中:
code复制[+0x10c] DeviceID : 0x89db9460 "ACPI\PNP0C08"
[+0x110] InstanceID : 0x89df9488 "0x5F534750"
函数调用IoAttachDeviceToDeviceStack将新设备附加到设备栈:
cpp复制tempDeviceObject = IoAttachDeviceToDeviceStack(
newDeviceObject,
PhysicalDeviceObject
);
附加后的设备关系:
code复制上层设备(ACPI): 0x89db4020
AttachedDevice -> 下层设备(ACPI_HAL): 0x89db5cb8
函数设置全局根设备扩展指针:
cpp复制RootDeviceExtension = deviceExtension;
验证设置:
code复制1: kd> x acpi!RootDeviceExtension
f743b710 ACPI!RootDeviceExtension = 0x89db4ea0
在设备初始化过程中,系统发送了IRP_MJ_PNP请求:
code复制[IRP_MJ_PNP(1b), IRP_MN_QUERY_INTERFACE(8)]
这个IRP的调用栈如下:
code复制00 ACPI!ACPIRootIrpQueryInterface
01 ACPI!ACPIDispatchIrp
02 nt!IofCallDriver
03 ACPI!ACPIGetRegisterInterfaces
04 ACPI!ACPIDispatchAddDevice
...
ACPI驱动使用分发表处理IRP:
cpp复制if (minorFunction == IRP_MN_START_DEVICE) {
dispatch = dispatchTable->PnpStartDevice;
} else if (minorFunction < (ACPIDispatchPnpTableSize-1)) {
dispatch = dispatchTable->Pnp[minorFunction];
}
分发表结构:
code复制[+0x000] CreateClose : 0xf740354e
[+0x004] DeviceControl : 0xf7429a84
[+0x008] PnpStartDevice : 0xf744f3ea
[+0x00c] Pnp : 0xf745b000
[+0x010] Power : 0xf7438168
[+0x014] SystemControl : 0xf741300c
[+0x018] Other : 0xf7403358
在ACPIDispatchAddDevice首次调用时,系统处于特殊状态:
正确的初始化顺序至关重要:
错误的顺序可能导致系统崩溃或设备无法正常工作。
在分配设备ID和实例ID时:
cpp复制deviceID = ExAllocatePoolWithTag(NonPagedPool, 14, ACPI_STRING_POOLTAG);
if (deviceID == NULL) {
status = STATUS_INSUFFICIENT_RESOURCES;
goto ACPIDispatchAddDeviceExit;
}
必须检查分配是否成功,失败时要妥善清理已分配资源。
在分析ACPI驱动时,这些断点非常有用:
code复制bp ACPI!ACPIDispatchAddDevice
bp ACPI!ACPIDispatchIrp
可以通过修改ACPI调试掩码获取更多信息:
code复制ed nt!Kd_ACPI_Mask ffffffff
这些命令有助于理解设备关系:
code复制!drvobj <驱动对象地址>
!devobj <设备对象地址>
!irp <IRP地址>
可以考虑预分配常用字符串,避免在每次调用时都进行内存分配。
对于频繁调用的IRP类型,可以优化分发逻辑,减少不必要的判断。
根据字段访问频率重新排列设备扩展结构,提高缓存命中率。
需要注意不同Windows版本中ACPI驱动的实现可能有差异,特别是在以下方面:
ACPI驱动需要处理不同硬件平台的特性,特别是在以下方面:
所有从用户模式传入的参数必须严格验证,特别是:
确保:
通过分析ACPIDispatchAddDevice的首次调用过程,我们深入理解了Windows ACPI驱动的初始化机制。在实际开发中,建议:
掌握这些ACPI驱动的内部机制,对于开发高质量的内核模式驱动和调试复杂的系统问题都有极大帮助。