diff options
| author | Tom Rini <[email protected]> | 2025-11-03 10:12:05 -0600 |
|---|---|---|
| committer | Tom Rini <[email protected]> | 2025-11-03 10:12:05 -0600 |
| commit | 9ccda31f54881d3321263a81599454a1d6efb65e (patch) | |
| tree | 71c250bf67f39df36d05ef55512692132b99fa40 /boot | |
| parent | c2637036b8f0c90a2cfc59900f7da31eae646b03 (diff) | |
| parent | e9dc6c12958fc5d909848fc3999e6be5df1cd3ae (diff) | |
Merge patch series "Convert extension support to UCLASS and adds its support to boot flows"
Kory Maincent (TI.com) <[email protected]> says:
This series converts the extension board framework to use UCLASS as
requested by Simon Glass, then adds extension support to pxe_utils
and bootmeth_efi (not tested) to enable extension boards devicetree load
in the standard boot process.
I can't test the imx8 extension scan enabled by the
imx8mm-cl-iot-gate_defconfig as I don't have this board.
I also can't test the efi bootmeth change as I don't have such board.
Link: https://lore.kernel.org/r/20251030-feature_sysboot_extension_board-v5-0-cfb77672fc68@bootlin.com
Diffstat (limited to 'boot')
| -rw-r--r-- | boot/Kconfig | 4 | ||||
| -rw-r--r-- | boot/Makefile | 1 | ||||
| -rw-r--r-- | boot/bootmeth_efi.c | 79 | ||||
| -rw-r--r-- | boot/extension-uclass.c | 93 | ||||
| -rw-r--r-- | boot/pxe_utils.c | 92 |
5 files changed, 253 insertions, 16 deletions
diff --git a/boot/Kconfig b/boot/Kconfig index 9adb051400f..921f096da56 100644 --- a/boot/Kconfig +++ b/boot/Kconfig @@ -1909,6 +1909,10 @@ endmenu endif # OF_LIBFDT +config SUPPORT_EXTENSION_SCAN + select OF_LIBFDT_OVERLAY + bool + config USE_BOOTARGS bool "Enable boot arguments" help diff --git a/boot/Makefile b/boot/Makefile index 3da6f7a0914..7fb56e7ef37 100644 --- a/boot/Makefile +++ b/boot/Makefile @@ -9,6 +9,7 @@ obj-$(CONFIG_BOOT_RETRY) += bootretry.o obj-$(CONFIG_CMD_BOOTM) += bootm.o bootm_os.o obj-$(CONFIG_CMD_BOOTZ) += bootm.o bootm_os.o obj-$(CONFIG_CMD_BOOTI) += bootm.o bootm_os.o +obj-$(CONFIG_SUPPORT_EXTENSION_SCAN) += extension-uclass.o obj-$(CONFIG_PXE_UTILS) += pxe_utils.o diff --git a/boot/bootmeth_efi.c b/boot/bootmeth_efi.c index 0af23df3a4a..f592fec07f6 100644 --- a/boot/bootmeth_efi.c +++ b/boot/bootmeth_efi.c @@ -16,6 +16,7 @@ #include <efi.h> #include <efi_loader.h> #include <env.h> +#include <extension_board.h> #include <fs.h> #include <malloc.h> #include <mapmem.h> @@ -99,8 +100,11 @@ static int distro_efi_check(struct udevice *dev, struct bootflow_iter *iter) static int distro_efi_try_bootflow_files(struct udevice *dev, struct bootflow *bflow) { + ulong fdt_addr, size, overlay_addr; + const struct extension *extension; + struct fdt_header *working_fdt; struct blk_desc *desc = NULL; - ulong fdt_addr, size; + struct alist *extension_list; char fname[256]; int ret, seq; @@ -148,23 +152,66 @@ static int distro_efi_try_bootflow_files(struct udevice *dev, return log_msg_ret("fil", -ENOMEM); } - if (!ret) { - bflow->fdt_size = size; - bflow->fdt_addr = fdt_addr; - - /* - * TODO: Apply extension overlay - * - * Here we need to load and apply the extension overlay. This is - * not implemented. See do_extension_apply(). The extension - * stuff needs an implementation in boot/extension.c so it is - * separate from the command code. Really the extension stuff - * should use the device tree and a uclass / driver interface - * rather than implementing its own list - */ - } else { + if (ret) { log_debug("No device tree available\n"); bflow->flags |= BOOTFLOWF_USE_BUILTIN_FDT; + return 0; + } + + bflow->fdt_size = size; + bflow->fdt_addr = fdt_addr; + + if (!CONFIG_IS_ENABLED(SUPPORT_EXTENSION_SCAN)) + return 0; + + ret = extension_scan(); + if (ret < 0) + return 0; + + extension_list = extension_get_list(); + if (!extension_list) + return 0; + + working_fdt = map_sysmem(fdt_addr, 0); + if (fdt_check_header(working_fdt)) + return 0; + + overlay_addr = env_get_hex("extension_overlay_addr", 0); + if (!overlay_addr) { + log_debug("Environment extension_overlay_addr is missing\n"); + return 0; + } + + alist_for_each(extension, extension_list) { + char *overlay_file; + int len; + + len = sizeof(EFI_DIRNAME) + strlen(extension->overlay); + overlay_file = calloc(1, len); + if (!overlay_file) + return -ENOMEM; + + snprintf(overlay_file, len, "%s%s", EFI_DIRNAME, + extension->overlay); + + ret = bootmeth_common_read_file(dev, bflow, overlay_file, + overlay_addr, + (enum bootflow_img_t)IH_TYPE_FLATDT, + &size); + if (ret) { + log_debug("Failed loading overlay %s\n", overlay_file); + free(overlay_file); + continue; + } + + ret = extension_apply(working_fdt, size); + if (ret) { + log_debug("Failed applying overlay %s\n", overlay_file); + free(overlay_file); + continue; + } + bflow->fdt_size += size; + free(overlay_file); } return 0; diff --git a/boot/extension-uclass.c b/boot/extension-uclass.c new file mode 100644 index 00000000000..4b3dd1bc0cd --- /dev/null +++ b/boot/extension-uclass.c @@ -0,0 +1,93 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * (C) Copyright 2025 Köry Maincent <[email protected]> + */ + +#include <alist.h> +#include <command.h> +#include <env.h> +#include <extension_board.h> +#include <fdt_support.h> +#include <malloc.h> +#include <mapmem.h> +#include <dm/device-internal.h> +#include <dm/lists.h> +#include <dm/uclass.h> + +struct alist *extension_get_list(void) +{ + struct udevice *dev; + + if (uclass_first_device_err(UCLASS_EXTENSION, &dev)) + return NULL; + + return dev_get_priv(dev); +} + +int extension_probe(struct udevice *dev) +{ + struct alist *extension_list = dev_get_priv(dev); + + alist_init_struct(extension_list, struct extension); + return 0; +} + +int extension_remove(struct udevice *dev) +{ + struct alist *extension_list = dev_get_priv(dev); + + alist_uninit(extension_list); + return 0; +} + +int extension_scan(void) +{ + struct alist *extension_list = extension_get_list(); + const struct extension_ops *ops; + struct udevice *dev; + int ret; + + ret = uclass_first_device_err(UCLASS_EXTENSION, &dev); + if (ret) + return ret; + + if (!extension_list) + return -ENODEV; + + ops = extension_get_ops(dev); + alist_empty(extension_list); + return ops->scan(dev, extension_list); +} + +int extension_apply(struct fdt_header *working_fdt, ulong size) +{ + struct fdt_header *blob; + ulong overlay_addr; + int ret; + + overlay_addr = env_get_hex("extension_overlay_addr", 0); + if (!overlay_addr) { + printf("Environment extension_overlay_addr is missing\n"); + return -EINVAL; + } + + fdt_shrink_to_minimum(working_fdt, size); + + blob = map_sysmem(overlay_addr, 0); + if (!fdt_valid(&blob)) { + printf("Invalid overlay devicetree\n"); + return -EINVAL; + } + + /* Apply method prints messages on error */ + ret = fdt_overlay_apply_verbose(working_fdt, blob); + if (ret) + printf("Failed to apply overlay\n"); + + return ret; +} + +UCLASS_DRIVER(extension) = { + .name = "extension", + .id = UCLASS_EXTENSION, +}; diff --git a/boot/pxe_utils.c b/boot/pxe_utils.c index eb4d7723481..038416203fc 100644 --- a/boot/pxe_utils.c +++ b/boot/pxe_utils.c @@ -10,6 +10,7 @@ #include <command.h> #include <dm.h> #include <env.h> +#include <extension_board.h> #include <image.h> #include <log.h> #include <malloc.h> @@ -432,6 +433,95 @@ skip_overlay: } #endif +/* + * label_boot_extension - scan extension boards and load overlay associated + */ + +static void label_boot_extension(struct pxe_context *ctx, + struct pxe_label *label) +{ +#if CONFIG_IS_ENABLED(SUPPORT_EXTENSION_SCAN) + const struct extension *extension; + struct fdt_header *working_fdt; + struct alist *extension_list; + int ret, dir_len, len; + char *overlay_dir; + const char *slash; + ulong fdt_addr; + + ret = extension_scan(); + if (ret < 0) + return; + + extension_list = extension_get_list(); + if (!extension_list) + return; + + /* Get the main fdt and map it */ + fdt_addr = env_get_hex("fdt_addr_r", 0); + working_fdt = map_sysmem(fdt_addr, 0); + if (fdt_check_header(working_fdt)) + return; + + /* Use fdtdir for now as the overlay devicetree directory */ + if (label->fdtdir) { + len = strlen(label->fdtdir); + if (!len) + slash = "./"; + else if (label->fdtdir[len - 1] != '/') + slash = "/"; + else + slash = ""; + + dir_len = strlen(label->fdtdir) + strlen(slash) + 1; + overlay_dir = calloc(1, len); + if (!overlay_dir) + return; + + snprintf(overlay_dir, dir_len, "%s%s", label->fdtdir, + slash); + } else { + dir_len = 2; + snprintf(overlay_dir, dir_len, "/"); + } + + alist_for_each(extension, extension_list) { + char *overlay_file; + ulong size; + + len = dir_len + strlen(extension->overlay); + overlay_file = calloc(1, len); + if (!overlay_file) + goto cleanup; + + snprintf(overlay_file, len, "%s%s", overlay_dir, + extension->overlay); + + /* Load extension overlay file */ + ret = get_relfile_envaddr(ctx, overlay_file, + "extension_overlay_addr", + (enum bootflow_img_t)IH_TYPE_FLATDT, + &size); + if (ret < 0) { + printf("Failed loading overlay %s\n", overlay_file); + free(overlay_file); + continue; + } + + ret = extension_apply(working_fdt, size); + if (ret) { + printf("Failed applying overlay %s\n", overlay_file); + free(overlay_file); + continue; + } + free(overlay_file); + } + +cleanup: + free(overlay_dir); +#endif +} + /** * label_boot() - Boot according to the contents of a pxe_label * @@ -685,6 +775,8 @@ static int label_boot(struct pxe_context *ctx, struct pxe_label *label) if (label->fdtoverlays) label_boot_fdtoverlay(ctx, label); #endif + label_boot_extension(ctx, label); + } else { bootm_argv[3] = NULL; } |
