/** @file Definitions of the UEFI Executable (UE) file format. Copyright (c) 2021 - 2023, Marvin Häuser. All rights reserved.
SPDX-License-Identifier: BSD-2-Clause-Patent **/ #ifndef UE_IMAGE_H_ #define UE_IMAGE_H_ #include // // UE segment definitions. // /// /// Definition of the UE segment permission configurations. /// enum { UeSegmentPermX = 0, UeSegmentPermRX = 1, UeSegmentPermRW = 2, // // Read-only is the last value, as this makes it easier to implement it as // the else/default case. // UeSegmentPermR = 3, UeSegmentPermMax }; /// /// The minimum alignment requirement, in bytes, of each UE segment in the UE /// address space. /// #define UE_SEGMENT_MIN_ALIGNMENT 0x00001000U /// /// The maximum alignment requirement, in bytes, of each UE segment in the UE /// address space. /// #define UE_SEGMENT_MAX_ALIGNMENT 0x08000000U /// /// Information about the UE segment in the UE address space. /// /// [Bits 19:0] The size, in 4-KiB units, of the UE segment in the UE address /// space. /// [Bits 21:20] The UE segment permissions. /// [Bits 31:22] Reserved for future use. Must be zero. /// typedef UINT32 UE_SEGMENT_IMAGE_INFO; /// /// Definition of a UE segment header. /// typedef struct { /// /// Information about the UE segment in the UE address space. /// UE_SEGMENT_IMAGE_INFO ImageInfo; /// /// The size, in bytes, of the UE segment in the UE file. /// UINT32 FileSize; } UE_SEGMENT; STATIC_ASSERT ( sizeof (UE_SEGMENT) == 8 && ALIGNOF (UE_SEGMENT) == 4, "The UE segment definition does not meet the specification." ); /// /// Definition of a UE XIP segment header. /// typedef struct { /// /// Information about the UE segment in the UE address space. /// UE_SEGMENT_IMAGE_INFO ImageInfo; } UE_SEGMENT_XIP; STATIC_ASSERT ( sizeof (UE_SEGMENT_XIP) == 4 && ALIGNOF (UE_SEGMENT_XIP) == 4, "The UE XIP segment definition does not meet the specification." ); /** Retrieve the UE segment memory permissions. @param[in] ImageInfo The UE segment image information. **/ #define UE_SEGMENT_PERMISSIONS(ImageInfo) \ ((UINT8)(((ImageInfo) >> 20U) & 0x03U)) /** Retrieve the size, in bytes, of the UE segment in the UE address space. @param[in] ImageInfo The UE segment image information. **/ #define UE_SEGMENT_SIZE(ImageInfo) ((ImageInfo) << 12U) STATIC_ASSERT ( IS_ALIGNED (UE_SEGMENT_SIZE (0xFFFFFFFF), UE_SEGMENT_MIN_ALIGNMENT), "The UE segment size definition does not meet the specification." ); // // UE load table definitions. // /// /// The alignment, in bytes, of each UE load table in the UE file. /// #define UE_LOAD_TABLE_ALIGNMENT 8U /// /// Definition of the UE load table identifiers. /// enum { // // An array of UE fixup roots. Blocks are ordered ascending by their // base address. // UeLoadTableIdReloc = 0x00, // // An instance of the UE debug table.. // UeLoadTableIdDebug = 0x01 }; /// /// Definition of a UE load table header. /// typedef struct { /// /// Information about the UE load table. /// /// [Bits 28:0] The size, in 8-byte units, of the UE load table in the UE /// file. /// [Bits 31:29] The identifier of the UE load table. /// UINT32 FileInfo; } UE_LOAD_TABLE; STATIC_ASSERT ( sizeof (UE_LOAD_TABLE) == 4 && ALIGNOF (UE_LOAD_TABLE) == 4, "The UE load table definition does not meet the specification." ); /** Retrieves the UE load table identifier. @param[in] FileInfo The UE load table file information. **/ #define UE_LOAD_TABLE_ID(FileInfo) ((UINT8)((FileInfo) >> 29U)) /** Retrieves the size, in bytes, of the UE load table in the UE file. @param[in] FileInfo The UE load table file information. **/ #define UE_LOAD_TABLE_SIZE(FileInfo) ((FileInfo) << 3U) STATIC_ASSERT ( IS_ALIGNED (UE_LOAD_TABLE_SIZE (0xFFFFFFFF), UE_LOAD_TABLE_ALIGNMENT), "The UE load table size definition does not meet the specification." ); // // UE relocation table definitions. // /// /// Definitions of the generic UE relocation identifiers. /// enum { UeReloc32 = 0x00, UeReloc64 = 0x01, UeReloc32NoMeta = 0x02, UeRelocGenericMax }; #if 0 /// /// Definition of the ARM UE relocation identifiers. /// enum { UeRelocArmMovtMovw = 0x02 }; #endif /// /// The alignment requirement for a UE fixup root. /// #define UE_FIXUP_ROOT_ALIGNMENT 4U STATIC_ASSERT ( UE_FIXUP_ROOT_ALIGNMENT <= UE_LOAD_TABLE_ALIGNMENT, "The UE fixup root definition does not meet the specification." ); /// /// Definition of a UE fixup root. /// typedef struct { /// /// The offset of the first head fixup, in bytes, from the end of the previous /// UE relocation fixup (chained or not). The first UE fixup root is /// relative to 0. /// UINT32 FirstOffset; /// /// The head fixups of the UE fixup root. /// /// [Bits 3:0] The type of the UE relocation fixup. /// [Bits 15:4] The offset of the next UE head fixup from the end of the last /// UE relocation fixup in the chain (if chained). If 0x0FFF, the /// current fixup root is terminated. /// UINT16 Heads[]; } UE_FIXUP_ROOT; STATIC_ASSERT ( sizeof (UE_FIXUP_ROOT) == 4 && ALIGNOF (UE_FIXUP_ROOT) == UE_FIXUP_ROOT_ALIGNMENT, "The UE fixup root definition does not meet the specification." ); STATIC_ASSERT ( OFFSET_OF (UE_FIXUP_ROOT, Heads) == sizeof (UE_FIXUP_ROOT), "The UE fixup root definition does not meet the specification." ); STATIC_ASSERT ( sizeof (UE_FIXUP_ROOT) <= UE_LOAD_TABLE_ALIGNMENT, "The UE fixup root definition is misaligned." ); #define MIN_SIZE_OF_UE_FIXUP_ROOT (sizeof (UE_FIXUP_ROOT) + sizeof (UINT16)) /// /// The maximum offset, in bytes, of the next UE head fixup. /// #define UE_HEAD_FIXUP_MAX_OFFSET 0x0FFEU /// /// UE head fixup offset that terminates a fixup root. /// #define UE_HEAD_FIXUP_OFFSET_END 0x0FFFU /** Retrieves the target offset of the UE relocation fixup. @param[in] FixupInfo The UE relocation fixup information. **/ #define UE_RELOC_FIXUP_OFFSET(FixupInfo) ((UINT16)((FixupInfo) >> 4U)) /** Retrieves the type of the UE relocation fixup. @param[in] FixupInfo The UE relocation fixup information. **/ #define UE_RELOC_FIXUP_TYPE(FixupInfo) ((FixupInfo) & 0x000FU) /** Retrieves the offset of the next UE chained relocation fixup. @param[in] FixupInfo The UE relocation fixup information. **/ #define UE_CHAINED_RELOC_FIXUP_NEXT_OFFSET(FixupInfo) \ ((UINT16)((UINT16)(FixupInfo) >> 4U) & 0x0FFFU) /// /// The maximum offset, in bytes, of the next UE chained relocation fixup. /// #define UE_CHAINED_RELOC_FIXUP_MAX_OFFSET 0x0FFEU /// /// UE chained relocation fixup offset that terminates a chain. /// #define UE_CHAINED_RELOC_FIXUP_OFFSET_END 0x0FFFU /** Retrieves the type of the next UE chained relocation fixup. @param[in] FixupInfo The UE relocation fixup information. **/ #define UE_CHAINED_RELOC_FIXUP_NEXT_TYPE(FixupInfo) \ ((UINT8)((UINT16)(FixupInfo) & 0x0FU)) /// /// The shift exponent for UE chained relocation fixup values. /// #define UE_CHAINED_RELOC_FIXUP_VALUE_SHIFT 16U /** Retrieves the value of the current UE chained relocation fixup. @param[in] FixupInfo The UE relocation fixup information. **/ #define UE_CHAINED_RELOC_FIXUP_VALUE(FixupInfo) \ RShiftU64 (FixupInfo, UE_CHAINED_RELOC_FIXUP_VALUE_SHIFT) /// /// Definition of the common header of UE chained relocation fixups. /// /// [Bits 3:0] The relocation type of the next chained relocation fixup. Only /// valid when [Bits 15:4] are not 0x0FFF. /// [Bits 15:4] The offset to the next chained relocation fixup from the end /// of the current one. If 0x0FFF, the current chain is terminated. /// Consult the fixup root for further relocation fixups. /// typedef UINT16 UE_RELOC_FIXUP_HDR; /// /// Definition of the generic 64-bit UE chained relocation fixup. /// /// [Bits 15:0] The common header of UE chained relocation fixups. /// [Bits 47:16] The address value to relocate. /// [Bits 63:48] Must be zero. /// typedef UINT64 UE_RELOC_FIXUP_64; /// /// The shift exponent for UE chained 32-bit relocation fixup values. /// #define UE_CHAINED_RELOC_FIXUP_VALUE_32_SHIFT 12U /** Retrieves the value of the current UE chained 32-bit relocation fixup. @param[in] FixupInfo The UE relocation fixup information. **/ #define UE_CHAINED_RELOC_FIXUP_VALUE_32(FixupInfo) \ (UINT32)((UINT32)(FixupInfo) >> UE_CHAINED_RELOC_FIXUP_VALUE_32_SHIFT) /// /// Definition of the generic 32-bit UE chained relocation fixup. /// /// [Bits 11:0] The offset to the next chained relocation fixup from the end /// of the current one. If 0x0FFF, the current chain is terminated. /// Consult the fixup root for further relocation fixups. /// [Bits 31:12] The address value to relocate. /// typedef UINT32 UE_RELOC_FIXUP_32; #if 0 /// /// Definition of the ARM Thumb MOVT/MOVW UE chained relocation fixup. /// /// [Bits 15:0] The common header of UE chained relocation fixups. /// [Bits 31:16] The 16-bit immediate value to relocate. /// typedef UINT32 UE_RELOC_FIXUP_ARM_MOVT_MOVW; #endif // // UE debug table definitions. // // NOTE: The UE symbols base address offset is required for conversion of // PE Images that have their first section start after the end of the // Image headers. As PDBs cannot easily be rebased, store the offset. // /// /// Definition of a UE segment name. Must be \0-terminated. /// typedef UINT8 UE_SEGMENT_NAME[8]; STATIC_ASSERT ( sizeof (UE_SEGMENT_NAME) == 8 && ALIGNOF (UE_SEGMENT_NAME) == 1, "The UE segment name definition does not meet the specification." ); /// /// Definition of the UE debug table header. /// typedef struct { /// /// Information about the image regarding the symbols file. /// /// [Bits 1:0] The offset, in image alignment units, to be subtracted from the /// UE base address in order to retrieve the UE symbols base /// address. /// [Bits 7:2] Reserved for future use. Must be zero. /// UINT8 ImageInfo; /// /// The length, in bytes, of the UE symbols path (excluding the terminator). /// UINT8 SymbolsPathLength; /// /// The UE symbols path. Must be \0-terminated. /// UINT8 SymbolsPath[]; /// /// The UE segment name table. The order matches the UE segment table. /// //UE_SEGMENT_NAME SegmentNames[]; } UE_DEBUG_TABLE; /// /// The minimum size, in bytes, of the UE debug table. /// #define MIN_SIZE_OF_UE_DEBUG_TABLE \ (OFFSET_OF (UE_DEBUG_TABLE, SymbolsPath) + 1U) /** Retrieves the UE symbol address subtrahend in SegmentAlignment-units. @param[in] ImageInfo The UE debug table image information. **/ #define UE_DEBUG_TABLE_IMAGE_INFO_SYM_SUBTRAHEND_FACTOR(ImageInfo) \ ((UINT8)((ImageInfo) & 0x03U)) /** Retrieves the UE segment name table of a UE debug table. @param[in] DebugTable The UE debug table. **/ #define UE_DEBUG_TABLE_SEGMENT_NAMES(DebugTable) \ (CONST UE_SEGMENT_NAME *) ( \ (DebugTable)->SymbolsPath + (DebugTable)->SymbolsPathLength + 1 \ ) STATIC_ASSERT ( sizeof (UE_DEBUG_TABLE) == 2 && ALIGNOF (UE_DEBUG_TABLE) == 1, "The UE debug table definition does not meet the specification." ); STATIC_ASSERT ( ALIGNOF (UE_DEBUG_TABLE) <= UE_LOAD_TABLE_ALIGNMENT, "The UE debug table definition is misaligned." ); STATIC_ASSERT ( OFFSET_OF (UE_DEBUG_TABLE, SymbolsPath) == sizeof (UE_DEBUG_TABLE), "The UE fixup root definition does not meet the specification." ); // // UE header definitions. // /// /// The file magic number of a UE header. /// #define UE_HEADER_MAGIC SIGNATURE_16 ('U', 'E') /// /// Definition of the UE machine identifiers. /// enum { UeMachineI386 = 0, UeMachineX64 = 1, UeMachineArmThumbMixed = 2, UeMachineArm64 = 3, UeMachineRiscV32 = 4, UeMachineRiscV64 = 5, UeMachineRiscV128 = 6 }; /// /// Definition of the UE subsystem identifiers. /// enum { UeSubsystemEfiApplication = 0, UeSubsystemEfiBootServicesDriver = 1, UeSubsystemEfiRuntimeDriver = 2 }; /// /// Definition of a UE file header. /// typedef struct { /// /// The file magic number to identify the UE file format. Must be 'UE'. /// UINT16 Magic; /// /// Information about the image kind and supported architectures. /// /// [Bits 2:0] Indicates the subsystem. /// [Bits 7:3] Indicates the supported architectures. /// UINT8 Type; /// /// Information about the UE load tables and segments. /// /// [Bits 2:0] The number of UE load tables. /// [Bits 7:3] The index of the last segment in the UE segment table. /// UINT8 TableCounts; /// /// Indicates the offset of the UE entry point in the UE address space. /// UINT32 EntryPointAddress; /// /// Information about the UE image. /// /// [Bits 51:0] The base UEFI page of the UE image, i.e., the base address in /// 4 KiB units. /// [Bits 55:52] Reserved for future use. Must be zero. /// [Bit 56] Indicates whether the UE image is XIP /// [Bit 57] Indicates whether the UE image is designated for a fixed /// address. /// [Bit 58] Indicates whether the UE relocation table has been stripped. /// [Bit 59] Indicates whether UE chained fixups are used. /// [Bits 63:60] The shift exponent, offset by -12, for the UE segment /// alignment in bytes. /// UINT64 ImageInfo; /// /// The UE segment table. It contains all data of the UE address space. /// /// All UE segments are contiguous in the UE address space. /// The offset of the first UE segment in the UE address space is 0. /// /// All UE segments' data are contiguous in the UE file. /// The offset of the first UE segment in the UE file is the end of the UE /// file header. /// UE_SEGMENT Segments[]; /// /// The UE load tables. They contain data useful for UE loading. /// /// All UE load tables are contiguous in the UE file. /// The offset of the first UE load table in the UE file is the end of the last /// UE segment in the UE file. /// /// All UE load tables are ordered ascending by their identifier. /// //UE_LOAD_TABLE LoadTables[]; } UE_HEADER; /// /// The minimum size, in bytes, of a valid UE header. /// #define MIN_SIZE_OF_UE_HEADER \ (OFFSET_OF (UE_HEADER, Segments) + sizeof (UE_SEGMENT)) STATIC_ASSERT ( sizeof (UE_HEADER) == 16 && ALIGNOF (UE_HEADER) == 8, "The UE header definition does not meet the specification." ); STATIC_ASSERT ( ALIGNOF (UE_SEGMENT) <= ALIGNOF (UE_LOAD_TABLE), "The UE header definition is misaligned." ); STATIC_ASSERT ( OFFSET_OF (UE_HEADER, Segments) == sizeof (UE_HEADER), "The UE header definition does not meet the specification." ); /** Retrieves the UE base address. @param[in] ImageInfo The UE header image information. **/ #define UE_HEADER_BASE_ADDRESS(ImageInfo) LShiftU64 (ImageInfo, 12) /** Retrieves the UE segment alignment, in bytes, as a power of two. @param[in] ImageInfo The UE header image information. **/ #define UE_HEADER_SEGMENT_ALIGNMENT(ImageInfo) \ (1U << ((UINT8)RShiftU64 (ImageInfo, 60) + 12U)) /// /// UE header image information bit that indicates whether the image is XIP. /// #define UE_HEADER_IMAGE_INFO_XIP 0x0100000000000000ULL /// /// UE header image information bit that indicates whether the image is /// designated to be loaded to a fixed address. /// #define UE_HEADER_IMAGE_INFO_FIXED_ADDRESS 0x0200000000000000ULL /// /// UE header image information bit that indicates whether the relocation fixups /// have been stripped. /// #define UE_HEADER_IMAGE_INFO_RELOCATION_FIXUPS_STRIPPED 0x0400000000000000ULL /// /// UE header image information bit that indicates whether UE relocation fixup /// chains are utilized. /// #define UE_HEADER_IMAGE_INFO_CHAINED_FIXUPS 0x0800000000000000ULL /** Retrieves the UE subsystem. @param[in] Type The UE header type information. **/ #define UE_HEADER_SUBSYSTEM(Type) ((Type) & 0x07U) /** Retrieves the UE supported architectures. @param[in] Type The UE header type information. **/ #define UE_HEADER_ARCH(Type) ((Type) >> 3U) /// /// The maximum number of UE load tables. /// #define UE_HEADER_NUM_LOAD_TABLES_MAX 7U /** Retrieves the number of UE load tables. @param[in] TableCounts The UE header segment and load table information. **/ #define UE_HEADER_NUM_LOAD_TABLES(TableCounts) ((TableCounts) & 0x07U) STATIC_ASSERT ( UE_HEADER_NUM_LOAD_TABLES (0xFFU) == UE_HEADER_NUM_LOAD_TABLES_MAX, "The number of load tables violates the specification." ); /// /// The maximum number of UE segments. /// #define UE_HEADER_NUM_SEGMENTS_MAX 32U /** Retrieves the index of the last UE segment, i.e., their amount minus 1. @param[in] TableCounts The UE header segment and load table information. **/ #define UE_HEADER_LAST_SEGMENT_INDEX(TableCounts) ((TableCounts) >> 3U) STATIC_ASSERT ( UE_HEADER_LAST_SEGMENT_INDEX (0xFFU) + 1U == UE_HEADER_NUM_SEGMENTS_MAX, "The number of load tables violates the specification." ); /** Retrieves the 8 byte aligned UE file size. If the file size is larger than this value, the appended data may be the UE certificate table. @param[in] FileInfo The UE header file information. **/ #define UE_HEADER_FILE_SIZE(FileInfo) ((FileInfo) << 3U) STATIC_ASSERT ( IS_ALIGNED (UE_HEADER_FILE_SIZE (0xFFFFFFFF), UE_LOAD_TABLE_ALIGNMENT), "The UE file size definition does not meet the specification." ); /// /// The maximum size, in bytes, of a valid UE header. /// #define MAX_SIZE_OF_UE_HEADER \ MIN_SIZE_OF_UE_HEADER + \ UE_HEADER_NUM_SEGMENTS_MAX * sizeof (UE_SEGMENT) + \ UE_HEADER_NUM_LOAD_TABLES_MAX * sizeof (UE_LOAD_TABLE) #endif // UE_IMAGE_H_