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 seems to be that the LOADER_PARAMETER_BLOCK should be relatively stable across Windows versions, which indeed it was until Windows 7, but the LOADER_PARAMETER_EXTENSION can vary significantly and often has.

It cannot be stressed enough that the LOADER_PARAMETER_EXTENSION, however vital as shared data between the loader, kernel and HAL, is highly variable. Indeed, it is greatly expanded in later versions. Importantly, the change is not just from growth at the end: members are removed, changed and inserted without regard for continuity. If only for now, I do not propose to track the variations much beyond the more or less mechanical work of reading symbol files. However, some measure of variability is readily available from the changing size of the structure. The following are known:

Version Size (x86) Size (x64)
5.0 0x28  
5.1 0x3C  
5.1 starting with SP1 0x40  
5.2 0x50  
5.2 starting with SP1 0x58  
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

Layout

Until recently, Microsoft’s names for the LOADER_PARAMETER_EXTENSION members and types were known only from the published 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. Windows 10, however, brings something new…

Windows 10

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 is included by mistake.

The following table presents the layout of the LOADER_PARAMETER_EXTENSION for the original release of Windows 10 (build 10240), using names, types and offsets from Microsoft’s header:

Offset (x86) Offset (x64) Definition
0x00 same
ULONG Size;
0x04 same
PROFILE_PARAMETER_BLOCK Profile;
0x14 0x18
PVOID EmInfFileImage;
0x18 0x20
ULONG EmInfFileSize;
0x1C 0x28
PVOID TriageDumpBlock;
0x20 0x30
HEADLESS_LOADER_BLOCK *HeadlessLoaderBlock;
0x24 0x38
SMBIOS_TABLE_HEADER *SMBiosEPSHeader;
0x28 0x40
PVOID DrvDBImage;
0x2C 0x48
ULONG DrvDBSize;
0x30 0x50
NETWORK_LOADER_BLOCK *NetworkLoaderBlock;
0x34  
PUCHAR HalpIRQLToTPR;
0x38  
PUCHAR HalpVectorToIRQL;
0x3C 0x58
LIST_ENTRY FirmwareDescriptorListHead;
0x44 0x68
PVOID AcpiTable;
0x48 0x70
ULONG AcpiTableSize;
0x4C 0x74
struct {
    ULONG LastBootSucceeded : 1;            // 0x00000001
    ULONG LastBootShutdown : 1;             // 0x00000002
    ULONG IoPortAccessSupported : 1;        // 0x00000004
    ULONG BootDebuggerActive : 1;           // 0x00000008
    ULONG StrongCodeGuarantees : 1;         // 0x00000010
    ULONG HardStrongCodeGuarantees : 1;     // 0x00000020
    ULONG SidSharingDisabled : 1;           // 0x00000040
    ULONG TpmInitialized : 1;               // 0x00000080
    ULONG VsmConfigured : 1;                // 0x00000100
    ULONG IumEnabled : 1;                   // 0x00000200
    ULONG IsSmbboot : 1;                    // 0x00000400
    ULONG Reserved : 21;
};
0x50 0x78
LOADER_PERFORMANCE_DATA *LoaderPerformanceData;
0x54 0x80
LIST_ENTRY BootApplicationPersistentData;
0x5C 0x90
PVOID WmdTestResult;
0x60 0x98
GUID BootIdentifier;
0x70 0xA8
ULONG ResumePages;
0x74 0xB0
PVOID DumpHeader;
0x78 0xB8
PVOID BgContext;
0x7C 0xC0
PVOID NumaLocalityInfo;
0x80 0xC8
PVOID NumaGroupAssignment;
0x84 0xD0
LIST_ENTRY AttachedHives;
0x8C 0xE0
ULONG MemoryCachingRequirementsCount;
0x90 0xE8
PVOID MemoryCachingRequirements;
0x98 0xF0
BOOT_ENTROPY_LDR_RESULT BootEntropyResult;
0x0810 0x0868
ULONGLONG ProcessorCounterFrequency;
0x0818 0x0870
LOADER_PARAMETER_HYPERVISOR_EXTENSION HypervisorExtension;
0x0850 0x08A8
GUID HardwareConfigurationId;
0x0860 0x08B8
LIST_ENTRY HalExtensionModuleList;
0x0868 0x08C8
LARGE_INTEGER SystemTime;
0x0870 0x08D0
ULONGLONG TimeStampAtSystemTimeRead;
0x0878 0x08D8
ULONGLONG BootFlags;
0x0880 0x08E0
ULONGLONG InternalBootFlags;
0x0888 0x08E8
PVOID WfsFPData;
0x088C 0x08F0
ULONG WfsFPDataSize;
0x0890 0x08F8
LOADER_BUGCHECK_PARAMETERS BugcheckParameters;
0x08A4 0x0920
PVOID ApiSetSchema;
0x08A8 0x0928
ULONG ApiSetSchemaSize;
0x08AC 0x0930
LIST_ENTRY ApiSetSchemaExtensions;
0x08B4 0x0940
UNICODE_STRING AcpiBiosVersion;
0x08BC 0x0950
UNICODE_STRING SmbiosVersion;
0x08C4 0x0960
UNICODE_STRING EfiVersion;
0x08CC 0x0970
DEBUG_DEVICE_DESCRIPTOR *KdDebugDevice;
0x08D0 0x0978
OFFLINE_CRASHDUMP_CONFIGURATION_TABLE OfflineCrashdumpConfigurationTable;
0x08F0 0x0998
UNICODE_STRING ManufacturingProfile;
0x08F8 0x09A8
PVOID BbtBuffer;
0x0900 0x09B0
ULONG64 XsaveAllowedFeatures;
0x0908 0x09B8
ULONG XsaveFlags;
0x090C 0x09C0
PVOID BootOptions;
0x0910 0x09C8
ULONG BootId;
0x0914 0x09D0
LOADER_PARAMETER_CI_EXTENSION *CodeIntegrityData;
0x0918 0x09D8
ULONG CodeIntegrityDataSize;

