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

Ahmad Fatoum
2026-03-18T09:17:51Z

Hi,

On 3/18/26 10:01, Sascha Hauer wrote:
> 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?

Sorry, that's confusingly written, A FIT replaces everything in the
selected configuration. So if it has kernel + DT, it overrides those and
leaves only the original initramfs.

Cheers,
Ahmad

>
> 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 |