diff options
Diffstat (limited to 'cmd')
-rw-r--r-- | cmd/bootefi.c | 229 |
1 files changed, 145 insertions, 84 deletions
diff --git a/cmd/bootefi.c b/cmd/bootefi.c index 6546272348..5a2a81005f 100644 --- a/cmd/bootefi.c +++ b/cmd/bootefi.c @@ -22,37 +22,65 @@ DECLARE_GLOBAL_DATA_PTR; -static uint8_t efi_obj_list_initalized; +#define OBJ_LIST_NOT_INITIALIZED 1 + +static efi_status_t efi_obj_list_initialized = OBJ_LIST_NOT_INITIALIZED; static struct efi_device_path *bootefi_image_path; static struct efi_device_path *bootefi_device_path; /* Initialize and populate EFI object list */ -static void efi_init_obj_list(void) +efi_status_t efi_init_obj_list(void) { - efi_obj_list_initalized = 1; + efi_status_t ret = EFI_SUCCESS; + + /* Initialize once only */ + if (efi_obj_list_initialized != OBJ_LIST_NOT_INITIALIZED) + return efi_obj_list_initialized; /* Initialize EFI driver uclass */ - efi_driver_init(); + ret = efi_driver_init(); + if (ret != EFI_SUCCESS) + goto out; - efi_console_register(); + ret = efi_console_register(); + if (ret != EFI_SUCCESS) + goto out; #ifdef CONFIG_PARTITIONS - efi_disk_register(); + ret = efi_disk_register(); + if (ret != EFI_SUCCESS) + goto out; #endif #if defined(CONFIG_LCD) || defined(CONFIG_DM_VIDEO) - efi_gop_register(); + ret = efi_gop_register(); + if (ret != EFI_SUCCESS) + goto out; #endif #ifdef CONFIG_CMD_NET - efi_net_register(); + ret = efi_net_register(); + if (ret != EFI_SUCCESS) + goto out; #endif #ifdef CONFIG_GENERATE_SMBIOS_TABLE - efi_smbios_register(); + ret = efi_smbios_register(); + if (ret != EFI_SUCCESS) + goto out; #endif - efi_watchdog_register(); + ret = efi_watchdog_register(); + if (ret != EFI_SUCCESS) + goto out; /* Initialize EFI runtime services */ - efi_reset_system_init(); - efi_get_time_init(); + ret = efi_reset_system_init(); + if (ret != EFI_SUCCESS) + goto out; + ret = efi_get_time_init(); + if (ret != EFI_SUCCESS) + goto out; + +out: + efi_obj_list_initialized = ret; + return ret; } /* @@ -150,24 +178,85 @@ static efi_status_t efi_run_in_el2(EFIAPI efi_status_t (*entry)( } #endif +/* Carve out DT reserved memory ranges */ +static efi_status_t efi_carve_out_dt_rsv(void *fdt) +{ + int nr_rsv, i; + uint64_t addr, size, pages; + + nr_rsv = fdt_num_mem_rsv(fdt); + + /* Look for an existing entry and add it to the efi mem map. */ + for (i = 0; i < nr_rsv; i++) { + if (fdt_get_mem_rsv(fdt, i, &addr, &size) != 0) + continue; + + pages = ALIGN(size, EFI_PAGE_SIZE) >> EFI_PAGE_SHIFT; + efi_add_memory_map(addr, pages, EFI_RESERVED_MEMORY_TYPE, + false); + } + + return EFI_SUCCESS; +} + +static efi_status_t efi_install_fdt(void *fdt) +{ + bootm_headers_t img = { 0 }; + ulong fdt_pages, fdt_size, fdt_start, fdt_end; + efi_status_t ret; + + if (fdt_check_header(fdt)) { + printf("ERROR: invalid device tree\n"); + return EFI_INVALID_PARAMETER; + } + + /* Prepare fdt for payload */ + fdt = copy_fdt(fdt); + if (!fdt) + return EFI_OUT_OF_RESOURCES; + + if (image_setup_libfdt(&img, fdt, 0, NULL)) { + printf("ERROR: failed to process device tree\n"); + return EFI_LOAD_ERROR; + } + + if (efi_carve_out_dt_rsv(fdt) != EFI_SUCCESS) { + printf("ERROR: failed to carve out memory\n"); + return EFI_LOAD_ERROR; + } + + /* Link to it in the efi tables */ + ret = efi_install_configuration_table(&efi_guid_fdt, fdt); + if (ret != EFI_SUCCESS) + return EFI_OUT_OF_RESOURCES; + + /* And reserve the space in the memory map */ + fdt_start = ((ulong)fdt) & ~EFI_PAGE_MASK; + fdt_end = ((ulong)fdt) + fdt_totalsize(fdt); + fdt_size = (fdt_end - fdt_start) + EFI_PAGE_MASK; + fdt_pages = fdt_size >> EFI_PAGE_SHIFT; + /* Give a bootloader the chance to modify the device tree */ + fdt_pages += 2; + ret = efi_add_memory_map(fdt_start, fdt_pages, + EFI_BOOT_SERVICES_DATA, true); + return ret; +} + /* * Load an EFI payload into a newly allocated piece of memory, register all * EFI objects it would want to access and jump to it. */ -static efi_status_t do_bootefi_exec(void *efi, void *fdt, +static efi_status_t do_bootefi_exec(void *efi, struct efi_device_path *device_path, struct efi_device_path *image_path) { struct efi_loaded_image loaded_image_info = {}; struct efi_object loaded_image_info_obj = {}; struct efi_device_path *memdp = NULL; - ulong ret; + efi_status_t ret; EFIAPI efi_status_t (*entry)(efi_handle_t image_handle, struct efi_system_table *st); - ulong fdt_pages, fdt_size, fdt_start, fdt_end; - const efi_guid_t fdt_guid = EFI_FDT_GUID; - bootm_headers_t img = { 0 }; /* * Special case for efi payload not loaded from disk, such as @@ -183,10 +272,6 @@ static efi_status_t do_bootefi_exec(void *efi, void *fdt, assert(device_path && image_path); } - /* Initialize and populate EFI object list */ - if (!efi_obj_list_initalized) - efi_init_obj_list(); - efi_setup_loaded_image(&loaded_image_info, &loaded_image_info_obj, device_path, image_path); @@ -196,38 +281,12 @@ static efi_status_t do_bootefi_exec(void *efi, void *fdt, */ efi_save_gd(); - if (fdt && !fdt_check_header(fdt)) { - /* Prepare fdt for payload */ - fdt = copy_fdt(fdt); - - if (image_setup_libfdt(&img, fdt, 0, NULL)) { - printf("ERROR: Failed to process device tree\n"); - return -EINVAL; - } - - /* Link to it in the efi tables */ - efi_install_configuration_table(&fdt_guid, fdt); - - /* And reserve the space in the memory map */ - fdt_start = ((ulong)fdt) & ~EFI_PAGE_MASK; - fdt_end = ((ulong)fdt) + fdt_totalsize(fdt); - fdt_size = (fdt_end - fdt_start) + EFI_PAGE_MASK; - fdt_pages = fdt_size >> EFI_PAGE_SHIFT; - /* Give a bootloader the chance to modify the device tree */ - fdt_pages += 2; - efi_add_memory_map(fdt_start, fdt_pages, - EFI_BOOT_SERVICES_DATA, true); - } else { - printf("WARNING: Invalid device tree, expect boot to fail\n"); - efi_install_configuration_table(&fdt_guid, NULL); - } - /* Transfer environment variable bootargs as load options */ set_load_options(&loaded_image_info, "bootargs"); /* Load the EFI payload */ entry = efi_load_pe(efi, &loaded_image_info); if (!entry) { - ret = -ENOENT; + ret = EFI_LOAD_ERROR; goto exit; } @@ -277,16 +336,12 @@ exit: return ret; } -static int do_bootefi_bootmgr_exec(unsigned long fdt_addr) +static int do_bootefi_bootmgr_exec(void) { struct efi_device_path *device_path, *file_path; void *addr; efi_status_t r; - /* Initialize and populate EFI object list */ - if (!efi_obj_list_initalized) - efi_init_obj_list(); - /* * gd lives in a fixed register which may get clobbered while we execute * the payload. So save it here and restore it on every callback entry @@ -298,7 +353,7 @@ static int do_bootefi_bootmgr_exec(unsigned long fdt_addr) return 1; printf("## Starting EFI application at %p ...\n", addr); - r = do_bootefi_exec(addr, (void *)fdt_addr, device_path, file_path); + r = do_bootefi_exec(addr, device_path, file_path); printf("## Application terminated, r = %lu\n", r & ~EFI_ERROR_MASK); @@ -311,12 +366,37 @@ static int do_bootefi_bootmgr_exec(unsigned long fdt_addr) /* Interpreter command to boot an arbitrary EFI image from memory */ static int do_bootefi(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) { - char *saddr, *sfdt; - unsigned long addr, fdt_addr = 0; + unsigned long addr; + char *saddr; efi_status_t r; + void *fdt_addr; + + /* Initialize EFI drivers */ + r = efi_init_obj_list(); + if (r != EFI_SUCCESS) { + printf("Error: Cannot set up EFI drivers, r = %lu\n", + r & ~EFI_ERROR_MASK); + return CMD_RET_FAILURE; + } if (argc < 2) return CMD_RET_USAGE; + + if (argc > 2) { + fdt_addr = (void *)simple_strtoul(argv[2], NULL, 16); + if (!fdt_addr && *argv[2] != '0') + return CMD_RET_USAGE; + /* Install device tree */ + r = efi_install_fdt(fdt_addr); + if (r != EFI_SUCCESS) { + printf("ERROR: failed to install device tree\n"); + return CMD_RET_FAILURE; + } + } else { + /* Remove device tree. EFI_NOT_FOUND can be ignored here */ + efi_install_configuration_table(&efi_guid_fdt, NULL); + printf("WARNING: booting without device tree\n"); + } #ifdef CONFIG_CMD_BOOTEFI_HELLO if (!strcmp(argv[1], "hello")) { ulong size = __efi_helloworld_end - __efi_helloworld_begin; @@ -350,8 +430,7 @@ static int do_bootefi(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) */ efi_save_gd(); /* Initialize and populate EFI object list */ - if (!efi_obj_list_initalized) - efi_init_obj_list(); + efi_init_obj_list(); /* Transfer environment variable efi_selftest as load options */ set_load_options(&loaded_image_info, "efi_selftest"); /* Execute the test */ @@ -363,12 +442,7 @@ static int do_bootefi(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) } else #endif if (!strcmp(argv[1], "bootmgr")) { - unsigned long fdt_addr = 0; - - if (argc > 2) - fdt_addr = simple_strtoul(argv[2], NULL, 16); - - return do_bootefi_bootmgr_exec(fdt_addr); + return do_bootefi_bootmgr_exec(); } else { saddr = argv[1]; @@ -377,15 +451,11 @@ static int do_bootefi(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) if (!addr && *saddr != '0') return CMD_RET_USAGE; - if (argc > 2) { - sfdt = argv[2]; - fdt_addr = simple_strtoul(sfdt, NULL, 16); - } } printf("## Starting EFI application at %08lx ...\n", addr); - r = do_bootefi_exec((void *)addr, (void *)fdt_addr, - bootefi_device_path, bootefi_image_path); + r = do_bootefi_exec((void *)addr, bootefi_device_path, + bootefi_image_path); printf("## Application terminated, r = %lu\n", r & ~EFI_ERROR_MASK); @@ -406,7 +476,7 @@ static char bootefi_help_text[] = " - boot a sample Hello World application stored within U-Boot\n" #endif #ifdef CONFIG_CMD_BOOTEFI_SELFTEST - "bootefi selftest\n" + "bootefi selftest [fdt address]\n" " - boot an EFI selftest application stored within U-Boot\n" " Use environment variable efi_selftest to select a single test.\n" " Use 'setenv efi_selftest list' to enumerate all tests.\n" @@ -424,16 +494,6 @@ U_BOOT_CMD( bootefi_help_text ); -static int parse_partnum(const char *devnr) -{ - const char *str = strchr(devnr, ':'); - if (str) { - str++; - return simple_strtoul(str, NULL, 16); - } - return 0; -} - void efi_set_bootdev(const char *dev, const char *devnr, const char *path) { char filename[32] = { 0 }; /* dp->str is u16[32] long */ @@ -441,12 +501,13 @@ void efi_set_bootdev(const char *dev, const char *devnr, const char *path) if (strcmp(dev, "Net")) { struct blk_desc *desc; + disk_partition_t fs_partition; int part; - desc = blk_get_dev(dev, simple_strtol(devnr, NULL, 10)); - if (!desc) + part = blk_get_device_part_str(dev, devnr, &desc, &fs_partition, + 1); + if (part < 0) return; - part = parse_partnum(devnr); bootefi_device_path = efi_dp_from_part(desc, part); } else { |