The definition in Microsoft’s header 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.

Some changes on the way to Windows 10 are known. Especially notable is the huge expansion that came when version 6.2 changed from a TPM_BOOT_ENTROPY_LDR_RESULT to a BOOT_ENTROPY_LDR_RESULT (which then changes internally for version 6.3). The three members starting with ApiSetSchema were inserted for version 6.3 (in front of the AcpiBiosVersion that was already defined for version 6.2).

History

A detailed history surely will be presented here some time, but the work has no sort of priority. Meanwhile, the following names, types and offsets are known from symbol files for Windows Vista and Windows 7. Type information for the LOADER_PARAMETER_EXTENSION is also in symbol files for Windows 2000 Service Packs 3 and 4. How the type information gets into symbol files for some versions but not others is not known.

Offset (x86) Offset (x64) Definition Versions
0x00 (6.0);
0x00
0x00 (6.0);
0x00
ULONG Size;
6.0 to 6.1
0x04 (6.0);
0x04
0x04 (6.0);
0x04
PROFILE_PARAMETER_BLOCK Profile;
6.0 to 6.1
0x14 (6.0) 0x14 (6.0)
ULONG MajorVersion;
6.0 only
0x18 (6.0) 0x18 (6.0)
ULONG MinorVersion;
6.0 only
0x1C (6.0);
0x14
0x20 (6.0);
0x18
PVOID EmInfFileImage;
6.0 to 6.1
0x20 (6.0);
0x18
0x28 (6.0);
0x20
ULONG EmInfFileSize;
6.0 to 6.1
0x24 (6.0);
0x1C
0x30 (6.0);
0x28
PVOID TriageDumpBlock;
6.0 to 6.1
0x28 (6.0);
0x20
0x38 (6.0);
0x30
ULONG_PTR LoaderPagesSpanned;
6.0 to 6.1
0x2C (6.0);
0x24
0x40 (6.0);
0x38
HEADLESS_LOADER_BLOCK *HeadlessLoaderBlock;
6.0 to 6.1
0x30 (6.0);
0x28
0x48 (6.0);
0x40
SMBIOS_TABLE_HEADER *SMBiosEPSHeader;
6.0 to 6.1
0x34 (6.0);
0x2C
0x50 (6.0);
0x48
PVOID DrvDBImage;
6.0 to 6.1
0x38 (6.0);
0x30
0x58 (6.0);
0x50
ULONG DrvDBSize;
6.0 to 6.1
0x3C (6.0);
0x34
0x60 (6.0);
0x58
NETWORK_LOADER_BLOCK *NetworkLoaderBlock;
6.0 to 6.1
0x40 (6.0);
0x38
 
PUCHAR HalpIRQLToTPR;
6.0 to 6.1
0x44 (6.0);
0x3C
 
PUCHAR HalpVectorToIRQL;
6.0 to 6.1
0x48 (6.0);
0x40
0x68 (6.0);
0x60
LIST_ENTRY FirmwareDescriptorListHead;
6.0 to 6.1
0x50 (6.0);
0x48
0x78 (6.0);
0x70
PVOID AcpiTable;
6.0 to 6.1
0x54 (6.0);
0x4C
0x80 (6.0);
0x78
ULONG AcpiTableSize;
6.0 to 6.1
0x58 (6.0);
0x50
0x84 (6.0);
0x7C
struct {
    ULONG BootViaWinload : 1;           // 0x01
    ULONG Reserved : 31;
};
6.0 only
struct {
    ULONG LastBootSucceeded : 1;        // 0x01
    ULONG LastBootShutdown : 1;         // 0x02
    ULONG IoPortAccessSupported : 1;    // 0x04
    ULONG Reserved : 29;
};
6.1 only
0x5C (6.0);
0x54
0x88 (6.0);
0x80
LOADER_PERFORMANCE_DATA *LoaderPerformanceData;
6.0 to 6.1
0x60 (6.0);
0x58
0x90 (6.0);
0x88
LIST_ENTRY BootApplicationPersistentData;
6.0 to 6.1
0x68 (6.0);
0x60
0xA0 (6.0);
0x98
PVOID WmdTestResult;
6.0 to 6.1
0x6C (6.0);
0x64
0xA8 (6.0);
0xA0
GUID BootIdentifier;
6.0 to 6.1
0x74 0xB0
ULONG ResumePages;
6.1 only
0x78 0xB8
PVOID DumpHeader;
6.1 only
0x7C 0xC0
PVOID BgContext;
6.1 only
0x80 0xC8
PVOID NumaLocalityInfo;
6.1 only
0x84 0xD0
PVOID NumaGroupAssignment;
6.1 only
0x88 0xD8
LIST_ENTRY AttachedHives;
6.1 only
0x90 0xE8
ULONG MemoryCachingRequirementsCount;
6.1 only
0x94 0xF0
PVOID MemoryCachingRequirements;
6.1 only
0x98 0xF8
TPM_BOOT_ENTROPY_LDR_RESULT TpmBootEntropyResult;
6.1 only
0xE0 0x0140
ULONGLONG ProcessorCounterFrequency;
6.1 only

Especially notable above is that Windows 7 does away with the MajorVersion and MinorVersion (and LoaderPagesSpanned disappears with version 6.2).