HAL_DISPATCH

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.

Documentation Status and Variability

Neither the HAL_DISPATCH nor the HalDispatchTable are formally documented. Or so I wrote in 2016. Since then Microsoft has published documentation online. What’s there today, 29th October 2022, is dated 05/31/22 in plain sight and 03/07/2022 in an HTML <meta> tag named “ms.date”. Recent or not, it’s a superb example of documentation that exists for no more reason than to allow that someone might say its subject is documented—not usefully, but documented nonetheless. It adds nothing to a comment-free C-language definition. Indeed, it starts with a comment-free C-language definition and then the remainder of this so-called documentation is just a (possibly automated) restatement in plain language. For instance, what’s expressed in C as

pHalQuerySystemInformation HalQuerySystemInformation;

is then re-expressed in English as

Defines the pHalQuerySystemInformation member HalQuerySystemInformation.

This, repeated for all the structure’s members, is the whole of the documentation. Perhaps it’s a placeholder for work in progress.

Whatever’s to be made of what a supposedly more open Microsoft now passes off as documentation, the HAL_DISPATCH and HalDispatchTable 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 the 2004 edition of 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 to 2004 0x5C 0xB8

Layout

These sizes in the preceding table, and the offsets, types and names in the table that follows, are from Microsoft’s C-language definitions in NTDDK.H, 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
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 (3.51 to 6.0) 0x30 (5.2 to 6.0)
VOID
(FASTCALL *HalIoAssignDriveLetters) (
    LOADER_PARAMETER_BLOCK *,
    STRING *,
    UCHAR *,
    STRING *);
3.51 to 6.0
0x1C (3.51 to 6.0);
0x18
0x38 (5.2 to 6.0);
0x30
NTSTATUS
(FASTCALL *HalIoReadPartitionTable) (
    DEVICE_OBJECT *,
    ULONG,
    BOOLEAN,
    DRIVE_LAYOUT_INFORMATION **);
3.51 and higher
0x20 (3.51 to 6.0);
0x1C
0x40 (5.2 to 6.0);
0x38
NTSTATUS
(FASTCALL *HalIoSetPartitionInformation) (
    DEVICE_OBJECT *,
    ULONG,
    ULONG,
    ULONG);
3.51 and higher
0x24 (3.51 to 6.0);
0x20
0x48 (5.2 to 6.0);
0x40
NTSTATUS 
(FASTCALL *HalIoWritePartitionTable) (
    DEVICE_OBJECT *,
    ULONG,
    ULONG,
    ULONG,
    DRIVE_LAYOUT_INFORMATION *);
3.51 and higher

Appended for Windows NT 4.0

Offset (x86) Offset (x64) Definition Versions
0x28 (4.0 to 6.0);
0x24
0x50 (5.2 to 6.0);
0x48
BUS_HANDLER *
(FASTCALL *HalReferenceHandlerForBus) (
    INTERFACE_TYPE,
    ULONG);
4.0 and higher
0x2C (4.0 to 6.0);
0x28
0x58 (5.2 to 6.0);
0x50
VOID
(FASTCALL *HalReferenceBusHandler) (
    BUS_HANDLER *);
4.0 and higher
0x30 (4.0 to 6.0);
0x2C
0x60 (5.2 to 6.0);
0x58
VOID
(FASTCALL *HalDereferenceBusHandler) (
    BUS_HANDLER *);
4.0 and higher

Appended for Windows 2000

Offset (x86) Offset (x64) Definition Versions Remarks
0x34 (5.0 to 6.0);
0x30
0x68 (5.2 to 6.0);
0x60
NTSTATUS
(*HalInitPnpDriver) (
    VOID);
5.0 and higher  
0x38 (5.0 to 6.0);
0x34
0x70 (5.2 to 6.0);
0x68
NTSTATUS
(*HalInitPowerManagement) (
    PM_DISPATCH_TABLE *,
    PM_DISPATCH_TABLE *);
5.0 and higher  
0x3C (5.0 to 6.0);
0x38
0x78 (5.2 to 6.0);
0x70
DMA_ADAPTER *
(*HalGetDmaAdapter) (
    PVOID,
    DEVICE_DESCRIPTION *,
    ULONG *);
5.0 and higher no default
0x40 (5.0 to 6.0);
0x3C
0x80 (5.2 to 6.0);
0x78
NTSTATUS
(*HalGetInterruptTranslator) (
    INTERFACE_TYPE,
    ULONG,
    INTERFACE_TYPE,
    USHORT,
    USHORT,
    TRANSLATOR_INTERFACE *,
    ULONG *);
5.0 and higher  

Appended for Windows XP

Offset (x86) Offset (x64) Definition Versions
0x44 (5.1 to 6.0);
0x40
0x88 (5.2 to 6.0);
0x80
NTSTATUS
(*HalStartMirroring) (
    VOID);
5.1 and higher
0x48 (5.1 to 6.0);
0x44
0x90 (5.2 to 6.0);
0x88
NTSTATUS
(*HalEndMirroring) (
    ULONG);
5.1 and higher
0x4C (5.1 to 6.0);
0x48
0x98 (5.2 to 6.0);
0x90
NTSTATUS
(*HalMirrorPhysicalMemory) (
    PHYSICAL_ADDRESS,
    LARGE_INTEGER);
5.1 and higher
0x50 (5.1 to 6.0);
0x4C
0xA0 (5.2 to 6.0);
0x98
VOID
(*HalEndOfBoot) (
    VOID);
5.1 and higher
0x54 (5.1 to 6.0);
0x50
0xA8 (5.2 to 6.0);
0xA0
NTSTATUS
(*HalMirrorVerify) (
    PHYSICAL_ADDRESS,
    LARGE_INTEGER);
5.1 and higher

Appended for Windows 7

Offset (x86) Offset (x64) Definition Versions Remarks
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

Function Pointers

All non-obvious types in the preceding tables 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, and Microsoft’s NTDDK.H defines types for them too. Those that I use here are just the ones that can be given as arguments: function pointers in function pointers get just a bit too complicated for easy presentation.