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 efi_status_t
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",
66 return EFI_LOAD_ERROR
;
70 rel
= (const IMAGE_BASE_RELOCATION
*)relocs
;
75 void __weak
invalidate_icache_all(void)
77 /* If the system doesn't support icache_all flush, cross our fingers */
81 * This function loads all sections from a PE binary into a newly reserved
82 * piece of memory. On successful load it then returns the entry point for
83 * the binary. Otherwise NULL.
85 void *efi_load_pe(void *efi
, struct efi_loaded_image
*loaded_image_info
)
87 IMAGE_NT_HEADERS32
*nt
;
88 IMAGE_DOS_HEADER
*dos
;
89 IMAGE_SECTION_HEADER
*sections
;
93 const IMAGE_BASE_RELOCATION
*rel
;
94 unsigned long rel_size
;
95 int rel_idx
= IMAGE_DIRECTORY_ENTRY_BASERELOC
;
98 unsigned long virt_size
= 0;
99 bool can_run_nt64
= true;
100 bool can_run_nt32
= true;
102 #if defined(CONFIG_ARM64)
103 can_run_nt32
= false;
104 #elif defined(CONFIG_ARM)
105 can_run_nt64
= false;
109 if (dos
->e_magic
!= IMAGE_DOS_SIGNATURE
) {
110 printf("%s: Invalid DOS Signature\n", __func__
);
114 nt
= (void *) ((char *)efi
+ dos
->e_lfanew
);
115 if (nt
->Signature
!= IMAGE_NT_SIGNATURE
) {
116 printf("%s: Invalid NT Signature\n", __func__
);
120 /* Calculate upper virtual address boundary */
121 num_sections
= nt
->FileHeader
.NumberOfSections
;
122 sections
= (void *)&nt
->OptionalHeader
+
123 nt
->FileHeader
.SizeOfOptionalHeader
;
125 for (i
= num_sections
- 1; i
>= 0; i
--) {
126 IMAGE_SECTION_HEADER
*sec
= §ions
[i
];
127 virt_size
= max_t(unsigned long, virt_size
,
128 sec
->VirtualAddress
+ sec
->Misc
.VirtualSize
);
131 /* Read 32/64bit specific header bits */
133 (nt
->OptionalHeader
.Magic
== IMAGE_NT_OPTIONAL_HDR64_MAGIC
)) {
134 IMAGE_NT_HEADERS64
*nt64
= (void *)nt
;
135 IMAGE_OPTIONAL_HEADER64
*opt
= &nt64
->OptionalHeader
;
136 image_size
= opt
->SizeOfImage
;
137 efi_reloc
= efi_alloc(virt_size
, EFI_LOADER_DATA
);
139 printf("%s: Could not allocate %ld bytes\n",
140 __func__
, virt_size
);
143 entry
= efi_reloc
+ opt
->AddressOfEntryPoint
;
144 rel_size
= opt
->DataDirectory
[rel_idx
].Size
;
145 rel
= efi_reloc
+ opt
->DataDirectory
[rel_idx
].VirtualAddress
;
146 } else if (can_run_nt32
&&
147 (nt
->OptionalHeader
.Magic
== IMAGE_NT_OPTIONAL_HDR32_MAGIC
)) {
148 IMAGE_OPTIONAL_HEADER32
*opt
= &nt
->OptionalHeader
;
149 image_size
= opt
->SizeOfImage
;
150 efi_reloc
= efi_alloc(virt_size
, EFI_LOADER_DATA
);
152 printf("%s: Could not allocate %ld bytes\n",
153 __func__
, virt_size
);
156 entry
= efi_reloc
+ opt
->AddressOfEntryPoint
;
157 rel_size
= opt
->DataDirectory
[rel_idx
].Size
;
158 rel
= efi_reloc
+ opt
->DataDirectory
[rel_idx
].VirtualAddress
;
160 printf("%s: Invalid optional header magic %x\n", __func__
,
161 nt
->OptionalHeader
.Magic
);
165 /* Load sections into RAM */
166 for (i
= num_sections
- 1; i
>= 0; i
--) {
167 IMAGE_SECTION_HEADER
*sec
= §ions
[i
];
168 memset(efi_reloc
+ sec
->VirtualAddress
, 0,
169 sec
->Misc
.VirtualSize
);
170 memcpy(efi_reloc
+ sec
->VirtualAddress
,
171 efi
+ sec
->PointerToRawData
,
175 /* Run through relocations */
176 if (efi_loader_relocate(rel
, rel_size
, efi_reloc
) != EFI_SUCCESS
) {
177 efi_free_pages((uintptr_t) efi_reloc
,
178 (virt_size
+ EFI_PAGE_MASK
) >> EFI_PAGE_SHIFT
);
183 flush_cache((ulong
)efi_reloc
,
184 ALIGN(virt_size
, CONFIG_SYS_CACHELINE_SIZE
));
185 invalidate_icache_all();
187 /* Populate the loaded image interface bits */
188 loaded_image_info
->image_base
= efi
;
189 loaded_image_info
->image_size
= image_size
;