bootefi.c 5.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206
  1. /*
  2. * EFI application loader
  3. *
  4. * Copyright (c) 2016 Alexander Graf
  5. *
  6. * SPDX-License-Identifier: GPL-2.0+
  7. */
  8. #include <common.h>
  9. #include <command.h>
  10. #include <efi_loader.h>
  11. #include <errno.h>
  12. #include <libfdt.h>
  13. #include <libfdt_env.h>
  14. /*
  15. * When booting using the "bootefi" command, we don't know which
  16. * physical device the file came from. So we create a pseudo-device
  17. * called "bootefi" with the device path /bootefi.
  18. *
  19. * In addition to the originating device we also declare the file path
  20. * of "bootefi" based loads to be /bootefi.
  21. */
  22. static struct efi_device_path_file_path bootefi_image_path[] = {
  23. {
  24. .dp.type = DEVICE_PATH_TYPE_MEDIA_DEVICE,
  25. .dp.sub_type = DEVICE_PATH_SUB_TYPE_FILE_PATH,
  26. .dp.length = sizeof(bootefi_image_path[0]),
  27. .str = { 'b','o','o','t','e','f','i' },
  28. }, {
  29. .dp.type = DEVICE_PATH_TYPE_END,
  30. .dp.sub_type = DEVICE_PATH_SUB_TYPE_END,
  31. .dp.length = sizeof(bootefi_image_path[0]),
  32. }
  33. };
  34. static efi_status_t bootefi_open_dp(void *handle, efi_guid_t *protocol,
  35. void **protocol_interface, void *agent_handle,
  36. void *controller_handle, uint32_t attributes)
  37. {
  38. *protocol_interface = bootefi_image_path;
  39. return EFI_SUCCESS;
  40. }
  41. /* The EFI loaded_image interface for the image executed via "bootefi" */
  42. static struct efi_loaded_image loaded_image_info = {
  43. .device_handle = bootefi_image_path,
  44. .file_path = bootefi_image_path,
  45. };
  46. /* The EFI object struct for the image executed via "bootefi" */
  47. static struct efi_object loaded_image_info_obj = {
  48. .handle = &loaded_image_info,
  49. .protocols = {
  50. {
  51. /*
  52. * When asking for the loaded_image interface, just
  53. * return handle which points to loaded_image_info
  54. */
  55. .guid = &efi_guid_loaded_image,
  56. .open = &efi_return_handle,
  57. },
  58. {
  59. /*
  60. * When asking for the device path interface, return
  61. * bootefi_image_path
  62. */
  63. .guid = &efi_guid_device_path,
  64. .open = &bootefi_open_dp,
  65. },
  66. },
  67. };
  68. /* The EFI object struct for the device the "bootefi" image was loaded from */
  69. static struct efi_object bootefi_device_obj = {
  70. .handle = bootefi_image_path,
  71. .protocols = {
  72. {
  73. /* When asking for the device path interface, return
  74. * bootefi_image_path */
  75. .guid = &efi_guid_device_path,
  76. .open = &bootefi_open_dp,
  77. }
  78. },
  79. };
  80. /*
  81. * Load an EFI payload into a newly allocated piece of memory, register all
  82. * EFI objects it would want to access and jump to it.
  83. */
  84. static unsigned long do_bootefi_exec(void *efi)
  85. {
  86. ulong (*entry)(void *image_handle, struct efi_system_table *st);
  87. ulong fdt_pages, fdt_size, fdt_start, fdt_end;
  88. bootm_headers_t img = { 0 };
  89. /*
  90. * gd lives in a fixed register which may get clobbered while we execute
  91. * the payload. So save it here and restore it on every callback entry
  92. */
  93. efi_save_gd();
  94. /* Update system table to point to our currently loaded FDT */
  95. if (working_fdt) {
  96. /* Prepare fdt for payload */
  97. if (image_setup_libfdt(&img, working_fdt, 0, NULL)) {
  98. printf("ERROR: Failed to process device tree\n");
  99. return -EINVAL;
  100. }
  101. /* Link to it in the efi tables */
  102. systab.tables[0].guid = EFI_FDT_GUID;
  103. systab.tables[0].table = working_fdt;
  104. systab.nr_tables = 1;
  105. /* And reserve the space in the memory map */
  106. fdt_start = ((ulong)working_fdt) & ~EFI_PAGE_MASK;
  107. fdt_end = ((ulong)working_fdt) + fdt_totalsize(working_fdt);
  108. fdt_size = (fdt_end - fdt_start) + EFI_PAGE_MASK;
  109. fdt_pages = fdt_size >> EFI_PAGE_SHIFT;
  110. /* Give a bootloader the chance to modify the device tree */
  111. fdt_pages += 2;
  112. efi_add_memory_map(fdt_start, fdt_pages,
  113. EFI_BOOT_SERVICES_DATA, true);
  114. } else {
  115. printf("WARNING: No device tree loaded, expect boot to fail\n");
  116. systab.nr_tables = 0;
  117. }
  118. /* Load the EFI payload */
  119. entry = efi_load_pe(efi, &loaded_image_info);
  120. if (!entry)
  121. return -ENOENT;
  122. /* Initialize and populate EFI object list */
  123. INIT_LIST_HEAD(&efi_obj_list);
  124. list_add_tail(&loaded_image_info_obj.link, &efi_obj_list);
  125. list_add_tail(&bootefi_device_obj.link, &efi_obj_list);
  126. #ifdef CONFIG_PARTITIONS
  127. efi_disk_register();
  128. #endif
  129. /* Call our payload! */
  130. #ifdef DEBUG_EFI
  131. printf("%s:%d Jumping to 0x%lx\n", __func__, __LINE__, (long)entry);
  132. #endif
  133. return entry(&loaded_image_info, &systab);
  134. }
  135. /* Interpreter command to boot an arbitrary EFI image from memory */
  136. static int do_bootefi(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
  137. {
  138. char *saddr;
  139. unsigned long addr;
  140. int r = 0;
  141. if (argc < 2)
  142. return 1;
  143. saddr = argv[1];
  144. addr = simple_strtoul(saddr, NULL, 16);
  145. printf("## Starting EFI application at 0x%08lx ...\n", addr);
  146. r = do_bootefi_exec((void *)addr);
  147. printf("## Application terminated, r = %d\n", r);
  148. if (r != 0)
  149. r = 1;
  150. return r;
  151. }
  152. #ifdef CONFIG_SYS_LONGHELP
  153. static char bootefi_help_text[] =
  154. "<image address>\n"
  155. " - boot EFI payload stored at address <image address>\n"
  156. "\n"
  157. "Since most EFI payloads want to have a device tree provided, please\n"
  158. "make sure you load a device tree using the fdt addr command before\n"
  159. "executing bootefi.\n";
  160. #endif
  161. U_BOOT_CMD(
  162. bootefi, 2, 0, do_bootefi,
  163. "Boots an EFI payload from memory\n",
  164. bootefi_help_text
  165. );
  166. void efi_set_bootdev(const char *dev, const char *devnr)
  167. {
  168. char devname[16] = { 0 }; /* dp->str is u16[16] long */
  169. char *colon;
  170. /* Assemble the condensed device name we use in efi_disk.c */
  171. snprintf(devname, sizeof(devname), "%s%s", dev, devnr);
  172. colon = strchr(devname, ':');
  173. if (colon)
  174. *colon = '\0';
  175. /* Patch the bootefi_image_path to the target device */
  176. memset(bootefi_image_path[0].str, 0, sizeof(bootefi_image_path[0].str));
  177. ascii2unicode(bootefi_image_path[0].str, devname);
  178. }