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