LOADER_PARAMETER_EXTENSION

The LOADER_PARAMETER_EXTENSION structure is part of the mechanism through which the kernel and HAL learn the initialisation data that was gathered by the loader. It exists only as data that is pointed to from the LOADER_PARAMETER_BLOCK whose address the loader passes to the kernel for the latter’s initialisation.

Variability

The architectural point to having two structures is that the LOADER_PARAMETER_BLOCK should be relatively stable across Windows versions, which indeed it was before Windows 7, but the LOADER_PARAMETER_EXTENSION can vary significantly and often has.

This is not just theoretical. Before version 6.0, the LOADER_PARAMETER_BLOCK really did need to be stable enough that the one NTLDR in the root directory of the bootable partition might load a kernel from a different Windows version, certainly any earlier version if not also any later one. Variability between versions was more for things that the LOADER_PARAMETER_BLOCK points to from its stable offsets. The LOADER_PARAMETER_EXTENSION is one such thing. It was a far-sighted allowance. An Extension pointer seems to have been allowed for, if not formally defined, right from the start, but not until version 5.0 does the loader create a LOADER_PARAMETER_EXTENSION to point to.

Version 6.0 separated NTLDR into a boot manager, e.g., BOOTMGR, and boot loader, e.g., WINLOAD, such that the latter should always match the kernel of whatever Windows version is being booted. Since the boot loader prepares the LOADER_PARAMETER_EXTENSION, considerations for backwards compatibility have essentially disappared. Subsequent changes are not just from growth at the end: members are removed, changed and inserted without regard for continuity. Especially notable among the changes is that Windows 7 does away with the MajorVersion and MinorVersion—or, if you prefer, moves them to the LOADER_PARAMETER_BLOCK. The Size at the start of the LOADER_PARAMETER_EXTENSION is then the only means of identifying which version did the preparation.

It cannot be stressed enough that the LOADER_PARAMETER_EXTENSION, however vital as shared data between the loader, kernel and HAL, is highly variable. Though early versions change organically, i.e., by adding only to the end so that the Size at the start differentiates the layouts, they change even between builds. The structure is greatly expanded in later versions.

Version Size (x86) Size (x64)
5.0 0x28  
original 5.1 0x3C  
late 5.1 starting with SP1 0x40  
early 5.2 0x50  
late 5.2, starting with SP1 0x58 0x88
6.0 0x7C 0xB8
6.1 0xE8 0x0148
6.2 0x0870 0x0920
6.3 0x08E0 0x0988
10.0 0x0920 0x09E0
10.0 starting with Version 1511 0x0930 0x09F0

Beware that the change within version 5.1 starts with Windows XP Service Pack 1. On numerous other pages at this website, the abbreviation “late 5.1” means version 5.1 starting with Windows XP SP2. Many advances and fixes that came with the introduction of the amd64 architecture for the version 5.2 from Windows Server 2003 SP1 found their way into the roughly contemporaneous Windows XP SP2, but none affected the LOADER_PARAMETER_EXTENSION.

Layout

Until recently, Microsoft’s names for the LOADER_PARAMETER_EXTENSION members and types were known only from type information in the symbol files for occasional Windows versions: first for Windows 2000 SP3 and SP4, then for all releases of Windows Vista and Windows 7, but for none since. How the type information gets into symbol files for some versions but not others is not known. Windows 10, however, brings something new…

A header file, ARC.H, in the Windows Driver Kit (WDK) for Windows 10 supplies a C-language definition of the LOADER_PARAMETER_EXTENSION. This appears to be Microsoft’s first formal disclosure of the structure’s layout. It comes with no conditional compilation blocks for accommodating earlier versions. As supplied, it is immediately useful only for programming that targets not just Windows 10 specifically but one particular update of Windows 10, yet doesn’t say so. Add that the header is beneath a subdirectory named “um”, presumably to mean user-mode, but that the LOADER_PARAMETER_EXTENSION is long gone by the time any user-mode software gets to execute, and one might wonder if this structure’s definition was published by mistake.

