1 // SPDX-License-Identifier: GPL-2.0+ 2 /* 3 * EFI image loader 4 * 5 * based partly on wine code 6 * 7 * Copyright (c) 2016 Alexander Graf 8 */ 9 10 #include <common.h> 11 #include <efi_loader.h> 12 #include <pe.h> 13 14 const efi_guid_t efi_global_variable_guid = EFI_GLOBAL_VARIABLE_GUID; 15 const efi_guid_t efi_guid_device_path = DEVICE_PATH_GUID; 16 const efi_guid_t efi_guid_loaded_image = LOADED_IMAGE_GUID; 17 const efi_guid_t efi_simple_file_system_protocol_guid = 18 EFI_SIMPLE_FILE_SYSTEM_PROTOCOL_GUID; 19 const efi_guid_t efi_file_info_guid = EFI_FILE_INFO_GUID; 20 21 static int machines[] = { 22 #if defined(__aarch64__) 23 IMAGE_FILE_MACHINE_ARM64, 24 #elif defined(__arm__) 25 IMAGE_FILE_MACHINE_ARM, 26 IMAGE_FILE_MACHINE_THUMB, 27 IMAGE_FILE_MACHINE_ARMNT, 28 #endif 29 30 #if defined(__x86_64__) 31 IMAGE_FILE_MACHINE_AMD64, 32 #elif defined(__i386__) 33 IMAGE_FILE_MACHINE_I386, 34 #endif 35 36 #if defined(__riscv) && (__riscv_xlen == 32) 37 IMAGE_FILE_MACHINE_RISCV32, 38 #endif 39 40 #if defined(__riscv) && (__riscv_xlen == 64) 41 IMAGE_FILE_MACHINE_RISCV64, 42 #endif 43 0 }; 44 45 /* 46 * Print information about a loaded image. 47 * 48 * If the program counter is located within the image the offset to the base 49 * address is shown. 50 * 51 * @obj: EFI object 52 * @image: loaded image 53 * @pc: program counter (use NULL to suppress offset output) 54 * @return: status code 55 */ 56 static efi_status_t efi_print_image_info(struct efi_loaded_image_obj *obj, 57 struct efi_loaded_image *image, 58 void *pc) 59 { 60 printf("UEFI image"); 61 printf(" [0x%p:0x%p]", 62 obj->reloc_base, obj->reloc_base + obj->reloc_size - 1); 63 if (pc && pc >= obj->reloc_base && 64 pc < obj->reloc_base + obj->reloc_size) 65 printf(" pc=0x%zx", pc - obj->reloc_base); 66 if (image->file_path) 67 printf(" '%pD'", image->file_path); 68 printf("\n"); 69 return EFI_SUCCESS; 70 } 71 72 /* 73 * Print information about all loaded images. 74 * 75 * @pc: program counter (use NULL to suppress offset output) 76 */ 77 void efi_print_image_infos(void *pc) 78 { 79 struct efi_object *efiobj; 80 struct efi_handler *handler; 81 82 list_for_each_entry(efiobj, &efi_obj_list, link) { 83 list_for_each_entry(handler, &efiobj->protocols, link) { 84 if (!guidcmp(handler->guid, &efi_guid_loaded_image)) { 85 efi_print_image_info( 86 (struct efi_loaded_image_obj *)efiobj, 87 handler->protocol_interface, pc); 88 } 89 } 90 } 91 } 92 93 static efi_status_t efi_loader_relocate(const IMAGE_BASE_RELOCATION *rel, 94 unsigned long rel_size, void *efi_reloc, 95 unsigned long pref_address) 96 { 97 unsigned long delta = (unsigned long)efi_reloc - pref_address; 98 const IMAGE_BASE_RELOCATION *end; 99 int i; 100 101 if (delta == 0) 102 return EFI_SUCCESS; 103 104 end = (const IMAGE_BASE_RELOCATION *)((const char *)rel + rel_size); 105 while (rel < end - 1 && rel->SizeOfBlock) { 106 const uint16_t *relocs = (const uint16_t *)(rel + 1); 107 i = (rel->SizeOfBlock - sizeof(*rel)) / sizeof(uint16_t); 108 while (i--) { 109 uint32_t offset = (uint32_t)(*relocs & 0xfff) + 110 rel->VirtualAddress; 111 int type = *relocs >> EFI_PAGE_SHIFT; 112 uint64_t *x64 = efi_reloc + offset; 113 uint32_t *x32 = efi_reloc + offset; 114 uint16_t *x16 = efi_reloc + offset; 115 116 switch (type) { 117 case IMAGE_REL_BASED_ABSOLUTE: 118 break; 119 case IMAGE_REL_BASED_HIGH: 120 *x16 += ((uint32_t)delta) >> 16; 121 break; 122 case IMAGE_REL_BASED_LOW: 123 *x16 += (uint16_t)delta; 124 break; 125 case IMAGE_REL_BASED_HIGHLOW: 126 *x32 += (uint32_t)delta; 127 break; 128 case IMAGE_REL_BASED_DIR64: 129 *x64 += (uint64_t)delta; 130 break; 131 #ifdef __riscv 132 case IMAGE_REL_BASED_RISCV_HI20: 133 *x32 = ((*x32 & 0xfffff000) + (uint32_t)delta) | 134 (*x32 & 0x00000fff); 135 break; 136 case IMAGE_REL_BASED_RISCV_LOW12I: 137 case IMAGE_REL_BASED_RISCV_LOW12S: 138 /* We know that we're 4k aligned */ 139 if (delta & 0xfff) { 140 printf("Unsupported reloc offset\n"); 141 return EFI_LOAD_ERROR; 142 } 143 break; 144 #endif 145 default: 146 printf("Unknown Relocation off %x type %x\n", 147 offset, type); 148 return EFI_LOAD_ERROR; 149 } 150 relocs++; 151 } 152 rel = (const IMAGE_BASE_RELOCATION *)relocs; 153 } 154 return EFI_SUCCESS; 155 } 156 157 void __weak invalidate_icache_all(void) 158 { 159 /* If the system doesn't support icache_all flush, cross our fingers */ 160 } 161 162 /* 163 * Determine the memory types to be used for code and data. 164 * 165 * @loaded_image_info image descriptor 166 * @image_type field Subsystem of the optional header for 167 * Windows specific field 168 */ 169 static void efi_set_code_and_data_type( 170 struct efi_loaded_image *loaded_image_info, 171 uint16_t image_type) 172 { 173 switch (image_type) { 174 case IMAGE_SUBSYSTEM_EFI_APPLICATION: 175 loaded_image_info->image_code_type = EFI_LOADER_CODE; 176 loaded_image_info->image_data_type = EFI_LOADER_DATA; 177 break; 178 case IMAGE_SUBSYSTEM_EFI_BOOT_SERVICE_DRIVER: 179 loaded_image_info->image_code_type = EFI_BOOT_SERVICES_CODE; 180 loaded_image_info->image_data_type = EFI_BOOT_SERVICES_DATA; 181 break; 182 case IMAGE_SUBSYSTEM_EFI_RUNTIME_DRIVER: 183 case IMAGE_SUBSYSTEM_EFI_ROM: 184 loaded_image_info->image_code_type = EFI_RUNTIME_SERVICES_CODE; 185 loaded_image_info->image_data_type = EFI_RUNTIME_SERVICES_DATA; 186 break; 187 default: 188 printf("%s: invalid image type: %u\n", __func__, image_type); 189 /* Let's assume it is an application */ 190 loaded_image_info->image_code_type = EFI_LOADER_CODE; 191 loaded_image_info->image_data_type = EFI_LOADER_DATA; 192 break; 193 } 194 } 195 196 /* 197 * This function loads all sections from a PE binary into a newly reserved 198 * piece of memory. On successful load it then returns the entry point for 199 * the binary. Otherwise NULL. 200 */ 201 void *efi_load_pe(struct efi_loaded_image_obj *handle, void *efi, 202 struct efi_loaded_image *loaded_image_info) 203 { 204 IMAGE_NT_HEADERS32 *nt; 205 IMAGE_DOS_HEADER *dos; 206 IMAGE_SECTION_HEADER *sections; 207 int num_sections; 208 void *efi_reloc; 209 int i; 210 const IMAGE_BASE_RELOCATION *rel; 211 unsigned long rel_size; 212 int rel_idx = IMAGE_DIRECTORY_ENTRY_BASERELOC; 213 void *entry; 214 uint64_t image_base; 215 uint64_t image_size; 216 unsigned long virt_size = 0; 217 int supported = 0; 218 219 dos = efi; 220 if (dos->e_magic != IMAGE_DOS_SIGNATURE) { 221 printf("%s: Invalid DOS Signature\n", __func__); 222 return NULL; 223 } 224 225 nt = (void *) ((char *)efi + dos->e_lfanew); 226 if (nt->Signature != IMAGE_NT_SIGNATURE) { 227 printf("%s: Invalid NT Signature\n", __func__); 228 return NULL; 229 } 230 231 for (i = 0; machines[i]; i++) 232 if (machines[i] == nt->FileHeader.Machine) { 233 supported = 1; 234 break; 235 } 236 237 if (!supported) { 238 printf("%s: Machine type 0x%04x is not supported\n", 239 __func__, nt->FileHeader.Machine); 240 return NULL; 241 } 242 243 /* Calculate upper virtual address boundary */ 244 num_sections = nt->FileHeader.NumberOfSections; 245 sections = (void *)&nt->OptionalHeader + 246 nt->FileHeader.SizeOfOptionalHeader; 247 248 for (i = num_sections - 1; i >= 0; i--) { 249 IMAGE_SECTION_HEADER *sec = §ions[i]; 250 virt_size = max_t(unsigned long, virt_size, 251 sec->VirtualAddress + sec->Misc.VirtualSize); 252 } 253 254 /* Read 32/64bit specific header bits */ 255 if (nt->OptionalHeader.Magic == IMAGE_NT_OPTIONAL_HDR64_MAGIC) { 256 IMAGE_NT_HEADERS64 *nt64 = (void *)nt; 257 IMAGE_OPTIONAL_HEADER64 *opt = &nt64->OptionalHeader; 258 image_base = opt->ImageBase; 259 image_size = opt->SizeOfImage; 260 efi_set_code_and_data_type(loaded_image_info, opt->Subsystem); 261 efi_reloc = efi_alloc(virt_size, 262 loaded_image_info->image_code_type); 263 if (!efi_reloc) { 264 printf("%s: Could not allocate %lu bytes\n", 265 __func__, virt_size); 266 return NULL; 267 } 268 entry = efi_reloc + opt->AddressOfEntryPoint; 269 rel_size = opt->DataDirectory[rel_idx].Size; 270 rel = efi_reloc + opt->DataDirectory[rel_idx].VirtualAddress; 271 virt_size = ALIGN(virt_size, opt->SectionAlignment); 272 } else if (nt->OptionalHeader.Magic == IMAGE_NT_OPTIONAL_HDR32_MAGIC) { 273 IMAGE_OPTIONAL_HEADER32 *opt = &nt->OptionalHeader; 274 image_base = opt->ImageBase; 275 image_size = opt->SizeOfImage; 276 efi_set_code_and_data_type(loaded_image_info, opt->Subsystem); 277 efi_reloc = efi_alloc(virt_size, 278 loaded_image_info->image_code_type); 279 if (!efi_reloc) { 280 printf("%s: Could not allocate %lu bytes\n", 281 __func__, virt_size); 282 return NULL; 283 } 284 entry = efi_reloc + opt->AddressOfEntryPoint; 285 rel_size = opt->DataDirectory[rel_idx].Size; 286 rel = efi_reloc + opt->DataDirectory[rel_idx].VirtualAddress; 287 virt_size = ALIGN(virt_size, opt->SectionAlignment); 288 } else { 289 printf("%s: Invalid optional header magic %x\n", __func__, 290 nt->OptionalHeader.Magic); 291 return NULL; 292 } 293 294 /* Load sections into RAM */ 295 for (i = num_sections - 1; i >= 0; i--) { 296 IMAGE_SECTION_HEADER *sec = §ions[i]; 297 memset(efi_reloc + sec->VirtualAddress, 0, 298 sec->Misc.VirtualSize); 299 memcpy(efi_reloc + sec->VirtualAddress, 300 efi + sec->PointerToRawData, 301 sec->SizeOfRawData); 302 } 303 304 /* Run through relocations */ 305 if (efi_loader_relocate(rel, rel_size, efi_reloc, 306 (unsigned long)image_base) != EFI_SUCCESS) { 307 efi_free_pages((uintptr_t) efi_reloc, 308 (virt_size + EFI_PAGE_MASK) >> EFI_PAGE_SHIFT); 309 return NULL; 310 } 311 312 /* Flush cache */ 313 flush_cache((ulong)efi_reloc, 314 ALIGN(virt_size, EFI_CACHELINE_SIZE)); 315 invalidate_icache_all(); 316 317 /* Populate the loaded image interface bits */ 318 loaded_image_info->image_base = efi; 319 loaded_image_info->image_size = image_size; 320 handle->reloc_base = efi_reloc; 321 handle->reloc_size = virt_size; 322 323 return entry; 324 } 325