efi_loader: support device tree for bootefi selftest
authorHeinrich Schuchardt <xypron.glpk@gmx.de>
Sat, 3 Mar 2018 14:29:03 +0000 (15:29 +0100)
committerAlexander Graf <agraf@suse.de>
Wed, 4 Apr 2018 09:00:06 +0000 (11:00 +0200)
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@gmx.de>
Signed-off-by: Alexander Graf <agraf@suse.de>
cmd/bootefi.c
include/efi_loader.h
lib/efi_loader/efi_boottime.c

index 025a3dd1718a506438291d593ea0b7b7882cffab..6afece10bc12e5679d7d4216722320a9d4398c1e 100644 (file)
@@ -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"
index b6335182eda3beaaf8871ad3c69f517a366efc30..60f84dcf24bf6fa1d97a019d427bffa34003e496 100644 (file)
@@ -96,6 +96,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;
index 4e133e9b47d64cc2977ed4a143819b3a2335d7a5..3cee8d607c8278e5c7ff02217c64ebc9cf8bfd5d 100644 (file)
@@ -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;