efi_image_loader.c 5.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187
  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. #include <common.h>
  11. #include <efi_loader.h>
  12. #include <pe.h>
  13. #include <asm/global_data.h>
  14. DECLARE_GLOBAL_DATA_PTR;
  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. static efi_status_t efi_loader_relocate(const IMAGE_BASE_RELOCATION *rel,
  21. unsigned long rel_size, void *efi_reloc)
  22. {
  23. const IMAGE_BASE_RELOCATION *end;
  24. int i;
  25. end = (const IMAGE_BASE_RELOCATION *)((const char *)rel + rel_size);
  26. while (rel < end - 1 && rel->SizeOfBlock) {
  27. const uint16_t *relocs = (const uint16_t *)(rel + 1);
  28. i = (rel->SizeOfBlock - sizeof(*rel)) / sizeof(uint16_t);
  29. while (i--) {
  30. uint32_t offset = (uint32_t)(*relocs & 0xfff) +
  31. rel->VirtualAddress;
  32. int type = *relocs >> EFI_PAGE_SHIFT;
  33. unsigned long delta = (unsigned long)efi_reloc;
  34. uint64_t *x64 = efi_reloc + offset;
  35. uint32_t *x32 = efi_reloc + offset;
  36. uint16_t *x16 = efi_reloc + offset;
  37. switch (type) {
  38. case IMAGE_REL_BASED_ABSOLUTE:
  39. break;
  40. case IMAGE_REL_BASED_HIGH:
  41. *x16 += ((uint32_t)delta) >> 16;
  42. break;
  43. case IMAGE_REL_BASED_LOW:
  44. *x16 += (uint16_t)delta;
  45. break;
  46. case IMAGE_REL_BASED_HIGHLOW:
  47. *x32 += (uint32_t)delta;
  48. break;
  49. case IMAGE_REL_BASED_DIR64:
  50. *x64 += (uint64_t)delta;
  51. break;
  52. default:
  53. printf("Unknown Relocation off %x type %x\n",
  54. offset, type);
  55. return EFI_LOAD_ERROR;
  56. }
  57. relocs++;
  58. }
  59. rel = (const IMAGE_BASE_RELOCATION *)relocs;
  60. }
  61. return EFI_SUCCESS;
  62. }
  63. void __weak invalidate_icache_all(void)
  64. {
  65. /* If the system doesn't support icache_all flush, cross our fingers */
  66. }
  67. /*
  68. * This function loads all sections from a PE binary into a newly reserved
  69. * piece of memory. On successful load it then returns the entry point for
  70. * the binary. Otherwise NULL.
  71. */
  72. void *efi_load_pe(void *efi, struct efi_loaded_image *loaded_image_info)
  73. {
  74. IMAGE_NT_HEADERS32 *nt;
  75. IMAGE_DOS_HEADER *dos;
  76. IMAGE_SECTION_HEADER *sections;
  77. int num_sections;
  78. void *efi_reloc;
  79. int i;
  80. const IMAGE_BASE_RELOCATION *rel;
  81. unsigned long rel_size;
  82. int rel_idx = IMAGE_DIRECTORY_ENTRY_BASERELOC;
  83. void *entry;
  84. uint64_t image_size;
  85. unsigned long virt_size = 0;
  86. bool can_run_nt64 = true;
  87. bool can_run_nt32 = true;
  88. #if defined(CONFIG_ARM64)
  89. can_run_nt32 = false;
  90. #elif defined(CONFIG_ARM)
  91. can_run_nt64 = false;
  92. #endif
  93. dos = efi;
  94. if (dos->e_magic != IMAGE_DOS_SIGNATURE) {
  95. printf("%s: Invalid DOS Signature\n", __func__);
  96. return NULL;
  97. }
  98. nt = (void *) ((char *)efi + dos->e_lfanew);
  99. if (nt->Signature != IMAGE_NT_SIGNATURE) {
  100. printf("%s: Invalid NT Signature\n", __func__);
  101. return NULL;
  102. }
  103. /* Calculate upper virtual address boundary */
  104. num_sections = nt->FileHeader.NumberOfSections;
  105. sections = (void *)&nt->OptionalHeader +
  106. nt->FileHeader.SizeOfOptionalHeader;
  107. for (i = num_sections - 1; i >= 0; i--) {
  108. IMAGE_SECTION_HEADER *sec = &sections[i];
  109. virt_size = max_t(unsigned long, virt_size,
  110. sec->VirtualAddress + sec->Misc.VirtualSize);
  111. }
  112. /* Read 32/64bit specific header bits */
  113. if (can_run_nt64 &&
  114. (nt->OptionalHeader.Magic == IMAGE_NT_OPTIONAL_HDR64_MAGIC)) {
  115. IMAGE_NT_HEADERS64 *nt64 = (void *)nt;
  116. IMAGE_OPTIONAL_HEADER64 *opt = &nt64->OptionalHeader;
  117. image_size = opt->SizeOfImage;
  118. efi_reloc = efi_alloc(virt_size, EFI_LOADER_DATA);
  119. if (!efi_reloc) {
  120. printf("%s: Could not allocate %ld bytes\n",
  121. __func__, virt_size);
  122. return NULL;
  123. }
  124. entry = efi_reloc + opt->AddressOfEntryPoint;
  125. rel_size = opt->DataDirectory[rel_idx].Size;
  126. rel = efi_reloc + opt->DataDirectory[rel_idx].VirtualAddress;
  127. } else if (can_run_nt32 &&
  128. (nt->OptionalHeader.Magic == IMAGE_NT_OPTIONAL_HDR32_MAGIC)) {
  129. IMAGE_OPTIONAL_HEADER32 *opt = &nt->OptionalHeader;
  130. image_size = opt->SizeOfImage;
  131. efi_reloc = efi_alloc(virt_size, EFI_LOADER_DATA);
  132. if (!efi_reloc) {
  133. printf("%s: Could not allocate %ld bytes\n",
  134. __func__, virt_size);
  135. return NULL;
  136. }
  137. entry = efi_reloc + opt->AddressOfEntryPoint;
  138. rel_size = opt->DataDirectory[rel_idx].Size;
  139. rel = efi_reloc + opt->DataDirectory[rel_idx].VirtualAddress;
  140. } else {
  141. printf("%s: Invalid optional header magic %x\n", __func__,
  142. nt->OptionalHeader.Magic);
  143. return NULL;
  144. }
  145. /* Load sections into RAM */
  146. for (i = num_sections - 1; i >= 0; i--) {
  147. IMAGE_SECTION_HEADER *sec = &sections[i];
  148. memset(efi_reloc + sec->VirtualAddress, 0,
  149. sec->Misc.VirtualSize);
  150. memcpy(efi_reloc + sec->VirtualAddress,
  151. efi + sec->PointerToRawData,
  152. sec->SizeOfRawData);
  153. }
  154. /* Run through relocations */
  155. if (efi_loader_relocate(rel, rel_size, efi_reloc) != EFI_SUCCESS) {
  156. efi_free_pages((uintptr_t) efi_reloc,
  157. (virt_size + EFI_PAGE_MASK) >> EFI_PAGE_SHIFT);
  158. return NULL;
  159. }
  160. /* Flush cache */
  161. flush_cache((ulong)efi_reloc,
  162. ALIGN(virt_size, CONFIG_SYS_CACHELINE_SIZE));
  163. invalidate_icache_all();
  164. /* Populate the loaded image interface bits */
  165. loaded_image_info->image_base = efi;
  166. loaded_image_info->image_size = image_size;
  167. return entry;
  168. }