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