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_guid_device_path
= DEVICE_PATH_GUID
;
19 const efi_guid_t efi_guid_loaded_image
= LOADED_IMAGE_GUID
;
21 efi_status_t EFIAPI
efi_return_handle(void *handle
, efi_guid_t
*protocol
,
22 void **protocol_interface
, void *agent_handle
,
23 void *controller_handle
, uint32_t attributes
)
25 *protocol_interface
= handle
;
29 static void efi_loader_relocate(const IMAGE_BASE_RELOCATION
*rel
,
30 unsigned long rel_size
, void *efi_reloc
)
32 const IMAGE_BASE_RELOCATION
*end
;
35 end
= (const IMAGE_BASE_RELOCATION
*)((const char *)rel
+ rel_size
);
36 while (rel
< end
- 1 && rel
->SizeOfBlock
) {
37 const uint16_t *relocs
= (const uint16_t *)(rel
+ 1);
38 i
= (rel
->SizeOfBlock
- sizeof(*rel
)) / sizeof(uint16_t);
40 uint32_t offset
= (uint32_t)(*relocs
& 0xfff) +
42 int type
= *relocs
>> EFI_PAGE_SHIFT
;
43 unsigned long delta
= (unsigned long)efi_reloc
;
44 uint64_t *x64
= efi_reloc
+ offset
;
45 uint32_t *x32
= efi_reloc
+ offset
;
46 uint16_t *x16
= efi_reloc
+ offset
;
49 case IMAGE_REL_BASED_ABSOLUTE
:
51 case IMAGE_REL_BASED_HIGH
:
52 *x16
+= ((uint32_t)delta
) >> 16;
54 case IMAGE_REL_BASED_LOW
:
55 *x16
+= (uint16_t)delta
;
57 case IMAGE_REL_BASED_HIGHLOW
:
58 *x32
+= (uint32_t)delta
;
60 case IMAGE_REL_BASED_DIR64
:
61 *x64
+= (uint64_t)delta
;
64 printf("Unknown Relocation off %x type %x\n",
69 rel
= (const IMAGE_BASE_RELOCATION
*)relocs
;
73 void __weak
invalidate_icache_all(void)
75 /* If the system doesn't support icache_all flush, cross our fingers */
79 * This function loads all sections from a PE binary into a newly reserved
80 * piece of memory. On successful load it then returns the entry point for
81 * the binary. Otherwise NULL.
83 void *efi_load_pe(void *efi
, struct efi_loaded_image
*loaded_image_info
)
85 IMAGE_NT_HEADERS32
*nt
;
86 IMAGE_DOS_HEADER
*dos
;
87 IMAGE_SECTION_HEADER
*sections
;
91 const IMAGE_BASE_RELOCATION
*rel
;
92 unsigned long rel_size
;
93 int rel_idx
= IMAGE_DIRECTORY_ENTRY_BASERELOC
;
96 unsigned long virt_size
= 0;
97 bool can_run_nt64
= true;
98 bool can_run_nt32
= true;
100 #if defined(CONFIG_ARM64)
101 can_run_nt32
= false;
102 #elif defined(CONFIG_ARM)
103 can_run_nt64
= false;
107 if (dos
->e_magic
!= IMAGE_DOS_SIGNATURE
) {
108 printf("%s: Invalid DOS Signature\n", __func__
);
112 nt
= (void *) ((char *)efi
+ dos
->e_lfanew
);
113 if (nt
->Signature
!= IMAGE_NT_SIGNATURE
) {
114 printf("%s: Invalid NT Signature\n", __func__
);
118 /* Calculate upper virtual address boundary */
119 num_sections
= nt
->FileHeader
.NumberOfSections
;
120 sections
= (void *)&nt
->OptionalHeader
+
121 nt
->FileHeader
.SizeOfOptionalHeader
;
123 for (i
= num_sections
- 1; i
>= 0; i
--) {
124 IMAGE_SECTION_HEADER
*sec
= §ions
[i
];
125 virt_size
= max_t(unsigned long, virt_size
,
126 sec
->VirtualAddress
+ sec
->Misc
.VirtualSize
);
129 /* Read 32/64bit specific header bits */
131 (nt
->OptionalHeader
.Magic
== IMAGE_NT_OPTIONAL_HDR64_MAGIC
)) {
132 IMAGE_NT_HEADERS64
*nt64
= (void *)nt
;
133 IMAGE_OPTIONAL_HEADER64
*opt
= &nt64
->OptionalHeader
;
134 image_size
= opt
->SizeOfImage
;
135 efi_reloc
= efi_alloc(virt_size
, EFI_LOADER_DATA
);
137 printf("%s: Could not allocate %ld bytes\n",
138 __func__
, virt_size
);
141 entry
= efi_reloc
+ opt
->AddressOfEntryPoint
;
142 rel_size
= opt
->DataDirectory
[rel_idx
].Size
;
143 rel
= efi_reloc
+ opt
->DataDirectory
[rel_idx
].VirtualAddress
;
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 %ld 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
;
158 printf("%s: Invalid optional header magic %x\n", __func__
,
159 nt
->OptionalHeader
.Magic
);
163 /* Load sections into RAM */
164 for (i
= num_sections
- 1; i
>= 0; i
--) {
165 IMAGE_SECTION_HEADER
*sec
= §ions
[i
];
166 memset(efi_reloc
+ sec
->VirtualAddress
, 0,
167 sec
->Misc
.VirtualSize
);
168 memcpy(efi_reloc
+ sec
->VirtualAddress
,
169 efi
+ sec
->PointerToRawData
,
173 /* Run through relocations */
174 efi_loader_relocate(rel
, rel_size
, efi_reloc
);
177 flush_cache((ulong
)efi_reloc
,
178 ALIGN(virt_size
, CONFIG_SYS_CACHELINE_SIZE
));
179 invalidate_icache_all();
181 /* Populate the loaded image interface bits */
182 loaded_image_info
->image_base
= efi
;
183 loaded_image_info
->image_size
= image_size
;