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_image_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_image_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_image_path[0]), 34 } 35 }; 36 37 static struct efi_device_path_file_path bootefi_device_path[] = { 38 { 39 .dp.type = DEVICE_PATH_TYPE_MEDIA_DEVICE, 40 .dp.sub_type = DEVICE_PATH_SUB_TYPE_FILE_PATH, 41 .dp.length = sizeof(bootefi_image_path[0]), 42 .str = { 'b','o','o','t','e','f','i' }, 43 }, { 44 .dp.type = DEVICE_PATH_TYPE_END, 45 .dp.sub_type = DEVICE_PATH_SUB_TYPE_END, 46 .dp.length = sizeof(bootefi_image_path[0]), 47 } 48 }; 49 50 static efi_status_t bootefi_open_dp(void *handle, efi_guid_t *protocol, 51 void **protocol_interface, void *agent_handle, 52 void *controller_handle, uint32_t attributes) 53 { 54 *protocol_interface = bootefi_device_path; 55 return EFI_SUCCESS; 56 } 57 58 /* The EFI loaded_image interface for the image executed via "bootefi" */ 59 static struct efi_loaded_image loaded_image_info = { 60 .device_handle = bootefi_device_path, 61 .file_path = bootefi_image_path, 62 }; 63 64 /* The EFI object struct for the image executed via "bootefi" */ 65 static struct efi_object loaded_image_info_obj = { 66 .handle = &loaded_image_info, 67 .protocols = { 68 { 69 /* 70 * When asking for the loaded_image interface, just 71 * return handle which points to loaded_image_info 72 */ 73 .guid = &efi_guid_loaded_image, 74 .open = &efi_return_handle, 75 }, 76 { 77 /* 78 * When asking for the device path interface, return 79 * bootefi_device_path 80 */ 81 .guid = &efi_guid_device_path, 82 .open = &bootefi_open_dp, 83 }, 84 }, 85 }; 86 87 /* The EFI object struct for the device the "bootefi" image was loaded from */ 88 static struct efi_object bootefi_device_obj = { 89 .handle = bootefi_device_path, 90 .protocols = { 91 { 92 /* When asking for the device path interface, return 93 * bootefi_device_path */ 94 .guid = &efi_guid_device_path, 95 .open = &bootefi_open_dp, 96 } 97 }, 98 }; 99 100 /* 101 * Load an EFI payload into a newly allocated piece of memory, register all 102 * EFI objects it would want to access and jump to it. 103 */ 104 static unsigned long do_bootefi_exec(void *efi) 105 { 106 ulong (*entry)(void *image_handle, struct efi_system_table *st); 107 ulong fdt_pages, fdt_size, fdt_start, fdt_end; 108 bootm_headers_t img = { 0 }; 109 110 /* 111 * gd lives in a fixed register which may get clobbered while we execute 112 * the payload. So save it here and restore it on every callback entry 113 */ 114 efi_save_gd(); 115 116 /* Update system table to point to our currently loaded FDT */ 117 118 if (working_fdt) { 119 /* Prepare fdt for payload */ 120 if (image_setup_libfdt(&img, working_fdt, 0, NULL)) { 121 printf("ERROR: Failed to process device tree\n"); 122 return -EINVAL; 123 } 124 125 /* Link to it in the efi tables */ 126 systab.tables[0].guid = EFI_FDT_GUID; 127 systab.tables[0].table = working_fdt; 128 systab.nr_tables = 1; 129 130 /* And reserve the space in the memory map */ 131 fdt_start = ((ulong)working_fdt) & ~EFI_PAGE_MASK; 132 fdt_end = ((ulong)working_fdt) + fdt_totalsize(working_fdt); 133 fdt_size = (fdt_end - fdt_start) + EFI_PAGE_MASK; 134 fdt_pages = fdt_size >> EFI_PAGE_SHIFT; 135 /* Give a bootloader the chance to modify the device tree */ 136 fdt_pages += 2; 137 efi_add_memory_map(fdt_start, fdt_pages, 138 EFI_BOOT_SERVICES_DATA, true); 139 140 } else { 141 printf("WARNING: No device tree loaded, expect boot to fail\n"); 142 systab.nr_tables = 0; 143 } 144 145 /* Load the EFI payload */ 146 entry = efi_load_pe(efi, &loaded_image_info); 147 if (!entry) 148 return -ENOENT; 149 150 /* Initialize and populate EFI object list */ 151 INIT_LIST_HEAD(&efi_obj_list); 152 list_add_tail(&loaded_image_info_obj.link, &efi_obj_list); 153 list_add_tail(&bootefi_device_obj.link, &efi_obj_list); 154 #ifdef CONFIG_PARTITIONS 155 efi_disk_register(); 156 #endif 157 #ifdef CONFIG_LCD 158 efi_gop_register(); 159 #endif 160 161 /* Call our payload! */ 162 #ifdef DEBUG_EFI 163 printf("%s:%d Jumping to 0x%lx\n", __func__, __LINE__, (long)entry); 164 #endif 165 return entry(&loaded_image_info, &systab); 166 } 167 168 169 /* Interpreter command to boot an arbitrary EFI image from memory */ 170 static int do_bootefi(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) 171 { 172 char *saddr; 173 unsigned long addr; 174 int r = 0; 175 176 if (argc < 2) 177 return 1; 178 saddr = argv[1]; 179 180 addr = simple_strtoul(saddr, NULL, 16); 181 182 printf("## Starting EFI application at 0x%08lx ...\n", addr); 183 r = do_bootefi_exec((void *)addr); 184 printf("## Application terminated, r = %d\n", r); 185 186 if (r != 0) 187 r = 1; 188 189 return r; 190 } 191 192 #ifdef CONFIG_SYS_LONGHELP 193 static char bootefi_help_text[] = 194 "<image address>\n" 195 " - boot EFI payload stored at address <image address>\n" 196 "\n" 197 "Since most EFI payloads want to have a device tree provided, please\n" 198 "make sure you load a device tree using the fdt addr command before\n" 199 "executing bootefi.\n"; 200 #endif 201 202 U_BOOT_CMD( 203 bootefi, 2, 0, do_bootefi, 204 "Boots an EFI payload from memory\n", 205 bootefi_help_text 206 ); 207 208 void efi_set_bootdev(const char *dev, const char *devnr, const char *path) 209 { 210 __maybe_unused struct blk_desc *desc; 211 char devname[32] = { 0 }; /* dp->str is u16[32] long */ 212 char *colon; 213 214 /* Assemble the condensed device name we use in efi_disk.c */ 215 snprintf(devname, sizeof(devname), "%s%s", dev, devnr); 216 colon = strchr(devname, ':'); 217 218 #ifdef CONFIG_ISO_PARTITION 219 /* For ISOs we create partition block devices */ 220 desc = blk_get_dev(dev, simple_strtol(devnr, NULL, 10)); 221 if (desc && (desc->type != DEV_TYPE_UNKNOWN) && 222 (desc->part_type == PART_TYPE_ISO)) { 223 if (!colon) 224 snprintf(devname, sizeof(devname), "%s%s:1", dev, 225 devnr); 226 colon = NULL; 227 } 228 #endif 229 230 if (colon) 231 *colon = '\0'; 232 233 /* Patch bootefi_device_path to the target device */ 234 memset(bootefi_device_path[0].str, 0, sizeof(bootefi_device_path[0].str)); 235 ascii2unicode(bootefi_device_path[0].str, devname); 236 237 /* Patch bootefi_image_path to the target file path */ 238 memset(bootefi_image_path[0].str, 0, sizeof(bootefi_image_path[0].str)); 239 snprintf(devname, sizeof(devname), "%s", path); 240 ascii2unicode(bootefi_image_path[0].str, devname); 241 } 242