1 /* SPDX-License-Identifier: LGPL-2.1-or-later */
9 #define DOS_FILE_MAGIC "MZ"
10 #define PE_FILE_MAGIC "PE\0\0"
11 #define MAX_SECTIONS 96
14 #define TARGET_MACHINE_TYPE EFI_IMAGE_MACHINE_IA32
15 #elif defined(__x86_64__)
16 #define TARGET_MACHINE_TYPE EFI_IMAGE_MACHINE_X64
17 #elif defined(__aarch64__)
18 #define TARGET_MACHINE_TYPE EFI_IMAGE_MACHINE_AARCH64
19 #elif defined(__arm__)
20 #define TARGET_MACHINE_TYPE EFI_IMAGE_MACHINE_ARMTHUMB_MIXED
21 #elif defined(__riscv) && __riscv_xlen == 64
22 #define TARGET_MACHINE_TYPE EFI_IMAGE_MACHINE_RISCV64
24 #error Unknown EFI arch
27 struct DosFileHeader
{
49 struct CoffFileHeader
{
51 UINT16 NumberOfSections
;
53 UINT32 PointerToSymbolTable
;
54 UINT32 NumberOfSymbols
;
55 UINT16 SizeOfOptionalHeader
;
56 UINT16 Characteristics
;
61 struct CoffFileHeader FileHeader
;
62 /* OptionalHeader omitted */
65 struct PeSectionHeader
{
68 UINT32 VirtualAddress
;
70 UINT32 PointerToRawData
;
71 UINT32 PointerToRelocations
;
72 UINT32 PointerToLinenumbers
;
73 UINT16 NumberOfRelocations
;
74 UINT16 NumberOfLinenumbers
;
75 UINT32 Characteristics
;
78 static inline BOOLEAN
verify_dos(const struct DosFileHeader
*dos
) {
80 return CompareMem(dos
->Magic
, DOS_FILE_MAGIC
, STRLEN(DOS_FILE_MAGIC
)) == 0;
83 static inline BOOLEAN
verify_pe(const struct PeFileHeader
*pe
) {
85 return CompareMem(pe
->Magic
, PE_FILE_MAGIC
, STRLEN(PE_FILE_MAGIC
)) == 0 &&
86 pe
->FileHeader
.Machine
== TARGET_MACHINE_TYPE
&&
87 pe
->FileHeader
.NumberOfSections
> 0 &&
88 pe
->FileHeader
.NumberOfSections
<= MAX_SECTIONS
;
91 static inline UINTN
section_table_offset(const struct DosFileHeader
*dos
, const struct PeFileHeader
*pe
) {
94 return dos
->ExeHeader
+ sizeof(struct PeFileHeader
) + pe
->FileHeader
.SizeOfOptionalHeader
;
97 static VOID
locate_sections(
98 const struct PeSectionHeader section_table
[],
100 const CHAR8
**sections
,
105 assert(section_table
);
109 for (UINTN i
= 0; i
< n_table
; i
++) {
110 const struct PeSectionHeader
*sect
= section_table
+ i
;
112 for (UINTN j
= 0; sections
[j
]; j
++) {
113 if (CompareMem(sect
->Name
, sections
[j
], strlena(sections
[j
])) != 0)
117 addrs
[j
] = sect
->VirtualAddress
;
119 offsets
[j
] = sect
->PointerToRawData
;
120 sizes
[j
] = sect
->VirtualSize
;
125 EFI_STATUS
pe_memory_locate_sections(
127 const CHAR8
**sections
,
130 const struct DosFileHeader
*dos
;
131 const struct PeFileHeader
*pe
;
139 dos
= (const struct DosFileHeader
*)base
;
140 if (!verify_dos(dos
))
141 return EFI_LOAD_ERROR
;
143 pe
= (const struct PeFileHeader
*)&base
[dos
->ExeHeader
];
145 return EFI_LOAD_ERROR
;
147 offset
= section_table_offset(dos
, pe
);
148 locate_sections((struct PeSectionHeader
*)&base
[offset
], pe
->FileHeader
.NumberOfSections
,
149 sections
, addrs
, NULL
, sizes
);
154 EFI_STATUS
pe_file_locate_sections(
157 const CHAR8
**sections
,
160 _cleanup_freepool_
struct PeSectionHeader
*section_table
= NULL
;
161 _cleanup_(FileHandleClosep
) EFI_FILE_HANDLE handle
= NULL
;
162 struct DosFileHeader dos
;
163 struct PeFileHeader pe
;
164 UINTN len
, section_table_len
;
173 err
= uefi_call_wrapper(dir
->Open
, 5, dir
, &handle
, (CHAR16
*)path
, EFI_FILE_MODE_READ
, 0ULL);
178 err
= uefi_call_wrapper(handle
->Read
, 3, handle
, &len
, &dos
);
181 if (len
!= sizeof(dos
) || !verify_dos(&dos
))
182 return EFI_LOAD_ERROR
;
184 err
= uefi_call_wrapper(handle
->SetPosition
, 2, handle
, dos
.ExeHeader
);
189 err
= uefi_call_wrapper(handle
->Read
, 3, handle
, &len
, &pe
);
192 if (len
!= sizeof(pe
) || !verify_pe(&pe
))
193 return EFI_LOAD_ERROR
;
195 section_table_len
= pe
.FileHeader
.NumberOfSections
* sizeof(struct PeSectionHeader
);
196 section_table
= AllocatePool(section_table_len
);
198 return EFI_OUT_OF_RESOURCES
;
200 err
= uefi_call_wrapper(handle
->SetPosition
, 2, handle
, section_table_offset(&dos
, &pe
));
204 len
= section_table_len
;
205 err
= uefi_call_wrapper(handle
->Read
, 3, handle
, &len
, section_table
);
208 if (len
!= section_table_len
)
209 return EFI_LOAD_ERROR
;
211 locate_sections(section_table
, pe
.FileHeader
.NumberOfSections
,
212 sections
, NULL
, offsets
, sizes
);