1f739fcd8STom Rini // SPDX-License-Identifier: GPL-2.0+ 2b9939336SAlexander Graf /* 3b9939336SAlexander Graf * EFI application loader 4b9939336SAlexander Graf * 5b9939336SAlexander Graf * Copyright (c) 2016 Alexander Graf 6b9939336SAlexander Graf */ 7b9939336SAlexander Graf 8b9939336SAlexander Graf #include <common.h> 9f6c6df7eSHeinrich Schuchardt #include <bootm.h> 10f6c6df7eSHeinrich Schuchardt #include <charset.h> 11b9939336SAlexander Graf #include <command.h> 129d922450SSimon Glass #include <dm.h> 13b9939336SAlexander Graf #include <efi_loader.h> 14d78e40d6SHeinrich Schuchardt #include <efi_selftest.h> 15b9939336SAlexander Graf #include <errno.h> 16b08c8c48SMasahiro Yamada #include <linux/libfdt.h> 17b08c8c48SMasahiro Yamada #include <linux/libfdt_env.h> 18354264b3SAlexander Graf #include <mapmem.h> 19ad0c1a3dSAlexander Graf #include <memalign.h> 200d9d501fSAlexander Graf #include <asm/global_data.h> 21e275458cSSimon Glass #include <asm-generic/sections.h> 22c3b11deaSHeinrich Schuchardt #include <asm-generic/unaligned.h> 23e275458cSSimon Glass #include <linux/linkage.h> 240d9d501fSAlexander Graf 250d9d501fSAlexander Graf DECLARE_GLOBAL_DATA_PTR; 26b9939336SAlexander Graf 2795c5553eSRob Clark static struct efi_device_path *bootefi_image_path; 2895c5553eSRob Clark static struct efi_device_path *bootefi_device_path; 29b9939336SAlexander Graf 30d78e40d6SHeinrich Schuchardt /* 31c3b11deaSHeinrich Schuchardt * Allow unaligned memory access. 32c3b11deaSHeinrich Schuchardt * 33c3b11deaSHeinrich Schuchardt * This routine is overridden by architectures providing this feature. 34c3b11deaSHeinrich Schuchardt */ 35c3b11deaSHeinrich Schuchardt void __weak allow_unaligned(void) 36c3b11deaSHeinrich Schuchardt { 37c3b11deaSHeinrich Schuchardt } 38c3b11deaSHeinrich Schuchardt 39c3b11deaSHeinrich Schuchardt /* 40d78e40d6SHeinrich Schuchardt * Set the load options of an image from an environment variable. 41d78e40d6SHeinrich Schuchardt * 42d78e40d6SHeinrich Schuchardt * @loaded_image_info: the image 43d78e40d6SHeinrich Schuchardt * @env_var: name of the environment variable 44d78e40d6SHeinrich Schuchardt */ 45d78e40d6SHeinrich Schuchardt static void set_load_options(struct efi_loaded_image *loaded_image_info, 46d78e40d6SHeinrich Schuchardt const char *env_var) 47d78e40d6SHeinrich Schuchardt { 48d78e40d6SHeinrich Schuchardt size_t size; 49d78e40d6SHeinrich Schuchardt const char *env = env_get(env_var); 507086a71aSHeinrich Schuchardt u16 *pos; 51d78e40d6SHeinrich Schuchardt 52d78e40d6SHeinrich Schuchardt loaded_image_info->load_options = NULL; 53d78e40d6SHeinrich Schuchardt loaded_image_info->load_options_size = 0; 54d78e40d6SHeinrich Schuchardt if (!env) 55d78e40d6SHeinrich Schuchardt return; 567086a71aSHeinrich Schuchardt size = utf8_utf16_strlen(env) + 1; 57d78e40d6SHeinrich Schuchardt loaded_image_info->load_options = calloc(size, sizeof(u16)); 58d78e40d6SHeinrich Schuchardt if (!loaded_image_info->load_options) { 59d78e40d6SHeinrich Schuchardt printf("ERROR: Out of memory\n"); 60d78e40d6SHeinrich Schuchardt return; 61d78e40d6SHeinrich Schuchardt } 627086a71aSHeinrich Schuchardt pos = loaded_image_info->load_options; 637086a71aSHeinrich Schuchardt utf8_utf16_strcpy(&pos, env); 64d78e40d6SHeinrich Schuchardt loaded_image_info->load_options_size = size * 2; 65d78e40d6SHeinrich Schuchardt } 66d78e40d6SHeinrich Schuchardt 679dff4900SSimon Glass /** 689dff4900SSimon Glass * copy_fdt() - Copy the device tree to a new location available to EFI 699dff4900SSimon Glass * 7016b615d9SHeinrich Schuchardt * The FDT is copied to a suitable location within the EFI memory map. 71c3772ca1SHeinrich Schuchardt * Additional 12 KiB are added to the space in case the device tree needs to be 729dff4900SSimon Glass * expanded later with fdt_open_into(). 739dff4900SSimon Glass * 7416b615d9SHeinrich Schuchardt * @fdtp: On entry a pointer to the flattened device tree. 7516b615d9SHeinrich Schuchardt * On exit a pointer to the copy of the flattened device tree. 769dff4900SSimon Glass * FDT start 774574d1b3SHeinrich Schuchardt * Return: status code 789dff4900SSimon Glass */ 7916b615d9SHeinrich Schuchardt static efi_status_t copy_fdt(void **fdtp) 800d9d501fSAlexander Graf { 81ad0c1a3dSAlexander Graf unsigned long fdt_ram_start = -1L, fdt_pages; 829dff4900SSimon Glass efi_status_t ret = 0; 839dff4900SSimon Glass void *fdt, *new_fdt; 84ad0c1a3dSAlexander Graf u64 new_fdt_addr; 859dff4900SSimon Glass uint fdt_size; 86ad0c1a3dSAlexander Graf int i; 870d9d501fSAlexander Graf 88ad0c1a3dSAlexander Graf for (i = 0; i < CONFIG_NR_DRAM_BANKS; i++) { 89ad0c1a3dSAlexander Graf u64 ram_start = gd->bd->bi_dram[i].start; 90ad0c1a3dSAlexander Graf u64 ram_size = gd->bd->bi_dram[i].size; 910d9d501fSAlexander Graf 92ad0c1a3dSAlexander Graf if (!ram_size) 93ad0c1a3dSAlexander Graf continue; 94ad0c1a3dSAlexander Graf 95ad0c1a3dSAlexander Graf if (ram_start < fdt_ram_start) 96ad0c1a3dSAlexander Graf fdt_ram_start = ram_start; 97ad0c1a3dSAlexander Graf } 98ad0c1a3dSAlexander Graf 99bc9a638aSSimon Glass /* 100c3772ca1SHeinrich Schuchardt * Give us at least 12 KiB of breathing room in case the device tree 101c3772ca1SHeinrich Schuchardt * needs to be expanded later. 102bc9a638aSSimon Glass */ 10316b615d9SHeinrich Schuchardt fdt = *fdtp; 104c3772ca1SHeinrich Schuchardt fdt_pages = efi_size_in_pages(fdt_totalsize(fdt) + 0x3000); 105c3772ca1SHeinrich Schuchardt fdt_size = fdt_pages << EFI_PAGE_SHIFT; 106ad0c1a3dSAlexander Graf 10716b615d9SHeinrich Schuchardt /* 10816b615d9SHeinrich Schuchardt * Safe fdt location is at 127 MiB. 10916b615d9SHeinrich Schuchardt * On the sandbox convert from the sandbox address space. 11016b615d9SHeinrich Schuchardt */ 11116b615d9SHeinrich Schuchardt new_fdt_addr = (uintptr_t)map_sysmem(fdt_ram_start + 0x7f00000 + 11216b615d9SHeinrich Schuchardt fdt_size, 0); 1139dff4900SSimon Glass ret = efi_allocate_pages(EFI_ALLOCATE_MAX_ADDRESS, 114e09159c8SHeinrich Schuchardt EFI_RUNTIME_SERVICES_DATA, fdt_pages, 1159dff4900SSimon Glass &new_fdt_addr); 1169dff4900SSimon Glass if (ret != EFI_SUCCESS) { 117ad0c1a3dSAlexander Graf /* If we can't put it there, put it somewhere */ 118a44bffccSxypron.glpk@gmx.de new_fdt_addr = (ulong)memalign(EFI_PAGE_SIZE, fdt_size); 1199dff4900SSimon Glass ret = efi_allocate_pages(EFI_ALLOCATE_MAX_ADDRESS, 120e09159c8SHeinrich Schuchardt EFI_RUNTIME_SERVICES_DATA, fdt_pages, 1219dff4900SSimon Glass &new_fdt_addr); 1229dff4900SSimon Glass if (ret != EFI_SUCCESS) { 12385a6e9b3SAlexander Graf printf("ERROR: Failed to reserve space for FDT\n"); 1249dff4900SSimon Glass goto done; 125ad0c1a3dSAlexander Graf } 12685a6e9b3SAlexander Graf } 12716b615d9SHeinrich Schuchardt new_fdt = (void *)(uintptr_t)new_fdt_addr; 1280d9d501fSAlexander Graf memcpy(new_fdt, fdt, fdt_totalsize(fdt)); 1290d9d501fSAlexander Graf fdt_set_totalsize(new_fdt, fdt_size); 1300d9d501fSAlexander Graf 13116b615d9SHeinrich Schuchardt *fdtp = (void *)(uintptr_t)new_fdt_addr; 1329dff4900SSimon Glass done: 1339dff4900SSimon Glass return ret; 1340d9d501fSAlexander Graf } 1350d9d501fSAlexander Graf 136416e07e2SSimon Glass /* 137416e07e2SSimon Glass * efi_carve_out_dt_rsv() - Carve out DT reserved memory ranges 138416e07e2SSimon Glass * 139416e07e2SSimon Glass * The mem_rsv entries of the FDT are added to the memory map. Any failures are 140416e07e2SSimon Glass * ignored because this is not critical and we would rather continue to try to 141416e07e2SSimon Glass * boot. 142416e07e2SSimon Glass * 143416e07e2SSimon Glass * @fdt: Pointer to device tree 144416e07e2SSimon Glass */ 145416e07e2SSimon Glass static void efi_carve_out_dt_rsv(void *fdt) 146806d2fa8SAlexander Graf { 147806d2fa8SAlexander Graf int nr_rsv, i; 148806d2fa8SAlexander Graf uint64_t addr, size, pages; 149806d2fa8SAlexander Graf 150806d2fa8SAlexander Graf nr_rsv = fdt_num_mem_rsv(fdt); 151806d2fa8SAlexander Graf 152806d2fa8SAlexander Graf /* Look for an existing entry and add it to the efi mem map. */ 153806d2fa8SAlexander Graf for (i = 0; i < nr_rsv; i++) { 154806d2fa8SAlexander Graf if (fdt_get_mem_rsv(fdt, i, &addr, &size) != 0) 155806d2fa8SAlexander Graf continue; 156806d2fa8SAlexander Graf 15716b615d9SHeinrich Schuchardt /* Convert from sandbox address space. */ 15816b615d9SHeinrich Schuchardt addr = (uintptr_t)map_sysmem(addr, 0); 15916b615d9SHeinrich Schuchardt 160c3772ca1SHeinrich Schuchardt pages = efi_size_in_pages(size + (addr & EFI_PAGE_MASK)); 16123fd84b3SHeinrich Schuchardt addr &= ~EFI_PAGE_MASK; 162416e07e2SSimon Glass if (!efi_add_memory_map(addr, pages, EFI_RESERVED_MEMORY_TYPE, 163416e07e2SSimon Glass false)) 164416e07e2SSimon Glass printf("FDT memrsv map %d: Failed to add to map\n", i); 165806d2fa8SAlexander Graf } 166806d2fa8SAlexander Graf } 167806d2fa8SAlexander Graf 1689dff4900SSimon Glass static efi_status_t efi_install_fdt(ulong fdt_addr) 169bc4f9133SHeinrich Schuchardt { 170bc4f9133SHeinrich Schuchardt bootm_headers_t img = { 0 }; 171bc4f9133SHeinrich Schuchardt efi_status_t ret; 1729dff4900SSimon Glass void *fdt; 173bc4f9133SHeinrich Schuchardt 1749dff4900SSimon Glass fdt = map_sysmem(fdt_addr, 0); 175bc4f9133SHeinrich Schuchardt if (fdt_check_header(fdt)) { 176bc4f9133SHeinrich Schuchardt printf("ERROR: invalid device tree\n"); 177bc4f9133SHeinrich Schuchardt return EFI_INVALID_PARAMETER; 178bc4f9133SHeinrich Schuchardt } 179bc4f9133SHeinrich Schuchardt 1800c9ac06aSHeinrich Schuchardt /* Create memory reservation as indicated by the device tree */ 1810c9ac06aSHeinrich Schuchardt efi_carve_out_dt_rsv(fdt); 1820c9ac06aSHeinrich Schuchardt 183bc4f9133SHeinrich Schuchardt /* Prepare fdt for payload */ 18416b615d9SHeinrich Schuchardt ret = copy_fdt(&fdt); 1859dff4900SSimon Glass if (ret) 1869dff4900SSimon Glass return ret; 187bc4f9133SHeinrich Schuchardt 188bc4f9133SHeinrich Schuchardt if (image_setup_libfdt(&img, fdt, 0, NULL)) { 189bc4f9133SHeinrich Schuchardt printf("ERROR: failed to process device tree\n"); 190bc4f9133SHeinrich Schuchardt return EFI_LOAD_ERROR; 191bc4f9133SHeinrich Schuchardt } 192bc4f9133SHeinrich Schuchardt 193bc4f9133SHeinrich Schuchardt /* Link to it in the efi tables */ 194bc4f9133SHeinrich Schuchardt ret = efi_install_configuration_table(&efi_guid_fdt, fdt); 195bc4f9133SHeinrich Schuchardt if (ret != EFI_SUCCESS) 196bc4f9133SHeinrich Schuchardt return EFI_OUT_OF_RESOURCES; 197bc4f9133SHeinrich Schuchardt 198bc4f9133SHeinrich Schuchardt return ret; 199bc4f9133SHeinrich Schuchardt } 200bc4f9133SHeinrich Schuchardt 201f4f0f7cbSSimon Glass static efi_status_t bootefi_run_prepare(const char *load_options_path, 202f4f0f7cbSSimon Glass struct efi_device_path *device_path, 203f4f0f7cbSSimon Glass struct efi_device_path *image_path, 204f4f0f7cbSSimon Glass struct efi_loaded_image_obj **image_objp, 205f4f0f7cbSSimon Glass struct efi_loaded_image **loaded_image_infop) 206f4f0f7cbSSimon Glass { 207f4f0f7cbSSimon Glass efi_status_t ret; 208f4f0f7cbSSimon Glass 209f4f0f7cbSSimon Glass ret = efi_setup_loaded_image(device_path, image_path, image_objp, 210f4f0f7cbSSimon Glass loaded_image_infop); 211f4f0f7cbSSimon Glass if (ret != EFI_SUCCESS) 212f4f0f7cbSSimon Glass return ret; 213f4f0f7cbSSimon Glass 214f4f0f7cbSSimon Glass /* Transfer environment variable as load options */ 215f4f0f7cbSSimon Glass set_load_options(*loaded_image_infop, load_options_path); 216f4f0f7cbSSimon Glass 217f4f0f7cbSSimon Glass return 0; 218f4f0f7cbSSimon Glass } 219f4f0f7cbSSimon Glass 220c982874eSHeinrich Schuchardt /** 2215e2f0391SSimon Glass * bootefi_run_finish() - finish up after running an EFI test 2225e2f0391SSimon Glass * 2235e2f0391SSimon Glass * @loaded_image_info: Pointer to a struct which holds the loaded image info 2245e2f0391SSimon Glass * @image_objj: Pointer to a struct which holds the loaded image object 2255e2f0391SSimon Glass */ 2265e2f0391SSimon Glass static void bootefi_run_finish(struct efi_loaded_image_obj *image_obj, 2275e2f0391SSimon Glass struct efi_loaded_image *loaded_image_info) 2285e2f0391SSimon Glass { 2295e2f0391SSimon Glass efi_restore_gd(); 2305e2f0391SSimon Glass free(loaded_image_info->load_options); 2315e2f0391SSimon Glass efi_delete_handle(&image_obj->header); 2325e2f0391SSimon Glass } 2335e2f0391SSimon Glass 2345e2f0391SSimon Glass /** 235c982874eSHeinrich Schuchardt * do_bootefi_exec() - execute EFI binary 236c982874eSHeinrich Schuchardt * 237c982874eSHeinrich Schuchardt * @efi: address of the binary 238c982874eSHeinrich Schuchardt * @device_path: path of the device from which the binary was loaded 239c982874eSHeinrich Schuchardt * @image_path: device path of the binary 240c982874eSHeinrich Schuchardt * Return: status code 241c982874eSHeinrich Schuchardt * 242c982874eSHeinrich Schuchardt * Load the EFI binary into a newly assigned memory unwinding the relocation 243c982874eSHeinrich Schuchardt * information, install the loaded image protocol, and call the binary. 244b9939336SAlexander Graf */ 245bc4f9133SHeinrich Schuchardt static efi_status_t do_bootefi_exec(void *efi, 24695c5553eSRob Clark struct efi_device_path *device_path, 24795c5553eSRob Clark struct efi_device_path *image_path) 248b9939336SAlexander Graf { 2498887acc6SHeinrich Schuchardt efi_handle_t mem_handle = NULL; 250bf19273eSRob Clark struct efi_device_path *memdp = NULL; 25145204b10SHeinrich Schuchardt efi_status_t ret; 252faea1041SHeinrich Schuchardt struct efi_loaded_image_obj *image_obj = NULL; 253c982874eSHeinrich Schuchardt struct efi_loaded_image *loaded_image_info = NULL; 25495c5553eSRob Clark 255bf19273eSRob Clark /* 256bf19273eSRob Clark * Special case for efi payload not loaded from disk, such as 257bf19273eSRob Clark * 'bootefi hello' or for example payload loaded directly into 258e1fec152SHeinrich Schuchardt * memory via JTAG, etc: 259bf19273eSRob Clark */ 260bf19273eSRob Clark if (!device_path && !image_path) { 261bf19273eSRob Clark printf("WARNING: using memory device/image path, this may confuse some payloads!\n"); 262bf19273eSRob Clark /* actual addresses filled in after efi_load_pe() */ 2630a76ba65SHeinrich Schuchardt memdp = efi_dp_from_mem(EFI_RESERVED_MEMORY_TYPE, 0, 0); 264bf19273eSRob Clark device_path = image_path = memdp; 2658887acc6SHeinrich Schuchardt /* 2668887acc6SHeinrich Schuchardt * Grub expects that the device path of the loaded image is 2678887acc6SHeinrich Schuchardt * installed on a handle. 2688887acc6SHeinrich Schuchardt */ 2698887acc6SHeinrich Schuchardt ret = efi_create_handle(&mem_handle); 2708887acc6SHeinrich Schuchardt if (ret != EFI_SUCCESS) 2715e2f0391SSimon Glass return ret; /* TODO: leaks device_path */ 2728887acc6SHeinrich Schuchardt ret = efi_add_protocol(mem_handle, &efi_guid_device_path, 27358bc69d2SAlexander Graf device_path); 27458bc69d2SAlexander Graf if (ret != EFI_SUCCESS) 2755e2f0391SSimon Glass goto err_add_protocol; 276bf19273eSRob Clark } else { 277bf19273eSRob Clark assert(device_path && image_path); 278bf19273eSRob Clark } 279bf19273eSRob Clark 280f4f0f7cbSSimon Glass ret = bootefi_run_prepare("bootargs", device_path, image_path, 281f4f0f7cbSSimon Glass &image_obj, &loaded_image_info); 282f4f0f7cbSSimon Glass if (ret) 2835e2f0391SSimon Glass goto err_prepare; 28495c5553eSRob Clark 285b9939336SAlexander Graf /* Load the EFI payload */ 2868f7e2b29SHeinrich Schuchardt ret = efi_load_pe(image_obj, efi, loaded_image_info); 2878f7e2b29SHeinrich Schuchardt if (ret != EFI_SUCCESS) 2885e2f0391SSimon Glass goto err_prepare; 28980a4800eSAlexander Graf 290bf19273eSRob Clark if (memdp) { 291bf19273eSRob Clark struct efi_device_path_memory *mdp = (void *)memdp; 292c982874eSHeinrich Schuchardt mdp->memory_type = loaded_image_info->image_code_type; 293c982874eSHeinrich Schuchardt mdp->start_address = (uintptr_t)loaded_image_info->image_base; 294bf19273eSRob Clark mdp->end_address = mdp->start_address + 295c982874eSHeinrich Schuchardt loaded_image_info->image_size; 296bf19273eSRob Clark } 297bf19273eSRob Clark 298ad644e7cSRob Clark /* we don't support much: */ 299ad644e7cSRob Clark env_set("efi_8be4df61-93ca-11d2-aa0d-00e098032b8c_OsIndicationsSupported", 300ad644e7cSRob Clark "{ro,boot}(blob)0000000000000000"); 301ad644e7cSRob Clark 302b9939336SAlexander Graf /* Call our payload! */ 3038f7e2b29SHeinrich Schuchardt debug("%s: Jumping to 0x%p\n", __func__, image_obj->entry); 304f69d63faSHeinrich Schuchardt ret = EFI_CALL(efi_start_image(&image_obj->header, NULL, NULL)); 30595c5553eSRob Clark 3065e2f0391SSimon Glass err_prepare: 30795c5553eSRob Clark /* image has returned, loaded-image obj goes *poof*: */ 3085e2f0391SSimon Glass bootefi_run_finish(image_obj, loaded_image_info); 3095e2f0391SSimon Glass 3105e2f0391SSimon Glass err_add_protocol: 3118887acc6SHeinrich Schuchardt if (mem_handle) 3128887acc6SHeinrich Schuchardt efi_delete_handle(mem_handle); 31395c5553eSRob Clark 31495c5553eSRob Clark return ret; 315b9939336SAlexander Graf } 316b9939336SAlexander Graf 317d9717eaeSSimon Glass #ifdef CONFIG_CMD_BOOTEFI_SELFTEST 318d9717eaeSSimon Glass /** 319d9717eaeSSimon Glass * bootefi_test_prepare() - prepare to run an EFI test 320d9717eaeSSimon Glass * 321*1504bb0dSHeinrich Schuchardt * Prepare to run a test as if it were provided by a loaded image. 322d9717eaeSSimon Glass * 323*1504bb0dSHeinrich Schuchardt * @image_objp: pointer to be set to the loaded image handle 324*1504bb0dSHeinrich Schuchardt * @loaded_image_infop: pointer to be set to the loaded image protocol 325*1504bb0dSHeinrich Schuchardt * @path: dummy file path used to construct the device path 326*1504bb0dSHeinrich Schuchardt * set in the loaded image protocol 327*1504bb0dSHeinrich Schuchardt * @load_options_path: name of a U-Boot environment variable. Its value is 328*1504bb0dSHeinrich Schuchardt * set as load options in the loaded image protocol. 329*1504bb0dSHeinrich Schuchardt * Return: status code 330d9717eaeSSimon Glass */ 331d9717eaeSSimon Glass static efi_status_t bootefi_test_prepare 332d9717eaeSSimon Glass (struct efi_loaded_image_obj **image_objp, 333f4f0f7cbSSimon Glass struct efi_loaded_image **loaded_image_infop, const char *path, 334*1504bb0dSHeinrich Schuchardt const char *load_options_path) 335d9717eaeSSimon Glass { 336*1504bb0dSHeinrich Schuchardt efi_status_t ret; 337*1504bb0dSHeinrich Schuchardt 338d9717eaeSSimon Glass /* Construct a dummy device path */ 339*1504bb0dSHeinrich Schuchardt bootefi_device_path = efi_dp_from_mem(EFI_RESERVED_MEMORY_TYPE, 0, 0); 340d9717eaeSSimon Glass if (!bootefi_device_path) 341d9717eaeSSimon Glass return EFI_OUT_OF_RESOURCES; 342d9717eaeSSimon Glass 343*1504bb0dSHeinrich Schuchardt bootefi_image_path = efi_dp_from_file(NULL, 0, path); 344*1504bb0dSHeinrich Schuchardt if (!bootefi_image_path) { 345*1504bb0dSHeinrich Schuchardt ret = EFI_OUT_OF_RESOURCES; 346*1504bb0dSHeinrich Schuchardt goto failure; 347*1504bb0dSHeinrich Schuchardt } 348*1504bb0dSHeinrich Schuchardt 349*1504bb0dSHeinrich Schuchardt ret = bootefi_run_prepare(load_options_path, bootefi_device_path, 350f4f0f7cbSSimon Glass bootefi_image_path, image_objp, 351f4f0f7cbSSimon Glass loaded_image_infop); 352*1504bb0dSHeinrich Schuchardt if (ret == EFI_SUCCESS) 353*1504bb0dSHeinrich Schuchardt return ret; 354*1504bb0dSHeinrich Schuchardt 355*1504bb0dSHeinrich Schuchardt efi_free_pool(bootefi_image_path); 356*1504bb0dSHeinrich Schuchardt bootefi_image_path = NULL; 357*1504bb0dSHeinrich Schuchardt failure: 358*1504bb0dSHeinrich Schuchardt efi_free_pool(bootefi_device_path); 359*1504bb0dSHeinrich Schuchardt bootefi_device_path = NULL; 360*1504bb0dSHeinrich Schuchardt return ret; 361d9717eaeSSimon Glass } 362d9717eaeSSimon Glass 363d9717eaeSSimon Glass #endif /* CONFIG_CMD_BOOTEFI_SELFTEST */ 364d9717eaeSSimon Glass 365bc4f9133SHeinrich Schuchardt static int do_bootefi_bootmgr_exec(void) 3669975fe96SRob Clark { 3679975fe96SRob Clark struct efi_device_path *device_path, *file_path; 3689975fe96SRob Clark void *addr; 3699975fe96SRob Clark efi_status_t r; 3709975fe96SRob Clark 3719975fe96SRob Clark addr = efi_bootmgr_load(&device_path, &file_path); 3729975fe96SRob Clark if (!addr) 3739975fe96SRob Clark return 1; 3749975fe96SRob Clark 3759975fe96SRob Clark printf("## Starting EFI application at %p ...\n", addr); 376bc4f9133SHeinrich Schuchardt r = do_bootefi_exec(addr, device_path, file_path); 3779975fe96SRob Clark printf("## Application terminated, r = %lu\n", 3789975fe96SRob Clark r & ~EFI_ERROR_MASK); 3799975fe96SRob Clark 3809975fe96SRob Clark if (r != EFI_SUCCESS) 3819975fe96SRob Clark return 1; 3829975fe96SRob Clark 3839975fe96SRob Clark return 0; 3849975fe96SRob Clark } 3859975fe96SRob Clark 386b9939336SAlexander Graf /* Interpreter command to boot an arbitrary EFI image from memory */ 387b9939336SAlexander Graf static int do_bootefi(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) 388b9939336SAlexander Graf { 389bc4f9133SHeinrich Schuchardt unsigned long addr; 390bc4f9133SHeinrich Schuchardt char *saddr; 3913eb0841bSHeinrich Schuchardt efi_status_t r; 392354264b3SAlexander Graf unsigned long fdt_addr; 393b9939336SAlexander Graf 394c3b11deaSHeinrich Schuchardt /* Allow unaligned memory access */ 395c3b11deaSHeinrich Schuchardt allow_unaligned(); 396c3b11deaSHeinrich Schuchardt 397f6c6df7eSHeinrich Schuchardt switch_to_non_secure_mode(); 398f6c6df7eSHeinrich Schuchardt 399fc225e60SHeinrich Schuchardt /* Initialize EFI drivers */ 400fc225e60SHeinrich Schuchardt r = efi_init_obj_list(); 401fc225e60SHeinrich Schuchardt if (r != EFI_SUCCESS) { 402fc225e60SHeinrich Schuchardt printf("Error: Cannot set up EFI drivers, r = %lu\n", 403fc225e60SHeinrich Schuchardt r & ~EFI_ERROR_MASK); 404fc225e60SHeinrich Schuchardt return CMD_RET_FAILURE; 405fc225e60SHeinrich Schuchardt } 406fc225e60SHeinrich Schuchardt 407b9939336SAlexander Graf if (argc < 2) 4083c1dcef6SBin Meng return CMD_RET_USAGE; 409bc4f9133SHeinrich Schuchardt 410bc4f9133SHeinrich Schuchardt if (argc > 2) { 411354264b3SAlexander Graf fdt_addr = simple_strtoul(argv[2], NULL, 16); 412bc4f9133SHeinrich Schuchardt if (!fdt_addr && *argv[2] != '0') 413bc4f9133SHeinrich Schuchardt return CMD_RET_USAGE; 414bc4f9133SHeinrich Schuchardt /* Install device tree */ 4159dff4900SSimon Glass r = efi_install_fdt(fdt_addr); 416bc4f9133SHeinrich Schuchardt if (r != EFI_SUCCESS) { 417bc4f9133SHeinrich Schuchardt printf("ERROR: failed to install device tree\n"); 418bc4f9133SHeinrich Schuchardt return CMD_RET_FAILURE; 419bc4f9133SHeinrich Schuchardt } 420bc4f9133SHeinrich Schuchardt } else { 421bc4f9133SHeinrich Schuchardt /* Remove device tree. EFI_NOT_FOUND can be ignored here */ 422bc4f9133SHeinrich Schuchardt efi_install_configuration_table(&efi_guid_fdt, NULL); 423bc4f9133SHeinrich Schuchardt printf("WARNING: booting without device tree\n"); 424bc4f9133SHeinrich Schuchardt } 425c7ae3dfdSSimon Glass #ifdef CONFIG_CMD_BOOTEFI_HELLO 426c7ae3dfdSSimon Glass if (!strcmp(argv[1], "hello")) { 4275e44489bSHeinrich Schuchardt ulong size = __efi_helloworld_end - __efi_helloworld_begin; 428c7ae3dfdSSimon Glass 42951c533fdSHeinrich Schuchardt saddr = env_get("loadaddr"); 43051c533fdSHeinrich Schuchardt if (saddr) 43151c533fdSHeinrich Schuchardt addr = simple_strtoul(saddr, NULL, 16); 43251c533fdSHeinrich Schuchardt else 433c7ae3dfdSSimon Glass addr = CONFIG_SYS_LOAD_ADDR; 434354264b3SAlexander Graf memcpy(map_sysmem(addr, size), __efi_helloworld_begin, size); 435c7ae3dfdSSimon Glass } else 436c7ae3dfdSSimon Glass #endif 437623b3a57SHeinrich Schuchardt #ifdef CONFIG_CMD_BOOTEFI_SELFTEST 438623b3a57SHeinrich Schuchardt if (!strcmp(argv[1], "selftest")) { 439faea1041SHeinrich Schuchardt struct efi_loaded_image_obj *image_obj; 440c982874eSHeinrich Schuchardt struct efi_loaded_image *loaded_image_info; 4417aca68caSHeinrich Schuchardt 442*1504bb0dSHeinrich Schuchardt r = bootefi_test_prepare(&image_obj, &loaded_image_info, 443*1504bb0dSHeinrich Schuchardt "\\selftest", "efi_selftest"); 444*1504bb0dSHeinrich Schuchardt if (r != EFI_SUCCESS) 4452ab7ef74SSimon Glass return CMD_RET_FAILURE; 4462ab7ef74SSimon Glass 447d78e40d6SHeinrich Schuchardt /* Execute the test */ 448914df75bSHeinrich Schuchardt r = EFI_CALL(efi_selftest(&image_obj->header, &systab)); 4495e2f0391SSimon Glass bootefi_run_finish(image_obj, loaded_image_info); 450c2b53902SHeinrich Schuchardt return r != EFI_SUCCESS; 451623b3a57SHeinrich Schuchardt } else 452623b3a57SHeinrich Schuchardt #endif 4539975fe96SRob Clark if (!strcmp(argv[1], "bootmgr")) { 454bc4f9133SHeinrich Schuchardt return do_bootefi_bootmgr_exec(); 4559975fe96SRob Clark } else { 456b9939336SAlexander Graf saddr = argv[1]; 457b9939336SAlexander Graf 458b9939336SAlexander Graf addr = simple_strtoul(saddr, NULL, 16); 45949db1cb8SHeinrich Schuchardt /* Check that a numeric value was passed */ 46049db1cb8SHeinrich Schuchardt if (!addr && *saddr != '0') 46149db1cb8SHeinrich Schuchardt return CMD_RET_USAGE; 462b9939336SAlexander Graf 463c7ae3dfdSSimon Glass } 4641c39809bSAlexander Graf 4655ee31bafSSimon Glass printf("## Starting EFI application at %08lx ...\n", addr); 466354264b3SAlexander Graf r = do_bootefi_exec(map_sysmem(addr, 0), bootefi_device_path, 467bc4f9133SHeinrich Schuchardt bootefi_image_path); 4681da1bac4Sxypron.glpk@gmx.de printf("## Application terminated, r = %lu\n", 4691da1bac4Sxypron.glpk@gmx.de r & ~EFI_ERROR_MASK); 470b9939336SAlexander Graf 4711da1bac4Sxypron.glpk@gmx.de if (r != EFI_SUCCESS) 4721da1bac4Sxypron.glpk@gmx.de return 1; 4731da1bac4Sxypron.glpk@gmx.de else 4741da1bac4Sxypron.glpk@gmx.de return 0; 475b9939336SAlexander Graf } 476b9939336SAlexander Graf 477b9939336SAlexander Graf #ifdef CONFIG_SYS_LONGHELP 478b9939336SAlexander Graf static char bootefi_help_text[] = 4791c39809bSAlexander Graf "<image address> [fdt address]\n" 4801c39809bSAlexander Graf " - boot EFI payload stored at address <image address>.\n" 4811c39809bSAlexander Graf " If specified, the device tree located at <fdt address> gets\n" 482c7ae3dfdSSimon Glass " exposed as EFI configuration table.\n" 483c7ae3dfdSSimon Glass #ifdef CONFIG_CMD_BOOTEFI_HELLO 484623b3a57SHeinrich Schuchardt "bootefi hello\n" 485623b3a57SHeinrich Schuchardt " - boot a sample Hello World application stored within U-Boot\n" 486623b3a57SHeinrich Schuchardt #endif 487623b3a57SHeinrich Schuchardt #ifdef CONFIG_CMD_BOOTEFI_SELFTEST 488bc4f9133SHeinrich Schuchardt "bootefi selftest [fdt address]\n" 489623b3a57SHeinrich Schuchardt " - boot an EFI selftest application stored within U-Boot\n" 490d78e40d6SHeinrich Schuchardt " Use environment variable efi_selftest to select a single test.\n" 491d78e40d6SHeinrich Schuchardt " Use 'setenv efi_selftest list' to enumerate all tests.\n" 492c7ae3dfdSSimon Glass #endif 493f623e07fSHeinrich Schuchardt "bootefi bootmgr [fdt addr]\n" 4949975fe96SRob Clark " - load and boot EFI payload based on BootOrder/BootXXXX variables.\n" 4959975fe96SRob Clark "\n" 4969975fe96SRob Clark " If specified, the device tree located at <fdt address> gets\n" 4979975fe96SRob Clark " exposed as EFI configuration table.\n"; 498b9939336SAlexander Graf #endif 499b9939336SAlexander Graf 500b9939336SAlexander Graf U_BOOT_CMD( 5011c39809bSAlexander Graf bootefi, 3, 0, do_bootefi, 50292dfd922SSergey Kubushyn "Boots an EFI payload from memory", 503b9939336SAlexander Graf bootefi_help_text 504b9939336SAlexander Graf ); 5050f4060ebSAlexander Graf 506c07ad7c0SAlexander Graf void efi_set_bootdev(const char *dev, const char *devnr, const char *path) 5070f4060ebSAlexander Graf { 508f1589ffbSAKASHI Takahiro struct efi_device_path *device, *image; 509f1589ffbSAKASHI Takahiro efi_status_t ret; 5100f4060ebSAlexander Graf 51179276eb2SHeinrich Schuchardt /* efi_set_bootdev is typically called repeatedly, recover memory */ 51279276eb2SHeinrich Schuchardt efi_free_pool(bootefi_device_path); 51379276eb2SHeinrich Schuchardt efi_free_pool(bootefi_image_path); 514f1589ffbSAKASHI Takahiro 515f1589ffbSAKASHI Takahiro ret = efi_dp_from_name(dev, devnr, path, &device, &image); 516f1589ffbSAKASHI Takahiro if (ret == EFI_SUCCESS) { 517f1589ffbSAKASHI Takahiro bootefi_device_path = device; 518f1589ffbSAKASHI Takahiro bootefi_image_path = image; 519f1589ffbSAKASHI Takahiro } else { 52079276eb2SHeinrich Schuchardt bootefi_device_path = NULL; 52179276eb2SHeinrich Schuchardt bootefi_image_path = NULL; 522f9d334bdSAlexander Graf } 5230f4060ebSAlexander Graf } 524