4 * based partly on wine code
6 * Copyright (c) 2016 Alexander Graf
8 * SPDX-License-Identifier: GPL-2.0+
12 #include <efi_loader.h>
14 #include <asm/global_data.h>
16 DECLARE_GLOBAL_DATA_PTR
;
18 const efi_guid_t efi_global_variable_guid
= EFI_GLOBAL_VARIABLE_GUID
;
19 const efi_guid_t efi_guid_device_path
= DEVICE_PATH_GUID
;
20 const efi_guid_t efi_guid_loaded_image
= LOADED_IMAGE_GUID
;
21 const efi_guid_t efi_simple_file_system_protocol_guid
=
22 EFI_SIMPLE_FILE_SYSTEM_PROTOCOL_GUID
;
23 const efi_guid_t efi_file_info_guid
= EFI_FILE_INFO_GUID
;
25 static efi_status_t
efi_loader_relocate(const IMAGE_BASE_RELOCATION
*rel
,
26 unsigned long rel_size
, void *efi_reloc
)
28 const IMAGE_BASE_RELOCATION
*end
;
31 end
= (const IMAGE_BASE_RELOCATION
*)((const char *)rel
+ rel_size
);
32 while (rel
< end
- 1 && rel
->SizeOfBlock
) {
33 const uint16_t *relocs
= (const uint16_t *)(rel
+ 1);
34 i
= (rel
->SizeOfBlock
- sizeof(*rel
)) / sizeof(uint16_t);
36 uint32_t offset
= (uint32_t)(*relocs
& 0xfff) +
38 int type
= *relocs
>> EFI_PAGE_SHIFT
;
39 unsigned long delta
= (unsigned long)efi_reloc
;
40 uint64_t *x64
= efi_reloc
+ offset
;
41 uint32_t *x32
= efi_reloc
+ offset
;
42 uint16_t *x16
= efi_reloc
+ offset
;
45 case IMAGE_REL_BASED_ABSOLUTE
:
47 case IMAGE_REL_BASED_HIGH
:
48 *x16
+= ((uint32_t)delta
) >> 16;
50 case IMAGE_REL_BASED_LOW
:
51 *x16
+= (uint16_t)delta
;
53 case IMAGE_REL_BASED_HIGHLOW
:
54 *x32
+= (uint32_t)delta
;
56 case IMAGE_REL_BASED_DIR64
:
57 *x64
+= (uint64_t)delta
;
60 printf("Unknown Relocation off %x type %x\n",
62 return EFI_LOAD_ERROR
;
66 rel
= (const IMAGE_BASE_RELOCATION
*)relocs
;
71 void __weak
invalidate_icache_all(void)
73 /* If the system doesn't support icache_all flush, cross our fingers */
77 * Determine the memory types to be used for code and data.
79 * @loaded_image_info image descriptor
80 * @image_type field Subsystem of the optional header for
81 * Windows specific field
83 static void efi_set_code_and_data_type(
84 struct efi_loaded_image
*loaded_image_info
,
88 case IMAGE_SUBSYSTEM_EFI_APPLICATION
:
89 loaded_image_info
->image_code_type
= EFI_LOADER_CODE
;
90 loaded_image_info
->image_data_type
= EFI_LOADER_DATA
;
92 case IMAGE_SUBSYSTEM_EFI_BOOT_SERVICE_DRIVER
:
93 loaded_image_info
->image_code_type
= EFI_BOOT_SERVICES_CODE
;
94 loaded_image_info
->image_data_type
= EFI_BOOT_SERVICES_DATA
;
96 case IMAGE_SUBSYSTEM_EFI_RUNTIME_DRIVER
:
97 case IMAGE_SUBSYSTEM_EFI_ROM
:
98 loaded_image_info
->image_code_type
= EFI_RUNTIME_SERVICES_CODE
;
99 loaded_image_info
->image_data_type
= EFI_RUNTIME_SERVICES_DATA
;
102 printf("%s: invalid image type: %u\n", __func__
, image_type
);
103 /* Let's assume it is an application */
104 loaded_image_info
->image_code_type
= EFI_LOADER_CODE
;
105 loaded_image_info
->image_data_type
= EFI_LOADER_DATA
;
111 * This function loads all sections from a PE binary into a newly reserved
112 * piece of memory. On successful load it then returns the entry point for
113 * the binary. Otherwise NULL.
115 void *efi_load_pe(void *efi
, struct efi_loaded_image
*loaded_image_info
)
117 IMAGE_NT_HEADERS32
*nt
;
118 IMAGE_DOS_HEADER
*dos
;
119 IMAGE_SECTION_HEADER
*sections
;
123 const IMAGE_BASE_RELOCATION
*rel
;
124 unsigned long rel_size
;
125 int rel_idx
= IMAGE_DIRECTORY_ENTRY_BASERELOC
;
128 unsigned long virt_size
= 0;
129 bool can_run_nt64
= true;
130 bool can_run_nt32
= true;
132 #if defined(CONFIG_ARM64)
133 can_run_nt32
= false;
134 #elif defined(CONFIG_ARM)
135 can_run_nt64
= false;
139 if (dos
->e_magic
!= IMAGE_DOS_SIGNATURE
) {
140 printf("%s: Invalid DOS Signature\n", __func__
);
144 nt
= (void *) ((char *)efi
+ dos
->e_lfanew
);
145 if (nt
->Signature
!= IMAGE_NT_SIGNATURE
) {
146 printf("%s: Invalid NT Signature\n", __func__
);
150 /* Calculate upper virtual address boundary */
151 num_sections
= nt
->FileHeader
.NumberOfSections
;
152 sections
= (void *)&nt
->OptionalHeader
+
153 nt
->FileHeader
.SizeOfOptionalHeader
;
155 for (i
= num_sections
- 1; i
>= 0; i
--) {
156 IMAGE_SECTION_HEADER
*sec
= §ions
[i
];
157 virt_size
= max_t(unsigned long, virt_size
,
158 sec
->VirtualAddress
+ sec
->Misc
.VirtualSize
);
161 /* Read 32/64bit specific header bits */
163 (nt
->OptionalHeader
.Magic
== IMAGE_NT_OPTIONAL_HDR64_MAGIC
)) {
164 IMAGE_NT_HEADERS64
*nt64
= (void *)nt
;
165 IMAGE_OPTIONAL_HEADER64
*opt
= &nt64
->OptionalHeader
;
166 image_size
= opt
->SizeOfImage
;
167 efi_set_code_and_data_type(loaded_image_info
, opt
->Subsystem
);
168 efi_reloc
= efi_alloc(virt_size
,
169 loaded_image_info
->image_code_type
);
171 printf("%s: Could not allocate %lu bytes\n",
172 __func__
, virt_size
);
175 entry
= efi_reloc
+ opt
->AddressOfEntryPoint
;
176 rel_size
= opt
->DataDirectory
[rel_idx
].Size
;
177 rel
= efi_reloc
+ opt
->DataDirectory
[rel_idx
].VirtualAddress
;
178 } else if (can_run_nt32
&&
179 (nt
->OptionalHeader
.Magic
== IMAGE_NT_OPTIONAL_HDR32_MAGIC
)) {
180 IMAGE_OPTIONAL_HEADER32
*opt
= &nt
->OptionalHeader
;
181 image_size
= opt
->SizeOfImage
;
182 efi_set_code_and_data_type(loaded_image_info
, opt
->Subsystem
);
183 efi_reloc
= efi_alloc(virt_size
,
184 loaded_image_info
->image_code_type
);
186 printf("%s: Could not allocate %lu bytes\n",
187 __func__
, virt_size
);
190 entry
= efi_reloc
+ opt
->AddressOfEntryPoint
;
191 rel_size
= opt
->DataDirectory
[rel_idx
].Size
;
192 rel
= efi_reloc
+ opt
->DataDirectory
[rel_idx
].VirtualAddress
;
194 printf("%s: Invalid optional header magic %x\n", __func__
,
195 nt
->OptionalHeader
.Magic
);
199 /* Load sections into RAM */
200 for (i
= num_sections
- 1; i
>= 0; i
--) {
201 IMAGE_SECTION_HEADER
*sec
= §ions
[i
];
202 memset(efi_reloc
+ sec
->VirtualAddress
, 0,
203 sec
->Misc
.VirtualSize
);
204 memcpy(efi_reloc
+ sec
->VirtualAddress
,
205 efi
+ sec
->PointerToRawData
,
209 /* Run through relocations */
210 if (efi_loader_relocate(rel
, rel_size
, efi_reloc
) != EFI_SUCCESS
) {
211 efi_free_pages((uintptr_t) efi_reloc
,
212 (virt_size
+ EFI_PAGE_MASK
) >> EFI_PAGE_SHIFT
);
217 flush_cache((ulong
)efi_reloc
,
218 ALIGN(virt_size
, CONFIG_SYS_CACHELINE_SIZE
));
219 invalidate_icache_all();
221 /* Populate the loaded image interface bits */
222 loaded_image_info
->image_base
= efi
;
223 loaded_image_info
->image_size
= image_size
;