summaryrefslogtreecommitdiff
path: root/cmd
diff options
context:
space:
mode:
authorTom Rini <trini@konsulko.com>2018-09-26 15:14:02 -0400
committerTom Rini <trini@konsulko.com>2018-09-26 17:02:46 -0400
commit0ae8dcfef7c890330c62bb34c724126ffc169bef (patch)
treeaeeaa9a83efad66ca4db0b4aca2ee5cf3478728e /cmd
parentd8d81d4a5d0e5aaef5a005a357d3b9ed2b7cc4b2 (diff)
parenteaac4fb296b1899369e49d941f2c0d346c7f5c7a (diff)
Merge tag 'signed-efi-next' of git://github.com/agraf/u-boot
Patch queue for efi - 2018-09-26 A lot of goodness in this release. We're *very* close to running the UEFI Shell and SCT natively. The only missing piece are HII protocols. - FAT write support (needed for SCT) - improved FAT directory support (needed for SCT) - RTC support with QEMU -M virt - Sandbox support (run UEFI binaries in Linux - yay) - Proper UTF-16 support - EFI_UNICODE_COLLATION_PROTOCOL support (for UEFI Shell) - EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL support (for UEFI Shell) - Fix window size determination - Fix Tegra by explicitly unmapping RAM - Clean up handle entanglement - Lots of generic code cleanup [trini: Fixup merge conflict in include/configs/qemu-arm.h] Signed-off-by: Tom Rini <trini@konsulko.com>
Diffstat (limited to 'cmd')
-rw-r--r--cmd/bootefi.c187
-rw-r--r--cmd/fat.c34
2 files changed, 151 insertions, 70 deletions
diff --git a/cmd/bootefi.c b/cmd/bootefi.c
index b60c151fb4..82d755ceb3 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)
@@ -116,32 +121,47 @@ 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;
}
-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 +174,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 128MB */
- new_fdt_addr = fdt_ram_start + (128 * 1024 * 1024) + fdt_size;
- if (efi_allocate_pages(EFI_ALLOCATE_MAX_ADDRESS,
- EFI_RUNTIME_SERVICES_DATA, fdt_pages,
- &new_fdt_addr) != EFI_SUCCESS) {
+ /* Safe fdt location is at 127MB */
+ new_fdt_addr = fdt_ram_start + (127 * 1024 * 1024) + fdt_size;
+ 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 +277,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,30 +311,35 @@ 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;
}
-/*
- * 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 = {};
- struct efi_object mem_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);
@@ -310,16 +347,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;
@@ -327,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
@@ -337,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;
@@ -347,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: */
@@ -360,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;
}
@@ -373,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);
@@ -390,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 */
@@ -398,13 +442,14 @@ 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 (mem_obj.handle)
- list_del(&mem_obj.link);
+ if (image_handle)
+ efi_delete_handle(&image_handle->parent);
+ if (mem_handle)
+ efi_delete_handle(mem_handle);
return ret;
}
@@ -443,7 +488,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 +508,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;
@@ -489,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,
@@ -498,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
@@ -508,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
@@ -575,6 +621,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;
diff --git a/cmd/fat.c b/cmd/fat.c
index 03de5d11af..4b9a7eaab0 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,10 +145,35 @@ 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",
- "<interface> <dev[:part]> <addr> <filename> [<bytes>]\n"
+ "<interface> <dev[:part]> <addr> <filename> [<bytes> [<offset>]]\n"
" - write file 'filename' from the address 'addr' in RAM\n"
" 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",
+ "<interface> [<dev[:part]>] <filename>\n"
+ " - delete a file from '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",
+ "<interface> [<dev[:part]>] <directory>\n"
+ " - create a directory in 'dev' on 'interface'"
+);
#endif