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 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_image_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_image_path, 48 .file_path = bootefi_image_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_image_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_image_path, 77 .protocols = { 78 { 79 /* When asking for the device path interface, return 80 * bootefi_image_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 bootm_headers_t img = { 0 }; 96 97 /* 98 * gd lives in a fixed register which may get clobbered while we execute 99 * the payload. So save it here and restore it on every callback entry 100 */ 101 efi_save_gd(); 102 103 /* Update system table to point to our currently loaded FDT */ 104 105 if (working_fdt) { 106 /* Prepare fdt for payload */ 107 if (image_setup_libfdt(&img, working_fdt, 0, NULL)) { 108 printf("ERROR: Failed to process device tree\n"); 109 return -EINVAL; 110 } 111 112 /* Link to it in the efi tables */ 113 systab.tables[0].guid = EFI_FDT_GUID; 114 systab.tables[0].table = working_fdt; 115 systab.nr_tables = 1; 116 117 /* And reserve the space in the memory map */ 118 fdt_start = ((ulong)working_fdt) & ~EFI_PAGE_MASK; 119 fdt_end = ((ulong)working_fdt) + fdt_totalsize(working_fdt); 120 fdt_size = (fdt_end - fdt_start) + EFI_PAGE_MASK; 121 fdt_pages = fdt_size >> EFI_PAGE_SHIFT; 122 /* Give a bootloader the chance to modify the device tree */ 123 fdt_pages += 2; 124 efi_add_memory_map(fdt_start, fdt_pages, 125 EFI_BOOT_SERVICES_DATA, true); 126 127 } else { 128 printf("WARNING: No device tree loaded, expect boot to fail\n"); 129 systab.nr_tables = 0; 130 } 131 132 /* Load the EFI payload */ 133 entry = efi_load_pe(efi, &loaded_image_info); 134 if (!entry) 135 return -ENOENT; 136 137 /* Initialize and populate EFI object list */ 138 INIT_LIST_HEAD(&efi_obj_list); 139 list_add_tail(&loaded_image_info_obj.link, &efi_obj_list); 140 list_add_tail(&bootefi_device_obj.link, &efi_obj_list); 141 #ifdef CONFIG_PARTITIONS 142 efi_disk_register(); 143 #endif 144 145 /* Call our payload! */ 146 #ifdef DEBUG_EFI 147 printf("%s:%d Jumping to 0x%lx\n", __func__, __LINE__, (long)entry); 148 #endif 149 return entry(&loaded_image_info, &systab); 150 } 151 152 153 /* Interpreter command to boot an arbitrary EFI image from memory */ 154 static int do_bootefi(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) 155 { 156 char *saddr; 157 unsigned long addr; 158 int r = 0; 159 160 if (argc < 2) 161 return 1; 162 saddr = argv[1]; 163 164 addr = simple_strtoul(saddr, NULL, 16); 165 166 printf("## Starting EFI application at 0x%08lx ...\n", addr); 167 r = do_bootefi_exec((void *)addr); 168 printf("## Application terminated, r = %d\n", r); 169 170 if (r != 0) 171 r = 1; 172 173 return r; 174 } 175 176 #ifdef CONFIG_SYS_LONGHELP 177 static char bootefi_help_text[] = 178 "<image address>\n" 179 " - boot EFI payload stored at address <image address>\n" 180 "\n" 181 "Since most EFI payloads want to have a device tree provided, please\n" 182 "make sure you load a device tree using the fdt addr command before\n" 183 "executing bootefi.\n"; 184 #endif 185 186 U_BOOT_CMD( 187 bootefi, 2, 0, do_bootefi, 188 "Boots an EFI payload from memory\n", 189 bootefi_help_text 190 ); 191 192 void efi_set_bootdev(const char *dev, const char *devnr) 193 { 194 char devname[16] = { 0 }; /* dp->str is u16[16] long */ 195 char *colon; 196 197 /* Assemble the condensed device name we use in efi_disk.c */ 198 snprintf(devname, sizeof(devname), "%s%s", dev, devnr); 199 colon = strchr(devname, ':'); 200 if (colon) 201 *colon = '\0'; 202 203 /* Patch the bootefi_image_path to the target device */ 204 memset(bootefi_image_path[0].str, 0, sizeof(bootefi_image_path[0].str)); 205 ascii2unicode(bootefi_image_path[0].str, devname); 206 } 207