I386_LOADER_BLOCK

The I386_LOADER_BLOCK is a structure within the x86 and x64 builds of the LOADER_PARAMETER_BLOCK, which is in turn the structure through which the kernel and HAL learn the initialisation data that was gathered by the loader.

Layout

The I386_LOADER_BLOCK has changed just once, in the version 4.0 from Windows NT 4.0 SP3. This extended it from 0x08 to 0x0C bytes in 32-bit Windows. It is 0x10 bytes in all known versions of 64-bit Windows. Offsets, names and types in the table that follows are from type information in public symbol files for occasional Windows versions: first for Windows 2000 SP3 and SP4; next for all releases of Windows Vista and Windows 7; and starting again with the 1803 release of Windows 10. How the type information gets into symbol files for some versions but not others is not known. A C-language definition is published in a header named arc.h from editions of the Windows Driver Kit (WDK) for the original release of Windows 10 and for Version 1511.

Offset (x86) Offset (x64) Definition Versions
0x00 0x00
PVOID CommonDataArea;
all
0x04 0x08
ULONG MachineType;
all
0x08 0x0C
ULONG VirtualBias;
late 4.0 and higher

Common Data Area

The CommonDataArea is for the 32-bit kernel’s use of the Advanced BIOS (ABIOS) through the exported functions KeI386AbiosCall and KeI386GetLid. The ABIOS was a Basic I/O System (BIOS) that could operate peripheral devices from protected mode without needing a reversion to real-mode addressing.

That all the necessary details for using a computer’s hardware are built into firmware by the computer’s manufacturer would surely have seemed attractive to the manufacturer of an operating system. ABIOS support was evidently important enough that it was given its own NTSTATUS codes: eight of them, starting with STATUS_ABIOS_NOT_PRESENT (0xC000010F). That the kernel’s functions for ABIOS support never got documented may mean they were important as an internal detail to be kept just for Microsoft to use within the kernel or even for its own system-supplied drivers—but might as easily mean they were soon seen as not worth bothering with.

In some sense it no longer matters, perhaps not even as history. All ABIOS support was removed from the kernel for version 6.2. But this had been a long time coming. The loader lost its code for preparing the CommonDataArea in version 5.1. This anyway was a holdover: only one driver from Microsoft, named ABIOSDSK.SYS, is known to have used ABIOS support, and it had not survived even to version 5.0.

Machine Type

A comment in the C-language definition that Microsoft published for the first two releases of Windows 10 would have it that the MachineType is “Temporary only”. This comment is plausibly very old. The low byte of the MachineType, zero-extended to a dword, is the source of what all versions of the 32-bit kernel export as the KeI386MachineType variable, but it is very many years since either had any known usefulness to anyone. The last driver from Microsoft that is known to have used the KeI386MachineType variable is SETUPDD.SYS, and it stopped this for Windows XP. The kernel has its own use for the variable in versions 4.0 to 5.2. Further study may be justified.

Except for initialising the kernel’s KeI386MachineType, the last-known use of the MachineType is by the HAL. Up to and including Windows Vista, the HAL interprets the low byte of the MachineType as a bus type. Early versions depend on knowing this bus type for correctly initialising such vital peripherals as the Programmable Interrupt Controller (PIC), so much so that most HAL variants before Windows Vista stop Windows at startup (with the MISMATCHED_HAL bug check) if the MachineType is incompatible with whether the HAL does or does not support the Micro Channel Architecture (MCA). Aside from this particular interpretation within the HAL, most HAL variants map the undocumented MachineType to the documented INTERFACE_TYPE for the HAL’s report of resource usage, such as persists under the registry key HKEY_LOCAL_MACHINE\HARDWARE\RESOURCEMAP\Hardware Abstraction Layer:

MachineType INTERFACE_TYPE HAL Versions
MACHINE_TYPE_ISA (0) Isa (1) 3.10 to 6.0
MACHINE_TYPE_EISA (1) Eisa (2) 3.10 to 6.0
MACHINE_TYPE_MCA (2) Internal (0) 3.10 to 3.50 for some variants, e.g., HALCBUS
MicroChannel (3) 3.10 to 6.0
else PCIBus (5) 5.1 to 6.0 for some variants, e.g., HALAACPI, HALAPIC, HALMACPI, HALMPS
Internal (0) 3.10 to 6.0

Be aware, however, that some HAL variants ignore the MachineType for this purpose and instead report a hard-coded INTERFACE_TYPE. Notable examples are: Internal by HALBORG; Eisa by HALAST, HALOLI, HALSP and HALWYSE7; and MicroChannel by HALNCR. None of these particular cases are known beyond Windows XP, but their ignoring of the MachineType becomes the generality in Windows 7, both of whose HALs are hard-coded to report Isa as if the MachineType could only be zero. Windows 8 and higher have just the one HAL: it changes the hard coding to Internal, as if a valid MachineType were not provided.

Windows 8 thus formalised that the MachineType had been meaningless for years. In the reworking from NTLDR and its embedded OSLOADER to a separate BOOTMGR and WINLOAD for Windows Vista, the loader simply stopped setting the MachineType. Where Windows Vista shows Isa as the Interface Type among the Resource Lists for the HAL, as in

Windows Vista HAL mistakenly showing ISA bus in registry

it’s not that there actually is an ISA bus: it’s just that the loader left the MachineType as zero-initialised.

Even before Windows Vista, the loader had long before cut down on what it can set for the MachineType. The work of determining the machine type is done during real-mode execution by the NTLDR and is passed as input to the protected-mode OSLOADER.EXE (which is embedded in the NTLDR binary). Though the OSLOADER before Windows Vista and the HAL before Windows 7 have code that would vary their behaviour if the machine type is MCA, it’s redundant in Windows XP and higher, since the NTLDR no longer bothers with Micro Channel detection.

Virtual Bias

The VirtualBias member was added in version 4.0, apparently for Windows NT 4.0 SP3, to allow for increasing user-mode address space at the expense of kernel-mode (via the /3GB switch in the BOOT.INI configuration file). What contortions await the kernel for fitting its work into a system address space that may be only half of the usual 2GB are a long way off, but some adjustment is needed by the loader just for choosing where to place the kernel. The loader would ordinarily treat 0x80000000 as a base address for what it prepares of the system address space. The VirtualBias tells how much higher the loader chose instead.

Multi-Boot Compatibility

Appending the VirtualBias brought an under-noted side-effect. The kernels for which the VirtualBias is intended merely assume that it’s provided and is meaningful. An older NTLDR cannot have made any such provision. Before Windows NT 4.0 SP3, having NTLDR from the latest Windows installation that might be booted was desirable but not vital. The interface between the loader and kernel had not changed. The worst to expect of a mismatch was that an old loader might not detect new features that a new kernel could use. When Windows NT 4.0 SP3 extended the I386_LOADER_BLOCK, this was a breaking change of interface. For booting a new kernel, it became vital that the matching NTLDR not have been replaced by one from an earlier Windows version.

If Microsoft ever did document this—it could easily have been hard to tell at the time, let alone two decades on—then candidates in the Microsoft Knowledge Base include Dualboot of WinNT 3.51 and 4.0 Fails After SP Installation (Q149180, October 1, 1997) and the section headed Installing Windows NT 4.0 on a Windows NT 5.0 Computer in the Windows NT 4.0 Service Pack 4.0 Readme.txt File (Q194507, October 29, 1998). Both have advice that boils down to copying NTLDR from the newer operating system, an inference being that this is a restoration, the newer file having been overwritten by installing the older operating system. Both artlcles are long gone from Microsoft’s website.