[U-Boot] [PATCH v1 15/15] efi_loader: add bootmgr

Rob Clark robdclark at gmail.com
Sat Aug 12 14:11:04 UTC 2017


On Sat, Aug 12, 2017 at 9:10 AM, Alexander Graf <agraf at suse.de> wrote:
>
>
> On 10.08.17 20:29, Rob Clark wrote:
>>
>> Similar to a "real" UEFI implementation, the bootmgr looks at the
>> BootOrder and BootXXXX variables to try to find an EFI payload to load
>> and boot.  This is added as a sub-command of bootefi.
>>
>> The idea is that the distro bootcmd would first try loading a payload
>> via the bootmgr, and then if that fails (ie. first boot or corrupted
>> EFI variables) it would fallback to loading bootaa64.efi.  (Which
>> would then load fallback.efi which would look for \EFI\*\boot.csv and
>> populate BootOrder and BootXXXX based on what it found.)
>>
>> Signed-off-by: Rob Clark <robdclark at gmail.com>
>> ---
>>   cmd/bootefi.c                     |  48 ++++++++++-
>>   include/config_distro_bootcmd.h   |   5 ++
>>   include/efi_api.h                 |   4 +
>>   include/efi_loader.h              |   6 ++
>>   lib/efi_loader/Makefile           |   2 +-
>>   lib/efi_loader/efi_bootmgr.c      | 169
>> ++++++++++++++++++++++++++++++++++++++
>>   lib/efi_loader/efi_boottime.c     |   6 +-
>>   lib/efi_loader/efi_image_loader.c |   1 +
>>   8 files changed, 235 insertions(+), 6 deletions(-)
>>   create mode 100644 lib/efi_loader/efi_bootmgr.c
>>
>> diff --git a/cmd/bootefi.c b/cmd/bootefi.c
>> index 80f52e9e35..02a0dd159b 100644
>> --- a/cmd/bootefi.c
>> +++ b/cmd/bootefi.c
>> @@ -219,6 +219,36 @@ exit:
>>         return ret;
>>   }
>>   +static int do_bootefi_bootmgr_exec(unsigned long fdt_addr)
>> +{
>> +       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
>> +        */
>> +       efi_save_gd();
>> +
>> +       addr = efi_bootmgr_load(&device_path, &file_path);
>> +       if (!addr)
>> +               return 1;
>> +
>> +       printf("## Starting EFI application at %p ...\n", addr);
>> +       r = do_bootefi_exec(addr, (void*)fdt_addr, device_path,
>> file_path);
>> +       printf("## Application terminated, r = %lu\n",
>> +              r & ~EFI_ERROR_MASK);
>> +
>> +       if (r != EFI_SUCCESS)
>> +               return 1;
>> +
>> +       return 0;
>> +}
>>     /* 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[])
>> @@ -237,7 +267,14 @@ static int do_bootefi(cmd_tbl_t *cmdtp, int flag, int
>> argc, char * const argv[])
>>                 memcpy((char *)addr, __efi_hello_world_begin, size);
>>         } 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);
>> +       } else {
>>                 saddr = argv[1];
>>                 addr = simple_strtoul(saddr, NULL, 16);
>> @@ -270,7 +307,11 @@ static char bootefi_help_text[] =
>>         "hello\n"
>>         "  - boot a sample Hello World application stored within U-Boot"
>>   #endif
>> -       ;
>> +       "bootmgr [fdt addr]\n"
>> +       "  - load and boot EFI payload based on BootOrder/BootXXXX
>> variables.\n"
>> +       "\n"
>> +       "    If specified, the device tree located at <fdt address>
>> gets\n"
>> +       "    exposed as EFI configuration table.\n";
>>   #endif
>>     U_BOOT_CMD(
>> @@ -308,6 +349,9 @@ void efi_set_bootdev(const char *dev, const char
>> *devnr, const char *path)
>>   #endif
>>         }
>>   +     if (!path)
>> +               return;
>> +
>>         if (strcmp(dev, "Net")) {
>>                 /* Add leading / to fs paths, because they're absolute */
>>                 snprintf(filename, sizeof(filename), "/%s", path);
>> diff --git a/include/config_distro_bootcmd.h
>> b/include/config_distro_bootcmd.h
>> index d8dab8e46a..94ccab02d2 100644
>> --- a/include/config_distro_bootcmd.h
>> +++ b/include/config_distro_bootcmd.h
>> @@ -112,6 +112,11 @@
>>     #define BOOTENV_SHARED_EFI
>> \
>>         "boot_efi_binary="
>> \
>> +               "if fdt addr ${fdt_addr_r}; then "
>> \
>> +                       "bootefi bootmgr ${fdt_addr_r};"
>> \
>
>
> This is too late. At this point you already checked that there indeed is a
> fallback binary. Since the bootmgr target actually knows which device it
> loads itself from, it can occur way before in the boot chain.
>
> Maybe we should just add a new boot_target for bootmgr. That way it
> naturally fits into the distro boot flow. You could then add a
> BOOTENV_DEV_BOOTMGR and simply run it from there.
>
> The only thing missing in that case is the device tree override - hmm...
>
> Oh well, if you need that I'm fine to leave it as hacky as it is here, but
> this boot protocol is definitely not what the UEFI guys had envisioned ;).
>

tbh I'm pretty lost in the distro bootcmd stuff, so if someone wants
to take a stab at a better approach, have at it.

We could possibly do 'bootefi bootmgr' earlier, if we already had the
fdt.  I'm not sure about all the various cases here.  I think the
*main* thing is that we try bootmgr first before falling back to
/efi/boot/bootxyzw.efi.  The rest is just optimization.

BR,
-R


More information about the U-Boot mailing list