diff options
Diffstat (limited to 'boot')
| -rw-r--r-- | boot/Kconfig | 45 | ||||
| -rw-r--r-- | boot/Makefile | 1 | ||||
| -rw-r--r-- | boot/bootflow.c | 216 | ||||
| -rw-r--r-- | boot/bootmeth-uclass.c | 12 | ||||
| -rw-r--r-- | boot/bootmeth_android.c | 35 | ||||
| -rw-r--r-- | boot/bootmeth_efi.c | 79 | ||||
| -rw-r--r-- | boot/bootmeth_efi_mgr.c | 9 | ||||
| -rw-r--r-- | boot/bootmeth_rauc.c | 3 | ||||
| -rw-r--r-- | boot/bootmeth_script.c | 6 | ||||
| -rw-r--r-- | boot/extension-uclass.c | 93 | ||||
| -rw-r--r-- | boot/fdt_support.c | 17 | ||||
| -rw-r--r-- | boot/image-fit.c | 2 | ||||
| -rw-r--r-- | boot/pxe_utils.c | 90 | ||||
| -rw-r--r-- | boot/upl_write.c | 6 |
14 files changed, 545 insertions, 69 deletions
diff --git a/boot/Kconfig b/boot/Kconfig index dd047365754..85f4d468069 100644 --- a/boot/Kconfig +++ b/boot/Kconfig @@ -33,6 +33,24 @@ config TIMESTAMP loaded that does not, the message 'Wrong FIT format: no timestamp' is shown. +config LIB_BOOTI + bool + +config LIB_BOOTM + bool + +config LIB_BOOTZ + bool + +config SPL_LIB_BOOTI + bool + +config SPL_LIB_BOOTM + bool + +config SPL_LIB_BOOTZ + bool + config BUTTON_CMD bool "Support for running a command if a button is held during boot" depends on CMDLINE @@ -193,18 +211,18 @@ config SPL_FIT_PRINT Support printing the content of the fitImage in a verbose manner in SPL. config SPL_FIT_FULL_CHECK - bool "Do a full check of the FIT before using it" + bool "Do a full check of the FIT within SPL before using it" depends on SPL_FIT help - Enable this do a full check of the FIT to make sure it is valid. This - helps to protect against carefully crafted FITs which take advantage - of bugs or omissions in the code. This includes a bad structure, - multiple root nodes and the like. + Enable this do a full check of the FIT within SPL to make sure it is + valid. This helps to protect against carefully crafted FITs which take + advantage of bugs or omissions in the code. This includes a bad + structure, multiple root nodes and the like. config SPL_FIT_SIGNATURE bool "Enable signature verification of FIT firmware within SPL" depends on SPL_DM - depends on SPL_LOAD_FIT || SPL_LOAD_FIT_FULL + depends on SPL_LOAD_FIT select FIT_SIGNATURE select SPL_FIT select SPL_CRYPTO @@ -282,7 +300,7 @@ config SPL_LOAD_FIT_APPLY_OVERLAY_BUF_SZ config SPL_LOAD_FIT_FULL bool "Enable SPL loading U-Boot as a FIT (full fitImage features)" - select SPL_FIT + depends on SPL_LOAD_FIT help Normally with the SPL framework a legacy image is generated as part of the build. This contains U-Boot along with information as to @@ -1053,7 +1071,7 @@ if MEASURED_BOOT endif # MEASURED_BOOT config SYS_BOOTM_LEN - hex "Maximum size of a decompresed OS image" + hex "Maximum size of a decompressed OS image" depends on CMD_BOOTM || CMD_BOOTI || CMD_BOOTZ || \ LEGACY_IMAGE_FORMAT || SPL_LEGACY_IMAGE_FORMAT default 0x8000000 if PPC || ARM64 || RISCV @@ -1093,6 +1111,7 @@ config SYS_RAMBOOT config RAMBOOT_PBL bool "Freescale PBL(pre-boot loader) image format support" + depends on ARCH_LS1021A || PPC select SYS_RAMBOOT if PPC help Some SoCs use PBL to load RCW and/or pre-initialization instructions. @@ -1779,7 +1798,7 @@ menu "Image support" config IMAGE_PRE_LOAD bool "Image pre-load support" help - Enable an image pre-load stage in the SPL. + Enable an image pre-load stage. This pre-load stage allows to do some manipulation or check (for example signature check) on an image before launching it. @@ -1811,7 +1830,7 @@ config IMAGE_PRE_LOAD_SIG u-boot. config SPL_IMAGE_PRE_LOAD_SIG - bool "Image pre-load signature support witin SPL" + bool "Image pre-load signature support within SPL" depends on SPL_IMAGE_PRE_LOAD && IMAGE_PRE_LOAD_SIG select SPL_FIT_SIGNATURE select SPL_RSA @@ -1852,6 +1871,7 @@ config OF_BOARD_SETUP config OF_BOARD_SETUP_EXTENDED bool "Set up latest board-specific details in device tree before boot" + depends on !COMPILE_TEST imply OF_BOARD_SETUP help This causes U-Boot to call ft_board_setup_ex() before booting into @@ -1862,6 +1882,7 @@ config OF_BOARD_SETUP_EXTENDED config OF_SYSTEM_SETUP bool "Set up system-specific details in device tree before boot" + depends on !COMPILE_TEST help This causes U-Boot to call ft_system_setup() before booting into the Operating System. This function can set up various @@ -1906,6 +1927,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/bootflow.c b/boot/bootflow.c index d79f303486d..d8a4a81a838 100644 --- a/boot/bootflow.c +++ b/boot/bootflow.c @@ -17,6 +17,10 @@ #include <dm/device-internal.h> #include <dm/uclass-internal.h> +/* ensure BOOTMETH_MAX_COUNT fits in method_flags field */ +static_assert(BOOTMETH_MAX_COUNT <= + (sizeof(((struct bootflow_iter *)NULL)->method_flags) * 8)); + /* error codes used to signal running out of things */ enum { BF_NO_MORE_PARTS = -ESHUTDOWN, @@ -109,11 +113,17 @@ int bootflow_iter_drop_bootmeth(struct bootflow_iter *iter, iter->method_order[iter->cur_method] != bmeth) return -EINVAL; + log_debug("Dropping bootmeth '%s'\n", bmeth->name); + memmove(&iter->method_order[iter->cur_method], &iter->method_order[iter->cur_method + 1], (iter->num_methods - iter->cur_method - 1) * sizeof(void *)); iter->num_methods--; + if (iter->first_glob_method > 0) { + iter->first_glob_method--; + log_debug("first_glob_method %d\n", iter->first_glob_method); + } return 0; } @@ -178,6 +188,101 @@ static void scan_next_in_uclass(struct udevice **devp) } /** + * bootmeth_glob_allowed() - Check if a global bootmeth is usable at this point + * + * @iter: Bootflow iterator being used + * Return: true if the global bootmeth has a suitable priority and has not + * already been used + */ +static bool bootmeth_glob_allowed(struct bootflow_iter *iter, int meth_seq) +{ + struct udevice *meth = iter->method_order[meth_seq]; + bool done = iter->methods_done & BIT(meth_seq); + struct bootmeth_uc_plat *ucp; + + ucp = dev_get_uclass_plat(meth); + log_debug("considering glob '%s': done %d glob_prio %d\n", meth->name, + done, ucp->glob_prio); + + /* + * if this one has already been used, or its priority is too low, try + * the next + */ + if (done || ucp->glob_prio > iter->cur_prio) + return false; + + return true; +} + +/** + * next_glob_bootmeth() - Find the next global bootmeth to use + * + * Scans the global bootmeths to find the first unused one whose priority has + * been reached. If found, iter->cur_method and iter->method are set up and + * doing_global is set to true + * + * @iter: Bootflow iterator being used + * Return 0 if found, -ENOENT if no more global bootmeths are available + */ +static int next_glob_bootmeth(struct bootflow_iter *iter) +{ + log_debug("rescan global bootmeths have_global %d\n", + iter->have_global); + if (IS_ENABLED(CONFIG_BOOTMETH_GLOBAL) && iter->have_global) { + int i; + + /* rescan the global bootmeths */ + log_debug("first_glob_method %d num_methods %d methods_done %x\n", + iter->first_glob_method, iter->num_methods, + iter->methods_done); + for (i = iter->first_glob_method; i < iter->num_methods; i++) { + if (bootmeth_glob_allowed(iter, i)) { + iter->cur_method = i; + iter->method = iter->method_order[i]; + iter->doing_global = true; + iter->dev = NULL; + return 0; + } + } + } + + return -ENOENT; +} + +/** + * prepare_bootdev() - Get ready to use a bootdev + * + * @iter: Bootflow iterator being used + * @dev: UCLASS_BOOTDEV device to use + * @method_flags: Method flag for the bootdev + * @check_global: true to check global bootmeths before processing @dev + * Return 0 if OK, -ve if the bootdev failed to probe + */ +static int prepare_bootdev(struct bootflow_iter *iter, struct udevice *dev, + int method_flags, bool check_global) +{ + int ret; + + if (check_global && !next_glob_bootmeth(iter)) { + iter->pending_bootdev = dev; + iter->pending_method_flags = method_flags; + return 0; + } + + /* + * Probe the bootdev. This does not probe any attached block device, + * since they are siblings + */ + ret = device_probe(dev); + log_debug("probe %s %d\n", dev->name, ret); + if (ret) + return log_msg_ret("probe", ret); + bootflow_iter_set_dev(iter, dev, method_flags); + + return 0; +} + +/** * iter_incr() - Move to the next item (method, part, bootdev) * * Return: 0 if OK, BF_NO_MORE_DEVICES if there are no more bootdevs @@ -195,27 +300,77 @@ static int iter_incr(struct bootflow_iter *iter) if (iter->err == BF_NO_MORE_DEVICES) return BF_NO_MORE_DEVICES; - if (iter->err != BF_NO_MORE_PARTS) { - /* Get the next boothmethod */ - if (++iter->cur_method < iter->num_methods) { + /* Get the next boothmethod */ + for (iter->cur_method++; iter->cur_method < iter->num_methods; + iter->cur_method++) { + /* loop until we find a global bootmeth we haven't used */ + if (IS_ENABLED(CONFIG_BOOTMETH_GLOBAL) && iter->doing_global) { + if (!bootmeth_glob_allowed(iter, iter->cur_method)) + continue; + iter->method = iter->method_order[iter->cur_method]; + log_debug("-> next global method '%s'\n", + iter->method->name); return 0; } + /* at this point we are only considering non-global bootmeths */ + if (IS_ENABLED(CONFIG_BOOTMETH_GLOBAL) && iter->have_global && + iter->cur_method >= iter->first_glob_method) + break; + + iter->method = iter->method_order[iter->cur_method]; + return 0; + } + + /* + * If we have finished scanning the global bootmeths, start the + * normal bootdev scan + */ + if (IS_ENABLED(CONFIG_BOOTMETH_GLOBAL) && global) { + iter->doing_global = false; + /* - * If we have finished scanning the global bootmeths, start the - * normal bootdev scan + * we've come to the end, so see if we should use a pending + * bootdev from when we decided to rescan the global bootmeths */ - if (IS_ENABLED(CONFIG_BOOTMETH_GLOBAL) && global) { - iter->num_methods = iter->first_glob_method; - iter->doing_global = false; - - /* - * Don't move to the next dev as we haven't tried this - * one yet! - */ - inc_dev = false; + if (iter->pending_bootdev) { + int meth_flags = iter->pending_method_flags; + + dev = iter->pending_bootdev; + iter->pending_bootdev = NULL; + iter->pending_method_flags = 0; + + ret = prepare_bootdev(iter, dev, meth_flags, false); + if (ret) + return log_msg_ret("ipb", ret); + + iter->cur_method = 0; + iter->method = iter->method_order[iter->cur_method]; + + log_debug("-> using pending bootdev '%s' method '%s'\n", + dev->name, iter->method->name); + + return 0; } + + /* if this was the final global bootmeth check, we are done */ + if (iter->cur_prio == BOOTDEVP_COUNT) { + log_debug("-> done global bootmeths\n"); + + /* print the same message as bootflow_iter_set_dev() */ + if ((iter->flags & (BOOTFLOWIF_SHOW | + BOOTFLOWIF_SINGLE_DEV)) == + BOOTFLOWIF_SHOW) + printf("No more bootdevs\n"); + return BF_NO_MORE_DEVICES; + } + + /* + * Don't move to the next dev as we haven't tried this + * one yet! + */ + inc_dev = false; } if (iter->flags & BOOTFLOWIF_SINGLE_PARTITION) @@ -310,17 +465,20 @@ static int iter_incr(struct bootflow_iter *iter) } log_debug("ret=%d, dev=%p %s\n", ret, dev, dev ? dev->name : "none"); - if (ret) { + if (ret) bootflow_iter_set_dev(iter, NULL, 0); - } else { - /* - * Probe the bootdev. This does not probe any attached - * block device, since they are siblings - */ - ret = device_probe(dev); - log_debug("probe %s %d\n", dev->name, ret); - if (!log_msg_ret("probe", ret)) - bootflow_iter_set_dev(iter, dev, method_flags); + else + ret = prepare_bootdev(iter, dev, method_flags, true); + } + + if (IS_ENABLED(CONFIG_BOOTMETH_GLOBAL) && ret) { + log_debug("no more bootdevs, trying global\n"); + + /* allow global bootmeths with any priority */ + iter->cur_prio = BOOTDEVP_COUNT; + if (!next_glob_bootmeth(iter)) { + log_debug("-> next method '%s'\n", iter->method->name); + return 0; } } @@ -344,6 +502,7 @@ static int bootflow_check(struct bootflow_iter *iter, struct bootflow *bflow) struct udevice *dev; int ret; + /* handle global bootmeths if needed */ if (IS_ENABLED(CONFIG_BOOTMETH_GLOBAL) && iter->doing_global) { bootflow_iter_set_dev(iter, NULL, 0); ret = bootmeth_get_bootflow(iter->method, bflow); @@ -410,6 +569,10 @@ int bootflow_scan_first(struct udevice *dev, const char *label, bootflow_iter_set_dev(iter, dev, method_flags); } + if (IS_ENABLED(CONFIG_BOOTMETH_GLOBAL)) { + iter->methods_done |= BIT(iter->cur_method); + log_debug("methods_done now %x\n", iter->cur_method); + } ret = bootflow_check(iter, bflow); if (ret) { log_debug("check - ret=%d\n", ret); @@ -437,6 +600,11 @@ int bootflow_scan_next(struct bootflow_iter *iter, struct bootflow *bflow) return log_msg_ret("done", ret); if (!ret) { + if (IS_ENABLED(CONFIG_BOOTMETH_GLOBAL)) { + iter->methods_done |= BIT(iter->cur_method); + log_debug("methods_done now %x\n", + iter->cur_method); + } ret = bootflow_check(iter, bflow); log_debug("check - ret=%d\n", ret); if (!ret) diff --git a/boot/bootmeth-uclass.c b/boot/bootmeth-uclass.c index 188f6ea1895..a9709465f6e 100644 --- a/boot/bootmeth-uclass.c +++ b/boot/bootmeth-uclass.c @@ -204,11 +204,23 @@ int bootmeth_setup_iter_order(struct bootflow_iter *iter, bool include_global) goto err_order; } + /* start with the global bootmeths */ if (IS_ENABLED(CONFIG_BOOTMETH_GLOBAL) && include_global && iter->first_glob_method != -1 && iter->first_glob_method != count) { iter->cur_method = iter->first_glob_method; iter->doing_global = true; + iter->have_global = true; } + + /* + * check we don't exceed the maximum bits in methods_done when tracking + * which global bootmeths have run + */ + if (IS_ENABLED(CONFIG_BOOTMETH_GLOBAL) && count > BOOTMETH_MAX_COUNT) { + free(order); + return log_msg_ret("tmb", -ENOSPC); + } + iter->method_order = order; iter->num_methods = count; diff --git a/boot/bootmeth_android.c b/boot/bootmeth_android.c index 8c2bde10e17..1374551dbeb 100644 --- a/boot/bootmeth_android.c +++ b/boot/bootmeth_android.c @@ -512,6 +512,37 @@ static int run_avb_verification(struct bootflow *bflow) } #endif /* AVB_VERIFY */ +static int append_bootargs_to_cmdline(struct bootflow *bflow) +{ + char *bootargs; + int len = 0; + + /* + * Check any additionnal bootargs coming from U-Boot env. If any, + * merge them with the current cmdline + */ + bootargs = env_get("bootargs"); + if (bootargs) { + len += strlen(bootargs) + 1; /* Extra space character needed */ + len += strlen(bflow->cmdline); + + char *newcmdline = malloc(len + 1); /* +1 for the '\0' */ + + if (!newcmdline) + return log_msg_ret("newcmdline malloc", -ENOMEM); + + strcpy(newcmdline, bootargs); + strcat(newcmdline, " "); + strcat(newcmdline, bflow->cmdline); + + /* Free the previous cmdline and replace it */ + free(bflow->cmdline); + bflow->cmdline = newcmdline; + } + + return 0; +} + static int boot_android_normal(struct bootflow *bflow) { struct blk_desc *desc = dev_get_uclass_plat(bflow->blk); @@ -546,6 +577,10 @@ static int boot_android_normal(struct bootflow *bflow) if (priv->slot) free(priv->slot); + ret = append_bootargs_to_cmdline(bflow); + if (ret < 0) + return log_msg_ret("bootargs append", ret); + ret = bootm_boot_start(loadaddr, bflow->cmdline); return log_msg_ret("boot", ret); 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/bootmeth_efi_mgr.c b/boot/bootmeth_efi_mgr.c index 42b8863815e..05fc35d01a9 100644 --- a/boot/bootmeth_efi_mgr.c +++ b/boot/bootmeth_efi_mgr.c @@ -99,6 +99,15 @@ static int bootmeth_efi_mgr_bind(struct udevice *dev) plat->desc = "EFI bootmgr flow"; plat->flags = BOOTMETHF_GLOBAL; + /* + * bootmgr scans all available devices which can take a while, + * especially for network devices. So choose the priority so that it + * comes just before the 'very slow' devices. This allows systems which + * don't rely on bootmgr to boot quickly, while allowing bootmgr to run + * on systems which need it. + */ + plat->glob_prio = BOOTDEVP_6_NET_BASE; + return 0; } diff --git a/boot/bootmeth_rauc.c b/boot/bootmeth_rauc.c index 81a73046e83..f5d5a971e87 100644 --- a/boot/bootmeth_rauc.c +++ b/boot/bootmeth_rauc.c @@ -18,6 +18,7 @@ #include <malloc.h> #include <mapmem.h> #include <string.h> +#include <linux/stringify.h> #include <asm/cache.h> /* Length of env var "BOOT_*_LEFT" */ @@ -304,7 +305,7 @@ static int find_active_slot(char **slot_name, ulong *slot_tries) if (!slot_found) { if (IS_ENABLED(CONFIG_BOOTMETH_RAUC_RESET_ALL_ZERO_TRIES)) { log_warning("WARNING: No valid slot found\n"); - log_info("INFO: Resetting boot order and all slot tries\n"); + log_info("INFO: Resetting all slot tries to " __stringify(CONFIG_BOOTMETH_RAUC_DEFAULT_TRIES) "\n"); boot_order_list = str_to_list(CONFIG_BOOTMETH_RAUC_BOOT_ORDER); for (i = 0; boot_order_list[i]; i++) { sprintf(boot_left, "BOOT_%s_LEFT", boot_order_list[i]); diff --git a/boot/bootmeth_script.c b/boot/bootmeth_script.c index 020cb8a7aec..cd50977cc40 100644 --- a/boot/bootmeth_script.c +++ b/boot/bootmeth_script.c @@ -129,7 +129,11 @@ static int script_read_bootflow_net(struct bootflow *bflow) if (!fname) return log_msg_ret("dhc", -EINVAL); - ret = dhcp_run(addr, fname, true); + if (IS_ENABLED(CONFIG_CMD_TFTPBOOT) && env_get_yesno("ip_dyn") == 0) + ret = tftpb_run(addr, fname); + else + ret = dhcp_run(addr, fname, true); + if (ret) return log_msg_ret("dhc", ret); 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 <kory.maincent@bootlin.com> + */ + +#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/fdt_support.c b/boot/fdt_support.c index b7331bb76b3..92f2f534ee0 100644 --- a/boot/fdt_support.c +++ b/boot/fdt_support.c @@ -224,24 +224,15 @@ int fdt_initrd(void *fdt, ulong initrd_start, ulong initrd_end) int is_u64; uint64_t addr, size; + /* just return if the size of initrd is zero */ + if (initrd_start == initrd_end) + return 0; + /* find or create "/chosen" node. */ nodeoffset = fdt_find_or_add_subnode(fdt, 0, "chosen"); if (nodeoffset < 0) return nodeoffset; - /* - * Although we didn't setup an initrd, there could be a stale - * initrd setting from the previous boot firmware in the live - * device tree. So, make sure there is no setting left if we - * don't want an initrd. - */ - if (initrd_start == initrd_end) { - fdt_delprop(fdt, nodeoffset, "linux,initrd-start"); - fdt_delprop(fdt, nodeoffset, "linux,initrd-end"); - - return 0; - } - total = fdt_num_mem_rsv(fdt); /* diff --git a/boot/image-fit.c b/boot/image-fit.c index 41ab1f552b0..2f2d3e9304d 100644 --- a/boot/image-fit.c +++ b/boot/image-fit.c @@ -1662,7 +1662,7 @@ int fit_check_format(const void *fit, ulong size) if (CONFIG_IS_ENABLED(FIT_FULL_CHECK)) { /* - * If we are not given the size, make do wtih calculating it. + * If we are not given the size, make do with calculating it. * This is not as secure, so we should consider a flag to * control this. */ diff --git a/boot/pxe_utils.c b/boot/pxe_utils.c index eb4d7723481..836e4eb526c 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,93 @@ 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 = 0; + 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 = ""; + } else { + slash = "/"; + } + dir_len = len + strlen(slash) + 1; + + overlay_dir = calloc(1, dir_len); + if (!overlay_dir) + return; + + snprintf(overlay_dir, dir_len, "%s%s", label->fdtdir ?: "", slash); + + 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 +773,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; } diff --git a/boot/upl_write.c b/boot/upl_write.c index 7d637c15ba0..4185e59becf 100644 --- a/boot/upl_write.c +++ b/boot/upl_write.c @@ -301,7 +301,7 @@ static int add_upl_memory(const struct upl *upl, ofnode root) for (i = 0; i < upl->mem.count; i++) { const struct upl_mem *mem = alist_get(&upl->mem, i, struct upl_mem); - char buf[mem->region.count * sizeof(64) * 2]; + char buf[mem->region.count * sizeof(u64) * 2]; const struct memregion *first; char name[26]; int ret, len; @@ -354,7 +354,7 @@ static int add_upl_memmap(const struct upl *upl, ofnode root) for (i = 0; i < upl->memmap.count; i++) { const struct upl_memmap *memmap = alist_get(&upl->memmap, i, struct upl_memmap); - char buf[memmap->region.count * sizeof(64) * 2]; + char buf[memmap->region.count * sizeof(u64) * 2]; const struct memregion *first; char name[26]; int ret, len; @@ -411,7 +411,7 @@ static int add_upl_memres(const struct upl *upl, ofnode root, for (i = 0; i < upl->memres.count; i++) { const struct upl_memres *memres = alist_get(&upl->memres, i, struct upl_memres); - char buf[memres->region.count * sizeof(64) * 2]; + char buf[memres->region.count * sizeof(u64) * 2]; const struct memregion *first; char name[26]; int ret, len; |
