Geoff Chappell, Software Analyst
The HAL_DISPATCH structure is a table of pointers to optional HAL functionality. The kernel keeps the one instance of this table. It’s in the kernel’s read-write data section and its address is exported as HalDispatchTable. The table initially has the kernel’s built-in implementations of most (but not all) functions. Many are trivial. Some are substantial. The HAL overrides some. No known HAL overrides all. Functionality that has no meaning to a particular HAL is left to the kernel’s default (and HAL programmers are spared from writing even dummy code for nothing that matters to them). Moreover, since the address is exported, rather than communicated specifically to the HAL, it seems to have been intended all along that the functionality is exposed to other kernel-mode modules such as drivers not only for them to call but also to override further.
Neither the HAL_DISPATCH nor the HalDispatchTable are formally documented, but they have always been semi-documented: a C-language definition appears in every NTDDK.H even from as far back as the Device Driver Kit (DDK) for Windows NT 3.51. In each DDK or Windows Driver Kit (WDK), the definition is true for the Windows version that the kit is released for, but with no explicit indication that the definition might not be correct for other versions. This would be unremarkable if the history were just of extending the structure and incrementing the Version member at the very beginning. Instead, members have been added, or their types changed, without increasing the Version. One change of Version removes a member, thus shifting all subsequent ones. That said, since then, meaning Windows 7, the structure has not changed up to and including Windows 10, and may now be stable.
Microsoft’s C-language definitions don’t list what to expect as the Version member for each Windows version or what to expect in the structure for any given Version. The following table shows what correspondence is known from inspection:
Version | Windows Versions | Size (x86) | Size (x64) |
---|---|---|---|
1 | 3.51 | 0x28 | |
4.0 | 0x34 | ||
2 | 5.0 | 0x44 | |
3 | 5.1 to 6.0 | 0x58 | 0xB0 |
4 | 6.1 and higher | 0x5C | 0xB8 |
These sizes in the preceding table, and the offsets, types and names in the table that follows, are from Microsoft’s C-language definitions, checked against (some) inspection of what the kernel actually does have as its HalDispatchTable. It is left as understood that x64 offsets are meaningful only for those versions that have x64 builds, i.e., 5.2 from Windows Server 2003 SP1, and higher.
Offset (x86) | Offset (x64) | Definition | Versions | Remarks |
---|---|---|---|---|
0x00 | 0x00 |
ULONG Version; |
3.51 and higher | |
0x04 | 0x08 |
NTSTATUS (*HalQuerySystemInformation) ( HAL_QUERY_INFORMATION_CLASS, ULONG, PVOID, ULONG *); |
3.51 and higher | |
0x08 | 0x10 |
NTSTATUS (*HalSetSystemInformation) ( HAL_SET_INFORMATION_CLASS, ULONG, PVOID); |
3.51 and higher | |
0x0C |
NTSTATUS (*HalQueryBusSlots) ( INTERFACE_TYPE, ULONG, ULONG, ULONG *, ULONG *); |
3.51 only | ||
0x18 |
NTSTATUS (*HalQueryBusSlots) ( BUS_HANDLER *, ULONG, ULONG *, ULONG *); |
4.0 and higher | ||
0x10 |
NTSTATUS (*HalSlotControl) ( INTERFACE_TYPE, ULONG, ULONG, DEVICE_OBJECT *, ULONG, PVOID, ULONG *, PVOID, PSLOT_CONTROL_COMPLETION); |
3.51 only | ||
NTSTATUS (*HalDeviceControl) ( DEVICE_HANDLER_OBJECT *, DEVICE_OBJECT *, ULONG, PVOID, ULONG *, PVOID, PDEVICE_CONTROL_COMPLETION); |
4.0 only | |||
0x20 |
ULONG Spare1; |
5.0 and higher | ||
0x14 | 0x28 |
VOID (FASTCALL *HalExamineMBR) ( DEVICE_OBJECT *, ULONG, ULONG, PVOID *); |
3.51 and higher | |
0x18 | 0x30 |
VOID (FASTCALL *HalIoAssignDriverLetters) ( LOADER_PARAMETER_BLOCK *, STRING *, UCHAR *, STRING *); |
3.51 to 6.0 | |
0x1C (before 6.1) 0x18 |
0x38 (before 6.1) 0x30 |
NTSTATUS (FASTCALL *HalIoReadPartitionTable) ( DEVICE_OBJECT *, ULONG, BOOLEAN, DRIVE_LAYOUT_INFORMATION **); |
3.51 and higher | |
0x20 (before 6.1) 0x1C |
0x40 (before 6.1) 0x38 |
NTSTATUS (FASTCALL *HalIoSetPartitionInformation) ( DEVICE_OBJECT *, ULONG, ULONG, ULONG); |
3.51 and higher | |
0x24 (before 6.1) 0x20 |
0x48 (before 6.1) 0x40 |
NTSTATUS (FASTCALL *HalIoWritePartitionTable) ( DEVICE_OBJECT *, ULONG, ULONG, ULONG, DRIVE_LAYOUT_INFORMATION *); |
3.51 and higher | |
0x28 (before 6.1) 0x24 |
0x50 (before 6.1) 0x48 |
BUS_HANDLER * (FASTCALL *HalReferenceHandlerForBus) ( INTERFACE_TYPE, ULONG); |
4.0 and higher | |
0x2C (before 6.1) 0x28 |
0x58 (before 6.1) 0x50 |
VOID (FASTCALL *HalReferenceBusHandler) ( BUS_HANDLER *); |
4.0 and higher | |
0x30 (before 6.1) 0x2C |
0x60 (before 6.1) 0x58 |
VOID (FASTCALL *HalDereferenceBusHandler) ( BUS_HANDLER *); |
4.0 and higher | |
0x34 (before 6.1) 0x30 |
0x68 (before 6.1) 0x60 |
NTSTATUS (*HalInitPnpDriver) ( VOID); |
5.0 and higher | |
0x38 (before 6.1) 0x34 |
0x70 (before 6.1) 0x68 |
NTSTATUS (*HalInitPowerManagement) ( PM_DISPATCH_TABLE *, PM_DISPATCH_TABLE *); |
5.0 and higher | |
0x3C (before 6.1) 0x38 |
0x78 (before 6.1) 0x70 |
DMA_ADAPTER * (*HalGetDmaAdapter) ( PVOID, DEVICE_DESCRIPTION *, ULONG *); |
5.0 and higher | no default |
0x40 (before 6.1) 0x3C |
0x80 (before 6.1) 0x78 |
NTSTATUS (*HalGetInterruptTranslator) ( INTERFACE_TYPE, ULONG, INTERFACE_TYPE, USHORT, USHORT, TRANSLATOR_INTERFACE *, ULONG *); |
5.0 and higher | |
0x44 (before 6.1) 0x40 |
0x88 (before 6.1) 0x80 |
NTSTATUS (*HalStartMirroring) ( VOID); |
5.1 and higher | |
0x48 (before 6.1) 0x44 |
0x90 (before 6.1) 0x88 |
NTSTATUS (*HalEndMirroring) ( ULONG); |
5.1 and higher | |
0x4C (before 6.1) 0x48 |
0x98 (before 6.1) 0x90 |
NTSTATUS (*HalMirrorPhysicalMemory) ( PHYSICAL_ADDRESS, LARGE_INTEGER); |
5.1 and higher | |
0x50 (before 6.1) 0x4C |
0xA0 (before 6.1) 0x98 |
VOID (*HalEndOfBoot) ( VOID); |
5.1 and higher | |
0x54 (before 6.1) 0x50 |
0xA8 (before 6.1) 0xA0 |
NTSTATUS (*HalMirrorVerify) ( PHYSICAL_ADDRESS, LARGE_INTEGER); |
5.1 and higher | |
0x54 | 0xA8 |
PVOID (*HalGetCachedAcpiTable) ( ULONG, PCSTR, PCSTR); |
6.1 and higher | no default |
0x58 | 0xB0 |
VOID (*HalSetPciErrorHandlerCallback) ( PCI_ERROR_HANDLER_CALLBACK); |
6.1 and higher | no default |
All non-obvious types in the preceding table are structures or enumerations except for the following function pointers:
typedef VOID (*PSLOT_CONTROL_COMPLETION) (SLOT_CONTROL_CONTEXT *); typedef VOID (*PDEVICE_CONTROL_COMPLETION) (DEVICE_CONTROL_CONTEXT *); typedef VOID (*PCI_ERROR_HANDLER_CALLBACK) (VOID);
Of course, almost all members of the HAL_DISPATCH are function pointers, but these are the ones that can be given as arguments: function pointers in function pointers get just a bit too complicated for easy presentation.