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