From: Ahmad Fatoum <[email protected]> Extend the EFI payload boot flow to support loading kernel, initrd, and devicetree directly from a FIT image. When a FIT is present, the loader extracts the relevant subimages ("kernel", "ramdisk", and "fdt") also support falling back to external files when possible.
Signed-off-by: Chali Anis <[email protected]> --- efi/payload/Kconfig | 1 + efi/payload/bootm.c | 125 ++++++++++++++++++++++++++++++++++++-------- 2 files changed, 104 insertions(+), 22 deletions(-) diff --git a/efi/payload/Kconfig b/efi/payload/Kconfig index e3a6a72d6a1c..4fb866210a69 100644 --- a/efi/payload/Kconfig +++ b/efi/payload/Kconfig @@ -32,6 +32,7 @@ config EFI_HANDOVER_PROTOCOL config EFI_PAYLOAD_BOOTM bool "EFI bootm protocol" + select BOOTM_FITIMAGE default !X86 endif diff --git a/efi/payload/bootm.c b/efi/payload/bootm.c index d0e995be5d7c..3e9ccd42bf7f 100644 --- a/efi/payload/bootm.c +++ b/efi/payload/bootm.c @@ -34,11 +34,74 @@ #include "image.h" #include "setup_header.h" +static bool ramdisk_is_fit(struct image_data *data) +{ + struct stat st; + + if (bootm_signed_images_are_forced()) + return true; + + if (data->initrd_file) { + if (!stat(data->initrd_file, &st) && st.st_size > 0) + return false; + } + + return data->os_fit ? fit_has_image(data->os_fit, + data->fit_config, "ramdisk") > 0 : false; +} + +static bool fdt_is_fit(struct image_data *data) +{ + struct stat st; + + if (bootm_signed_images_are_forced()) + return true; + + if (data->oftree_file) { + if (!stat(data->oftree_file, &st) && st.st_size > 0) + return false; + } + + return data->os_fit ? fit_has_image(data->os_fit, + data->fit_config, "fdt") > 0 : false; +} + static int efi_load_os(struct image_data *data, struct efi_loaded_image **loaded_image, efi_handle_t *handle) { - return efi_load_image(data->os_file, loaded_image, handle); + efi_status_t efiret; + efi_handle_t h; + + if (!data->os_fit) + return efi_load_image(data->os_file, loaded_image, handle); + + if (!data->fit_kernel) + return -ENOENT; + + efiret = BS->load_image(false, efi_parent_image, efi_device_path, + (void *)data->fit_kernel, data->fit_kernel_size, &h); + if (EFI_ERROR(efiret)) { + pr_err("failed to LoadImage: %s\n", efi_strerror(efiret)); + goto out_mem; + }; + + efiret = BS->open_protocol(h, &efi_loaded_image_protocol_guid, + (void **)loaded_image, efi_parent_image, + NULL, EFI_OPEN_PROTOCOL_GET_PROTOCOL); + if (EFI_ERROR(efiret)) { + pr_err("failed to OpenProtocol: %s\n", efi_strerror(efiret)); + goto out_unload; + } + + *handle = h; + + return 0; + +out_unload: + BS->unload_image(h); +out_mem: + return -efi_errno(efiret); } static int efi_load_ramdisk(struct image_data *data, void **initrd) @@ -47,17 +110,26 @@ static int efi_load_ramdisk(struct image_data *data, void **initrd) void *initrd_mem; int ret; - if (!data->initrd_file) - return 0; - - pr_info("Loading ramdisk from '%s'\n", data->initrd_file); - - initrd_mem = read_file(data->initrd_file, &initrd_size); - if (!initrd_mem) { - ret = -errno; - pr_err("Failed to read initrd from file '%s': %m\n", - data->initrd_file); - return ret; + if (ramdisk_is_fit(data)) { + ret = fit_open_image(data->os_fit, data->fit_config, "ramdisk", + (const void **)&initrd_mem, &initrd_size); + if (ret) { + pr_err("Cannot open ramdisk image in FIT image: %m\n"); + return ret; + } + } else { + if (!data->initrd_file) + return 0; + + pr_info("Loading ramdisk from '%s'\n", data->initrd_file); + + initrd_mem = read_file(data->initrd_file, &initrd_size); + if (!initrd_mem) { + ret = -errno; + pr_err("Failed to read initrd from file '%s': %m\n", + data->initrd_file); + return ret; + } } ret = efi_initrd_register(initrd_mem, initrd_size); @@ -84,16 +156,25 @@ static int efi_load_fdt(struct image_data *data, void **fdt) unsigned long of_size; int ret; - if (!data->oftree_file) - return 0; - - pr_info("Loading devicetree from '%s'\n", data->oftree_file); - - of_tree = read_file(data->oftree_file, &of_size); - if (!of_tree) { - ret = -errno; - pr_err("Failed to read oftree: %m\n"); - return ret; + if (fdt_is_fit(data)) { + ret = fit_open_image(data->os_fit, data->fit_config, "fdt", + (const void **)&of_tree, &of_size); + if (ret) { + pr_err("Cannot open FDT image in FIT image: %m\n"); + return ret; + } + } else { + if (!data->oftree_file) + return 0; + + pr_info("Loading devicetree from '%s'\n", data->oftree_file); + + of_tree = read_file(data->oftree_file, &of_size); + if (!of_tree) { + ret = -errno; + pr_err("Failed to read oftree: %m\n"); + return ret; + } } efiret = BS->allocate_pages(EFI_ALLOCATE_ANY_PAGES, -- 2.34.1