Still, published it is. The following table presents the layout of the LOADER_PARAMETER_EXTENSION for the original release of Windows 10 (build 10240), as inferred from Microsoft’s header. For earlier versions, the layout is directly from type information in symbol files, if available. Names, types and offsets for other versions are something of a guess from assuming continuity except where inspection of the loader or kernel shows that members have come and gone.

Offset (x86) Offset (x64) Definition Versions Remarks
0x00 0x00
ULONG Size;
5.0 and higher  
0x04 0x04
PROFILE_PARAMETER_BLOCK Profile;
5.0 and higher  
0x14 (5.0 to 6.0) 0x14 (5.2 to 6.0)
ULONG MajorVersion;
5.0 to 6.0  
0x18 (5.0 to 6.0) 0x18 (5.2 to 6.0)
ULONG MinorVersion;
5.0 to 6.0  
0x1C (5.0 to 6.0);
0x14
0x20 (5.2 to 6.0);
0x18
PVOID EmInfFileImage;
5.0 and higher  
0x20 (5.0 to 6.0);
0x18
0x28 (5.2 to 6.0);
0x20
ULONG EmInfFileSize;
5.0 and higher  
0x24 (5.0 to 6.0);
0x1C
0x30 (5.2 to 6.0);
0x28
PVOID TriageDumpBlock;
5.0 and higher last member in 5.0
0x28 (5.1 to 6.0);
0x20 (6.1)
0x38 (5.2 to 6.0);
0x30 (6.1)
ULONG_PTR LoaderPagesSpanned;
5.1 to 6.1  
0x2C (5.1 to 6.0);
0x24 (6.1);
0x20
0x40 (5.2 to 6.0);
0x38 (6.1);
0x30
HEADLESS_LOADER_BLOCK *HeadlessLoaderBlock;
5.1 and higher  
0x30 (5.1 to 6.0);
0x28 (6.1);
0x24
0x48 (5.2 to 6.0);
0x40 (6.1);
0x38
SMBIOS_TABLE_HEADER *SMBiosEPSHeader;
5.1 and higher  
0x34 (5.1 to 6.0);
0x2C (6.1);
0x28
0x50 (5.2 to 6.0);
0x48 (6.1);
0x40
PVOID DrvDBImage;
5.1 and higher  
0x38 (5.1 to 6.0);
0x30 (6.1);
0x2C
0x58 (5.2 to 6.0);
0x50 (6.1);
0x48
ULONG DrvDBSize;
5.1 and higher last member in original 5.1
0x3C (late 5.1 to 6.0);
0x34 (6.1);
0x30
0x60 (5.2 to 6.0);
0x58 (6.1);
0x50
NETWORK_LOADER_BLOCK *NetworkLoaderBlock;
late 5.1 and higher last member in late 5.1
0x40 (5.2 to 6.0);
0x38 (6.1);
0x34
 
PUCHAR HalpIRQLToTPR;
5.2 and higher  
0x44 (5.2 to 6.0);
0x3C (6.1);
0x38
 
