[U-Boot] [PATCH 8/9] efi_loader: Add "bootefi" command

Matwey V. Kornilov matwey.kornilov at gmail.com
Thu Dec 24 12:15:52 CET 2015


Why just not to implement standard EFI behaviour when EFI looks for
boot-efi partition and proceed?

If ARM board developers will enable EFI support in the future, we can
have single one JeOS having all possible dtb in KIWI image.
BeagleBone Black has its own u-boot on eMMC, and the user need to push
S2 button to force hardware to use our openSUSE u-boot from SD card.
Maybe something like that is for other boards. If the single one
required u-boot feature is to run EFI grub, then we can even don't
touch preinstalled bootloader, that is not possible now, because we
need our openSUSE boot scripts.

2015-12-22 16:57 GMT+03:00 Alexander Graf <agraf at suse.de>:
> In order to execute an EFI application, we need to bridge the gap between
> U-Boot's notion of executing images and EFI's notion of doing the same.
>
> The best path forward IMHO here is to stick completely to the way U-Boot
> deals with payloads. You manually load them using whatever method to RAM
> and then have a simple boot command to execute them. So in our case, you
> would do
>
>   # load mmc 0:1 $loadaddr grub.efi
>   # bootefi $loadaddr
>
> which then gets you into a grub shell. Fdt information known to U-boot
> via the fdt addr command is also passed to the EFI payload.
>
> Signed-off-by: Alexander Graf <agraf at suse.de>
> ---
>  common/Makefile      |   1 +
>  common/cmd_bootefi.c | 168 +++++++++++++++++++++++++++++++++++++++++++++++++++
>  2 files changed, 169 insertions(+)
>  create mode 100644 common/cmd_bootefi.c
>
> diff --git a/common/Makefile b/common/Makefile
> index 2a1d9f8..a7a728a 100644
> --- a/common/Makefile
> +++ b/common/Makefile
> @@ -67,6 +67,7 @@ obj-$(CONFIG_CMD_SOURCE) += cmd_source.o
>  obj-$(CONFIG_CMD_BDI) += cmd_bdinfo.o
>  obj-$(CONFIG_CMD_BEDBUG) += bedbug.o cmd_bedbug.o
>  obj-$(CONFIG_CMD_BMP) += cmd_bmp.o
> +obj-$(CONFIG_EFI_LOADER) += cmd_bootefi.o
>  obj-$(CONFIG_CMD_BOOTMENU) += cmd_bootmenu.o
>  obj-$(CONFIG_CMD_BOOTLDR) += cmd_bootldr.o
>  obj-$(CONFIG_CMD_BOOTSTAGE) += cmd_bootstage.o
> diff --git a/common/cmd_bootefi.c b/common/cmd_bootefi.c
> new file mode 100644
> index 0000000..8d872d0
> --- /dev/null
> +++ b/common/cmd_bootefi.c
> @@ -0,0 +1,168 @@
> +/*
> + *  EFI application loader
> + *
> + *  Copyright (c) 2015 Alexander Graf
> + *
> + *  This library is free software; you can redistribute it and/or
> + *  modify it under the terms of the GNU Lesser General Public
> + *  License as published by the Free Software Foundation; either
> + *  version 2.1 of the License, or (at your option) any later version.
> + *
> + *  This library is distributed in the hope that it will be useful,
> + *  but WITHOUT ANY WARRANTY; without even the implied warranty of
> + *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
> + *  Lesser General Public License for more details.
> + *
> + *  You should have received a copy of the GNU Lesser General Public
> + *  License along with this library; if not, write to the Free Software
> + *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
> + *
> + *  SPDX-License-Identifier:     LGPL-2.1+
> + */
> +
> +#include <common.h>
> +#include <command.h>
> +#include <efi_loader.h>
> +#include <libfdt_env.h>
> +
> +/* This list contains all the EFI objects our payload has access to */
> +LIST_HEAD(efi_obj_list);
> +
> +/*
> + * When booting using the "bootefi" command, we don't know which
> + * physical device the file came from. So we create a pseudo-device
> + * called "bootefi" with the device path /bootefi.
> + *
> + * In addition to the originating device we also declare the file path
> + * of "bootefi" based loads to be /bootefi.
> + */
> +static struct efi_device_path_file_path bootefi_dummy_path[] = {
> +       {
> +               .dp.type = DEVICE_PATH_TYPE_MEDIA_DEVICE,
> +               .dp.sub_type = DEVICE_PATH_SUB_TYPE_FILE_PATH,
> +               .dp.length = sizeof(bootefi_dummy_path[0]),
> +               .str = { 'b','o','o','t','e','f','i' },
> +       }, {
> +               .dp.type = DEVICE_PATH_TYPE_END,
> +               .dp.sub_type = DEVICE_PATH_SUB_TYPE_END,
> +               .dp.length = sizeof(bootefi_dummy_path[0]),
> +       }
> +};
> +
> +static efi_status_t bootefi_open_dp(void *handle, efi_guid_t *protocol,
> +                       void **protocol_interface, void *agent_handle,
> +                       void *controller_handle, uint32_t attributes)
> +{
> +       *protocol_interface = bootefi_dummy_path;
> +       return EFI_SUCCESS;
> +}
> +
> +/* The EFI loaded_image interface for the image executed via "bootefi" */
> +static struct efi_loaded_image loaded_image_info = {
> +       .device_handle = bootefi_dummy_path,
> +       .file_path = bootefi_dummy_path,
> +};
> +
> +/* The EFI object struct for the image executed via "bootefi" */
> +static struct efi_object loaded_image_info_obj = {
> +       .handle = &loaded_image_info,
> +       .protocols = {
> +               {
> +                       /* When asking for the loaded_image interface, just
> +                        * return handle which points to loaded_image_info */
> +                       .guid = &efi_guid_loaded_image,
> +                       .open = &efi_return_handle,
> +               },
> +               {
> +                       /* When asking for the device path interface, return
> +                        * bootefi_dummy_path */
> +                       .guid = &efi_guid_device_path,
> +                       .open = &bootefi_open_dp,
> +               },
> +       },
> +};
> +
> +/* The EFI object struct for the device the "bootefi" image was loaded from */
> +static struct efi_object bootefi_device_obj = {
> +       .handle = bootefi_dummy_path,
> +       .protocols = {
> +               {
> +                       /* When asking for the device path interface, return
> +                        * bootefi_dummy_path */
> +                       .guid = &efi_guid_device_path,
> +                       .open = &bootefi_open_dp,
> +               }
> +       },
> +};
> +
> +/*
> + * 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 unsigned long do_bootefi_exec(void *efi)
> +{
> +       ulong (*entry)(void *image_handle, struct efi_system_table *st);
> +
> +       /*
> +        * 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();
> +
> +       /* Update system table to point to our currently loaded FDT */
> +       systab.tables[0].table = working_fdt;
> +
> +       if (!working_fdt) {
> +               printf("WARNING: No device tree loaded, expect boot to fail\n");
> +               systab.nr_tables = 0;
> +       }
> +
> +       /* Load the EFI payload */
> +       entry = efi_load_pe(efi, &loaded_image_info);
> +       if (!entry)
> +               return -1;
> +
> +       /* Initialize and populate EFI object list */
> +       INIT_LIST_HEAD(&efi_obj_list);
> +       list_add_tail(&loaded_image_info_obj.link, &efi_obj_list);
> +       list_add_tail(&bootefi_device_obj.link, &efi_obj_list);
> +#ifdef CONFIG_PARTITIONS
> +       efi_disk_register();
> +#endif
> +
> +       /* Call our payload! */
> +#ifdef DEBUG_EFI
> +       printf("%s:%d Jumping to 0x%lx\n", __func__, __LINE__, (long)entry);
> +#endif
> +       return entry(&loaded_image_info, &systab);
> +}
> +
> +
> +/* 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;
> +       unsigned long addr;
> +       int r = 0;
> +
> +       if (argc < 2)
> +               return 1;
> +       saddr = argv[1];
> +
> +       addr = simple_strtoul(saddr, NULL, 16);
> +
> +       printf("## Starting EFI application at 0x%08lx ...\n", addr);
> +       r = do_bootefi_exec((void *)addr);
> +       printf("## Application terminated, r = %d\n", r);
> +
> +       if (r != 0)
> +               r = 1;
> +
> +       return r;
> +}
> +
> +U_BOOT_CMD(
> +       bootefi, 2, 0, do_bootefi,
> +       "Boot from an EFI image in memory",
> +       "<image address>\n"
> +);
> --
> 2.1.4
>



-- 
With best regards,
Matwey V. Kornilov
http://blog.matwey.name
xmpp://0x2207@jabber.ru


More information about the U-Boot mailing list