[U-Boot] [PATCH v3 10/11] efi_loader: support device tree for bootefi selftest

Heinrich Schuchardt xypron.glpk at gmx.de
Sat Mar 3 14:29:03 UTC 2018


The second argument of the bootefi command should always be usable to
specify a device tree. This was missing for bootefi selftest and
bootefi hello.

Proper error handling is added.

Signed-off-by: Heinrich Schuchardt <xypron.glpk at gmx.de>
---
v3
	Mention fdt address as argument in online help of bootefi selftest
v2
	new patch
---
 cmd/bootefi.c                 | 111 ++++++++++++++++++++++++------------------
 include/efi_loader.h          |   2 +
 lib/efi_loader/efi_boottime.c |   2 +
 3 files changed, 68 insertions(+), 47 deletions(-)

diff --git a/cmd/bootefi.c b/cmd/bootefi.c
index 0eb9a1baab..6de7d8c743 100644
--- a/cmd/bootefi.c
+++ b/cmd/bootefi.c
@@ -178,11 +178,49 @@ static efi_status_t efi_run_in_el2(EFIAPI efi_status_t (*entry)(
 }
 #endif
 
+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;
+	}
+
+	/* 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)
 {
@@ -193,9 +231,6 @@ static efi_status_t do_bootefi_exec(void *efi, void *fdt,
 
 	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
@@ -220,32 +255,6 @@ 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 */
@@ -301,7 +310,7 @@ 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;
@@ -318,7 +327,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);
 
@@ -331,9 +340,10 @@ 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();
@@ -345,6 +355,22 @@ static int do_bootefi(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
 
 	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;
@@ -390,12 +416,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];
 
@@ -404,15 +425,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);
 
@@ -433,7 +450,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"
diff --git a/include/efi_loader.h b/include/efi_loader.h
index 85a47ca2f5..3ccbb98aaf 100644
--- a/include/efi_loader.h
+++ b/include/efi_loader.h
@@ -93,6 +93,8 @@ extern const efi_guid_t efi_guid_console_control;
 extern const efi_guid_t efi_guid_device_path;
 /* GUID of the EFI_DRIVER_BINDING_PROTOCOL */
 extern const efi_guid_t efi_guid_driver_binding_protocol;
+/* GUID of the device tree table */
+extern const efi_guid_t efi_guid_fdt;
 extern const efi_guid_t efi_guid_loaded_image;
 extern const efi_guid_t efi_guid_device_path_to_text_protocol;
 extern const efi_guid_t efi_simple_file_system_protocol_guid;
diff --git a/lib/efi_loader/efi_boottime.c b/lib/efi_loader/efi_boottime.c
index b80f59fd92..2f67030151 100644
--- a/lib/efi_loader/efi_boottime.c
+++ b/lib/efi_loader/efi_boottime.c
@@ -56,6 +56,8 @@ static volatile void *efi_gd, *app_gd;
 
 static int entry_count;
 static int nesting_level;
+/* GUID of the device tree table */
+const efi_guid_t efi_guid_fdt = EFI_FDT_GUID;
 /* GUID of the EFI_DRIVER_BINDING_PROTOCOL */
 const efi_guid_t efi_guid_driver_binding_protocol =
 			EFI_DRIVER_BINDING_PROTOCOL_GUID;
-- 
2.14.2



More information about the U-Boot mailing list