Bug Check 0x79: Mismatched HAL

The MISMATCHED_HAL bug check reports that the loader, kernel and HAL disagree about their combination.

Availability

The MISMATCHED_HAL bug check can occur in all known Windows versions, i.e., 3.10 and higher.

Documentation Status

The MISMATCHED_HAL bug check is documented, but not to cover all the known cases that are distinguished by the first bug check parameter. Known cases are 0, 1, 2, 3, 4, and 6. Documentation is known only of cases 1, 2 and 3. Case 3 fell out of use after Windows XP and was repurposed for Windows Vista. Old documentation can of course have only the old interpretation. New documentation has only the new.

Parameters

Bug Check Code: MISMATCHED_HAL (0x79)
1st Parameter: case number, see below for details
2nd Parameter: in some cases, a vital property as actually found;
otherwise depends on case
3rd Parameter: in some cases, what was expected for the property from the 2nd parameter;
otherwise depends on case
4th Parameter: 0 typically;
but depends on case

This bug check is mostly raised by the HAL but can also be raised by the kernel (up to and including version 6.2). Half a dozen different cases are indicated by the first argument. The bug check seems to have started with a consistent scheme in which the 2nd and 3rd parameters describe respectively what was found and what was expected for a property that corresponds to the 1st parameter. However, additions have not kept to the pattern, and since at least one case is interpreted very differently in different Windows versions, the cases are here taken separately.

No Parameters

A 1st parameter of zero is merely incidental, the bug check having been raised by calling the simpler KeBugCheck function rather than KeBugCheckEx:

Bug Check Code: MISMATCHED_HAL
1st Parameter: 0, apparently not intended as anything specific
2nd Parameter: 0
3rd Parameter: 0
4th Parameter: 0

The HALCBUS and HALCBUSM variants raise case 0 if they are unable to find the identifying string “Corollary” in the BIOS. These variants are not known from later than version 4.0.

In versions 4.0 to 6.2, the x86 kernel raises case 0 if ever the HAL function HalSystemVectorDispatchEntry returns anything other than 0 or 1, but no known HAL implements this function to return anything else. Indeed, only one known HAL can return anything other than 0: this is HALSP.DLL, which is last known in version 5.1.

Processor Control Block

Cases 1 and 2 are raised by the HAL. Both concern the KPRCB, which is an important kernel-mode structure on which the kernel and HAL must agree. Both these cases of the bug check are supported from the start, i.e., version 3.10, but case 2 is x86-specific.

Major Version

Bug Check Code: MISMATCHED_HAL
1st Argument 1, indicating mismatched MajorVersion in KPRCB
2nd Argument MajorVersion from KPRCB
3rd Argument 1, presumably as HAL’s expected MajorVersion
4th Argument 0

The MajorVersion is the word at offset 0x02 in the x86 KPRCB in all known Windows versions. All known HALs require it to be 1. All known kernels set it to 1, too, which means that this case of the bug check cannot occur in real-world practice. In the x64 KPRCB, the MajorVersion is deeper into the structure. It is the word at offset 0x063A up to and including the 1607 release of Windows 10 and then moves to offset 0x8A. Again, however, all known HALs require it to be 1 and all known kernels set it to 1. A mismatch can perhaps be detected if one of the kernel and HAL is more recent than the 1607 release but the other is older.

Though the KPRCB has maintained the same version number for the whole history of Windows, it has of course not kept to one layout—not even for the relatively small part of it at the front which is mostly all that is shared between the kernel and the HAL. The kernel and HAL could be seriously mismatched with very different expectations of the KPRCB and not trigger this bug check. It’s usefulness as any sort of defence is at best dubious.

Build Type

The BuildType in the KPRCB distinguishes two characteristics of how the kernel is built. The kernel can on one hand be a free build (also named retail or release) or a checked build (also named debug). This note is concerned only with free builds. The kernel can also be built with savings of space and speed for single-processor execution, else more generally for multi-processor systems. The HAL can have these same contrasting characteristics. The x86 HAL has always required some agreement. No known x64 HAL does.

Bug Check Code: MISMATCHED_HAL
1st Parameter: 2, indicating mismatched BuildType in x86 KPRCB
2nd Parameter: BuildType from KPRCB
3rd Parameter: HAL’s expected or preferred BuildType
4th Parameter: 0

The BuildType is the word at offset 0x12 in the x86 KPRCB. It has the 0x01 bit set for a checked build and the 0x02 bit set for a single-processor build. Different HAL variants, all inspected only as free builds, have different expectations of the BuildType if they are to initialise without raising this bugcheck:

BuildType Requirement HAL Variants
equals 2;
free single-processor HAL requiring free single-processor kernel;
3rd parameter is 2
HAL (version 3.10),
HAL486C (version 3.10),
HALMCA (version 3.10)
equals zero;
free multi-processor HAL requiring free multi-processor kernel;
3rd parameter is 0
HALAST,
HALCBUS,
HALCBUSM,
HALNCR (version 3.10),
HALOLI (version 3.10),
HALSP (version 3.10),
HALWYSE7
0x01 bit clear, 0x02 bit ignored;
free single-processor HAL requiring free kernel, either single-processor or multi-processor;
3rd parameter is 0
HAL,
HAL486C,
HAL98APC,
HAL98TMR,
HAL98UP,
HALAACPI,
HALACPI (before version 6.0),
HALAPIC
HALMCA
0x01 and 0x02 bits both clear;
free multi-processor HAL requiring free multi-processor kernel;
3rd parameter is 0
HAL98MP,
HALACPI (version 6.0 to 6.1),
HALBORG,
HALMACPI,
HALMPS,
HALMPSM,
HALNCR,
HALOLI,
HALSP
HALWS3

