From baf70c02107a60603234a6871087368dc7bc3764 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Wed, 8 Aug 2018 03:54:29 -0600 Subject: efi: Relocate FDT to 127MB instead of 128MB Sandbox only has 128MB of memory so we cannot relocate the device tree up to start at 128MB. Use 127MB instead, which should be safe. Signed-off-by: Simon Glass Signed-off-by: Alexander Graf --- cmd/bootefi.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'cmd') diff --git a/cmd/bootefi.c b/cmd/bootefi.c index b60c151fb4a..c4797481595 100644 --- a/cmd/bootefi.c +++ b/cmd/bootefi.c @@ -158,8 +158,8 @@ static void *copy_fdt(void *fdt) fdt_size = ALIGN(fdt_size + EFI_PAGE_SIZE - 1, EFI_PAGE_SIZE); fdt_pages = fdt_size >> EFI_PAGE_SHIFT; - /* Safe fdt location is at 128MB */ - new_fdt_addr = fdt_ram_start + (128 * 1024 * 1024) + fdt_size; + /* Safe fdt location is at 127MB */ + new_fdt_addr = fdt_ram_start + (127 * 1024 * 1024) + fdt_size; if (efi_allocate_pages(EFI_ALLOCATE_MAX_ADDRESS, EFI_RUNTIME_SERVICES_DATA, fdt_pages, &new_fdt_addr) != EFI_SUCCESS) { -- cgit v1.3.1 From 9dff49008919b235bf93d078c531f2779fff975e Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Wed, 8 Aug 2018 03:54:30 -0600 Subject: efi: sandbox: Tidy up copy_fdt() to work with sandbox At present this function takes a pointer as its argument, then passes this to efi_allocate_pages(), which actually takes an address. It uses casts, which are not supported on sandbox. Also the function calculates the FDT size rounded up to the neared EFI page size, then its caller recalculates the size and adds a bit more to it. This function is much better written as something that works with addresses only, and returns both the address and the size of the relocated FDT. Also, copy_fdt() returns NULL on error, but really should propagate the error from efi_allocate_pages(). To do this it needs to return an efi_status_t, not a void *. Update the code in this way, so that it is easier to follow, and also supports sandbox. Signed-off-by: Simon Glass Signed-off-by: Alexander Graf --- cmd/bootefi.c | 79 +++++++++++++++++++++++++++++++++++++---------------------- 1 file changed, 50 insertions(+), 29 deletions(-) (limited to 'cmd') diff --git a/cmd/bootefi.c b/cmd/bootefi.c index c4797481595..e169f5edc0d 100644 --- a/cmd/bootefi.c +++ b/cmd/bootefi.c @@ -131,17 +131,30 @@ static void set_load_options(struct efi_loaded_image *loaded_image_info, loaded_image_info->load_options_size = size * 2; } -static void *copy_fdt(void *fdt) +/** + * copy_fdt() - Copy the device tree to a new location available to EFI + * + * The FDT is relocated into a suitable location within the EFI memory map. + * An additional 12KB is added to the space in case the device tree needs to be + * expanded later with fdt_open_into(). + * + * @fdt_addr: On entry, address of start of FDT. On exit, address of relocated + * FDT start + * @fdt_sizep: Returns new size of FDT, including + * @return new relocated address of FDT + */ +static efi_status_t copy_fdt(ulong *fdt_addrp, ulong *fdt_sizep) { - u64 fdt_size = fdt_totalsize(fdt); unsigned long fdt_ram_start = -1L, fdt_pages; + efi_status_t ret = 0; + void *fdt, *new_fdt; u64 new_fdt_addr; - void *new_fdt; + uint fdt_size; int i; - for (i = 0; i < CONFIG_NR_DRAM_BANKS; i++) { - u64 ram_start = gd->bd->bi_dram[i].start; - u64 ram_size = gd->bd->bi_dram[i].size; + for (i = 0; i < CONFIG_NR_DRAM_BANKS; i++) { + u64 ram_start = gd->bd->bi_dram[i].start; + u64 ram_size = gd->bd->bi_dram[i].size; if (!ram_size) continue; @@ -154,30 +167,37 @@ static void *copy_fdt(void *fdt) * Give us at least 4KB of breathing room in case the device tree needs * to be expanded later. Round up to the nearest EFI page boundary. */ - fdt_size += 4096; + fdt = map_sysmem(*fdt_addrp, 0); + fdt_size = fdt_totalsize(fdt); + fdt_size += 4096 * 3; fdt_size = ALIGN(fdt_size + EFI_PAGE_SIZE - 1, EFI_PAGE_SIZE); fdt_pages = fdt_size >> EFI_PAGE_SHIFT; /* Safe fdt location is at 127MB */ new_fdt_addr = fdt_ram_start + (127 * 1024 * 1024) + fdt_size; - if (efi_allocate_pages(EFI_ALLOCATE_MAX_ADDRESS, - EFI_RUNTIME_SERVICES_DATA, fdt_pages, - &new_fdt_addr) != EFI_SUCCESS) { + ret = efi_allocate_pages(EFI_ALLOCATE_MAX_ADDRESS, + EFI_RUNTIME_SERVICES_DATA, fdt_pages, + &new_fdt_addr); + if (ret != EFI_SUCCESS) { /* If we can't put it there, put it somewhere */ new_fdt_addr = (ulong)memalign(EFI_PAGE_SIZE, fdt_size); - if (efi_allocate_pages(EFI_ALLOCATE_MAX_ADDRESS, - EFI_RUNTIME_SERVICES_DATA, fdt_pages, - &new_fdt_addr) != EFI_SUCCESS) { + ret = efi_allocate_pages(EFI_ALLOCATE_MAX_ADDRESS, + EFI_RUNTIME_SERVICES_DATA, fdt_pages, + &new_fdt_addr); + if (ret != EFI_SUCCESS) { printf("ERROR: Failed to reserve space for FDT\n"); - return NULL; + goto done; } } - new_fdt = (void*)(ulong)new_fdt_addr; + new_fdt = map_sysmem(new_fdt_addr, fdt_size); memcpy(new_fdt, fdt, fdt_totalsize(fdt)); fdt_set_totalsize(new_fdt, fdt_size); - return new_fdt; + *fdt_addrp = new_fdt_addr; + *fdt_sizep = fdt_size; +done: + return ret; } static efi_status_t efi_do_enter( @@ -250,22 +270,27 @@ static void efi_carve_out_dt_rsv(void *fdt) } } -static efi_status_t efi_install_fdt(void *fdt) +static efi_status_t efi_install_fdt(ulong fdt_addr) { bootm_headers_t img = { 0 }; - ulong fdt_pages, fdt_size, fdt_start, fdt_end; + ulong fdt_pages, fdt_size, fdt_start; efi_status_t ret; + void *fdt; + fdt = map_sysmem(fdt_addr, 0); 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; + ret = copy_fdt(&fdt_addr, &fdt_size); + if (ret) + return ret; + unmap_sysmem(fdt); + fdt = map_sysmem(fdt_addr, 0); + fdt_size = fdt_totalsize(fdt); if (image_setup_libfdt(&img, fdt, 0, NULL)) { printf("ERROR: failed to process device tree\n"); return EFI_LOAD_ERROR; @@ -279,14 +304,12 @@ static efi_status_t efi_install_fdt(void *fdt) 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_start = fdt_addr; 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; } @@ -443,7 +466,6 @@ static int do_bootefi(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) char *saddr; efi_status_t r; unsigned long fdt_addr; - void *fdt; /* Allow unaligned memory access */ allow_unaligned(); @@ -464,8 +486,7 @@ static int do_bootefi(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) if (!fdt_addr && *argv[2] != '0') return CMD_RET_USAGE; /* Install device tree */ - fdt = map_sysmem(fdt_addr, 0); - r = efi_install_fdt(fdt); + r = efi_install_fdt(fdt_addr); if (r != EFI_SUCCESS) { printf("ERROR: failed to install device tree\n"); return CMD_RET_FAILURE; -- cgit v1.3.1 From 7086a71aa8a7312db7c58b3989ccce5caf4aedc7 Mon Sep 17 00:00:00 2001 From: Heinrich Schuchardt Date: Fri, 31 Aug 2018 21:31:33 +0200 Subject: efi_loader: buffer size for load options The number of bytes in an utf-8 string is an upper limit for the number of words in the equivalent utf-16 string. In so far the inumbant coding works correctly. For non-ASCII characters the utf-16 string is shorter. With the patch only the necessary buffer size is allocated for the load options. Signed-off-by: Heinrich Schuchardt Signed-off-by: Alexander Graf --- cmd/bootefi.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'cmd') diff --git a/cmd/bootefi.c b/cmd/bootefi.c index e169f5edc0d..a0a8a7cdac0 100644 --- a/cmd/bootefi.c +++ b/cmd/bootefi.c @@ -116,18 +116,20 @@ static void set_load_options(struct efi_loaded_image *loaded_image_info, { size_t size; const char *env = env_get(env_var); + u16 *pos; loaded_image_info->load_options = NULL; loaded_image_info->load_options_size = 0; if (!env) return; - size = strlen(env) + 1; + size = utf8_utf16_strlen(env) + 1; loaded_image_info->load_options = calloc(size, sizeof(u16)); if (!loaded_image_info->load_options) { printf("ERROR: Out of memory\n"); return; } - utf8_to_utf16(loaded_image_info->load_options, (u8 *)env, size); + pos = loaded_image_info->load_options; + utf8_utf16_strcpy(&pos, env); loaded_image_info->load_options_size = size * 2; } -- cgit v1.3.1 From cda40b2aea39ec05683a2895f31c630ef2ce5131 Mon Sep 17 00:00:00 2001 From: AKASHI Takahiro Date: Tue, 11 Sep 2018 15:59:07 +0900 Subject: cmd: fat: add offset parameter to fatwrite In this patch, fatwrite command is extended so as to accept an additional parameter of file offset. Signed-off-by: AKASHI Takahiro Signed-off-by: Alexander Graf --- cmd/fat.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) (limited to 'cmd') diff --git a/cmd/fat.c b/cmd/fat.c index 03de5d11afb..2a5f7bfc269 100644 --- a/cmd/fat.c +++ b/cmd/fat.c @@ -104,6 +104,7 @@ static int do_fat_fswrite(cmd_tbl_t *cmdtp, int flag, int ret; unsigned long addr; unsigned long count; + long offset; struct blk_desc *dev_desc = NULL; disk_partition_t info; int dev = 0; @@ -126,9 +127,11 @@ static int do_fat_fswrite(cmd_tbl_t *cmdtp, int flag, } addr = simple_strtoul(argv[3], NULL, 16); count = (argc <= 5) ? 0 : simple_strtoul(argv[5], NULL, 16); + /* offset should be a hex, but "-1" is allowed */ + offset = (argc <= 6) ? 0 : simple_strtol(argv[6], NULL, 16); buf = map_sysmem(addr, count); - ret = file_fat_write(argv[4], buf, 0, count, &size); + ret = file_fat_write(argv[4], buf, offset, count, &size); unmap_sysmem(buf); if (ret < 0) { printf("\n** Unable to write \"%s\" from %s %d:%d **\n", @@ -142,9 +145,9 @@ static int do_fat_fswrite(cmd_tbl_t *cmdtp, int flag, } U_BOOT_CMD( - fatwrite, 6, 0, do_fat_fswrite, + fatwrite, 7, 0, do_fat_fswrite, "write file into a dos filesystem", - " []\n" + " [ []]\n" " - write file 'filename' from the address 'addr' in RAM\n" " to 'dev' on 'interface'" ); -- cgit v1.3.1 From 0349da51009211b540a8653795dee5d4b872fd3b Mon Sep 17 00:00:00 2001 From: AKASHI Takahiro Date: Tue, 11 Sep 2018 15:59:11 +0900 Subject: cmd: fat: add fatmkdir command In this patch, a new command, fatmkdir, is added. Please note that, as there is no notion of "current directory" on u-boot, a directory name specified must contains an absolute directory path as a parent directory. Otherwise, "/" (root directory) is assumed. Signed-off-by: AKASHI Takahiro Signed-off-by: Alexander Graf --- cmd/fat.c | 13 +++++++++++++ 1 file changed, 13 insertions(+) (limited to 'cmd') diff --git a/cmd/fat.c b/cmd/fat.c index 2a5f7bfc269..b685bf70a2b 100644 --- a/cmd/fat.c +++ b/cmd/fat.c @@ -151,4 +151,17 @@ U_BOOT_CMD( " - write file 'filename' from the address 'addr' in RAM\n" " to 'dev' on 'interface'" ); + +static int do_fat_mkdir(cmd_tbl_t *cmdtp, int flag, int argc, + char * const argv[]) +{ + return do_mkdir(cmdtp, flag, argc, argv, FS_TYPE_FAT); +} + +U_BOOT_CMD( + fatmkdir, 4, 1, do_fat_mkdir, + "create a directory", + " [] \n" + " - create a directory in 'dev' on 'interface'" +); #endif -- cgit v1.3.1 From d4b751e9f3efc5f230c0596c082ba13ca89618e1 Mon Sep 17 00:00:00 2001 From: AKASHI Takahiro Date: Tue, 11 Sep 2018 15:59:15 +0900 Subject: cmd: fat: add fatrm command In this patch, a new command, fatrm, is added so as to delete a file or directory. Signed-off-by: AKASHI Takahiro Signed-off-by: Alexander Graf --- cmd/fat.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) (limited to 'cmd') diff --git a/cmd/fat.c b/cmd/fat.c index b685bf70a2b..4b9a7eaab05 100644 --- a/cmd/fat.c +++ b/cmd/fat.c @@ -152,6 +152,18 @@ U_BOOT_CMD( " to 'dev' on 'interface'" ); +static int do_fat_rm(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) +{ + return do_rm(cmdtp, flag, argc, argv, FS_TYPE_FAT); +} + +U_BOOT_CMD( + fatrm, 4, 1, do_fat_rm, + "delete a file", + " [] \n" + " - delete a file from 'dev' on 'interface'" +); + static int do_fat_mkdir(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) { -- cgit v1.3.1 From 8887acc68565cad187808db55cd4284385891b87 Mon Sep 17 00:00:00 2001 From: Heinrich Schuchardt Date: Sun, 16 Sep 2018 07:19:48 +0200 Subject: efi_loader: do not use local variable for handle Do not use a local variable for the handle backing the memory device path. Adjust relate comments. Signed-off-by: Heinrich Schuchardt Signed-off-by: Alexander Graf --- cmd/bootefi.c | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) (limited to 'cmd') diff --git a/cmd/bootefi.c b/cmd/bootefi.c index a0a8a7cdac0..d6366c3e26d 100644 --- a/cmd/bootefi.c +++ b/cmd/bootefi.c @@ -325,7 +325,7 @@ static efi_status_t do_bootefi_exec(void *efi, { struct efi_loaded_image loaded_image_info = {}; struct efi_object loaded_image_info_obj = {}; - struct efi_object mem_obj = {}; + efi_handle_t mem_handle = NULL; struct efi_device_path *memdp = NULL; efi_status_t ret; @@ -335,16 +335,21 @@ static efi_status_t do_bootefi_exec(void *efi, /* * Special case for efi payload not loaded from disk, such as * 'bootefi hello' or for example payload loaded directly into - * memory via jtag/etc: + * memory via jtag, etc: */ if (!device_path && !image_path) { printf("WARNING: using memory device/image path, this may confuse some payloads!\n"); /* actual addresses filled in after efi_load_pe() */ memdp = efi_dp_from_mem(0, 0, 0); device_path = image_path = memdp; - efi_add_handle(&mem_obj); - - ret = efi_add_protocol(mem_obj.handle, &efi_guid_device_path, + /* + * Grub expects that the device path of the loaded image is + * installed on a handle. + */ + ret = efi_create_handle(&mem_handle); + if (ret != EFI_SUCCESS) + goto exit; + ret = efi_add_protocol(mem_handle, &efi_guid_device_path, device_path); if (ret != EFI_SUCCESS) goto exit; @@ -428,8 +433,8 @@ static efi_status_t do_bootefi_exec(void *efi, exit: /* image has returned, loaded-image obj goes *poof*: */ list_del(&loaded_image_info_obj.link); - if (mem_obj.handle) - list_del(&mem_obj.link); + if (mem_handle) + efi_delete_handle(mem_handle); return ret; } -- cgit v1.3.1 From 79276eb2430d02c84a31fc5613e41aba05429184 Mon Sep 17 00:00:00 2001 From: Heinrich Schuchardt Date: Sun, 16 Sep 2018 07:20:21 +0200 Subject: efi_loader: memory leak in efi_set_bootdev() efi_set_bootdev() may be called repeatedly. Free the memory allocated for device paths in previous calls. Signed-off-by: Heinrich Schuchardt Signed-off-by: Alexander Graf --- cmd/bootefi.c | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'cmd') diff --git a/cmd/bootefi.c b/cmd/bootefi.c index d6366c3e26d..c8812b0f5e2 100644 --- a/cmd/bootefi.c +++ b/cmd/bootefi.c @@ -603,6 +603,13 @@ void efi_set_bootdev(const char *dev, const char *devnr, const char *path) char filename[32] = { 0 }; /* dp->str is u16[32] long */ char *s; + /* efi_set_bootdev is typically called repeatedly, recover memory */ + efi_free_pool(bootefi_device_path); + efi_free_pool(bootefi_image_path); + /* If blk_get_device_part_str fails, avoid duplicate free. */ + bootefi_device_path = NULL; + bootefi_image_path = NULL; + if (strcmp(dev, "Net")) { struct blk_desc *desc; disk_partition_t fs_partition; -- cgit v1.3.1 From 4e6b5d6503ce8f16f00df4aedd137e919026dfad Mon Sep 17 00:00:00 2001 From: Heinrich Schuchardt Date: Thu, 20 Sep 2018 21:58:23 +0200 Subject: efi_loader: create root node Currently we assign a lot of protocols to loaded images though these protocols are not related to them. Instead they should be installed on a separate handle. Via the device path it is the parent to the devices like the network adapter. Signed-off-by: Heinrich Schuchardt Signed-off-by: Alexander Graf --- cmd/bootefi.c | 5 +++ include/efi_loader.h | 9 +++++ lib/efi_loader/Makefile | 1 + lib/efi_loader/efi_boottime.c | 18 --------- lib/efi_loader/efi_device_path.c | 4 -- lib/efi_loader/efi_root_node.c | 79 ++++++++++++++++++++++++++++++++++++++++ 6 files changed, 94 insertions(+), 22 deletions(-) create mode 100644 lib/efi_loader/efi_root_node.c (limited to 'cmd') diff --git a/cmd/bootefi.c b/cmd/bootefi.c index c8812b0f5e2..5fc054c9dac 100644 --- a/cmd/bootefi.c +++ b/cmd/bootefi.c @@ -49,6 +49,11 @@ efi_status_t efi_init_obj_list(void) if (ret != EFI_SUCCESS) goto out; + /* Initialize root node */ + ret = efi_root_node_register(); + if (ret != EFI_SUCCESS) + goto out; + /* Initialize EFI driver uclass */ ret = efi_driver_init(); if (ret != EFI_SUCCESS) diff --git a/include/efi_loader.h b/include/efi_loader.h index 3bf059b447d..2855c01681a 100644 --- a/include/efi_loader.h +++ b/include/efi_loader.h @@ -20,6 +20,11 @@ /* Maximum number of configuration tables */ #define EFI_MAX_CONFIGURATION_TABLES 16 +/* GUID used by the root node */ +#define U_BOOT_GUID \ + EFI_GUID(0xe61d73b9, 0xa384, 0x4acc, \ + 0xae, 0xab, 0x82, 0xe8, 0x28, 0xf3, 0x62, 0x8b) + int __efi_entry_check(void); int __efi_exit_check(void); const char *__efi_nesting(void); @@ -104,6 +109,8 @@ extern const struct efi_unicode_collation_protocol uint16_t *efi_dp_str(struct efi_device_path *dp); +/* GUID of the U-Boot root node */ +extern const efi_guid_t efi_u_boot_guid; /* GUID of the EFI_BLOCK_IO_PROTOCOL */ extern const efi_guid_t efi_block_io_guid; extern const efi_guid_t efi_global_variable_guid; @@ -210,6 +217,8 @@ extern struct list_head efi_obj_list; /* List of all events */ extern struct list_head efi_events; +/* Called by bootefi to initialize root node */ +efi_status_t efi_root_node_register(void); /* Called by bootefi to initialize runtime */ efi_status_t efi_initialize_system_table(void); /* Called by bootefi to make console interface available */ diff --git a/lib/efi_loader/Makefile b/lib/efi_loader/Makefile index 7eebbc5b4e6..6703435947f 100644 --- a/lib/efi_loader/Makefile +++ b/lib/efi_loader/Makefile @@ -26,6 +26,7 @@ obj-y += efi_device_path_utilities.o obj-y += efi_file.o obj-y += efi_image_loader.o obj-y += efi_memory.o +obj-y += efi_root_node.o obj-y += efi_runtime.o obj-y += efi_unicode_collation.o obj-y += efi_variable.o diff --git a/lib/efi_loader/efi_boottime.c b/lib/efi_loader/efi_boottime.c index 5d93db8e0c7..b4de9961b88 100644 --- a/lib/efi_loader/efi_boottime.c +++ b/lib/efi_loader/efi_boottime.c @@ -1514,24 +1514,6 @@ efi_status_t efi_setup_loaded_image( if (ret != EFI_SUCCESS) goto failure; - ret = efi_add_protocol(obj->handle, - &efi_guid_device_path_to_text_protocol, - (void *)&efi_device_path_to_text); - if (ret != EFI_SUCCESS) - goto failure; - - ret = efi_add_protocol(obj->handle, - &efi_guid_device_path_utilities_protocol, - (void *)&efi_device_path_utilities); - if (ret != EFI_SUCCESS) - goto failure; - - ret = efi_add_protocol(obj->handle, - &efi_guid_unicode_collation_protocol, - (void *)&efi_unicode_collation_protocol); - if (ret != EFI_SUCCESS) - goto failure; - return ret; failure: printf("ERROR: Failure to install protocols for loaded image\n"); diff --git a/lib/efi_loader/efi_device_path.c b/lib/efi_loader/efi_device_path.c index 9d776a6d99f..5a61a1c1dcf 100644 --- a/lib/efi_loader/efi_device_path.c +++ b/lib/efi_loader/efi_device_path.c @@ -22,10 +22,6 @@ static const struct efi_device_path END = { .length = sizeof(END), }; -#define U_BOOT_GUID \ - EFI_GUID(0xe61d73b9, 0xa384, 0x4acc, \ - 0xae, 0xab, 0x82, 0xe8, 0x28, 0xf3, 0x62, 0x8b) - /* template ROOT node: */ static const struct efi_device_path_vendor ROOT = { .dp = { diff --git a/lib/efi_loader/efi_root_node.c b/lib/efi_loader/efi_root_node.c new file mode 100644 index 00000000000..b056ba3ee88 --- /dev/null +++ b/lib/efi_loader/efi_root_node.c @@ -0,0 +1,79 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Root node for system services + * + * Copyright (c) 2018 Heinrich Schuchardt + */ + +#include +#include +#include + +const efi_guid_t efi_u_boot_guid = U_BOOT_GUID; + +struct efi_root_dp { + struct efi_device_path_vendor vendor; + struct efi_device_path end; +} __packed; + +/** + * efi_root_node_register() - create root node + * + * Create the root node on which we install all protocols that are + * not related to a loaded image or a driver. + * + * Return: status code + */ +efi_status_t efi_root_node_register(void) +{ + efi_handle_t root; + efi_status_t ret; + struct efi_root_dp *dp; + + /* Create handle */ + ret = efi_create_handle(&root); + if (ret != EFI_SUCCESS) + return ret; + + /* Install device path protocol */ + dp = calloc(1, sizeof(*dp)); + if (!dp) + return EFI_OUT_OF_RESOURCES; + + /* Fill vendor node */ + dp->vendor.dp.type = DEVICE_PATH_TYPE_HARDWARE_DEVICE; + dp->vendor.dp.sub_type = DEVICE_PATH_SUB_TYPE_VENDOR; + dp->vendor.dp.length = sizeof(struct efi_device_path_vendor); + dp->vendor.guid = efi_u_boot_guid; + + /* Fill end node */ + dp->end.type = DEVICE_PATH_TYPE_END; + dp->end.sub_type = DEVICE_PATH_SUB_TYPE_END; + dp->end.length = sizeof(struct efi_device_path); + + /* Install device path protocol */ + ret = efi_add_protocol(root, &efi_guid_device_path, dp); + if (ret != EFI_SUCCESS) + goto failure; + + /* Install device path to text protocol */ + ret = efi_add_protocol(root, &efi_guid_device_path_to_text_protocol, + (void *)&efi_device_path_to_text); + if (ret != EFI_SUCCESS) + goto failure; + + /* Install device path utilities protocol */ + ret = efi_add_protocol(root, &efi_guid_device_path_utilities_protocol, + (void *)&efi_device_path_utilities); + if (ret != EFI_SUCCESS) + goto failure; + + /* Install Unicode collation protocol */ + ret = efi_add_protocol(root, &efi_guid_unicode_collation_protocol, + (void *)&efi_unicode_collation_protocol); + if (ret != EFI_SUCCESS) + goto failure; + +failure: + return ret; +} -- cgit v1.3.1 From 24638a1f2109f61834b212b1be73dd21da411e63 Mon Sep 17 00:00:00 2001 From: Alexander Graf Date: Sun, 23 Sep 2018 16:23:56 +0200 Subject: efi_loader: Fix loaded_image handle passing from EL3 When running in EL3 mode on AArch64, we have to first drop to EL2 to execute a UEFI payload. When dropping down, the arguments to the entry point have to stay identical to the ones for normal entry though. In commit ea54ad59286 ("efi_loader: pass handle of loaded image") we incorrectly changed that logic and had the el3 entry path diverge. Fix it up by syncing it back to what it's supposed to be. Fixes: ea54ad59286 ("efi_loader: pass handle of loaded image") Signed-off-by: Alexander Graf Reviewed-by: Mark Kettenis --- cmd/bootefi.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'cmd') diff --git a/cmd/bootefi.c b/cmd/bootefi.c index 5fc054c9dac..6395d4b9b0d 100644 --- a/cmd/bootefi.c +++ b/cmd/bootefi.c @@ -408,7 +408,7 @@ static efi_status_t do_bootefi_exec(void *efi, /* Move into EL2 and keep running there */ armv8_switch_to_el2((ulong)entry, - (ulong)&loaded_image_info_obj.handle, + (ulong)loaded_image_info_obj.handle, (ulong)&systab, 0, (ulong)efi_run_in_el2, ES_TO_AARCH64); -- cgit v1.3.1 From c982874e930d5d673501cd94df07bcbd215d5883 Mon Sep 17 00:00:00 2001 From: Heinrich Schuchardt Date: Sun, 23 Sep 2018 17:21:51 +0200 Subject: efi_loader: refactor efi_setup_loaded_image() Create the handle of loaded images and the EFI_LOADED_IMAGE_PROTOCOL inside efi_setup_loaded_image(). Do not use local variables. Currently we expect the loaded image handle to point to the loaded image protocol. Additionally we have appended private fields to the protocol. With the patch the handle points to a loaded image object and the private fields are added here. This matches how we handle the net and the gop object. Signed-off-by: Heinrich Schuchardt Signed-off-by: Alexander Graf --- cmd/bootefi.c | 67 ++++++++++++++++------------ include/efi_api.h | 8 ---- include/efi_loader.h | 27 +++++++++--- lib/efi_loader/efi_boottime.c | 92 +++++++++++++++++++-------------------- lib/efi_loader/efi_image_loader.c | 23 +++++----- 5 files changed, 117 insertions(+), 100 deletions(-) (limited to 'cmd') diff --git a/cmd/bootefi.c b/cmd/bootefi.c index 6395d4b9b0d..82d755ceb31 100644 --- a/cmd/bootefi.c +++ b/cmd/bootefi.c @@ -320,19 +320,26 @@ static efi_status_t efi_install_fdt(ulong fdt_addr) 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. +/** + * do_bootefi_exec() - execute EFI binary + * + * @efi: address of the binary + * @device_path: path of the device from which the binary was loaded + * @image_path: device path of the binary + * Return: status code + * + * Load the EFI binary into a newly assigned memory unwinding the relocation + * information, install the loaded image protocol, and call the binary. */ 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 = {}; efi_handle_t mem_handle = NULL; struct efi_device_path *memdp = NULL; efi_status_t ret; + struct efi_loaded_image_obj *image_handle = NULL; + struct efi_loaded_image *loaded_image_info = NULL; EFIAPI efi_status_t (*entry)(efi_handle_t image_handle, struct efi_system_table *st); @@ -362,8 +369,10 @@ static efi_status_t do_bootefi_exec(void *efi, assert(device_path && image_path); } - efi_setup_loaded_image(&loaded_image_info, &loaded_image_info_obj, - device_path, image_path); + ret = efi_setup_loaded_image(device_path, image_path, &image_handle, + &loaded_image_info); + if (ret != EFI_SUCCESS) + goto exit; /* * gd lives in a fixed register which may get clobbered while we execute @@ -372,9 +381,9 @@ static efi_status_t do_bootefi_exec(void *efi, efi_save_gd(); /* Transfer environment variable bootargs as load options */ - set_load_options(&loaded_image_info, "bootargs"); + set_load_options(loaded_image_info, "bootargs"); /* Load the EFI payload */ - entry = efi_load_pe(efi, &loaded_image_info); + entry = efi_load_pe(image_handle, efi, loaded_image_info); if (!entry) { ret = EFI_LOAD_ERROR; goto exit; @@ -382,10 +391,10 @@ static efi_status_t do_bootefi_exec(void *efi, if (memdp) { struct efi_device_path_memory *mdp = (void *)memdp; - mdp->memory_type = loaded_image_info.image_code_type; - mdp->start_address = (uintptr_t)loaded_image_info.image_base; + mdp->memory_type = loaded_image_info->image_code_type; + mdp->start_address = (uintptr_t)loaded_image_info->image_base; mdp->end_address = mdp->start_address + - loaded_image_info.image_size; + loaded_image_info->image_size; } /* we don't support much: */ @@ -395,8 +404,8 @@ static efi_status_t do_bootefi_exec(void *efi, /* Call our payload! */ debug("%s:%d Jumping to 0x%lx\n", __func__, __LINE__, (long)entry); - if (setjmp(&loaded_image_info.exit_jmp)) { - ret = loaded_image_info.exit_status; + if (setjmp(&image_handle->exit_jmp)) { + ret = image_handle->exit_status; goto exit; } @@ -408,7 +417,7 @@ static efi_status_t do_bootefi_exec(void *efi, /* Move into EL2 and keep running there */ armv8_switch_to_el2((ulong)entry, - (ulong)loaded_image_info_obj.handle, + (ulong)image_handle, (ulong)&systab, 0, (ulong)efi_run_in_el2, ES_TO_AARCH64); @@ -425,7 +434,7 @@ static efi_status_t do_bootefi_exec(void *efi, secure_ram_addr(_do_nonsec_entry)( efi_run_in_hyp, (uintptr_t)entry, - (uintptr_t)loaded_image_info_obj.handle, + (uintptr_t)image_handle, (uintptr_t)&systab); /* Should never reach here, efi exits with longjmp */ @@ -433,11 +442,12 @@ static efi_status_t do_bootefi_exec(void *efi, } #endif - ret = efi_do_enter(loaded_image_info_obj.handle, &systab, entry); + ret = efi_do_enter(image_handle, &systab, entry); exit: /* image has returned, loaded-image obj goes *poof*: */ - list_del(&loaded_image_info_obj.link); + if (image_handle) + efi_delete_handle(&image_handle->parent); if (mem_handle) efi_delete_handle(mem_handle); @@ -522,8 +532,8 @@ static int do_bootefi(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) #endif #ifdef CONFIG_CMD_BOOTEFI_SELFTEST if (!strcmp(argv[1], "selftest")) { - struct efi_loaded_image loaded_image_info = {}; - struct efi_object loaded_image_info_obj = {}; + struct efi_loaded_image_obj *image_handle; + struct efi_loaded_image *loaded_image_info; /* Construct a dummy device path. */ bootefi_device_path = efi_dp_from_mem(EFI_RESERVED_MEMORY_TYPE, @@ -531,9 +541,12 @@ static int do_bootefi(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) (uintptr_t)&efi_selftest); bootefi_image_path = efi_dp_from_file(NULL, 0, "\\selftest"); - efi_setup_loaded_image(&loaded_image_info, - &loaded_image_info_obj, - bootefi_device_path, bootefi_image_path); + r = efi_setup_loaded_image(bootefi_device_path, + bootefi_image_path, &image_handle, + &loaded_image_info); + if (r != EFI_SUCCESS) + return CMD_RET_FAILURE; + /* * gd lives in a fixed register which may get clobbered while we * execute the payload. So save it here and restore it on every @@ -541,12 +554,12 @@ static int do_bootefi(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) */ efi_save_gd(); /* Transfer environment variable efi_selftest as load options */ - set_load_options(&loaded_image_info, "efi_selftest"); + set_load_options(loaded_image_info, "efi_selftest"); /* Execute the test */ - r = efi_selftest(loaded_image_info_obj.handle, &systab); + r = efi_selftest(image_handle, &systab); efi_restore_gd(); - free(loaded_image_info.load_options); - list_del(&loaded_image_info_obj.link); + free(loaded_image_info->load_options); + efi_delete_handle(&image_handle->parent); return r != EFI_SUCCESS; } else #endif diff --git a/include/efi_api.h b/include/efi_api.h index d423521d0da..bea19a5a123 100644 --- a/include/efi_api.h +++ b/include/efi_api.h @@ -339,14 +339,6 @@ struct efi_loaded_image { unsigned int image_code_type; unsigned int image_data_type; unsigned long unload; - - /* Below are efi loader private fields */ -#ifdef CONFIG_EFI_LOADER - void *reloc_base; - aligned_u64 reloc_size; - efi_status_t exit_status; - struct jmp_buf_data exit_jmp; -#endif }; #define DEVICE_PATH_GUID \ diff --git a/include/efi_loader.h b/include/efi_loader.h index 5d522f133ec..34e44c6677c 100644 --- a/include/efi_loader.h +++ b/include/efi_loader.h @@ -183,6 +183,20 @@ struct efi_object { void *handle; }; +/** + * struct efi_loaded_image_obj - handle of a loaded image + */ +struct efi_loaded_image_obj { + /* Generic EFI object parent class data */ + struct efi_object parent; + void *reloc_base; + aligned_u64 reloc_size; + efi_status_t exit_status; + struct jmp_buf_data exit_jmp; + EFIAPI efi_status_t (*entry)(efi_handle_t image_handle, + struct efi_system_table *st); +}; + /** * struct efi_event * @@ -264,7 +278,8 @@ efi_status_t efi_set_watchdog(unsigned long timeout); /* Called from places to check whether a timer expired */ void efi_timer_check(void); /* PE loader implementation */ -void *efi_load_pe(void *efi, struct efi_loaded_image *loaded_image_info); +void *efi_load_pe(struct efi_loaded_image_obj *handle, void *efi, + struct efi_loaded_image *loaded_image_info); /* Called once to store the pristine gd pointer */ void efi_save_gd(void); /* Special case handler for error/abort that just tries to dtrt to get @@ -345,14 +360,12 @@ int efi_memory_init(void); /* Adds new or overrides configuration table entry to the system table */ efi_status_t efi_install_configuration_table(const efi_guid_t *guid, void *table); /* Sets up a loaded image */ -efi_status_t efi_setup_loaded_image( - struct efi_loaded_image *info, struct efi_object *obj, - struct efi_device_path *device_path, - struct efi_device_path *file_path); +efi_status_t efi_setup_loaded_image(struct efi_device_path *device_path, + struct efi_device_path *file_path, + struct efi_loaded_image_obj **handle_ptr, + struct efi_loaded_image **info_ptr); efi_status_t efi_load_image_from_path(struct efi_device_path *file_path, void **buffer); -/* Print information about a loaded image */ -efi_status_t efi_print_image_info(struct efi_loaded_image *image, void *pc); /* Print information about all loaded images */ void efi_print_image_infos(void *pc); diff --git a/lib/efi_loader/efi_boottime.c b/lib/efi_loader/efi_boottime.c index 8e0e2f7f87d..97eb19cd14d 100644 --- a/lib/efi_loader/efi_boottime.c +++ b/lib/efi_loader/efi_boottime.c @@ -1470,17 +1470,31 @@ static efi_status_t EFIAPI efi_install_configuration_table_ext(efi_guid_t *guid, * * Return: status code */ -efi_status_t efi_setup_loaded_image( - struct efi_loaded_image *info, struct efi_object *obj, - struct efi_device_path *device_path, - struct efi_device_path *file_path) +efi_status_t efi_setup_loaded_image(struct efi_device_path *device_path, + struct efi_device_path *file_path, + struct efi_loaded_image_obj **handle_ptr, + struct efi_loaded_image **info_ptr) { efi_status_t ret; + struct efi_loaded_image *info; + struct efi_loaded_image_obj *obj; + + info = calloc(1, sizeof(*info)); + if (!info) + return EFI_OUT_OF_RESOURCES; + obj = calloc(1, sizeof(*obj)); + if (!obj) { + free(info); + return EFI_OUT_OF_RESOURCES; + } /* Add internal object to object list */ - efi_add_handle(obj); - /* efi_exit() assumes that the handle points to the info */ - obj->handle = info; + efi_add_handle(&obj->parent); + + if (info_ptr) + *info_ptr = info; + if (handle_ptr) + *handle_ptr = obj; info->revision = EFI_LOADED_IMAGE_PROTOCOL_REVISION; info->file_path = file_path; @@ -1492,8 +1506,8 @@ efi_status_t efi_setup_loaded_image( * When asking for the device path interface, return * bootefi_device_path */ - ret = efi_add_protocol(obj->handle, &efi_guid_device_path, - device_path); + ret = efi_add_protocol(obj->parent.handle, + &efi_guid_device_path, device_path); if (ret != EFI_SUCCESS) goto failure; } @@ -1502,7 +1516,8 @@ efi_status_t efi_setup_loaded_image( * When asking for the loaded_image interface, just * return handle which points to loaded_image_info */ - ret = efi_add_protocol(obj->handle, &efi_guid_loaded_image, info); + ret = efi_add_protocol(obj->parent.handle, + &efi_guid_loaded_image, info); if (ret != EFI_SUCCESS) goto failure; @@ -1585,7 +1600,8 @@ static efi_status_t EFIAPI efi_load_image(bool boot_policy, efi_handle_t *image_handle) { struct efi_loaded_image *info; - struct efi_object *obj; + struct efi_loaded_image_obj **image_obj = + (struct efi_loaded_image_obj **)image_handle; efi_status_t ret; EFI_ENTRY("%d, %p, %pD, %p, %zd, %p", boot_policy, parent_image, @@ -1601,18 +1617,6 @@ static efi_status_t EFIAPI efi_load_image(bool boot_policy, goto error; } - info = calloc(1, sizeof(*info)); - if (!info) { - ret = EFI_OUT_OF_RESOURCES; - goto error; - } - obj = calloc(1, sizeof(*obj)); - if (!obj) { - free(info); - ret = EFI_OUT_OF_RESOURCES; - goto error; - } - if (!source_buffer) { struct efi_device_path *dp, *fp; @@ -1624,29 +1628,29 @@ static efi_status_t EFIAPI efi_load_image(bool boot_policy, * file parts: */ efi_dp_split_file_path(file_path, &dp, &fp); - ret = efi_setup_loaded_image(info, obj, dp, fp); + ret = efi_setup_loaded_image(dp, fp, image_obj, &info); if (ret != EFI_SUCCESS) goto failure; } else { /* In this case, file_path is the "device" path, i.e. * something like a HARDWARE_DEVICE:MEMORY_MAPPED */ - ret = efi_setup_loaded_image(info, obj, file_path, NULL); + ret = efi_setup_loaded_image(file_path, NULL, image_obj, &info); if (ret != EFI_SUCCESS) - goto failure; + goto error; } - info->reserved = efi_load_pe(source_buffer, info); - if (!info->reserved) { + (*image_obj)->entry = efi_load_pe(*image_obj, source_buffer, info); + if (!(*image_obj)->entry) { ret = EFI_UNSUPPORTED; goto failure; } info->system_table = &systab; info->parent_handle = parent_image; - *image_handle = obj->handle; return EFI_EXIT(EFI_SUCCESS); failure: + efi_delete_handle(*image_handle); + *image_handle = NULL; free(info); - efi_delete_handle(obj); error: return EFI_EXIT(ret); } @@ -1668,16 +1672,14 @@ static efi_status_t EFIAPI efi_start_image(efi_handle_t image_handle, unsigned long *exit_data_size, s16 **exit_data) { - EFIAPI efi_status_t (*entry)(efi_handle_t image_handle, - struct efi_system_table *st); - struct efi_loaded_image *info = image_handle; + struct efi_loaded_image_obj *image_obj = + (struct efi_loaded_image_obj *)image_handle; efi_status_t ret; EFI_ENTRY("%p, %p, %p", image_handle, exit_data_size, exit_data); - entry = info->reserved; /* call the image! */ - if (setjmp(&info->exit_jmp)) { + if (setjmp(&image_obj->exit_jmp)) { /* * We called the entry point of the child image with EFI_CALL * in the lines below. The child image called the Exit() boot @@ -1700,12 +1702,12 @@ static efi_status_t EFIAPI efi_start_image(efi_handle_t image_handle, assert(__efi_entry_check()); debug("%sEFI: %lu returned by started image\n", __efi_nesting_dec(), - (unsigned long)((uintptr_t)info->exit_status & + (unsigned long)((uintptr_t)image_obj->exit_status & ~EFI_ERROR_MASK)); - return EFI_EXIT(info->exit_status); + return EFI_EXIT(image_obj->exit_status); } - ret = EFI_CALL(entry(image_handle, &systab)); + ret = EFI_CALL(image_obj->entry(image_handle, &systab)); /* * Usually UEFI applications call Exit() instead of returning. @@ -1736,17 +1738,11 @@ static efi_status_t EFIAPI efi_exit(efi_handle_t image_handle, int16_t *exit_data) { /* - * We require that the handle points to the original loaded - * image protocol interface. - * - * For getting the longjmp address this is safer than locating - * the protocol because the protocol may have been reinstalled - * pointing to another memory location. - * * TODO: We should call the unload procedure of the loaded * image protocol. */ - struct efi_loaded_image *loaded_image_info = (void *)image_handle; + struct efi_loaded_image_obj *image_obj = + (struct efi_loaded_image_obj *)image_handle; EFI_ENTRY("%p, %ld, %ld, %p", image_handle, exit_status, exit_data_size, exit_data); @@ -1760,8 +1756,8 @@ static efi_status_t EFIAPI efi_exit(efi_handle_t image_handle, */ efi_restore_gd(); - loaded_image_info->exit_status = exit_status; - longjmp(&loaded_image_info->exit_jmp, 1); + image_obj->exit_status = exit_status; + longjmp(&image_obj->exit_jmp, 1); panic("EFI application exited"); } diff --git a/lib/efi_loader/efi_image_loader.c b/lib/efi_loader/efi_image_loader.c index fdf40a62c8e..a18ce0a5705 100644 --- a/lib/efi_loader/efi_image_loader.c +++ b/lib/efi_loader/efi_image_loader.c @@ -48,20 +48,21 @@ static int machines[] = { * If the program counter is located within the image the offset to the base * address is shown. * + * @obj: EFI object * @image: loaded image * @pc: program counter (use NULL to suppress offset output) * @return: status code */ -efi_status_t efi_print_image_info(struct efi_loaded_image *image, void *pc) +static efi_status_t efi_print_image_info(struct efi_loaded_image_obj *obj, + struct efi_loaded_image *image, + void *pc) { - if (!image) - return EFI_INVALID_PARAMETER; printf("UEFI image"); printf(" [0x%p:0x%p]", - image->reloc_base, image->reloc_base + image->reloc_size - 1); - if (pc && pc >= image->reloc_base && - pc < image->reloc_base + image->reloc_size) - printf(" pc=0x%zx", pc - image->reloc_base); + obj->reloc_base, obj->reloc_base + obj->reloc_size - 1); + if (pc && pc >= obj->reloc_base && + pc < obj->reloc_base + obj->reloc_size) + printf(" pc=0x%zx", pc - obj->reloc_base); if (image->file_path) printf(" '%pD'", image->file_path); printf("\n"); @@ -82,6 +83,7 @@ void efi_print_image_infos(void *pc) list_for_each_entry(handler, &efiobj->protocols, link) { if (!guidcmp(handler->guid, &efi_guid_loaded_image)) { efi_print_image_info( + (struct efi_loaded_image_obj *)efiobj, handler->protocol_interface, pc); } } @@ -196,7 +198,8 @@ static void efi_set_code_and_data_type( * piece of memory. On successful load it then returns the entry point for * the binary. Otherwise NULL. */ -void *efi_load_pe(void *efi, struct efi_loaded_image *loaded_image_info) +void *efi_load_pe(struct efi_loaded_image_obj *handle, void *efi, + struct efi_loaded_image *loaded_image_info) { IMAGE_NT_HEADERS32 *nt; IMAGE_DOS_HEADER *dos; @@ -314,8 +317,8 @@ void *efi_load_pe(void *efi, struct efi_loaded_image *loaded_image_info) /* Populate the loaded image interface bits */ loaded_image_info->image_base = efi; loaded_image_info->image_size = image_size; - loaded_image_info->reloc_base = efi_reloc; - loaded_image_info->reloc_size = virt_size; + handle->reloc_base = efi_reloc; + handle->reloc_size = virt_size; return entry; } -- cgit v1.3.1