1 // SPDX-License-Identifier: GPL-2.0+
5 * based partly on wine code
7 * Copyright (c) 2016 Alexander Graf
11 #include <efi_loader.h>
14 const efi_guid_t efi_global_variable_guid
= EFI_GLOBAL_VARIABLE_GUID
;
15 const efi_guid_t efi_guid_device_path
= EFI_DEVICE_PATH_PROTOCOL_GUID
;
16 const efi_guid_t efi_guid_loaded_image
= EFI_LOADED_IMAGE_PROTOCOL_GUID
;
17 const efi_guid_t efi_guid_loaded_image_device_path
=
18 EFI_LOADED_IMAGE_DEVICE_PATH_PROTOCOL_GUID
;
19 const efi_guid_t efi_simple_file_system_protocol_guid
=
20 EFI_SIMPLE_FILE_SYSTEM_PROTOCOL_GUID
;
21 const efi_guid_t efi_file_info_guid
= EFI_FILE_INFO_GUID
;
23 static int machines
[] = {
24 #if defined(__aarch64__)
25 IMAGE_FILE_MACHINE_ARM64
,
26 #elif defined(__arm__)
27 IMAGE_FILE_MACHINE_ARM
,
28 IMAGE_FILE_MACHINE_THUMB
,
29 IMAGE_FILE_MACHINE_ARMNT
,
32 #if defined(__x86_64__)
33 IMAGE_FILE_MACHINE_AMD64
,
34 #elif defined(__i386__)
35 IMAGE_FILE_MACHINE_I386
,
38 #if defined(__riscv) && (__riscv_xlen == 32)
39 IMAGE_FILE_MACHINE_RISCV32
,
42 #if defined(__riscv) && (__riscv_xlen == 64)
43 IMAGE_FILE_MACHINE_RISCV64
,
48 * efi_print_image_info() - print information about a loaded image
50 * If the program counter is located within the image the offset to the base
54 * @image: loaded image
55 * @pc: program counter (use NULL to suppress offset output)
58 static efi_status_t
efi_print_image_info(struct efi_loaded_image_obj
*obj
,
59 struct efi_loaded_image
*image
,
63 printf(" [0x%p:0x%p]",
64 image
->image_base
, image
->image_base
+ image
->image_size
- 1);
65 if (pc
&& pc
>= image
->image_base
&&
66 pc
< image
->image_base
+ image
->image_size
)
67 printf(" pc=0x%zx", pc
- image
->image_base
);
69 printf(" '%pD'", image
->file_path
);
75 * efi_print_image_infos() - print information about all loaded images
77 * @pc: program counter (use NULL to suppress offset output)
79 void efi_print_image_infos(void *pc
)
81 struct efi_object
*efiobj
;
82 struct efi_handler
*handler
;
84 list_for_each_entry(efiobj
, &efi_obj_list
, link
) {
85 list_for_each_entry(handler
, &efiobj
->protocols
, link
) {
86 if (!guidcmp(handler
->guid
, &efi_guid_loaded_image
)) {
88 (struct efi_loaded_image_obj
*)efiobj
,
89 handler
->protocol_interface
, pc
);
96 * efi_loader_relocate() - relocate UEFI binary
98 * @rel: pointer to the relocation table
99 * @rel_size: size of the relocation table in bytes
100 * @efi_reloc: actual load address of the image
101 * @pref_address: preferred load address of the image
102 * Return: status code
104 static efi_status_t
efi_loader_relocate(const IMAGE_BASE_RELOCATION
*rel
,
105 unsigned long rel_size
, void *efi_reloc
,
106 unsigned long pref_address
)
108 unsigned long delta
= (unsigned long)efi_reloc
- pref_address
;
109 const IMAGE_BASE_RELOCATION
*end
;
115 end
= (const IMAGE_BASE_RELOCATION
*)((const char *)rel
+ rel_size
);
116 while (rel
< end
&& rel
->SizeOfBlock
) {
117 const uint16_t *relocs
= (const uint16_t *)(rel
+ 1);
118 i
= (rel
->SizeOfBlock
- sizeof(*rel
)) / sizeof(uint16_t);
120 uint32_t offset
= (uint32_t)(*relocs
& 0xfff) +
122 int type
= *relocs
>> EFI_PAGE_SHIFT
;
123 uint64_t *x64
= efi_reloc
+ offset
;
124 uint32_t *x32
= efi_reloc
+ offset
;
125 uint16_t *x16
= efi_reloc
+ offset
;
128 case IMAGE_REL_BASED_ABSOLUTE
:
130 case IMAGE_REL_BASED_HIGH
:
131 *x16
+= ((uint32_t)delta
) >> 16;
133 case IMAGE_REL_BASED_LOW
:
134 *x16
+= (uint16_t)delta
;
136 case IMAGE_REL_BASED_HIGHLOW
:
137 *x32
+= (uint32_t)delta
;
139 case IMAGE_REL_BASED_DIR64
:
140 *x64
+= (uint64_t)delta
;
143 case IMAGE_REL_BASED_RISCV_HI20
:
144 *x32
= ((*x32
& 0xfffff000) + (uint32_t)delta
) |
147 case IMAGE_REL_BASED_RISCV_LOW12I
:
148 case IMAGE_REL_BASED_RISCV_LOW12S
:
149 /* We know that we're 4k aligned */
151 printf("Unsupported reloc offset\n");
152 return EFI_LOAD_ERROR
;
157 printf("Unknown Relocation off %x type %x\n",
159 return EFI_LOAD_ERROR
;
163 rel
= (const IMAGE_BASE_RELOCATION
*)relocs
;
168 void __weak
invalidate_icache_all(void)
170 /* If the system doesn't support icache_all flush, cross our fingers */
174 * efi_set_code_and_data_type() - determine the memory types to be used for code
177 * @loaded_image_info: image descriptor
178 * @image_type: field Subsystem of the optional header for
179 * Windows specific field
181 static void efi_set_code_and_data_type(
182 struct efi_loaded_image
*loaded_image_info
,
185 switch (image_type
) {
186 case IMAGE_SUBSYSTEM_EFI_APPLICATION
:
187 loaded_image_info
->image_code_type
= EFI_LOADER_CODE
;
188 loaded_image_info
->image_data_type
= EFI_LOADER_DATA
;
190 case IMAGE_SUBSYSTEM_EFI_BOOT_SERVICE_DRIVER
:
191 loaded_image_info
->image_code_type
= EFI_BOOT_SERVICES_CODE
;
192 loaded_image_info
->image_data_type
= EFI_BOOT_SERVICES_DATA
;
194 case IMAGE_SUBSYSTEM_EFI_RUNTIME_DRIVER
:
195 case IMAGE_SUBSYSTEM_EFI_ROM
:
196 loaded_image_info
->image_code_type
= EFI_RUNTIME_SERVICES_CODE
;
197 loaded_image_info
->image_data_type
= EFI_RUNTIME_SERVICES_DATA
;
200 printf("%s: invalid image type: %u\n", __func__
, image_type
);
201 /* Let's assume it is an application */
202 loaded_image_info
->image_code_type
= EFI_LOADER_CODE
;
203 loaded_image_info
->image_data_type
= EFI_LOADER_DATA
;
209 * efi_load_pe() - relocate EFI binary
211 * This function loads all sections from a PE binary into a newly reserved
212 * piece of memory. On success the entry point is returned as handle->entry.
214 * @handle: loaded image handle
215 * @efi: pointer to the EFI binary
216 * @loaded_image_info: loaded image protocol
217 * Return: status code
219 efi_status_t
efi_load_pe(struct efi_loaded_image_obj
*handle
, void *efi
,
220 struct efi_loaded_image
*loaded_image_info
)
222 IMAGE_NT_HEADERS32
*nt
;
223 IMAGE_DOS_HEADER
*dos
;
224 IMAGE_SECTION_HEADER
*sections
;
228 const IMAGE_BASE_RELOCATION
*rel
;
229 unsigned long rel_size
;
230 int rel_idx
= IMAGE_DIRECTORY_ENTRY_BASERELOC
;
232 unsigned long virt_size
= 0;
236 if (dos
->e_magic
!= IMAGE_DOS_SIGNATURE
) {
237 printf("%s: Invalid DOS Signature\n", __func__
);
238 return EFI_LOAD_ERROR
;
241 nt
= (void *) ((char *)efi
+ dos
->e_lfanew
);
242 if (nt
->Signature
!= IMAGE_NT_SIGNATURE
) {
243 printf("%s: Invalid NT Signature\n", __func__
);
244 return EFI_LOAD_ERROR
;
247 for (i
= 0; machines
[i
]; i
++)
248 if (machines
[i
] == nt
->FileHeader
.Machine
) {
254 printf("%s: Machine type 0x%04x is not supported\n",
255 __func__
, nt
->FileHeader
.Machine
);
256 return EFI_LOAD_ERROR
;
259 /* Calculate upper virtual address boundary */
260 num_sections
= nt
->FileHeader
.NumberOfSections
;
261 sections
= (void *)&nt
->OptionalHeader
+
262 nt
->FileHeader
.SizeOfOptionalHeader
;
264 for (i
= num_sections
- 1; i
>= 0; i
--) {
265 IMAGE_SECTION_HEADER
*sec
= §ions
[i
];
266 virt_size
= max_t(unsigned long, virt_size
,
267 sec
->VirtualAddress
+ sec
->Misc
.VirtualSize
);
270 /* Read 32/64bit specific header bits */
271 if (nt
->OptionalHeader
.Magic
== IMAGE_NT_OPTIONAL_HDR64_MAGIC
) {
272 IMAGE_NT_HEADERS64
*nt64
= (void *)nt
;
273 IMAGE_OPTIONAL_HEADER64
*opt
= &nt64
->OptionalHeader
;
274 image_base
= opt
->ImageBase
;
275 efi_set_code_and_data_type(loaded_image_info
, opt
->Subsystem
);
276 efi_reloc
= efi_alloc(virt_size
,
277 loaded_image_info
->image_code_type
);
279 printf("%s: Could not allocate %lu bytes\n",
280 __func__
, virt_size
);
281 return EFI_OUT_OF_RESOURCES
;
283 handle
->entry
= efi_reloc
+ opt
->AddressOfEntryPoint
;
284 rel_size
= opt
->DataDirectory
[rel_idx
].Size
;
285 rel
= efi_reloc
+ opt
->DataDirectory
[rel_idx
].VirtualAddress
;
286 virt_size
= ALIGN(virt_size
, opt
->SectionAlignment
);
287 } else if (nt
->OptionalHeader
.Magic
== IMAGE_NT_OPTIONAL_HDR32_MAGIC
) {
288 IMAGE_OPTIONAL_HEADER32
*opt
= &nt
->OptionalHeader
;
289 image_base
= opt
->ImageBase
;
290 efi_set_code_and_data_type(loaded_image_info
, opt
->Subsystem
);
291 efi_reloc
= efi_alloc(virt_size
,
292 loaded_image_info
->image_code_type
);
294 printf("%s: Could not allocate %lu bytes\n",
295 __func__
, virt_size
);
296 return EFI_OUT_OF_RESOURCES
;
298 handle
->entry
= efi_reloc
+ opt
->AddressOfEntryPoint
;
299 rel_size
= opt
->DataDirectory
[rel_idx
].Size
;
300 rel
= efi_reloc
+ opt
->DataDirectory
[rel_idx
].VirtualAddress
;
301 virt_size
= ALIGN(virt_size
, opt
->SectionAlignment
);
303 printf("%s: Invalid optional header magic %x\n", __func__
,
304 nt
->OptionalHeader
.Magic
);
305 return EFI_LOAD_ERROR
;
308 /* Copy PE headers */
309 memcpy(efi_reloc
, efi
, sizeof(*dos
) + sizeof(*nt
)
310 + nt
->FileHeader
.SizeOfOptionalHeader
311 + num_sections
* sizeof(IMAGE_SECTION_HEADER
));
313 /* Load sections into RAM */
314 for (i
= num_sections
- 1; i
>= 0; i
--) {
315 IMAGE_SECTION_HEADER
*sec
= §ions
[i
];
316 memset(efi_reloc
+ sec
->VirtualAddress
, 0,
317 sec
->Misc
.VirtualSize
);
318 memcpy(efi_reloc
+ sec
->VirtualAddress
,
319 efi
+ sec
->PointerToRawData
,
323 /* Run through relocations */
324 if (efi_loader_relocate(rel
, rel_size
, efi_reloc
,
325 (unsigned long)image_base
) != EFI_SUCCESS
) {
326 efi_free_pages((uintptr_t) efi_reloc
,
327 (virt_size
+ EFI_PAGE_MASK
) >> EFI_PAGE_SHIFT
);
328 return EFI_LOAD_ERROR
;
332 flush_cache((ulong
)efi_reloc
,
333 ALIGN(virt_size
, EFI_CACHELINE_SIZE
));
334 invalidate_icache_all();
336 /* Populate the loaded image interface bits */
337 loaded_image_info
->image_base
= efi_reloc
;
338 loaded_image_info
->image_size
= virt_size
;