PUCHAR HalpVectorToIRQL;
5.2 and higher  
0x48 (5.2 to 6.0);
0x40 (6.1);
0x3C
0x68 (5.2 to 6.0);
0x60 (6.1);
0x58
LIST_ENTRY FirmwareDescriptorListHead;
5.2 and higher last member in early 5.2
0x50 (late 5.2 to 6.0);
0x48 (6.1);
0x44
0x78 (5.2 to 6.0);
0x70 (6.1);
0x68
PVOID AcpiTable;
late 5.2 and higher  
0x54 (late 5.2 to 6.0);
0x4C (6.1);
0x48
0x80 (5.2 to 6.0);
0x78 (6.1);
0x70
ULONG AcpiTableSize;
late 5.2 and higher last member in late 5.2
0x58 (6.0);
0x50 (6.1);
0x4C
0x84 (6.0);
0x7C (6.1);
0x74
/*  bit fields, see below  */
6.0 and higher  
0x5C (6.0);
0x54 (6.1);
0x50
0x88 (6.0);
0x80 (6.1);
0x78
LOADER_PERFORMANCE_DATA *LoaderPerformanceData;
6.0 and higher  
0x60 (6.0);
0x58 (6.1);
0x54
0x90 (6.0);
0x88 (6.1);
0x80
LIST_ENTRY BootApplicationPersistentData;
6.0 and higher  
0x68 (6.0);
0x60 (6.1);
0x5C
0xA0 (6.0);
0x98 (6.1);
0x90
PVOID WmdTestResult;
6.0 and higher  
0x6C (6.0);
0x64 (6.1);
0x60
0xA8 (6.0);
0xA0 (6.1);
0x98
GUID BootIdentifier;
6.0 and higher last member in 6.0
0x74 (6.1);
0x70
0xB0 (6.1);
0xA8
ULONG ResumePages;
6.1 and higher  
0x78 (6.1);
0x74
0xB8 (6.1);
0xB0
PVOID DumpHeader;
6.1 and higher  
0x7C (6.1);
0x78
0xC0 (6.1);
0xB8
PVOID BgContext;
6.1 and higher  
0x80 (6.1);
0x7C
0xC8 (6.1);
0xC0
PVOID NumaLocalityInfo;
6.1 and higher  
0x84 (6.1);
0x80
0xD0 (6.1);
0xC8
PVOID NumaGroupAssignment;
6.1 and higher  
0x88 (6.1);
0x84
0xD8 (6.1);
0xD0
LIST_ENTRY AttachedHives;
6.1 and higher  
0x90 (6.1);
0x8C
0xE8 (6.1);
0xE0
ULONG MemoryCachingRequirementsCount;
6.1 and higher  
0x94 (6.1);
0x90
0xF0 (6.1);
0xE8
PVOID MemoryCachingRequirements;
6.1 and higher  
0x98 0xF8 (6.1);
0xF0
TPM_BOOT_ENTROPY_LDR_RESULT TpmBootEntropyResult;
6.1 only  
BOOT_ENTROPY_LDR_RESULT BootEntropyResult;
6.2 and higher  
0xE0 (6.1);
0x07A8 (6.2);
0x0810
0x0140 (6.1);
0x0800 (6.2);
0x0868
ULONGLONG ProcessorCounterFrequency;
6.1 and higher last member in 6.1
0x07B0 (6.2);
0x0818
0x0808 (6.2);
0x0870
LOADER_PARAMETER_HYPERVISOR_EXTENSION HypervisorExtension;
6.2 and higher  
0x07E8 (6.2);
0x0850
0x0840 (6.2);
0x08A8
GUID HardwareConfigurationId;
6.2 and higher  
0x07F8 (6.2);
0x0860
0x0850 (6.2);
0x08B8
LIST_ENTRY HalExtensionModuleList;
6.2 and higher  
0x0800 (6.2);
0x0868
0x0860 (6.2);
0x08C8
LARGE_INTEGER SystemTime;
6.2 and higher  
0x0808 (6.2);
0x0870
0x0868 (6.2);
0x08D0
ULONGLONG TimeStampAtSystemTimeRead;
6.2 and higher  
0x0810 (6.2);
0x0878
0x0870 (6.2);
0x08D8
ULONGLONG BootFlags;
6.2 and higher  
0x0818 (6.2);
0x0880
0x0878 (6.2);
0x08E0
ULONGLONG InternalBootFlags;
6.2 and higher  
0x0820 (6.2);
0x0888
0x0880 (6.2);
0x08E8
PVOID WfsFPData;
6.2 and higher  
0x0824 (6.2);
0x088C
0x0888 (6.2);
0x08F0
ULONG WfsFPDataSize;
6.2 and higher  
0x0828 (6.2);
0x0890
0x0890 (6.2);
0x08F8
array of 6 unknown structures 6.2 only  
LOADER_BUGCHECK_PARAMETERS BugcheckParameters;
6.2 and higher  
0x08A4 0x0920
PVOID ApiSetSchema;
6.3 and higher  
0x08A8 0x0928
ULONG ApiSetSchemaSize;
6.3 and higher  
0x08AC 0x0930
LIST_ENTRY ApiSetSchemaExtensions;
6.3 and higher  
0x0858 (6.2);
0x08B4
0x08F0 (6.2);
0x0940
UNICODE_STRING AcpiBiosVersion;
6.2 and higher  
0x0860 (6.2);
0x08BC
0x0900 (6.2);
0x0950
UNICODE_STRING SmbiosVersion;
6.2 and higher  
0x0868 (6.2);
0x08C4
0x0910 (6.2);
0x0960
UNICODE_STRING EfiVersion;
6.2 and higher last member in 6.2
0x08CC 0x0970
DEBUG_DEVICE_DESCRIPTOR *KdDebugDevice;
6.3 and higher  
0x08D0 0x0978
OFFLINE_CRASHDUMP_CONFIGURATION_TABLE OfflineCrashdumpConfigurationTable;
6.3 and higher last member in 6.3
0x08F0 0x0998
UNICODE_STRING ManufacturingProfile;
10.0 and higher  
0x08F8 0x09A8
PVOID BbtBuffer;
10.0 and higher  
0x0900 0x09B0
ULONG64 XsaveAllowedFeatures;
10.0 and higher  
0x0908 0x09B8
ULONG XsaveFlags;
10.0 and higher  
0x090C 0x09C0
PVOID BootOptions;
10.0 and higher  
0x0910 0x09C8
ULONG BootId;
10.0 and higher  
0x0914 0x09D0
LOADER_PARAMETER_CI_EXTENSION *CodeIntegrityData;
10.0 and higher  
0x0918 0x09D8
ULONG CodeIntegrityDataSize;
10.0 and higher  

