Geoff Chappell - Software Analyst
The HAL_PRIVATE_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 HalPrivateDispatchTable. The table initially has the kernel’s built-in implementations for most (but not all) of the functions. The HAL overrides most. 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—whatever might be inferred from the word private—that the functionality is exposed to other kernel-mode modules such as drivers not only for them to call but also to override further.
Though all Windows versions since 3.51 have a HalPrivateDispatchTable in the kernel and have the HAL override at least some functions, no calling of these functions through the table is known until Windows 2000 (which suggests that more research is required on this point). In that version and since, the kernel and the HAL each call through the table, and so do other kernel-mode modules. In Windows 2000, these others are BOOTVID.DLL (which calls through the table) and PCI.SYS (which overrides functionality in the table).
Both the HAL_PRIVATE_DISPATCH structure and he HalPrivateDispatchTable variable have always been undocumented.
As with many functions, structures can be left without formal documentation but still be known a little from C-language definitions in headers that Microsoft publishes with one or another programming kit. This has happened for the HAL_PRIVATE_DISPATCH in a header named NTOSP.H in the original and Version 1511 editions of the Windows Driver Kit (WDK) for Windows 10. It comes with no conditional compilation blocks for accommodating earlier versions. It is immediately useful only for programming that targets these specific versions of Windows 10, yet doesn’t say so. Add that this header appears under a directory named “um”, surely standing for user mode, even though the definition is meaningful only in kernel mode, and one might wonder if Microsoft disclosed it by mistake.
Many undocumented structures for which Microsoft publishes no C-language definition have the practical equivalent disclosed as type information in the public symbol files that Microsoft distributes to help with debugging. When this article was first prepared in 2016, the HAL_PRIVATE_DISPATCH did not yet have type information in any of Microsoft’s published symbol files for any known Windows version. How it happens that type information for the HAL_PRIVATE_DISPATCH turns up in public symbol files for the kernel in the 1803 release of Windows 10, having escaped such disclosure for most of two decades, I do not yet know, but published it is—and this has continued at least to the 2004 release.
In the other direction, time-wise, type information turns out to have been available from as long ago as Windows Vista—just not in symbol files but instead in a statically linked library, named CLFSMGMT.LIB, which Microsoft distributes with the Software Development Kit (SDK) for user-mode programming. How it has type information for something at the lowest levels of kernel-mode programming is that the library’s few intended object files are compiled with a pre-compiled header that is itself built from a source file such that an object file was produced as output and then got archived into the library. Do this with a pre-compiled header that you throw everything but the kitchen sink into and you risk publishing a library that contains type information for everything but the kitchen sink. Surely an oversight, but published it is.
Also likely as a disclosure by mistake is that where the NTDDK.H file, back as far as the Device Driver Kit (DDK) for Windows 2000, defines types for function pointers in the HAL_DISPATCH structure, it has others that can only be for function pointers in the otherwise unmentioned HAL_PRIVATE_DISPATCH. Thus, for instance, the Windows 2000 DDK defines pHalTranslateBusAddress and the Windows XP DDK defines pKdSetupPciDeviceForDebugging, yet uses them nowhere. They are instead the types for the HalPciTranslateBusAddress and KdSetupPciDeviceForDebugging members of the HAL_PRIVATE_DISPATCH. The information that’s disclosed this way is nowhere near complete and is sometimes fleeting: though the two preceding examples survive into the WDK for Windows 10, the pHalGetVectorInput type disappears betwen the WDKs for Windows Vista and Windows 7. Still, combined with symbols for the implementations in the kernel, the HAL and elsewhere, these type definitions have long sufficed for reverse engineers to make relatively easy and confident work of reconstructing what must be a close approximation to Microsoft’s own (evolving) definition of HAL_PRIVATE_DISPATCH. The structure may not have been defined in public until recently, but it has certainly not been unknown to those who fiddle around in the bowels of kernel-mode Windows. It’s not impossible that some have even used the information constructively (and, sadly, otherwise) in real-world kernel-mode code.
Part of knowing HAL_PRIVATE_DISPATCH, especially if imagining that you actually do have good cause to contemplate real-world use of it, is to appreciate how susceptible is its layout to change from one build of Windows to another. Being touched by many hands—not just shared between the kernel and HAL but also with bus drivers and others—it is far more stable than is any structure that’s internal to one module. Indeed, of all kernel-mode structures that are both long-lived and undocumented, the HAL_PRIVATE_DISPATCH has some of the best backwards compatibility. Yet it does change, including in ways that break the backwards compatibility.
If only so that the kernel and HAL can check that they agree on their expectations of the HAL_PRIVATE_DISPATCH, the very first member is a Version number. From the definition in the WDK for Windows 10, one might get the impression that the HAL_PRIVATE_DISPATCH structure accumulated functions in lock step with an increasing Version number, but this would be to misread what Microsoft has disclosed. A comment that “changes to this interface need to be backward-compatible” looks, with access to the historical record, to have been added as a warning, or even as admonishment, after the desired backward-compability had been broken more than a few times. Comments pick up the increasing Version only at 14, by when the changes were indeed more orderly.
The earliest history is a special shambles. Through the first three Windows versions that have the structure, the Version stayed at 1 while functions were not just added but redefined. During the life of the second Version, a function was inserted, thus changing the offsets of others. No third or fourth Version is observed in any formal release, but although Version 5 does extend the structure just by adding members, Version 6 not only adds but redefines, and additions for Version 7 get shifted by later insertions.
The definition in NTOSP.H breaks the member list into blocks for successive Version numbers, but only starting with 14. Whether this is for a late build of version 6.1 or, perhaps more likely, for pre-release development of version 6.2, it does mark the onset of stability. Offsets become reliable because the structure grows only by adding at its end, and functions that fall out of use are not removed but are instead changed to placeholders. Even so, functions do change type and no trace of this remains in Microsoft’s header to alert (even Microsoft’s own) programmers to the variability. Indeed, since functions continue to change type between releases of Windows 10, the header’s comment that “changes to this interface need to be backward-compatible” evidently isn’t heeded.
The following table summarises the correspondence between the Version member and the Windows version, as known from formal releases, giving in each case the size of the structure as a rough guide to its growth. Note that by far the most substantial growth was for Windows 8.
Version | Windows Versions | Size (x86) | Size (x64) |
---|---|---|---|
1 | 3.51 to 4.0 | 0x1C | |
5.0 | 0x30 | ||
2 | 5.1 | 0x4C | |
5.2 | 0x50 | 0xA0 | |
5 | early 6.0 (before SP1) | 0x6C | 0xD8 |
6 | late 6.0 (SP1) | 0x88 | 0x0110 |
7 | very late 6.0 (SP2) | 0x90 | 0x0120 |
13 | 6.1 | 0xB8 | 0x0170 |
21 | 6.2 | 0x016C | 0x02D8 |
23 | 6.3 | 0x01A8 | 0x0350 |
32 | 10.0 to 1511 | 0x01DC | 0x03B8 |
36 | 1607 | 0x01E8 | 0x03D0 |
40 | 1703 | 0x01F8 | 0x03F0 |
43 | 1709 | 0x0220 | 0x0440 |
46 | 1803 | 0x022C | 0x0458 |
48 | 1809 | 0x023C | 0x0478 |
49 | 1903 | 0x0250 | 0x04A0 |
51 | 2004 | 0x0258 | 0x04B0 |
The detailed layout below combines the “official” definitions from the NTOSP.H in early editions of the WDK for Windows 10 and the public symbol files for later releases of Windows 10 with the completely unofficial, meaning what I can add from old notes and new inspection. For no version before Windows 10 are Microsoft’s names for members known with certainty. The type of function that a member points to can often be deduced either from a known call through the pointer or from a known implementation of the function. Where the type has not changed on the way to Windows 10 I infer that the name has not changed either. Continuity of the name often seems reasonable even if the type has changed (as when arguments are added) and even if the member has moved (because of insertion or removal earlier in the structure). Still, you should understand that this attempt at conveying two decades of missing historical record cannot be perfect.
Offset (x86) | Offset (x64) | Definition | Versions | Remarks |
---|---|---|---|---|
0x00 | 0x00 |
ULONG Version; |
3.51 and higher | |
0x04 | 0x08 |
BUS_HANDLER * (FASTCALL *HalHandlerForBus) ( INTERFACE_TYPE, ULONG); |
3.51 and higher | |
0x08 | 0x10 |
BUS_HANDLER * (FASTCALL *HalHandlerForConfigSpace) ( BUS_DATA_TYPE, ULONG); |
3.51 and higher | |
0x0C |
VOID (*HalCompleteSlotControl) ( SLOT_CONTROL_CONTEXT *); |
3.51 only |
no default; name inferred from HAL symbols |
|
VOID (*HalCompleteDeviceControl) ( DEVICE_CONTROL_CONTEXT *); |
4.0 only |
no default; name inferred from HAL symbols |
||
0x18 |
VOID (*HalLocateHiberRanges) ( PVOID); |
5.0 and higher | ||
0x10 | 0x20 |
NTSTATUS (*HalRegisterBusHandler) ( INTERFACE_TYPE, BUS_DATA_TYPE, ULONG, INTERFACE_TYPE, ULONG, ULONG, PINSTALL_BUS_HANDLER, BUS_HANDLER **); |
3.51 and higher | |
0x14 | 0x28 | 3.51 and 4.0 |
no default; name and type not known |
|
VOID (*HalSetWakeEnable) ( BOOLEAN); |
5.0 and higher |
no default in 6.2 and higher | ||
0x18 |
NTSTATUS (*HalSuspendHibernateSystem) ( <unknown-arguments>); |
3.51 and 4.0 |
name inferred from kernel symbols; type not known (8 bytes of arguments) |
|
0x30 |
NTSTATUS (*HalSetWakeAlarm) ( ULONGLONG, TIME_FIELDS *); |
5.0 to 6.1 | ||
NTSTATUS (*HalSetWakeAlarm) ( ULONGLONG, ULONGLONG); |
6.2 and higher |
Offset (x86) | Offset (x64) | Definition | Versions | Remarks |
---|---|---|---|---|
0x1C | 0x38 |
BOOLEAN (*HalPciTranslateBusAddress) ( INTERFACE_TYPE, ULONG, PHYSICAL_ADDRESS, ULONG *, PHYSICAL_ADDRESS *); |
5.0 and higher | |
0x20 | 0x40 |
NTSTATUS (*HalPciAssignSlotResources) ( UNICODE_STRING *, UNICODE_STRING *, DRIVER_OBJECT *, DEVICE_OBJECT *, INTERFACE_TYPE, ULONG, ULONG, CM_RESOURCE_LIST **); |
5.0 and higher | |
0x24 | 0x48 |
VOID (*HalHaltSystem) ( VOID); |
5.0 and higher | |
0x28 | 0x50 |
BOOLEAN (*HalFindBusAddressTranslation) ( PHYSICAL_ADDRESS, ULONG *, PHYSICAL_ADDRESS *, ULONG_PTR *, BOOLEAN); |
5.0 and higher | no default |
0x2C | 0x58 |
BOOLEAN (*HalResetDisplay) ( VOID); |
5.0 and higher | no default |
Offset (x86) | Offset (x64) | Definition | Versions |
---|---|---|---|
0x30 | 0x60 |
NTSTATUS (*HalAllocateMapRegisters) ( ADAPTER_OBJECT *, ULONG, ULONG, MAP_REGISTER_ENTRY *); |
5.2 and higher |
Offset (x86) | Offset (x64) | Definition | Versions |
---|---|---|---|
0x30 (5.1) 0x34 |
0x68 |
NTSTATUS (*KdSetupPciDeviceForDebugging) ( PVOID, DEBUG_DEVICE_DESCRIPTOR *); |
5.1 and higher |
0x34 (5.1) 0x38 |
0x70 |
NTSTATUS (*KdReleasePciDeviceForDebugging) ( DEBUG_DEVICE_DESCRIPTOR *); |
5.1 and higher |
0x38 (5.1) 0x3C |
0x78 |
PVOID (*KdGetAcpiTablePhase0) ( LOADER_PARAMETER_BLOCK *, ULONG); |
5.1 and higher |
0x3C (5.1) 0x40 |
0x80 |
VOID (*KdCheckPowerButton) ( VOID); |
5.1 and higher |
0x40 (5.1) 0x44 |
0x88 |
UCHAR (*HalVectorToIDTEntry) ( ULONG); |
5.1 and higher |
0x44 (5.1) 0x48 |
0x90 |
PVOID (*KdMapPhysicalMemory64) ( PHYSICAL_ADDRESS, ULONG); |
5.1 to early 6.0 |
PVOID (*KdMapPhysicalMemory64) ( PHYSICAL_ADDRESS, ULONG, BOOLEAN); |
late 6.0 and higher | ||
0x48 (5.1) 0x4C |
0x98 |
VOID (*KdUnmapVirtualAddress) ( PVOID, ULONG); |
5.1 to early 6.0 |
VOID (*KdUnmapVirtualAddress) ( PVOID, ULONG, BOOLEAN); |
late 6.0 and higher |
Offset (x86) | Offset (x64) | Definition | Versions | Remarks |
---|---|---|---|---|
0x50 | 0xA0 |
ULONG (*KdGetPciDataByOffset) ( ULONG, ULONG, PVOID, ULONG, ULONG); |
6.0 and higher | no default |
0x54 | 0xA8 |
ULONG (*KdSetPciDataByOffset) ( ULONG, ULONG, PVOID, ULONG, ULONG); |
6.0 and higher | no default |
0x58 | 0xB0 |
ULONG (*HalGetInterruptVectorOverride) ( INTERFACE_TYPE, ULONG, ULONG, ULONG, KIRQL *, KAFFINITY *); |
6.0 and higher | |
0x5C | 0xB8 |
NTSTATUS (*HalGetVectorInputOverride) ( ULONG, KAFFINITY, ULONG *, KINTERRUPT_POLARITY *); |
6.0 only | |
NTSTATUS (*HalGetVectorInputOverride) ( ULONG, GROUP_AFFINITY *, ULONG *, KINTERRUPT_POLARITY *, INTERRUPT_REMAPPING_INFO *); |
6.1 and higher | |||
0x60 | 0xC0 |
NTSTATUS (*HalLoadMicrocode) ( PVOID); |
6.0 and higher | |
0x64 | 0xC8 |
NTSTATUS (*HalUnloadMicrocode) ( VOID); |
6.0 and higher | |
0x68 | 0xD0 |
NTSTATUS (*HalPostMicrocodeUpdate) ( VOID); |
6.0 and higher |
Offset (x86) | Offset (x64) | Definition | Versions |
---|---|---|---|
0x6C | 0xD8 |
NTSTATUS (*HalAllocateMessageTargetOverride) ( DEVICE_OBJECT *, KAFFINITY, ULONG, KINTERRUPT_MODE, BOOLEAN, ULONG *, KIRQL *, ULONG *); |
late 6.0 |
NTSTATUS (*HalAllocateMessageTargetOverride) ( DEVICE_OBJECT *, GROUP_AFFINITY *, ULONG, KINTERRUPT_MODE, BOOLEAN, ULONG *, KIRQL *, ULONG *); |
6.1 and higher | ||
0x70 | 0xE0 |
VOID (*HalFreeMessageTargetOverride) ( DEVICE_OBJECT *, ULONG, KAFFINITY); |
late 6.0 |
VOID (*HalFreeMessageTargetOverride) ( DEVICE_OBJECT *, ULONG, GROUP_AFFINITY *); |
6.1 and higher | ||
0x74 | 0xE8 |
NTSTATUS (*HalDpReplaceBegin) ( HAL_DP_REPLACE_PARAMETERS *, PVOID *); |
late 6.0 and higher |
0x78 | 0xF0 |
VOID (*HalDpReplaceTarget) ( PVOID); |
late 6.0 and higher |
0x7C | 0xF8 |
NTSTATUS (*HalDpReplaceControl) ( ULONG, PVOID); |
late 6.0 and higher |
0x80 | 0x0100 |
VOID (*HalDpReplaceEnd) ( PVOID); |
late 6.0 and higher |
0x84 | 0x0108 |
VOID (*HalPrepareForBugcheck) ( ULONG); |
late 6.0 and higher |
Offset (x86) | Offset (x64) | Definition | Versions |
---|---|---|---|
0x88 | 0x0110 |
NTSTATUS (*HalQueryWakeTime) ( ULONGLONG *); |
6.1 only |
BOOLEAN (*HalQueryWakeTime) ( ULONGLONG *, ULONGLONG *); |
6.2 and higher | ||
0x8C | 0x0118 |
VOID (*HalReportIdleStateUsage) ( UCHAR, AFFINITY_EX *); |
6.1 and higher |
0x90 | 0x0120 |
VOID (*HalTscSynchronization) ( BOOLEAN, ULONG *); |
6.1 and higher |
0x94 | 0x0128 |
NTSTATUS (*HalWheaInitProcessorGenericSection) ( WHEA_ERROR_RECORD_SECTION_DESCRIPTOR *, WHEA_PROCESSOR_GENERIC_ERROR_SECTION *); |
6.1 and higher |
0x98 | 0x0130 |
VOID (*HalStopLegacyUsbInterrupts) ( VOID); |
6.1 only |
VOID (*HalStopLegacyUsbInterrupts) ( SYSTEM_POWER_STATE); |
6.2 and higher |
Offset (x86) | Offset (x64) | Definition | Versions |
---|---|---|---|
0x88 (6.0) 0x9C |
0x0138 |
NTSTATUS (*HalReadWheaPhysicalMemory) ( PHYSICAL_ADDRESS, ULONG, PVOID); |
very late 6.0 and higher |
0x8C (6.0) 0xA0 |
0x0140 |
NTSTATUS (*HalWriteWheaPhysicalMemory) ( PHYSICAL_ADDRESS, ULONG, PVOID); |
very late 6.0 and higher |
Offset (x86) | Offset (x64) | Definition | Versions |
---|---|---|---|
0xA4 | 0x0148 |
NTSTATUS (*HalDpMaskLevelTriggeredInterrupts) ( VOID); |
6.1 and higher |
0xA8 | 0x0150 |
NTSTATUS (*HalDpUnmaskLevelTriggeredInterrupts) ( VOID); |
6.1 and higher |
0xAC | 0x0158 |
NTSTATUS (*HalDpGetInterruptReplayState) ( PVOID, PVOID *); |
6.1 and higher |
0xB0 | 0x0160 |
NTSTATUS (*HalDpReplayInterrupts) ( PVOID); |
6.1 and higher |
0xB4 | 0x0168 |
BOOLEAN (*HalQueryIoPortAccessSupported) ( VOID); |
6.1 and higher |
To go the Version member, the HAL_PRIVATE_DISPATCH was worked on very actively between Windows 7 and Windows 8. The Version is 13 for both the original Windows 7 and the first release of its only service pack, but it’s 21 for the released Windows 8. Comments in the C-language definition from NTOSP.H record the development.
The following were added for Version 14:
Offset (x86) | Offset (x64) | Definition | Versions | Remarks |
---|---|---|---|---|
0xB8 | 0x0170 |
NTSTATUS (*KdSetupIntegratedDeviceForDebugging) ( PVOID, DEBUG_DEVICE_DESCRIPTOR *); |
6.2 and higher | |
0xBC | 0x0178 |
NTSTATUS (*KdReleaseIntegratedDeviceForDebugging) ( DEBUG_DEVICE_DESCRIPTOR *); |
6.2 and higher | |
0xC0 | 0x0180 |
VOID (*HalGetEnlightenmentInformation) ( HAL_INTEL_ENLIGHTENMENT_INFORMATION *); |
6.2 and higher | conditional default |
0xC4 | 0x0188 |
PVOID (*HalAllocateEarlyPages) ( LOADER_PARAMETER_BLOCK *, ULONG, ULONG64 *, ULONG); |
6.2 and higher | no default |
0xC8 | 0x0190 |
PVOID (*HalMapEarlyPages) ( ULONG64, ULONG, ULONG); |
6.2 and higher | no default |
0xCC | 0x0198 |
ULONG (*HalGetClockOwner) ( VOID); |
6.2 only |
|
PVOID Dummy1; |
6.3 and higher | |||
0xD0 | 0x01A0 |
VOID (*HalGetClockConfiguration) ( ULONG *, ULONG *, UCHAR *); |
6.2 only |
next at 0x0170 and 0x02E0 |
PVOID Dummy2; |
6.3 and higher | |||
0xD4 | 0x01A8 |
VOID (*HalNotifyProcessorFreeze) ( BOOLEAN); |
6.2 only | |
VOID (*HalNotifyProcessorFreeze) ( BOOLEAN, BOOLEAN); |
6.3 and higher | |||
0xD8 | 0x01B0 |
NTSTATUS (*HalPrepareProcessorForIdle) ( ULONG, ULONG, ULONG); |
6.2 only |
|
NTSTATUS (*HalPrepareProcessorForIdle) ( ULONG); |
6.3 and higher | |||
0xDC | 0x01B8 |
VOID (*HalRegisterLogRoutine) ( HAL_LOG_REGISTER_CONTEXT *); |
6.2 and higher | |
0xE0 | 0x01C0 |
VOID (*HalResumeProcessorFromIdle) ( ULONG *); |
6.2 only |
|
VOID (*HalResumeProcessorFromIdle) ( VOID); |
6.3 and higher | |||
0xE4 | 0x01C8 |
PVOID Dummy; |
6.2 and higher |
What is meant by conditional about the default for HalGetEnlightenmentInformation is that the member starts as NULL in the kernel’s HalPrivateDispatchTable but the kernel may set a default while initialising.
The next set were added for Version 15:
Offset (x86) | Offset (x64) | Definition | Versions |
---|---|---|---|
0xE8 | 0x01D0 |
ULONG (*HalVectorToIDTEntryEx) ( ULONG); |
6.2 and higher |
0xEC | 0x01D8 |
NTSTATUS (*HalSecondaryInterruptQueryPrimaryInformation) ( INTERRUPT_VECTOR_DATA *, ULONG *); |
6.2 and higher |
0xF0 | 0x01E0 |
NTSTATUS (*HalMaskInterrupt) ( ULONG, ULONG); |
6.2 and higher |
0xF4 | 0x01E8 |
NTSTATUS (*HalUnmaskInterrupt) ( ULONG, ULONG); |
6.2 and higher |
0xF8 | 0x01F0 |
BOOLEAN (*HalIsInterruptTypeSecondary) ( ULONG, ULONG); |
6.2 and higher |
0xFC | 0x01F8 |
NTSTATUS (*HalAllocateGsivForSecondaryInterrupt) ( PCHAR, USHORT, ULONG *); |
6.2 and higher |
0x0100 | 0x0200 |
NTSTATUS (*HalAddInterruptRemapping) ( ULONG, ULONG, PCI_BUSMASTER_DESCRIPTOR *, UCHAR, INTERRUPT_VECTOR_DATA *, ULONG); |
6.2 and higher |
0x0104 | 0x0208 |
VOID (*HalRemoveInterruptRemapping) ( ULONG, ULONG, PCI_BUSMASTER_DESCRIPTOR *, UCHAR, INTERRUPT_VECTOR_DATA *, ULONG); |
6.2 and higher |
0x0108 | 0x0210 |
VOID (*HalSaveAndDisableHvEnlightenment) ( VOID); |
6.2 and higher |
0x010C | 0x0218 |
VOID (*HalRestoreHvEnlightenment) ( VOID); |
6.2 and higher |
Only two were added for Version 16:
Offset (x86) | Offset (x64) | Definition | Versions |
---|---|---|---|
0x0110 | 0x0220 |
VOID (*HalFlushIoBuffersExternalCache) ( MDL *, BOOLEAN); |
6.2 and higher |
0x0114 | 0x0228 |
VOID (*HalFlushExternalCache) ( BOOLEAN); |
6.2 and higher |
The advance was larger for Version 17:
Offset (x86) | Offset (x64) | Definition | Versions |
---|---|---|---|
0x0118 | 0x0230 |
NTSTATUS (*HalPciEarlyRestore) ( SYSTEM_POWER_STATE); |
6.2 and higher |
0x011C | 0x0238 |
NTSTATUS (*HalGetProcessorId) ( ULONG, ULONG *); |
6.2 and higher |
0x0120 | 0x0240 |
NTSTATUS (*HalAllocatePmcCounterSet) ( ULONG, KPROFILE_SOURCE *, ULONG, HAL_PMC_COUNTERS **); |
6.2 and higher |
0x0124 | 0x0248 |
VOID (*HalCollectPmcCounters) ( HAL_PMC_COUNTERS *, ULONG64 *); |
6.2 and higher |
0x0128 | 0x0250 |
VOID (*HalFreePmcCounterSet) ( HAL_PMC_COUNTERS *); |
6.2 and higher |
0x012C | 0x0258 |
NTSTATUS (*HalProcessorHalt) ( ULONG, PVOID, PPROCESSOR_HALT_ROUTINE); |
6.2 and higher |
0x0130 | 0x0260 |
ULONG (*HalTimerQueryCycleCounter) ( ULONGLONG *); |
6.2 and higher |
0x0134 | 0x0268 |
VOID (*HalGetNextTickDuration) ( KPRCB *, BOOLEAN, ULONG, ULONG64, ULONGLONG *); |
6.2 only |
PVOID Dummy3; |
6.3 and higher | ||
0x0138 | 0x0270 |
VOID (*HalPciMarkHiberPhase) ( VOID); |
6.2 and higher |
0x013C | 0x0278 |
NTSTATUS (*HalQueryProcessorRestartEntryPoint) ( PHYSICAL_ADDRESS *); |
6.2 and higher |
0x0140 | 0x0280 |
NTSTATUS (*HalRequestInterrupt) ( ULONG); |
6.2 and higher |
0x0144 | 0x0288 |
NTSTATUS (*HalEnumerateUnmaskedInterrupts) ( PHAL_ENUMERATE_INTERRUPT_SOURCE_CALLBACK, PVOID, HAL_UNMASKED_INTERRUPT_INFORMATION *); |
6.2 and higher |
The additions then seem to have settled as Windows 8 neared release. There are two for Version 18:
Offset (x86) | Offset (x64) | Definition | Versions |
---|---|---|---|
0x0148 | 0x0290 |
VOID (*HalFlushAndInvalidatePageExternalCache) ( PHYSICAL_ADDRESS); |
6.2 and higher |
0x014C | 0x0298 |
NTSTATUS (*KdEnumerateDebuggingDevices) ( PVOID, DEBUG_DEVICE_DESCRIPTOR *, PDEBUG_DEVICE_FOUND_FUNCTION); |
6.2 and higher |
Just one for Version 19:
Offset (x86) | Offset (x64) | Definition | Versions |
---|---|---|---|
0x0150 | 0x02A0 |
VOID (*HalFlushIoRectangleExternalCache) ( MDL *, ULONG, ULONG, ULONG, ULONG, BOOLEAN); |
6.2 and higher |
One more for Version 20:
Offset (x86) | Offset (x64) | Definition | Versions |
---|---|---|---|
0x0154 | 0x02A8 |
VOID (*HalPowerEarlyRestore) ( ULONG); |
6.2 and higher |
Microsoft’s history adds twelve for Version 21, but the original release of Windows 8 has Version 21 and adds only five:
Offset (x86) | Offset (x64) | Definition | Versions |
---|---|---|---|
0x0158 | 0x02B0 |
NTSTATUS (*HalQueryCapsuleCapabilities) ( PVOID, ULONG, ULONGLONG *, ULONG *); |
6.2 and higher |
0x015C | 0x02B8 |
NTSTATUS (*HalUpdateCapsule) ( PVOID, ULONG, PHYSICAL_ADDRESS); |
6.2 and higher |
0x0160 | 0x02C0 |
BOOLEAN (*HalPciMultiStageResumeCapable) ( VOID); |
6.2 and higher |
0x0164 | 0x02C8 |
VOID (*HalDmaFreeCrashDumpRegisters) ( ULONG); |
6.2 and higher |
0x0168 | 0x02D0 |
BOOLEAN (*HalAcpiAoacCapable) ( VOID); |
6.2 and higher |
Although the comments in the NTOSP.H definition places the following members after the “Start of version 21 functions” and before the “Start of version 22 functions”, testing for Version 21 to establish these members’ existence is unsound. Certainly there exist Windows 8 kernels that have Version 21 but do not provide their HalPrivateDispatchTable with space for the following:
Offset (x86) | Offset (x64) | Definition | Versions | Remarks |
---|---|---|---|---|
0x016C | 0x02D8 |
NTSTATUS (*HalInterruptSetDestination) ( INTERRUPT_CONNECTION_DATA *, GROUP_AFFINITY *); |
6.3 only |
|
NTSTATUS (*HalInterruptSetDestination) ( ULONG, INTERRUPT_VECTOR_DATA *, GROUP_AFFINITY *); |
10.0 to 1511 | |||
NTSTATUS (*HalInterruptSetDestination) ( INTERRUPT_VECTOR_DATA *, GROUP_AFFINITY *, ULONG *); |
1607 and higher | |||
0x0170 | 0x02E0 |
VOID (*HalGetClockConfiguration) ( HAL_CLOCK_TIMER_CONFIGURATION *); |
6.3 and higher | previously at 0xD0 and 0x01A0 |
0x0174 | 0x02E8 |
VOID (*HalClockTimerActivate) ( BOOLEAN); |
6.3 and higher | |
0x0178 | 0x02F0 |
VOID (*HalClockTimerInitialize) ( VOID); |
6.3 and higher | |
0x017C | 0x02F8 |
VOID (*HalClockTimerStop) ( VOID); |
6.3 and higher | |
0x0180 | 0x0300 |
NTSTATUS (*HalClockTimerArm) ( HAL_CLOCK_TIMER_MODE, ULONG64, ULONG64 *); |
6.3 and higher | |
0x0184 | 0x0308 |
BOOLEAN (*HalTimerOnlyClockInterruptPending) ( VOID); |
6.3 and higher |
Added for Version 22:
Offset (x86) | Offset (x64) | Definition | Versions |
---|---|---|---|
0x0188 | 0x0310 |
PVOID (*HalAcpiGetMultiNode) ( VOID); |
6.3 and higher |
0x018C | 0x0318 |
PHALREBOOTHANDLER (*HalPowerSetRebootHandler) ( PHALREBOOTHANDLER); |
6.3 and higher |
The original release of Windows 8.1 has Version 23. It got six more by then, but see that three have a change of type sooner or later:
Offset (x86) | Offset (x64) | Definition | Versions |
---|---|---|---|
0x0190 | 0x0320 |
VOID (*HalIommuRegisterDispatchTable) ( HAL_IOMMU_DISPATCH *); |
6.3 and higher |
0x0194 | 0x0328 |
NTSTATUS (*HalTimerWatchdogStart) ( VOID); |
6.3 to 1607 |
VOID (*HalTimerWatchdogStart) ( VOID); |
1703 and higher | ||
0x0198 | 0x0330 |
VOID (*HalTimerWatchdogResetCountdown) ( VOID); |
6.3 only |
VOID (*HalTimerWatchdogResetCountdown) ( LOGICAL); |
10.0 to 1607 | ||
VOID (*HalTimerWatchdogResetCountdown) ( VOID); |
1703 and higher | ||
0x019C | 0x0338 |
NTSTATUS (*HalTimerWatchdogStop) ( VOID); |
6.3 to 1607 |
VOID (*HalTimerWatchdogStop) ( VOID); |
1703 and higher | ||
0x01A0 | 0x0340 |
BOOLEAN (*HalTimerWatchdogGeneratedLastReset) ( VOID); |
6.3 and higher |
0x01A4 | 0x0348 |
NTSTATUS (*HalTimerWatchdogTriggerSystemReset) ( BOOLEAN); |
6.3 and higher |
The first release of Windows 10 has Version 32, up from 23 for Windows 8.1. Microsoft’s history records that the Version didn’t simply leap ahead, but was incremented for each new member (almost).
Added for Version 24:
Offset (x86) | Offset (x64) | Definition | Versions |
---|---|---|---|
0x01A8 | 0x0350 |
NTSTATUS (*HalInterruptVectorDataToGsiv) ( INTERRUPT_VECTOR_DATA *, ULONG *); |
10.0 and higher |
Added for Version 25:
Offset (x86) | Offset (x64) | Definition | Versions |
---|---|---|---|
0x01AC | 0x0358 |
NTSTATUS (*HalInterruptGetHighestPriorityInterrupt) ( ULONG *, BOOLEAN *); |
10.0 and higher |
Added for Version 26:
Offset (x86) | Offset (x64) | Definition | Versions |
---|---|---|---|
0x01B0 | 0x0360 |
NTSTATUS (*HalProcessorOn) ( ULONG); |
10.0 and higher |
0x01B4 | 0x0368 |
NTSTATUS (*HalProcessorOff) ( VOID); |
10.0 and higher |
Added for Version 27:
Offset (x86) | Offset (x64) | Definition | Versions |
---|---|---|---|
0x01B8 | 0x0370 |
NTSTATUS (*HalProcessorFreeze) ( VOID); |
10.0 and higher |
Added for Version 28:
Offset (x86) | Offset (x64) | Definition | Versions |
---|---|---|---|
0x01BC | 0x0378 |
NTSTATUS (*HalDmaLinkDeviceObjectByToken) ( ULONG_PTR, DEVICE_OBJECT *); |
10.0 and higher |
Added for Version 29:
Offset (x86) | Offset (x64) | Definition | Versions |
---|---|---|---|
0x01C0 | 0x0380 |
NTSTATUS (*HalDmaCheckAdapterToken) ( ULONG_PTR); |
10.0 and higher |
Added for Version 30:
Offset (x86) | Offset (x64) | Definition | Versions |
---|---|---|---|
0x01C4 | 0x0388 |
VOID (*HalPciLateRestore) ( VOID); |
10.0 to 1607 |
PVOID Dummy4; |
1703 and higher | ||
0x01C8 | 0x0390 |
NTSTATUS (*HalTimerConvertPerformanceCounterToAuxiliaryCounter) ( ULONG64, ULONG64 *, ULONG64 *); |
10.0 and higher |
0x01CC | 0x0398 |
NTSTATUS (*HalTimerConvertAuxiliaryCounterToPerformanceCounter) ( ULONG64, ULONG64 *, ULONG64 *); |
10.0 and higher |
0x01D0 | 0x03A0 |
NTSTATUS (*HalTimerQueryAuxiliaryCounterFrequency) ( ULONG64 *); |
10.0 and higher |
Added for Version 31:
Offset (x86) | Offset (x64) | Definition | Versions |
---|---|---|---|
0x01D4 | 0x03A8 |
NTSTATUS (*HalConnectThermalInterrupt) ( PKSERVICE_ROUTINE); |
10.0 and higher |
Added for Version 32:
Offset (x86) | Offset (x64) | Definition | Versions |
---|---|---|---|
0x01D8 | 0x03B0 |
BOOLEAN (*HalIsEFIRuntimeActive) ( VOID); |
10.0 and higher |
Offset (x86) | Offset (x64) | Definition | Versions |
---|---|---|---|
0x01DC | 0x03B8 |
BOOLEAN (*HalTimerQueryAndResetRtcErrors) ( BOOLEAN); |
1607 and higher |
0x01E0 | 0x03C0 |
VOID (*HalAcpiLateRestore) ( VOID); |
1607 and higher |
0x01E4 | 0x03C8 |
NTSTATUS (*KdWatchdogDelayExpiration) ( ULONG64 *); |
1607 and higher |
Offset (x86) | Offset (x64) | Definition | Versions |
---|---|---|---|
0x01E8 | 0x03D0 |
NTSTATUS (*HalGetProcessorStats) ( HAL_PROCESSOR_STAT_TYPE, ULONG, ULONG, ULONG_PTR *); |
1703 and higher |
0x01EC | 0x03D8 |
ULONG64 (*HalTimerWatchdogQueryDueTime) ( VOID); |
1703 and higher |
0x01F0 | 0x03E0 |
NTSTATUS (*HalConnectSyntheticInterrupt) ( PKSERVICE_ROUTINE); |
1703 and higher |
0x01F4 | 0x03E8 |
VOID (*HalPreprocessNmi) ( ULONG); |
1703 and higher |
Offset (x86) | Offset (x64) | Definition | Versions |
---|---|---|---|
0x01F8 | 0x03F0 |
NTSTATUS (*HalEnumerateEnvironmentVariablesWithFilter) ( ULONG, BOOLEAN (*) (GUID const *, PCWSTR), PVOID, ULONG *); |
1709 and higher |
0x01FC | 0x03F8 |
NTSTATUS (*HalCaptureLastBranchRecordStack) ( ULONG, HAL_LBR_ENTRY *, ULONG *); |
1709 and higher |
0x0200 | 0x0400 |
BOOLEAN (*HalClearLastBranchRecordStack) ( VOID); |
1709 and higher |
0x0204 | 0x0408 |
NTSTATUS (*HalConfigureLastBranchRecord) ( ULONG, ULONG); |
1709 and higher |
0x0208 | 0x0410 |
BOOLEAN (*HalGetLastBranchInformation) ( ULONG *, ULONG *); |
1709 and higher |
0x020C | 0x0418 |
VOID (*HalResumeLastBranchRecord) ( BOOLEAN); |
1709 and higher |
0x0210 | 0x0420 |
NTSTATUS (*HalStartLastBranchRecord) ( ULONG, ULONG *); |
1709 and higher |
0x0214 | 0x0428 |
NTSTATUS (*HalStopLastBranchRecord) ( ULONG); |
1709 and higher |
0x0218 | 0x0430 |
NTSTATUS (*HalIommuBlockDevice) ( PVOID); |
1709 and higher |
0x021C | 0x0438 |
NTSTATUS (*HalIommuUnblockDevice) ( EXT_IOMMU_DEVICE_ID *, PVOID *); |
1709 and higher |
Offset (x86) | Offset (x64) | Definition | Versions |
---|---|---|---|
0x0220 | 0x0440 |
NTSTATUS (*HalGetIommuInterface) ( ULONG, DMA_IOMMU_INTERFACE *); |
1803 and higher |
0x0224 | 0x0448 |
NTSTATUS (*HalRequestGenericErrorRecovery) ( PVOID, ULONG *); |
1803 and higher |
0x0228 | 0x0450 |
NTSTATUS (*HalTimerQueryHostPerformanceCounter) ( ULONG64 *); |
1803 and higher |
Offset (x86) | Offset (x64) | Definition | Versions | Remarks |
---|---|---|---|---|
0x022C | 0x0458 |
LONG (*HalTopologyQueryProcessorRelationships) ( ULONG, ULONG, UCHAR *, UCHAR *, UCHAR *, ULONG *, ULONG *); |
1809 and higher | |
0x0230 | 0x0460 |
VOID (*HalInitPlatformDebugTriggers) ( VOID); |
1809 and higher | no default |
0x0234 | 0x0468 |
VOID (*HalRunPlatformDebugTriggers) ( BOOLEAN); |
1809 and higher | no default |
0x0238 | 0x0470 |
PVOID (*HalTimerGetReferencePage) ( VOID); |
1809 and higher |
Offset (x86) | Offset (x64) | Definition | Versions | Remarks |
---|---|---|---|---|
0x023C | 0x0478 |
NTSTATUS (*HalGetHiddenProcessorPowerInterface) ( HIDDEN_PROCESSOR_POWER_INTERFACE *); |
1903 and higher | no default |
0x0240 | 0x0480 |
ULONG (*HalGetHiddenProcessorPackageId) ( ULONG); |
1903 and higher | no default |
0x0244 | 0x0488 |
ULONG (*HalGetHiddenPackageProcessorCount) ( ULONG); |
1903 and higher | no default |
0x0248 | 0x0490 |
NTSTATUS (*HalGetHiddenProcessorApicIdByIndex) ( ULONG, ULONG *); |
1903 and higher | no default |
0x024C | 0x0498 |
NTSTATUS (*HalRegisterHiddenProcessorIdleState) ( ULONG, ULONGLONG); |
1903 and higher | no default |
Offset (x86) | Offset (x64) | Definition | Versions | Remarks |
---|---|---|---|---|
0x0250 | 0x04A0 |
VOID (*HalIommuReportIommuFault) ( ULONGLONG, FAULT_INFORMATION *); |
2004 and higher | no default |
0x0254 | 0x04A8 |
BOOLEAN (*HalIommuDmaRemappingCapable) ( EXT_IOMMU_DEVICE_ID *, ULONG *); |
2004 and higher |
All non-obvious types in the preceding table are structures or enumerations except for the following function pointers (all of which are Microsoft’s type definitions from NTOSP.H):
typedef NTSTATUS (*PINSTALL_BUS_HANDLER) ( BUS_HANDLER *); typedef NTSTATUS (*PPROCESSOR_HALT_ROUTINE) ( PVOID); typedef BOOLEAN (*PHAL_ENUMERATE_INTERRUPT_SOURCE_CALLBACK) ( PVOID, HAL_UNMASKED_INTERRUPT_INFORMATION *); typedef KD_CALLBACK_ACTION (*PDEBUG_DEVICE_FOUND_FUNCTION) ( DEBUG_DEVICE_DESCRIPTOR *); typedef VOID (*PHALREBOOTHANDLER) ( ULONG, LONG volatile *); typedef BOOLEAN (*PKSERVICE_ROUTINE) ( KINTERRUPT *, PVOID);
Of course, almost all members of the HAL_PRIVATE_DISPATCH are function pointers, and Microsoft’s NTOSP.H does define 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.