summaryrefslogtreecommitdiff
path: root/boot
diff options
context:
space:
mode:
Diffstat (limited to 'boot')
-rw-r--r--boot/Kconfig45
-rw-r--r--boot/Makefile1
-rw-r--r--boot/bootflow.c216
-rw-r--r--boot/bootmeth-uclass.c12
-rw-r--r--boot/bootmeth_android.c35
-rw-r--r--boot/bootmeth_efi.c79
-rw-r--r--boot/bootmeth_efi_mgr.c9
-rw-r--r--boot/bootmeth_rauc.c3
-rw-r--r--boot/bootmeth_script.c6
-rw-r--r--boot/extension-uclass.c93
-rw-r--r--boot/fdt_support.c17
-rw-r--r--boot/image-fit.c2
-rw-r--r--boot/pxe_utils.c90
-rw-r--r--boot/upl_write.c6
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;