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 * This function loads all sections from a PE binary into a newly reserved
78 * piece of memory. On successful load it then returns the entry point for
79 * the binary. Otherwise NULL.
81 void *efi_load_pe(void *efi
, struct efi_loaded_image
*loaded_image_info
)
83 IMAGE_NT_HEADERS32
*nt
;
84 IMAGE_DOS_HEADER
*dos
;
85 IMAGE_SECTION_HEADER
*sections
;
89 const IMAGE_BASE_RELOCATION
*rel
;
90 unsigned long rel_size
;
91 int rel_idx
= IMAGE_DIRECTORY_ENTRY_BASERELOC
;
94 unsigned long virt_size
= 0;
95 bool can_run_nt64
= true;
96 bool can_run_nt32
= true;
99 #if defined(CONFIG_ARM64)
100 can_run_nt32
= false;
101 #elif defined(CONFIG_ARM)
102 can_run_nt64
= false;
106 if (dos
->e_magic
!= IMAGE_DOS_SIGNATURE
) {
107 printf("%s: Invalid DOS Signature\n", __func__
);
111 nt
= (void *) ((char *)efi
+ dos
->e_lfanew
);
112 if (nt
->Signature
!= IMAGE_NT_SIGNATURE
) {
113 printf("%s: Invalid NT Signature\n", __func__
);
117 /* Calculate upper virtual address boundary */
118 num_sections
= nt
->FileHeader
.NumberOfSections
;
119 sections
= (void *)&nt
->OptionalHeader
+
120 nt
->FileHeader
.SizeOfOptionalHeader
;
122 for (i
= num_sections
- 1; i
>= 0; i
--) {
123 IMAGE_SECTION_HEADER
*sec
= §ions
[i
];
124 virt_size
= max_t(unsigned long, virt_size
,
125 sec
->VirtualAddress
+ sec
->Misc
.VirtualSize
);
128 /* Read 32/64bit specific header bits */
130 (nt
->OptionalHeader
.Magic
== IMAGE_NT_OPTIONAL_HDR64_MAGIC
)) {
131 IMAGE_NT_HEADERS64
*nt64
= (void *)nt
;
132 IMAGE_OPTIONAL_HEADER64
*opt
= &nt64
->OptionalHeader
;
133 image_size
= opt
->SizeOfImage
;
134 efi_reloc
= efi_alloc(virt_size
, EFI_LOADER_DATA
);
136 printf("%s: Could not allocate %lu bytes\n",
137 __func__
, virt_size
);
140 entry
= efi_reloc
+ opt
->AddressOfEntryPoint
;
141 rel_size
= opt
->DataDirectory
[rel_idx
].Size
;
142 rel
= efi_reloc
+ opt
->DataDirectory
[rel_idx
].VirtualAddress
;
143 image_type
= opt
->Subsystem
;
144 } else if (can_run_nt32
&&
145 (nt
->OptionalHeader
.Magic
== IMAGE_NT_OPTIONAL_HDR32_MAGIC
)) {
146 IMAGE_OPTIONAL_HEADER32
*opt
= &nt
->OptionalHeader
;
147 image_size
= opt
->SizeOfImage
;
148 efi_reloc
= efi_alloc(virt_size
, EFI_LOADER_DATA
);
150 printf("%s: Could not allocate %lu bytes\n",
151 __func__
, virt_size
);
154 entry
= efi_reloc
+ opt
->AddressOfEntryPoint
;
155 rel_size
= opt
->DataDirectory
[rel_idx
].Size
;
156 rel
= efi_reloc
+ opt
->DataDirectory
[rel_idx
].VirtualAddress
;
157 image_type
= opt
->Subsystem
;
159 printf("%s: Invalid optional header magic %x\n", __func__
,
160 nt
->OptionalHeader
.Magic
);
164 switch (image_type
) {
165 case IMAGE_SUBSYSTEM_EFI_APPLICATION
:
166 loaded_image_info
->image_code_type
= EFI_LOADER_CODE
;
167 loaded_image_info
->image_data_type
= EFI_LOADER_DATA
;
169 case IMAGE_SUBSYSTEM_EFI_BOOT_SERVICE_DRIVER
:
170 loaded_image_info
->image_code_type
= EFI_BOOT_SERVICES_CODE
;
171 loaded_image_info
->image_data_type
= EFI_BOOT_SERVICES_DATA
;
173 case IMAGE_SUBSYSTEM_EFI_RUNTIME_DRIVER
:
174 case IMAGE_SUBSYSTEM_SAL_RUNTIME_DRIVER
:
175 loaded_image_info
->image_code_type
= EFI_RUNTIME_SERVICES_CODE
;
176 loaded_image_info
->image_data_type
= EFI_RUNTIME_SERVICES_DATA
;
179 printf("%s: invalid image type: %u\n", __func__
, image_type
);
183 /* Load sections into RAM */
184 for (i
= num_sections
- 1; i
>= 0; i
--) {
185 IMAGE_SECTION_HEADER
*sec
= §ions
[i
];
186 memset(efi_reloc
+ sec
->VirtualAddress
, 0,
187 sec
->Misc
.VirtualSize
);
188 memcpy(efi_reloc
+ sec
->VirtualAddress
,
189 efi
+ sec
->PointerToRawData
,
193 /* Run through relocations */
194 if (efi_loader_relocate(rel
, rel_size
, efi_reloc
) != EFI_SUCCESS
) {
195 efi_free_pages((uintptr_t) efi_reloc
,
196 (virt_size
+ EFI_PAGE_MASK
) >> EFI_PAGE_SHIFT
);
201 flush_cache((ulong
)efi_reloc
,
202 ALIGN(virt_size
, CONFIG_SYS_CACHELINE_SIZE
));
203 invalidate_icache_all();
205 /* Populate the loaded image interface bits */
206 loaded_image_info
->image_base
= efi
;
207 loaded_image_info
->image_size
= image_size
;