The discrepancy about testing for bit flags or comparing for particular values may tell something about the process of HAL adaptation. Early documentation, such as the Knowledge Base article Descriptions of Bug Codes for Windows NT (number 103059, apparently no longer available at Microsoft’s website), presented the build type as an enumeration with just three values:

Later documentation has four values, with interpretation in bit flags being obvious, but what does Microsoft define in the source code that is surely available to the manufacturers who pay for some sort of HAL development kit? Some HALs changed to testing for bit flags as early as version 3.50. Others never did, though none of those (which all require BuildType to equal zero) survive to version 5.0.

See that the change has a non-trivial implication. For version 3.10, every known HAL requires exact agreement: a single-processor HAL and kernel; or a multi-processor HAL and kernel; but no mixture. Version 3.50 and higher permit a relaxation: a single-processor HAL can tolerate a multi-processor kernel; but every known multi-processor x86 HAL insists on having a multi-processor kernel.

Bus Type

Before version 6.0, case 3 of the bug check indicates that the bus type as learnt from the loader is not acceptable to the x86 HAL.

Bug Check Code: MISMATCHED_HAL
1st Parameter: 3, indicating mismatched bus type
2nd Parameter: bus type from loader
3rd Parameter: HAL’s expected or preferred bus type
4th Parameter: 0

The bus type is passed from the loader to the x86 kernel and HAL as the byte at offset 0x60 in the LOADER_PARAMETER_BLOCK structure (whose address the kernel keeps in an exported variable named KeLoaderBlock). Microsoft’s assembly-language names for some possible values are known from the KS386.INC header: 

The only bus type that any known HAL cares about mismatching is the MCA. The HAL, HAL486C, HAL98TMR, HAL98UP, HALACPI, HALCBUS, HALOLI and HALSP variants all reject the MCA bus (reporting 0 for the 3rd argument), but HALCBUSM, HALMCA and HALNCR insist on it. Curiously, though HALMPS and HALMPSM differentiate themselves on the latter’s support for MCA, neither raises this bug check if loaded on a computer with the wrong bus type. None of the MCA-specific HALs survive to Windows 2000. The loader does not bother with MCA detection in Windows XP and higher.

Loader Parameter Extension

In version 6.0 only, case 3 is instead raised by the kernel to report a mismatch with the loader. The LOADER_PARAMETER_EXTENSION is a structure whose address is provided as the Extension member of the LOADER_PARAMETER_BLOCK.

Bug Check Code: MISMATCHED_HAL
1st Parameter: 3, indicating mismached LOADER_PARAMETER_EXTENSION
2nd Parameter: Size from LOADER_PARAMETER_EXTENSION
3rd Parameter: MajorVersion from LOADER_PARAMETER_EXTENSION
4th Parameter: MinorVersion from LOADER_PARAMETER_EXTENSION

The LOADER_PARAMETER_EXTENSION is shared with the HAL since at least version 5.2, such that agreement about its layout is surely good to check. The extension is deemed mismatched if:

Given that the structure’s MajorVersion and MinorVersion are Windows version numbers, checking the Size too will have looked prudent since the LOADER_PARAMETER_EXTENSION structure had changed for service packs of both versions 5.1 and 5.2, i.e., without a change of version numbers.

However prudent, it was soon superseded. The very next version makes a new bugcheck, LOADER_BLOCK_MISMATCH, for the kernel’s disagreement with the loader about either the LOADER_PARAMETER_BLOCK or LOADER_PARAMETER_EXTENSION.

Advanced Configuration and Power Interface (ACPI)

Case 4 of the bug check reports an inability to find the root of the ACPI tables. It applies only in versions 5.0 to 5.2 and only then to the HAL variants that know of ACPI version 1.0: the x86 HALAACPI, HALACPI and HALMACPI, and the x64 HAL.

Bug Check Code: MISMATCHED_HAL
1st Parameter: 4
2nd Parameter: 0xAC31
3rd Parameter: 0 or 1
4th Parameter: 0

The significance of the 2nd parameter is unknown. The 3rd parameter can be 0 or 1 in version 5.0 to differentiate two conditions:

Version 5.1 continues to check for both conditions but does not differentiate them for the 3rd parameter, which is only 0. For the second condition, version 5.1 adds the XSDT signature as acceptable and explains the bad signature by writing “Bad RSDT pointer” to the display (version 5.0 having kept it just as something to report through the kernel-mode debugger). The version 5.2 from Windows Server 2003 SP1 drops the first condition, so that although its occurrence may eventually be a problem elsewhere, it does not cause the bug check.

Advanced Programmable Interrupt Controller (APIC)

Before version 6.2, the HALAACPI, the HALMACPI and the x64 HAL must not only find the root of the ACPI tables, as above for case 4 before version 6.0, but must find specifically a Multiple APIC Description Table (with APIC as its signature). Without one, they halt the system at startup, i.e., by executing the hlt instruction, having displayed the message

HAL: No ACPI APIC Table Found

HAL: This HAL.DLL requires an MPS version 1.1 system
Replace HAL.DLL with the correct hal for this system
The system is halting

Even if these HALs find the APIC table, they raise case 6 of the MISMATCHED_HAL bug check unless the APIC table reports a PC-compatible configuration, i.e., unless the APIC table has PCAT_COMPAT bit (0x01) set in the flags at offset 0x28:

Bug Check Code: MISMATCHED_HAL
1st Parameter: 6, indicating APIC table without PC-compatible configuration
2nd Parameter: 0
3rd Parameter: 0
4th Parameter: 0