Re: [PATCH 11/16] bootm: implement plain and FIT bootm.image override

Sascha Hauer
2026-03-18T09:02:55Z

Hi Ahmad,

On Thu, Mar 12, 2026 at 03:44:54PM +0100, Ahmad Fatoum wrote:
> Add support for overriding the boot image via bootm.image when using
> either plain files or FIT images. The override behavior depends on the
> file types involved:
>
> - If the override is not a FIT image, it replaces only the OS loadable,
> regardless of whether the original was a FIT image or not.
>
> - If the override is a FIT image, it replaces the current OS, whether
> it's a FIT or not.

What's the "current OS" here? Is it just the kernel or dtb/initrd as
well?

Sascha

>
> This allows developers to use devboot scripts to redirect FIT image
> loading to alternate locations (e.g., network) while preserving the
> configuration selection from the original boot entry.
>
> Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
> Signed-off-by: Ahmad Fatoum <a.fatoum@pengutronix.de>
> ---
> commands/boot.c | 2 +-
> common/bootm-fit.c | 11 +++-
> common/bootm-overrides.c | 119 +++++++++++++++++++++++++++++++++++++-
> common/bootm.c | 4 +-
> include/bootm-fit.h | 4 +-
> include/bootm-overrides.h | 3 +
> include/bootm.h | 2 +
> 7 files changed, 134 insertions(+), 11 deletions(-)
>
> diff --git a/commands/boot.c b/commands/boot.c
> index 555667ee098c..04bb9eb9186f 100644
> --- a/commands/boot.c
> +++ b/commands/boot.c
> @@ -44,7 +44,7 @@ static int boot_add_override(struct bootm_overrides *overrides, char *var)
> if (!strcmp(var, "bootm.image")) {
> if (isempty(val))
> return -EINVAL;
> - return -ENOSYS;
> + overrides->os_file = val;
> } else if (!strcmp(var, "bootm.oftree")) {
> overrides->oftree_file = val;
> } else if (!strcmp(var, "bootm.initrd")) {
> diff --git a/common/bootm-fit.c b/common/bootm-fit.c
> index 5b110ad2f19e..995bd7181223 100644
> --- a/common/bootm-fit.c
> +++ b/common/bootm-fit.c
> @@ -4,6 +4,7 @@
> #include <image-fit.h>
> #include <bootm-fit.h>
> #include <memory.h>
> +#include <string.h>
> #include <zero_page.h>
> #include <filetype.h>
> #include <fs.h>
> @@ -143,7 +144,7 @@ static enum filetype bootm_fit_update_os_header(struct image_data *data)
> return os_type;
> }
>
> -int bootm_open_fit(struct image_data *data)
> +int bootm_open_fit(struct image_data *data, bool override)
> {
> struct fit_handle *fit;
> void *fit_config;
> @@ -164,8 +165,12 @@ int bootm_open_fit(struct image_data *data)
> }
>
> loadable_from_fit_os(data, fit, fit_config);
> - loadable_from_fit_initrd(data, fit, fit_config);
> - loadable_from_fit_oftree(data, fit, fit_config);
> + if (override)
> + data->is_override.os = true;
> + if (loadable_from_fit_initrd(data, fit, fit_config) && override)
> + data->is_override.initrd = true;
> + if (loadable_from_fit_oftree(data, fit, fit_config) && override)
> + data->is_override.oftree = true;
> loadable_from_fit_tee(data, fit, fit_config);
>
> data->kernel_type = bootm_fit_update_os_header(data);
> diff --git a/common/bootm-overrides.c b/common/bootm-overrides.c
> index 59ca90a58684..8c71ceb5f80d 100644
> --- a/common/bootm-overrides.c
> +++ b/common/bootm-overrides.c
> @@ -2,14 +2,118 @@
>
> #include <bootm.h>
> #include <bootm-overrides.h>
> +#include <bootm-fit.h>
> +#include <libfile.h>
> +#include <linux/pagemap.h>
> +
> +/**
> + * bootm_apply_image_override - apply bootm.image override
> + * @data: image data context
> + * @override: override path (may include @config suffix for FIT)
> + *
> + * Applies a bootm.image override according to these rules:
> + * - If the override is not a FIT image, it replaces only data->os.
> + * - If the override is a FIT image, it is re-opened via bootm_open_fit()
> + * using the default configuration or the @config suffix if given.
> + *
> + * Return: 0 on success, negative errno on failure
> + */
> +static int bootm_apply_image_override(struct image_data *data,
> + const char *override)
> +{
> + char *override_file, *override_part;
> + void *override_header = NULL;
> + int ret;
> +
> + ret = bootm_image_name_and_part(override, &override_file, &override_part);
> + if (ret)
> + return ret;
> +
> + /* Read header to detect file type */
> + ret = file_read_and_detect_boot_image_type(override_file, &override_header);
> + if (ret < 0) {
> + free(override_file);
> + return ret;
> + }
> +
> + data->image_type = ret;
> +
> + /*
> + * bootm_image_name_and_part() returns os_part pointing inside the
> + * os_file allocation, so we must NULLify os_part before freeing
> + * os_file to avoid a use-after-free.
> + */
> + data->os_part = NULL;
> + free(data->os_file);
> + data->os_file = override_file;
> + if (override_part)
> + data->os_part = override_part;
> +
> + /* Update the detected type for the handler */
> + free(data->os_header);
> + data->os_header = override_header;
> +
> + switch (data->image_type) {
> + case filetype_fit:
> + /* Restore, so bootm_open_fit looks for them in the new FIT */
> + data->os_address = data->os_address_hint;
> + data->os_entry = data->os_entry_hint;
> +
> + /* Re-open configuration and collect loadables */
> + return bootm_open_fit(data, true);
> + default:
> + loadable_release(&data->os);
> + data->os = loadable_from_file(override_file, LOADABLE_KERNEL);
> + if (IS_ERR(data->os))
> + return PTR_ERR(data->os);
> +
> + data->kernel_type = data->image_type;
> + data->is_override.os = true;
> +
> + if (file_is_compressed_file(data->kernel_type))
> + return bootm_open_os_compressed(data);
> +
> + return 0;
> + }
> +}
> +
> +static void report_active_override(const char *type_str, struct loadable *l)
> +{
> + struct loadable *lc;
> + char *buf = NULL;
> +
> + if (!l) {
> + pr_notice("[bootm override active] removed %s\n", type_str);
> + return;
> + }
> +
> + buf = xrasprintf(buf, "[bootm override active] replacement %s: %s",
> + type_str, l->name);
> +
> + list_for_each_entry(lc, &l->chained_loadables, list)
> + buf = xrasprintf(buf, ", %s", lc->name);
> +
> + pr_notice("%s\n", buf);
> + free(buf);
> +}
> +
> +static void report_active_overrides(const struct image_data *data)
> +{
> + if (data->is_override.os)
> + report_active_override("OS", data->os);
> + if (data->is_override.initrd)
> + report_active_override("initrd", data->initrd);
> + if (data->is_override.oftree)
> + report_active_override("FDT", data->oftree);
> +}
>
> /**
> * bootm_apply_overrides - apply overrides
> * @data: image data context
> * @overrides: overrides to apply
> *
> - * Applies bootm.initrd and bootm.oftree overrides by translating
> - * them into file-based loadables.
> + * Applies bootm.image, bootm.initrd, and bootm.oftree overrides by translating
> + * them into file-based loadables or FIT image replacements.
> *
> * Context: Called during boot preparation
> * Return: 0 on success, negative error code otherwise
> @@ -17,9 +121,17 @@
> int bootm_apply_overrides(struct image_data *data,
> const struct bootm_overrides *overrides)
> {
> + int ret;
> +
> if (bootm_signed_images_are_forced())
> return 0;
>
> + if (nonempty(overrides->os_file)) {
> + ret = bootm_apply_image_override(data, overrides->os_file);
> + if (ret)
> + return ret;
> + }
> +
> if (IS_ENABLED(CONFIG_BOOTM_INITRD) && overrides->initrd_file) {
> /* loadables_from_files() will set data->initrd on empty initrd_file */
> int ret = loadables_from_files(&data->initrd, overrides->initrd_file, ":",
> @@ -42,6 +154,7 @@ int bootm_apply_overrides(struct image_data *data,
> data->is_override.oftree = true;
> }
>
> + report_active_overrides(data);
> +
> return 0;
> }
> -
> diff --git a/common/bootm.c b/common/bootm.c
> index ddc656fb34c8..ed79c20c0972 100644
> --- a/common/bootm.c
> +++ b/common/bootm.c
> @@ -400,7 +400,7 @@ static void bootm_print_info(struct image_data *data)
> printf("OS image not yet relocated\n");
> }
>
> -static int bootm_image_name_and_part(const char *name, char **filename, char **part)
> +int bootm_image_name_and_part(const char *name, char **filename, char **part)
> {
> char *at, *ret;
>
> @@ -570,7 +570,7 @@ struct image_data *bootm_boot_prep(const struct bootm_data *bootm_data)
>
> switch (data->image_type) {
> case filetype_fit:
> - ret = bootm_open_fit(data);
> + ret = bootm_open_fit(data, false);
> break;
> case filetype_uimage:
> ret = bootm_open_uimage(data);
> diff --git a/include/bootm-fit.h b/include/bootm-fit.h
> index 05f4f5acfe9a..972d9e4fac8e 100644
> --- a/include/bootm-fit.h
> +++ b/include/bootm-fit.h
> @@ -10,11 +10,11 @@ struct image_data;
>
> #ifdef CONFIG_BOOTM_FITIMAGE
>
> -int bootm_open_fit(struct image_data *data);
> +int bootm_open_fit(struct image_data *data, bool override);
>
> #else
>
> -static inline int bootm_open_fit(struct image_data *data)
> +static inline int bootm_open_fit(struct image_data *data, bool override)
> {
> return -ENOSYS;
> }
> diff --git a/include/bootm-overrides.h b/include/bootm-overrides.h
> index a52a498b97a2..9b133928a923 100644
> --- a/include/bootm-overrides.h
> +++ b/include/bootm-overrides.h
> @@ -3,6 +3,7 @@
> #define __BOOTM_OVERRIDES_H
>
> struct bootm_overrides {
> + const char *os_file;
> const char *oftree_file;
> const char *initrd_file;
> };
> @@ -13,6 +14,8 @@ struct image_data;
> static inline void bootm_merge_overrides(struct bootm_overrides *dst,
> const struct bootm_overrides *src)
> {
> + if (src->os_file)
> + dst->os_file = src->os_file;
> if (src->oftree_file)
> dst->oftree_file = src->oftree_file;
> if (src->initrd_file)
> diff --git a/include/bootm.h b/include/bootm.h
> index 570ac4d289f2..85199fc702b4 100644
> --- a/include/bootm.h
> +++ b/include/bootm.h
> @@ -53,6 +53,8 @@ struct bootm_data {
> unsigned long os_entry;
> };
>
> +int bootm_image_name_and_part(const char *name, char **filename, char **part);
> +
> int bootm_boot(const struct bootm_data *data);
>
> struct image_data *bootm_boot_prep(const struct bootm_data *bootm_data);
> --
> 2.47.3
>
>
>

--
Pengutronix e.K. | |
Steuerwalder Str. 21 | http://www.pengutronix.de/ |
31137 Hildesheim, Germany | Phone: +49-5121-206917-0 |
Amtsgericht Hildesheim, HRA 2686 | Fax: +49-5121-206917-5555 |