The C-language definition in Microsoft’s ARC.H continues with a

LOADER_HIVE_RECOVER_INFO SystemHiveRecoveryInfo; 

which would be at offsets 0x091C and 0x09E0 in the 32-bit and 64-bit builds, respectively, and bring the structure to 0x0930 and 0x09F0 bytes. The preceding table omits this member because it is not in the structure as used in the original Windows 10. It is in the Version 1511 (build 10586), but not in the original—and working out how to present developments now that Microsoft says all future Windows releases will be version 10.0 is a problem I leave for another time.

Flags

Version 6.0 introduced a single bit-wide flag, plausibly anticipating that there would soon be more.

Mask Definition Versions
0x00000001
ULONG BootViaWinload : 1;
6.0 only
ULONG LastBootSucceeded : 1;
6.1 and higher
0x00000002
ULONG LastBootShutdown : 1;
6.1 and higher
0x00000004
ULONG IoPortAccessSupported : 1;
6.1 and higher
0x00000008
ULONG BootDebuggerActive : 1;
6.2 and higher
0x00000010
ULONG StrongCodeGuarantees : 1;
10.0 and higher
0x00000020
ULONG HardStrongCodeGuarantees : 1;
10.0 and higher
0x00000040
ULONG SidSharingDisabled : 1;
10.0 and higher
0x00000080
ULONG TpmInitialized : 1;
10.0 and higher
0x00000100
ULONG VsmConfigured : 1;
10.0 and higher
0x00000200
ULONG IumEnabled : 1;
10.0 and higher
0x00000400
ULONG IsSmbboot : 1;
10.0 and higher
 
ULONG Reserved : 31;
6.0 only
ULONG Reserved : 29;
6.1 only
ULONG Reserved : 28;
6.2 to 6.3
ULONG Reserved : 21;
10.0

Which version from 6.2 to 10.0 inclusive introduced StrongCodeGuarantees and HardStrongCodeGuarantees is not known: I don’t yet know where either is used in any version.