* [PATCH 02/16] bootm: split preparatory step from handler invocation
2026-03-12 14:44 [PATCH 01/16] lib: add lazy loadable infrastructure for deferred boot component loading Ahmad Fatoum
@ 2026-03-12 14:44 ` Ahmad Fatoum
2026-03-12 14:44 ` [PATCH 03/16] boot: add bootm_boot wrapper that takes struct bootentry Ahmad Fatoum
` (14 subsequent siblings)
15 siblings, 0 replies; 22+ messages in thread
From: Ahmad Fatoum @ 2026-03-12 14:44 UTC (permalink / raw)
To: barebox; +Cc: Ahmad Fatoum
The override handling is currently embedded very deep inside the bootm
code, despite that configuring overrides is only possible from the
boot command. With the switch to a generic loadable abstraction, it will
be possible to switch out loadable objects and avoid this invasiveness,
so prepare for that by splitting the part that would register loadables
from the part that would actually load them.
Signed-off-by: Ahmad Fatoum <a.fatoum@pengutronix.de>
---
common/bootm.c | 44 +++++++++++++++++++++++++++++++++++---------
include/bootm.h | 6 +++++-
2 files changed, 40 insertions(+), 10 deletions(-)
diff --git a/common/bootm.c b/common/bootm.c
index d43079bb81da..a10f3a4ea9dc 100644
--- a/common/bootm.c
+++ b/common/bootm.c
@@ -569,19 +569,15 @@ int file_read_and_detect_boot_image_type(const char *os_file, void **os_header)
return file_detect_boot_image_type(*os_header, PAGE_SIZE);
}
-/*
- * bootm_boot - Boot an application image described by bootm_data
- */
-int bootm_boot(struct bootm_data *bootm_data)
+struct image_data *bootm_boot_prep(const struct bootm_data *bootm_data)
{
struct image_data *data;
- struct image_handler *handler;
int ret;
const char *image_type_str;
if (!bootm_data->os_file) {
pr_err("no image given\n");
- return -ENOENT;
+ return ERR_PTR(-ENOENT);
}
data = xzalloc(sizeof(*data));
@@ -759,6 +755,17 @@ int bootm_boot(struct bootm_data *bootm_data)
free(hostname_bootarg);
}
+ return data;
+err_out:
+ bootm_boot_cleanup(data);
+ return ERR_PTR(ret);
+}
+
+int bootm_boot_handler(struct image_data *data)
+{
+ struct image_handler *handler;
+ int ret;
+
pr_info("\nLoading %s '%s'", file_type_to_string(data->kernel_type),
data->os_file);
if (data->kernel_type == filetype_uimage &&
@@ -777,8 +784,7 @@ int bootm_boot(struct bootm_data *bootm_data)
file_type_to_string(data->kernel_type));
if (data->kernel_type == filetype_uimage)
pr_err("and OS type: %d\n", data->os_uimage->header.ih_os);
- ret = -ENODEV;
- goto err_out;
+ return -ENODEV;
}
if (bootm_verbose(data)) {
@@ -797,7 +803,11 @@ int bootm_boot(struct bootm_data *bootm_data)
if (data->dryrun)
pr_info("Dryrun. Aborted\n");
-err_out:
+ return ret;
+}
+
+void bootm_boot_cleanup(struct image_data *data)
+{
release_sdram_region(data->os_res);
if (data->initrd_res)
of_del_reserve_entry(data->initrd_res->start, data->initrd_res->end);
@@ -819,7 +829,23 @@ int bootm_boot(struct bootm_data *bootm_data)
free(data->initrd_file);
free(data->tee_file);
free(data);
+}
+/*
+ * bootm_boot - Boot an application image described by bootm_data
+ */
+int bootm_boot(const struct bootm_data *bootm_data)
+{
+ struct image_data *data;
+ int ret;
+
+ data = bootm_boot_prep(bootm_data);
+ if (IS_ERR(data))
+ return PTR_ERR(data);
+
+ ret = bootm_boot_handler(data);
+
+ bootm_boot_cleanup(data);
return ret;
}
diff --git a/include/bootm.h b/include/bootm.h
index 21feb1ca98ae..da6cf7301709 100644
--- a/include/bootm.h
+++ b/include/bootm.h
@@ -52,7 +52,11 @@ struct bootm_data {
unsigned long os_entry;
};
-int bootm_boot(struct bootm_data *data);
+int bootm_boot(const struct bootm_data *data);
+
+struct image_data *bootm_boot_prep(const struct bootm_data *bootm_data);
+int bootm_boot_handler(struct image_data *data);
+void bootm_boot_cleanup(struct image_data *data);
struct image_data {
/* simplest case. barebox has already loaded the os here */
--
2.47.3
^ permalink raw reply [flat|nested] 22+ messages in thread* [PATCH 03/16] boot: add bootm_boot wrapper that takes struct bootentry
2026-03-12 14:44 [PATCH 01/16] lib: add lazy loadable infrastructure for deferred boot component loading Ahmad Fatoum
2026-03-12 14:44 ` [PATCH 02/16] bootm: split preparatory step from handler invocation Ahmad Fatoum
@ 2026-03-12 14:44 ` Ahmad Fatoum
2026-03-12 14:44 ` [PATCH 04/16] bootchooser: pass along " Ahmad Fatoum
` (13 subsequent siblings)
15 siblings, 0 replies; 22+ messages in thread
From: Ahmad Fatoum @ 2026-03-12 14:44 UTC (permalink / raw)
To: barebox; +Cc: Ahmad Fatoum
struct bootentry holds the overrides given to the boot command, but it's
not plumbed through to the end leading to storage of the overrides in
global variables, which is error prone with respect to nested bootm
handlers.
In preparation for passing the overrides via arguments throughout,
introduce the bootm_entry and switch users over to it.
Signed-off-by: Ahmad Fatoum <a.fatoum@pengutronix.de>
---
arch/arm/boards/protonic-imx6/board.c | 2 +-
common/blspec.c | 2 +-
common/boot.c | 37 ++++++++++++++++++++++-----
efi/loader/bootesp.c | 2 +-
include/boot.h | 3 +++
5 files changed, 37 insertions(+), 9 deletions(-)
diff --git a/arch/arm/boards/protonic-imx6/board.c b/arch/arm/boards/protonic-imx6/board.c
index c15a349c8a88..3bb2632693e5 100644
--- a/arch/arm/boards/protonic-imx6/board.c
+++ b/arch/arm/boards/protonic-imx6/board.c
@@ -406,7 +406,7 @@ static int prt_imx6_usb_boot(struct bootentry *entry, int verbose, int dryrun)
if (dryrun)
bootm_data.dryrun = dryrun;
- ret = bootm_boot(&bootm_data);
+ ret = bootm_entry(entry, &bootm_data);
if (ret)
goto exit_usb_boot;
diff --git a/common/blspec.c b/common/blspec.c
index c07e3a2d672d..ef7490085c7f 100644
--- a/common/blspec.c
+++ b/common/blspec.c
@@ -156,7 +156,7 @@ static int blspec_boot(struct bootentry *be, int verbose, int dryrun)
firmware_set_searchpath(fws);
free(fws);
- ret = bootm_boot(&data);
+ ret = bootm_entry(be, &data);
if (ret)
pr_err("Booting failed\n");
diff --git a/common/boot.c b/common/boot.c
index 0fa2022be1ac..b5a4205cd9e2 100644
--- a/common/boot.c
+++ b/common/boot.c
@@ -124,7 +124,7 @@ static int bootscript_boot(struct bootentry *entry, int verbose, int dryrun)
if (dryrun >= 2)
data.dryrun = dryrun - 1;
- ret = bootm_boot(&data);
+ ret = bootm_entry(entry, &data);
out:
bootm_data_restore_defaults(&backup);
return ret;
@@ -182,7 +182,6 @@ BAREBOX_MAGICVAR(global.boot.watchdog_timeout,
int boot_entry(struct bootentry *be, int verbose, int dryrun)
{
- struct bootm_overrides old;
int ret;
pr_info("Booting entry '%s'\n", be->title);
@@ -197,14 +196,10 @@ int boot_entry(struct bootentry *be, int verbose, int dryrun)
}
}
- old = bootm_save_overrides(be->overrides);
-
ret = be->boot(be, verbose, dryrun);
if (ret && ret != -ENOMEDIUM)
pr_err("Booting entry '%s' failed: %pe\n", be->title, ERR_PTR(ret));
- bootm_restore_overrides(old);
-
globalvar_set_match("linux.bootargs.dyn.", "");
return ret;
@@ -555,3 +550,33 @@ void bootsources_list(struct bootentries *bootentries)
}
BAREBOX_MAGICVAR(global.boot.default, "default boot order");
+
+/**
+ * bootm_entry - invoke bootm while taking care of overrides
+ * @be: bootentry
+ * @bootm_data: prepopulated bootm data for bootm_boot()
+ *
+ * Compared to bootm_boot(), this takes an extra @be that allows
+ * applying boot entry specific info like overrides.
+ *
+ * Return: 0 on success, or negative error code otherwise
+ */
+int bootm_entry(struct bootentry *be, const struct bootm_data *bootm_data)
+{
+ struct bootm_overrides old;
+ struct image_data *data;
+ int ret;
+
+ data = bootm_boot_prep(bootm_data);
+ if (IS_ERR(data))
+ return PTR_ERR(data);
+
+ old = bootm_save_overrides(be->overrides);
+
+ ret = bootm_boot_handler(data);
+
+ bootm_restore_overrides(old);
+
+ bootm_boot_cleanup(data);
+ return ret;
+}
diff --git a/efi/loader/bootesp.c b/efi/loader/bootesp.c
index afce5118aa68..85de1e7e6350 100644
--- a/efi/loader/bootesp.c
+++ b/efi/loader/bootesp.c
@@ -55,7 +55,7 @@ static int esp_boot(struct bootentry *be, int verbose, int dryrun)
* 2) implement device tree overlay patching protocol using it?
*/
- ret = bootm_boot(&data);
+ ret = bootm_entry(be, &data);
if (ret)
pr_err("Booting failed\n");
diff --git a/include/boot.h b/include/boot.h
index 836a180a0c7b..57f9cb409bf3 100644
--- a/include/boot.h
+++ b/include/boot.h
@@ -55,4 +55,7 @@ void bootsources_menu(struct bootentries *bootentries, unsigned default_entry, i
void bootsources_list(struct bootentries *bootentries);
int boot_entry(struct bootentry *be, int verbose, int dryrun);
+struct bootm_data;
+int bootm_entry(struct bootentry *be, const struct bootm_data *data);
+
#endif /* __BOOT_H */
--
2.47.3
^ permalink raw reply [flat|nested] 22+ messages in thread* [PATCH 04/16] bootchooser: pass along struct bootentry
2026-03-12 14:44 [PATCH 01/16] lib: add lazy loadable infrastructure for deferred boot component loading Ahmad Fatoum
2026-03-12 14:44 ` [PATCH 02/16] bootm: split preparatory step from handler invocation Ahmad Fatoum
2026-03-12 14:44 ` [PATCH 03/16] boot: add bootm_boot wrapper that takes struct bootentry Ahmad Fatoum
@ 2026-03-12 14:44 ` Ahmad Fatoum
2026-03-12 14:44 ` [PATCH 05/16] bootm: switch plain file names case to loadable API Ahmad Fatoum
` (12 subsequent siblings)
15 siblings, 0 replies; 22+ messages in thread
From: Ahmad Fatoum @ 2026-03-12 14:44 UTC (permalink / raw)
To: barebox; +Cc: Ahmad Fatoum
By plumbing through the parent bootentry, we can merge the overrides
applied for the bootchooser targets onto the actual children if boot
override support is enabled.
Signed-off-by: Ahmad Fatoum <a.fatoum@pengutronix.de>
---
common/bootchooser.c | 13 +++++++++----
include/bootchooser.h | 2 +-
2 files changed, 10 insertions(+), 5 deletions(-)
diff --git a/common/bootchooser.c b/common/bootchooser.c
index 07cbdacfeb0a..2a75dfdcc88e 100644
--- a/common/bootchooser.c
+++ b/common/bootchooser.c
@@ -839,7 +839,8 @@ void bootchooser_lock_attempts(bool locked)
attempts_locked = locked;
}
-static int bootchooser_boot_one(struct bootchooser *bc, int *tryagain)
+static int bootchooser_boot_one(struct bootchooser *bc, int *tryagain,
+ struct bootentry *parent_entry)
{
char *system;
struct bootentries *entries;
@@ -873,6 +874,10 @@ static int bootchooser_boot_one(struct bootchooser *bc, int *tryagain)
ret = -ENOENT;
bootentries_for_each_entry(entries, entry) {
+ if (parent_entry)
+ bootm_merge_overrides(&entry->overrides,
+ &parent_entry->overrides);
+
ret = boot_entry(entry, bc->verbose, bc->dryrun);
if (!ret) {
*tryagain = 0;
@@ -889,12 +894,12 @@ static int bootchooser_boot_one(struct bootchooser *bc, int *tryagain)
return ret;
}
-int bootchooser_boot(struct bootchooser *bc)
+int bootchooser_boot(struct bootchooser *bc, struct bootentry *entry)
{
int ret, tryagain;
do {
- ret = bootchooser_boot_one(bc, &tryagain);
+ ret = bootchooser_boot_one(bc, &tryagain, entry);
if (!retry)
break;
@@ -915,7 +920,7 @@ int bootchooser_entry_boot(struct bootentry *entry, int verbose, int dryrun)
bc->verbose = verbose;
bc->dryrun = dryrun;
- ret = bootchooser_boot(bc);
+ ret = bootchooser_boot(bc, entry);
bootchooser_put(bc);
diff --git a/include/bootchooser.h b/include/bootchooser.h
index 36cbd0dd0a01..da3b974ef6f6 100644
--- a/include/bootchooser.h
+++ b/include/bootchooser.h
@@ -14,7 +14,7 @@ int bootchooser_put(struct bootchooser *bootchooser);
void bootchooser_info(struct bootchooser *bootchooser);
-int bootchooser_boot(struct bootchooser *bc);
+int bootchooser_boot(struct bootchooser *bc, struct bootentry *entry);
struct bootchooser_target *bootchooser_get_last_chosen(struct bootchooser *bootchooser);
void bootchooser_lock_attempts(bool locked);
--
2.47.3
^ permalink raw reply [flat|nested] 22+ messages in thread* [PATCH 05/16] bootm: switch plain file names case to loadable API
2026-03-12 14:44 [PATCH 01/16] lib: add lazy loadable infrastructure for deferred boot component loading Ahmad Fatoum
` (2 preceding siblings ...)
2026-03-12 14:44 ` [PATCH 04/16] bootchooser: pass along " Ahmad Fatoum
@ 2026-03-12 14:44 ` Ahmad Fatoum
2026-03-12 14:44 ` [PATCH 06/16] uimage: add offset parameter to uimage_load Ahmad Fatoum
` (11 subsequent siblings)
15 siblings, 0 replies; 22+ messages in thread
From: Ahmad Fatoum @ 2026-03-12 14:44 UTC (permalink / raw)
To: barebox; +Cc: Ahmad Fatoum
The current bootm code has a number of downsides:
- uImage/FIT image support are deeply embedded in the code and every
bootm_load_* function needs to take care of them in addition to
the plain file load case
- Override handling is very invasive due to the above and needs to be
repeated at every bootm_load_*
- Once a suitable starting region is determined, there is sometimes
no bound checks to verify that the region is not exceeded
- Decompression necessarily needs a memory copy as only after a separate
bootm handle for the compressed binary runs, the inside decompressed
binary can actually have its bootm handler invoked
While trying to add support for multiple initrds, it became apparent, that
this further increase in complexity is not a good way forward.
As the current code is very intertwined and piece-wise migration would lead
to intermittent breakage, rework now everything except the uImage and
FIT image handling that will follow later.
This already has a number of benefits:
- override handling moved out of bootm code
- No separate compressed image bootm handler, decompression can be done
directly to the final load address (in theory, the uncompress
implementation still use an intermediate buffer for now).
Signed-off-by: Ahmad Fatoum <a.fatoum@pengutronix.de>
---
arch/arm/lib32/bootm.c | 41 +++--
common/Kconfig | 8 +
common/Makefile | 1 +
common/boot.c | 8 +-
common/bootm-overrides.c | 59 +++++++
common/bootm.c | 313 +++++++++++++++-----------------------
include/bootm-overrides.h | 30 ++--
include/bootm.h | 21 ++-
lib/Kconfig | 1 +
9 files changed, 254 insertions(+), 228 deletions(-)
create mode 100644 common/bootm-overrides.c
diff --git a/arch/arm/lib32/bootm.c b/arch/arm/lib32/bootm.c
index 22364beadcd5..7ad2a26fdc2f 100644
--- a/arch/arm/lib32/bootm.c
+++ b/arch/arm/lib32/bootm.c
@@ -194,41 +194,34 @@ static int bootm_load_tee_from_fit(struct image_data *data)
out:
return ret;
}
-static int bootm_load_tee_from_file(struct image_data *data)
+static int bootm_load_tee(struct image_data *data)
{
- int fd, ret;
+ int ret;
struct optee_header hdr;
- fd = open(data->tee_file, O_RDONLY);
- if (fd < 0) {
- pr_err("%m\n");
- return -errno;
- }
+ if (!data->tee)
+ return 0;
- if (read_full(fd, &hdr, sizeof(hdr)) < 0) {
- pr_err("%m\n");
- ret = -errno;
- goto out;
- }
+ ret = loadable_extract_into_buf(data->tee, &hdr, sizeof(hdr), 0,
+ LOADABLE_EXTRACT_PARTIAL);
+ if (ret < 0)
+ return ret;
ret = optee_verify_header_request_region(data, &hdr);
if (ret < 0)
- goto out;
+ return ret;
- if (read_full(fd, (void *)data->tee_res->start, hdr.init_size) < 0) {
- pr_err("%m\n");
- ret = -errno;
+ ret = loadable_extract_into_buf(data->tee, (void *)data->tee_res->start,
+ hdr.init_size, sizeof(hdr), 0);
+ if (ret < 0) {
release_region(data->tee_res);
- goto out;
+ return ret;
}
- printf("Read optee file to %pa, size 0x%08x\n", (void *)data->tee_res->start, hdr.init_size);
+ printf("Loaded TEE image to %pa, size 0x%08x\n",
+ (void *)data->tee_res->start, hdr.init_size);
- ret = 0;
-out:
- close(fd);
-
- return ret;
+ return 0;
}
static int __do_bootm_linux(struct image_data *data, unsigned long free_mem,
@@ -295,7 +288,7 @@ static int __do_bootm_linux(struct image_data *data, unsigned long free_mem,
if (IS_ENABLED(CONFIG_BOOTM_OPTEE)) {
if (data->tee_file && !bootm_signed_images_are_forced()) {
- ret = bootm_load_tee_from_file(data);
+ ret = bootm_load_tee(data);
if (ret)
return ret;
} else if (IS_ENABLED(CONFIG_FITIMAGE)) {
diff --git a/common/Kconfig b/common/Kconfig
index cd002865f736..fd422714d560 100644
--- a/common/Kconfig
+++ b/common/Kconfig
@@ -572,6 +572,14 @@ config TIMESTAMP
menuconfig BOOTM
default y if COMMAND_SUPPORT
bool "bootm support"
+ select LOADABLE
+
+config BOOTM_COMPRESSED
+ bool "bootm support for compressed images"
+ default y
+ depends on BOOTM
+ depends on UNCOMPRESS
+ select LOADABLE_DECOMPRESS
config BOOT_OVERRIDE
bool "Support partial override of boot entries"
diff --git a/common/Makefile b/common/Makefile
index ac39ee4e3ed5..27c5dea16860 100644
--- a/common/Makefile
+++ b/common/Makefile
@@ -29,6 +29,7 @@ obj-$(CONFIG_BLOCK) += block.o
obj-$(CONFIG_BLSPEC) += blspec.o
obj-$(CONFIG_BOOTM) += bootm.o booti.o
obj-$(CONFIG_BOOTM_AIMAGE) += bootm-android-image.o
+obj-$(CONFIG_BOOT_OVERRIDE) += bootm-overrides.o
obj-$(CONFIG_CMD_LOADS) += s_record.o
obj-$(CONFIG_MEMTEST) += memtest.o
obj-$(CONFIG_COMMAND_SUPPORT) += command.o
diff --git a/common/boot.c b/common/boot.c
index b5a4205cd9e2..dc1441d0dc91 100644
--- a/common/boot.c
+++ b/common/boot.c
@@ -563,7 +563,6 @@ BAREBOX_MAGICVAR(global.boot.default, "default boot order");
*/
int bootm_entry(struct bootentry *be, const struct bootm_data *bootm_data)
{
- struct bootm_overrides old;
struct image_data *data;
int ret;
@@ -571,12 +570,13 @@ int bootm_entry(struct bootentry *be, const struct bootm_data *bootm_data)
if (IS_ERR(data))
return PTR_ERR(data);
- old = bootm_save_overrides(be->overrides);
+ ret = bootm_apply_overrides(data, &be->overrides);
+ if (ret)
+ goto out;
ret = bootm_boot_handler(data);
- bootm_restore_overrides(old);
-
+out:
bootm_boot_cleanup(data);
return ret;
}
diff --git a/common/bootm-overrides.c b/common/bootm-overrides.c
new file mode 100644
index 000000000000..e1cba21e7711
--- /dev/null
+++ b/common/bootm-overrides.c
@@ -0,0 +1,59 @@
+// SPDX-License-Identifier: GPL-2.0-only
+
+#include <bootm.h>
+#include <bootm-overrides.h>
+
+/**
+ * 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.
+ *
+ * Context: Called during boot preparation
+ * Return: 0 on success, negative error code otherwise
+ */
+int bootm_apply_overrides(struct image_data *data,
+ const struct bootm_overrides *overrides)
+{
+ if (bootm_signed_images_are_forced())
+ return 0;
+
+ /* TODO: As we haven't switched over everything to loadables yet,
+ * we need a special marker to mean override to empty.
+ * We do this via a 0-byte file (/dev/null) for now..
+ */
+
+ if (overrides->initrd_file) {
+ loadable_release(&data->initrd);
+
+ /* Empty string means to mask the original initrd */
+ if (nonempty(overrides->initrd_file))
+ data->initrd = loadable_from_file(overrides->initrd_file,
+ LOADABLE_INITRD);
+ else
+ data->initrd = loadable_from_file("/dev/null",
+ LOADABLE_INITRD);
+ if (IS_ERR(data->initrd))
+ return PTR_ERR(data->initrd);
+ data->is_override.initrd = true;
+ }
+
+ if (overrides->oftree_file) {
+ loadable_release(&data->oftree);
+
+ /* Empty string means to mask the original FDT */
+ if (nonempty(overrides->oftree_file))
+ data->oftree = loadable_from_file(overrides->oftree_file,
+ LOADABLE_FDT);
+ else
+ data->oftree = loadable_from_file("/dev/null",
+ LOADABLE_FDT);
+ if (IS_ERR(data->oftree))
+ return PTR_ERR(data->oftree);
+ data->is_override.oftree = true;
+ }
+
+ return 0;
+}
diff --git a/common/bootm.c b/common/bootm.c
index a10f3a4ea9dc..74caa3b13d86 100644
--- a/common/bootm.c
+++ b/common/bootm.c
@@ -3,7 +3,6 @@
#include <common.h>
#include <bootargs.h>
#include <bootm.h>
-#include <bootm-overrides.h>
#include <fs.h>
#include <fcntl.h>
#include <efi/mode.h>
@@ -19,15 +18,12 @@
#include <environment.h>
#include <linux/stat.h>
#include <magicvar.h>
-#include <uncompress.h>
#include <zero_page.h>
#include <security/config.h>
static LIST_HEAD(handler_list);
static struct sconfig_notifier_block sconfig_notifier;
-static __maybe_unused struct bootm_overrides bootm_overrides;
-
static bool uimage_check(struct image_handler *handler,
struct image_data *data,
enum filetype detected_filetype)
@@ -211,23 +207,6 @@ static inline bool image_is_uimage(struct image_data *data)
return IS_ENABLED(CONFIG_BOOTM_UIMAGE) && data->os_uimage;
}
-static bool bootm_get_override(char **oldpath, const char *newpath)
-{
- if (!IS_ENABLED(CONFIG_BOOT_OVERRIDE))
- return false;
- if (bootm_signed_images_are_forced())
- return false;
- if (!newpath)
- return false;
-
- if (oldpath && !streq_ptr(*oldpath, newpath)) {
- free(*oldpath);
- *oldpath = *newpath ? xstrdup(newpath) : NULL;
- }
-
- return true;
-}
-
/**
* bootm_load_os() - load OS to RAM
* @data: image data context
@@ -243,6 +222,7 @@ static bool bootm_get_override(char **oldpath, const char *newpath)
const struct resource *bootm_load_os(struct image_data *data,
ulong load_address, ulong end_address)
{
+ struct resource *res;
int err;
if (data->os_res)
@@ -253,17 +233,22 @@ const struct resource *bootm_load_os(struct image_data *data,
if (end_address <= load_address)
return ERR_PTR(-EINVAL);
- if (data->os_fit) {
- err = bootm_load_fit_os(data, load_address);
- } else if (image_is_uimage(data)) {
- err = bootm_load_uimage_os(data, load_address);
- } else if (data->os_file) {
- data->os_res = file_to_sdram(data->os_file, load_address, MEMTYPE_LOADER_CODE);
- err = data->os_res ? 0 : -EBUSY;
- } else {
- err = -EINVAL;
+ if (data->os) {
+ res = loadable_extract_into_sdram_all(data->os, load_address, end_address);
+ if (!IS_ERR(res))
+ data->os_res = res;
+ return res;
}
+ /* TODO: eliminate below special cases */
+
+ if (data->os_fit)
+ err = bootm_load_fit_os(data, load_address);
+ else if (image_is_uimage(data))
+ err = bootm_load_uimage_os(data, load_address);
+ else
+ err = -EINVAL;
+
if (err)
return ERR_PTR(err);
@@ -308,7 +293,12 @@ bootm_load_initrd(struct image_data *data, ulong load_address, ulong end_address
if (end_address <= load_address)
return ERR_PTR(-EINVAL);
- bootm_get_override(&data->initrd_file, bootm_overrides.initrd_file);
+ if (data->initrd) {
+ res = loadable_extract_into_sdram_all(data->initrd, load_address, end_address);
+ if (!IS_ERR(res))
+ data->initrd_res = res;
+ return res;
+ }
initrd = data->initrd_file;
if (initrd) {
@@ -324,11 +314,6 @@ bootm_load_initrd(struct image_data *data, ulong load_address, ulong end_address
res = bootm_load_uimage_initrd(data, load_address);
if (data->initrd_uimage->header.ih_type == IH_TYPE_MULTI)
initrd_part = data->initrd_part;
-
- } else if (initrd) {
- res = file_to_sdram(initrd, load_address, MEMTYPE_LOADER_DATA)
- ?: ERR_PTR(-EBUSY);
-
} else if (data->os_fit) {
res = bootm_load_fit_initrd(data, load_address);
type = filetype_fit;
@@ -368,21 +353,40 @@ void *bootm_get_devicetree(struct image_data *data)
{
enum filetype type;
struct fdt_header *oftree;
- bool from_fit = false;
int ret;
if (!IS_ENABLED(CONFIG_OFTREE))
return ERR_PTR(-ENOSYS);
- from_fit = bootm_fit_has_fdt(data);
- if (bootm_get_override(&data->oftree_file, bootm_overrides.oftree_file))
- from_fit = false;
+ if (data->oftree) {
+ const struct fdt_header *oftree_view;
+ size_t size;
- if (from_fit) {
+ oftree_view = loadable_view(data->oftree, &size);
+ if (IS_ERR(oftree_view))
+ pr_err("could not open device tree \"%s\": %pe\n",
+ data->oftree_file, oftree_view);
+ if (IS_ERR_OR_NULL(oftree_view))
+ return ERR_CAST(oftree_view);
+
+ data->of_root_node = of_unflatten_dtb(oftree_view, size);
+ loadable_view_free(data->oftree, oftree_view, size);
+
+ if (IS_ERR(data->of_root_node)) {
+ data->of_root_node = NULL;
+ pr_err("unable to unflatten devicetree\n");
+ return ERR_PTR(-EINVAL);
+ }
+
+ } else if (bootm_fit_has_fdt(data)) {
data->of_root_node = bootm_get_fit_devicetree(data);
} else if (data->oftree_file) {
size_t size;
+ /* TODO: There's some duplication here, but that will go away
+ * once we switch this over to the loadable API
+ */
+
ret = file_name_detect_type(data->oftree_file, &type);
if (ret) {
pr_err("could not open device tree \"%s\": %pe\n", data->oftree_file,
@@ -390,21 +394,10 @@ void *bootm_get_devicetree(struct image_data *data)
return ERR_PTR(ret);
}
- switch (type) {
- case filetype_uimage:
- ret = bootm_open_oftree_uimage(data, &size, &oftree);
- break;
- case filetype_oftree:
- pr_info("Loading devicetree from '%s'\n", data->oftree_file);
- ret = read_file_2(data->oftree_file, &size, (void *)&oftree,
- FILESIZE_MAX);
- break;
- case filetype_empty:
- return NULL;
- default:
+ if (type != filetype_uimage)
return ERR_PTR(-EINVAL);
- }
+ ret = bootm_open_oftree_uimage(data, &size, &oftree);
if (ret)
return ERR_PTR(ret);
@@ -488,25 +481,18 @@ bootm_load_devicetree(struct image_data *data, void *fdt,
return data->oftree_res;
}
-int bootm_get_os_size(struct image_data *data)
+loff_t bootm_get_os_size(struct image_data *data)
{
- const char *os_file;
- struct stat s;
- int ret;
+ loff_t size;
+ if (data->os)
+ return loadable_get_size(data->os, &size) ?: size;
if (image_is_uimage(data))
return uimage_get_size(data->os_uimage, uimage_part_num(data->os_part));
if (data->os_fit)
return data->fit_kernel_size;
- if (!data->os_file)
- return -EINVAL;
- os_file = data->os_file;
- ret = stat(os_file, &s);
- if (ret)
- return ret;
-
- return s.st_size;
+ return -EINVAL;
}
static void bootm_print_info(struct image_data *data)
@@ -569,6 +555,63 @@ int file_read_and_detect_boot_image_type(const char *os_file, void **os_header)
return file_detect_boot_image_type(*os_header, PAGE_SIZE);
}
+static int bootm_open_files(struct image_data *data)
+{
+ data->os = loadable_from_file(data->os_file, LOADABLE_KERNEL);
+ if (IS_ERR(data->os))
+ return PTR_ERR(data->os);
+
+ if (data->oftree_file) {
+ data->oftree = loadable_from_file(data->oftree_file, LOADABLE_FDT);
+ if (IS_ERR(data->oftree))
+ return PTR_ERR(data->oftree);
+ }
+
+ if (data->initrd_file) {
+ data->initrd = loadable_from_file(data->initrd_file, LOADABLE_INITRD);
+ if (IS_ERR(data->initrd))
+ return PTR_ERR(data->initrd);
+ }
+
+ if (data->tee_file) {
+ data->tee = loadable_from_file(data->tee_file, LOADABLE_TEE);
+ if (IS_ERR(data->tee))
+ return PTR_ERR(data->tee);
+ }
+
+ return 0;
+}
+
+int bootm_open_os_compressed(struct image_data *data)
+{
+ void *header;
+ ssize_t ret;
+
+ if (!IS_ENABLED(CONFIG_BOOTM_COMPRESSED))
+ return -ENOSYS;
+
+ /* Wrap the OS loadable with transparent decompression */
+ data->os = loadable_decompress(data->os);
+
+ /* Read decompressed header to detect actual kernel type */
+ header = xzalloc(PAGE_SIZE);
+ ret = loadable_extract_into_buf(data->os, header, PAGE_SIZE, 0,
+ LOADABLE_EXTRACT_PARTIAL);
+ if (ret < 0) {
+ free(header);
+ return ret;
+ }
+
+ /* Detect actual image type from decompressed content */
+ data->kernel_type = file_detect_boot_image_type(header, ret);
+
+ /* Replace the os_header with the decompressed header */
+ free(data->os_header);
+ data->os_header = header;
+
+ return 0;
+}
+
struct image_data *bootm_boot_prep(const struct bootm_data *bootm_data)
{
struct image_data *data;
@@ -636,8 +679,20 @@ struct image_data *bootm_boot_prep(const struct bootm_data *bootm_data)
case filetype_uimage:
ret = bootm_open_uimage(data);
break;
+ case filetype_gzip:
+ case filetype_bzip2:
+ case filetype_lzo_compressed:
+ case filetype_lz4_compressed:
+ case filetype_xz_compressed:
+ case filetype_zstd_compressed:
+ ret = bootm_open_files(data);
+ if (!ret)
+ ret = bootm_open_os_compressed(data);
+ image_type_str = "compressed boot";
+ break;
default:
- ret = 0;
+ ret = bootm_open_files(data);
+ image_type_str = "boot";
break;
}
@@ -792,13 +847,6 @@ int bootm_boot_handler(struct image_data *data)
printf("Passing control to %s handler\n", handler->name);
}
- bootm_get_override(&data->oftree_file, bootm_overrides.oftree_file);
-
- if (bootm_get_override(&data->initrd_file, bootm_overrides.initrd_file)) {
- release_sdram_region(data->initrd_res);
- data->initrd_res = NULL;
- }
-
ret = handler->bootm(data);
if (data->dryrun)
pr_info("Dryrun. Aborted\n");
@@ -818,6 +866,10 @@ void bootm_boot_cleanup(struct image_data *data)
bootm_close_uimage(data);
if (data->os_fit)
bootm_close_fit(data);
+ loadable_release(&data->oftree);
+ loadable_release(&data->initrd);
+ loadable_release(&data->os);
+ loadable_release(&data->tee);
if (data->of_root_node)
of_delete_node(data->of_root_node);
@@ -849,20 +901,6 @@ int bootm_boot(const struct bootm_data *bootm_data)
return ret;
}
-#ifdef CONFIG_BOOT_OVERRIDE
-struct bootm_overrides bootm_save_overrides(const struct bootm_overrides overrides)
-{
- struct bootm_overrides old = bootm_overrides;
- /* bootm_merge_overrides copies only actual (non-NULL) overrides */
- bootm_merge_overrides(&bootm_overrides, &overrides);
- return old;
-}
-void bootm_restore_overrides(const struct bootm_overrides overrides)
-{
- bootm_overrides = overrides;
-}
-#endif
-
bool bootm_efi_check_image(struct image_handler *handler,
struct image_data *data,
enum filetype detected_filetype)
@@ -887,92 +925,6 @@ bool bootm_efi_check_image(struct image_handler *handler,
return detected_filetype == handler->filetype;
}
-static int do_bootm_compressed(struct image_data *img_data)
-{
- struct bootm_data bootm_data = {
- .oftree_file = img_data->oftree_file,
- .initrd_file = img_data->initrd_file,
- .tee_file = img_data->tee_file,
- .verbose = img_data->verbose,
- .verify = img_data->verify,
- .force = img_data->force,
- .dryrun = img_data->dryrun,
- .initrd_address = img_data->initrd_address,
- .os_address = img_data->os_address,
- .os_entry = img_data->os_entry,
- };
- int from, to, ret;
- char *dstpath;
-
- from = open(img_data->os_file, O_RDONLY);
- if (from < 0)
- return -ENODEV;
-
- dstpath = make_temp("bootm-compressed");
- if (!dstpath) {
- ret = -ENOMEM;
- goto fail_from;
- }
-
- to = open(dstpath, O_CREAT | O_WRONLY);
- if (to < 0) {
- ret = -ENODEV;
- goto fail_make_temp;
- }
-
- ret = uncompress_fd_to_fd(from, to, uncompress_err_stdout);
- if (ret)
- goto fail_to;
-
- bootm_data.os_file = dstpath;
- ret = bootm_boot(&bootm_data);
-
-fail_to:
- close(to);
- unlink(dstpath);
-fail_make_temp:
- free(dstpath);
-fail_from:
- close(from);
- return ret;
-}
-
-static struct image_handler bzip2_bootm_handler = {
- .name = "BZIP2 compressed file",
- .bootm = do_bootm_compressed,
- .filetype = filetype_bzip2,
-};
-
-static struct image_handler gzip_bootm_handler = {
- .name = "GZIP compressed file",
- .bootm = do_bootm_compressed,
- .filetype = filetype_gzip,
-};
-
-static struct image_handler lzo_bootm_handler = {
- .name = "LZO compressed file",
- .bootm = do_bootm_compressed,
- .filetype = filetype_lzo_compressed,
-};
-
-static struct image_handler lz4_bootm_handler = {
- .name = "LZ4 compressed file",
- .bootm = do_bootm_compressed,
- .filetype = filetype_lz4_compressed,
-};
-
-static struct image_handler xz_bootm_handler = {
- .name = "XZ compressed file",
- .bootm = do_bootm_compressed,
- .filetype = filetype_xz_compressed,
-};
-
-static struct image_handler zstd_bootm_handler = {
- .name = "ZSTD compressed file",
- .bootm = do_bootm_compressed,
- .filetype = filetype_zstd_compressed,
-};
-
int linux_rootwait_secs = 10;
static const char * const bootm_efi_loader_mode_names[] = {
@@ -1020,19 +972,6 @@ static int bootm_init(void)
bootm_efi_loader_mode_names,
ARRAY_SIZE(bootm_efi_loader_mode_names));
- if (IS_ENABLED(CONFIG_BZLIB))
- register_image_handler(&bzip2_bootm_handler);
- if (IS_ENABLED(CONFIG_ZLIB))
- register_image_handler(&gzip_bootm_handler);
- if (IS_ENABLED(CONFIG_LZO_DECOMPRESS))
- register_image_handler(&lzo_bootm_handler);
- if (IS_ENABLED(CONFIG_LZ4_DECOMPRESS))
- register_image_handler(&lz4_bootm_handler);
- if (IS_ENABLED(CONFIG_XZ_DECOMPRESS))
- register_image_handler(&xz_bootm_handler);
- if (IS_ENABLED(CONFIG_ZSTD_DECOMPRESS))
- register_image_handler(&zstd_bootm_handler);
-
return 0;
}
late_initcall(bootm_init);
diff --git a/include/bootm-overrides.h b/include/bootm-overrides.h
index b807e5be310a..a52a498b97a2 100644
--- a/include/bootm-overrides.h
+++ b/include/bootm-overrides.h
@@ -7,26 +7,32 @@ struct bootm_overrides {
const char *initrd_file;
};
-#ifdef CONFIG_BOOT_OVERRIDE
-struct bootm_overrides bootm_save_overrides(const struct bootm_overrides overrides);
-void bootm_restore_overrides(const struct bootm_overrides overrides);
-#else
-static inline struct bootm_overrides bootm_save_overrides(const struct bootm_overrides overrides)
-{
- return (struct bootm_overrides) {};
-}
-static inline void bootm_restore_overrides(const struct bootm_overrides overrides) {}
-#endif
+struct image_data;
+#ifdef CONFIG_BOOT_OVERRIDE
static inline void bootm_merge_overrides(struct bootm_overrides *dst,
const struct bootm_overrides *src)
{
- if (!IS_ENABLED(CONFIG_BOOT_OVERRIDE))
- return;
if (src->oftree_file)
dst->oftree_file = src->oftree_file;
if (src->initrd_file)
dst->initrd_file = src->initrd_file;
}
+int bootm_apply_overrides(struct image_data *data,
+ const struct bootm_overrides *overrides);
+#else
+
+static inline void bootm_merge_overrides(struct bootm_overrides *dst,
+ const struct bootm_overrides *src)
+{
+}
+
+static inline int bootm_apply_overrides(struct image_data *data,
+ const struct bootm_overrides *overrides)
+{
+ return 0;
+}
+#endif
+
#endif
diff --git a/include/bootm.h b/include/bootm.h
index da6cf7301709..1c3e06f20f47 100644
--- a/include/bootm.h
+++ b/include/bootm.h
@@ -5,6 +5,7 @@
#include <image.h>
#include <filetype.h>
#include <linux/list.h>
+#include <loadable.h>
enum bootm_verify {
BOOTM_VERIFY_NONE,
@@ -55,6 +56,7 @@ struct bootm_data {
int bootm_boot(const struct bootm_data *data);
struct image_data *bootm_boot_prep(const struct bootm_data *bootm_data);
+int bootm_open_os_compressed(struct image_data *data);
int bootm_boot_handler(struct image_data *data);
void bootm_boot_cleanup(struct image_data *data);
@@ -62,6 +64,9 @@ struct image_data {
/* simplest case. barebox has already loaded the os here */
struct resource *os_res;
+ /* Future default case: A generic loadable object */
+ struct loadable *os;
+
/* if os is an uImage this will be provided */
struct uimage_handle *os_uimage;
@@ -87,6 +92,9 @@ struct image_data {
/* if initrd is already loaded this resource will be !NULL */
struct resource *initrd_res;
+ /* Future default case: A generic loadable object */
+ struct loadable *initrd;
+
/* if initrd is an uImage this will be provided */
struct uimage_handle *initrd_uimage;
char *initrd_part;
@@ -106,6 +114,9 @@ struct image_data {
struct device_node *of_root_node;
struct resource *oftree_res;
+ /* Future default case: A generic loadable object */
+ struct loadable *oftree;
+
/*
* The first PAGE_SIZE bytes of the OS image. Can be used by the image
* handlers to analyze the OS image before actually loading the bulk of
@@ -115,6 +126,9 @@ struct image_data {
char *tee_file;
struct resource *tee_res;
+ /* Future default case: A generic loadable object */
+ struct loadable *tee;
+
/* Type of OS image, e.g. filetype_fit or the same as kernel_type */
enum filetype image_type;
/* Type of kernel image that's going to be booted */
@@ -124,6 +138,11 @@ struct image_data {
int verbose;
int force;
int dryrun;
+ struct {
+ u8 os:1;
+ u8 initrd:1;
+ u8 oftree:1;
+ } is_override;
enum bootm_efi_mode efi_boot;
};
@@ -171,7 +190,7 @@ void *bootm_get_devicetree(struct image_data *data);
const struct resource *
bootm_load_devicetree(struct image_data *data, void *fdt,
ulong load_address, ulong end_address);
-int bootm_get_os_size(struct image_data *data);
+loff_t bootm_get_os_size(struct image_data *data);
enum bootm_verify bootm_get_verify_mode(void);
void bootm_set_verify_mode(enum bootm_verify mode);
diff --git a/lib/Kconfig b/lib/Kconfig
index 3e314c05d7ee..5f5771ff2bdf 100644
--- a/lib/Kconfig
+++ b/lib/Kconfig
@@ -14,6 +14,7 @@ config LOADABLE
Provides infrastructure for lazy-loadable resources that can be
queried for metadata without loading data, and extracted to memory
on demand.
+ Used mainly by bootm for managing kernel/initrd/fdt loading.
config LOADABLE_DECOMPRESS
bool "Decompression support for loadable resources" if COMPILE_TEST
--
2.47.3
^ permalink raw reply [flat|nested] 22+ messages in thread* [PATCH 06/16] uimage: add offset parameter to uimage_load
2026-03-12 14:44 [PATCH 01/16] lib: add lazy loadable infrastructure for deferred boot component loading Ahmad Fatoum
` (3 preceding siblings ...)
2026-03-12 14:44 ` [PATCH 05/16] bootm: switch plain file names case to loadable API Ahmad Fatoum
@ 2026-03-12 14:44 ` Ahmad Fatoum
2026-03-12 14:44 ` [PATCH 07/16] bootm: uimage: switch to loadable API Ahmad Fatoum
` (10 subsequent siblings)
15 siblings, 0 replies; 22+ messages in thread
From: Ahmad Fatoum @ 2026-03-12 14:44 UTC (permalink / raw)
To: barebox; +Cc: Ahmad Fatoum
The loadable API allows users to specify an offset at which reading
should start. In preparation for wrapping the uImage loading as
loadable, extend uimage_load to allow specifying a start offset.
Signed-off-by: Ahmad Fatoum <a.fatoum@pengutronix.de>
---
common/bootm-uimage.c | 4 ++--
common/uimage.c | 39 ++++++++++++++++++++++++++++++++++-----
include/image.h | 2 +-
3 files changed, 37 insertions(+), 8 deletions(-)
diff --git a/common/bootm-uimage.c b/common/bootm-uimage.c
index b32ed5b0e95f..a1cb39d3ecd8 100644
--- a/common/bootm-uimage.c
+++ b/common/bootm-uimage.c
@@ -30,7 +30,7 @@ int bootm_load_uimage_os(struct image_data *data, unsigned long load_address)
num = uimage_part_num(data->os_part);
data->os_res = uimage_load_to_sdram(data->os_uimage,
- num, load_address);
+ num, load_address, 0);
if (!data->os_res)
return -ENOMEM;
@@ -91,7 +91,7 @@ bootm_load_uimage_initrd(struct image_data *data, unsigned long load_address)
num = uimage_part_num(data->initrd_part);
res = uimage_load_to_sdram(data->initrd_uimage,
- num, load_address);
+ num, load_address, 0);
if (!res)
return ERR_PTR(-ENOMEM);
diff --git a/common/uimage.c b/common/uimage.c
index d34205572510..510f91a26bee 100644
--- a/common/uimage.c
+++ b/common/uimage.c
@@ -338,10 +338,24 @@ EXPORT_SYMBOL(uimage_load);
static void *uimage_buf;
static size_t uimage_size;
+static size_t uimage_skip;
static struct resource *uimage_resource;
static long uimage_sdram_flush(void *buf, unsigned long len)
{
+ unsigned long skip_now = 0;
+
+ /* Skip the first uimage_skip bytes of decompressed data */
+ if (uimage_skip > 0) {
+ skip_now = min_t(unsigned long, uimage_skip, len);
+ buf += skip_now;
+ len -= skip_now;
+ uimage_skip -= skip_now;
+
+ if (len == 0)
+ return skip_now;
+ }
+
if (uimage_size + len > resource_size(uimage_resource)) {
resource_size_t start = uimage_resource->start;
resource_size_t size = resource_size(uimage_resource) + len;
@@ -362,27 +376,42 @@ static long uimage_sdram_flush(void *buf, unsigned long len)
uimage_size += len;
- return len;
+ return len + skip_now;
}
/*
* Load an uImage to a dynamically allocated sdram resource.
* the resource must be freed afterwards with release_sdram_region
+ *
+ * @handle: uImage handle
+ * @image_no: image number within the uImage
+ * @load_address: address to load the image to
+ * @offset: offset in bytes to skip from the beginning of the decompressed data
+ *
+ * Returns: SDRAM resource on success, NULL on error
*/
struct resource *uimage_load_to_sdram(struct uimage_handle *handle,
- int image_no, unsigned long load_address)
+ int image_no, unsigned long load_address, loff_t offset)
{
int ret;
- ssize_t size;
+ ssize_t total_size;
+ size_t size;
resource_size_t start = (resource_size_t)load_address;
uimage_buf = (void *)load_address;
uimage_size = 0;
+ uimage_skip = offset;
- size = uimage_get_size(handle, image_no);
- if (size < 0)
+ total_size = uimage_get_size(handle, image_no);
+ if (total_size < 0)
return NULL;
+ if (offset > total_size)
+ return NULL;
+
+ /* Allocate for the data after offset: size = total_size - offset */
+ size = total_size - offset;
+
uimage_resource = request_sdram_region("uimage",
start, size, MEMTYPE_LOADER_CODE,
MEMATTRS_RWX);
diff --git a/include/image.h b/include/image.h
index 769523d6fcaf..b37e04f54bae 100644
--- a/include/image.h
+++ b/include/image.h
@@ -304,7 +304,7 @@ int uimage_load(struct uimage_handle *handle, unsigned int image_no,
void uimage_print_contents(struct uimage_handle *handle);
ssize_t uimage_get_size(struct uimage_handle *handle, unsigned int image_no);
struct resource *uimage_load_to_sdram(struct uimage_handle *handle,
- int image_no, unsigned long load_address);
+ int image_no, unsigned long load_address, loff_t offset);
void *uimage_load_to_buf(struct uimage_handle *handle, int image_no,
size_t *size);
#define MAX_MULTI_IMAGE_COUNT 16
--
2.47.3
^ permalink raw reply [flat|nested] 22+ messages in thread* [PATCH 07/16] bootm: uimage: switch to loadable API
2026-03-12 14:44 [PATCH 01/16] lib: add lazy loadable infrastructure for deferred boot component loading Ahmad Fatoum
` (4 preceding siblings ...)
2026-03-12 14:44 ` [PATCH 06/16] uimage: add offset parameter to uimage_load Ahmad Fatoum
@ 2026-03-12 14:44 ` Ahmad Fatoum
2026-03-12 14:44 ` [PATCH 08/16] bootm: fit: switch to new " Ahmad Fatoum
` (9 subsequent siblings)
15 siblings, 0 replies; 22+ messages in thread
From: Ahmad Fatoum @ 2026-03-12 14:44 UTC (permalink / raw)
To: barebox; +Cc: Ahmad Fatoum
Optimally, common/bootm.c should not contain uImage specific code at
all. Leverage the new loadable support, so loadables for the boot
artifacts are created once and then we can remove much of the uImage
specific code that happens later in bootm.c
Signed-off-by: Ahmad Fatoum <a.fatoum@pengutronix.de>
---
common/bootm-uimage.c | 340 +++++++++++++++++++++++++++++++----------
common/bootm.c | 76 +--------
common/uimage.c | 60 +++-----
include/bootm-uimage.h | 31 +---
include/bootm.h | 3 +
include/image.h | 5 +-
6 files changed, 292 insertions(+), 223 deletions(-)
diff --git a/common/bootm-uimage.c b/common/bootm-uimage.c
index a1cb39d3ecd8..f2d8d7b22db9 100644
--- a/common/bootm-uimage.c
+++ b/common/bootm-uimage.c
@@ -11,37 +11,56 @@ static int uimage_part_num(const char *partname)
return simple_strtoul(partname, NULL, 0);
}
-/*
- * bootm_load_uimage_os() - load uImage OS to RAM
- *
- * @data: image data context
- * @load_address: The address where the OS should be loaded to
- *
- * This loads the OS to a RAM location. load_address must be a valid
- * address. If the image_data doesn't have a OS specified it's considered
- * an error.
- *
- * Return: 0 on success, negative error code otherwise
- */
-int bootm_load_uimage_os(struct image_data *data, unsigned long load_address)
+static struct loadable *loadable_from_uimage(struct uimage_handle *uimage,
+ int part_num,
+ enum loadable_type type,
+ bool exclusive);
+
+static void loadable_from_uimage_os(struct image_data *data)
{
int num;
num = uimage_part_num(data->os_part);
- data->os_res = uimage_load_to_sdram(data->os_uimage,
- num, load_address, 0);
- if (!data->os_res)
- return -ENOMEM;
-
- return 0;
+ loadable_release(&data->os);
+ data->os = loadable_from_uimage(data->os_uimage, num, LOADABLE_KERNEL, true);
}
-static int bootm_open_initrd_uimage(struct image_data *data)
+static int file_name_detect_type_is_uimage(const char *filename, const char *desc)
{
+ enum filetype type;
int ret;
- if (strcmp(data->os_file, data->initrd_file)) {
+ ret = file_name_detect_type(filename, &type);
+ if (ret < 0) {
+ pr_err("could not open %s \"%s\": %pe\n",
+ desc, filename, ERR_PTR(ret));
+ return ret;
+ }
+
+ return type == filetype_uimage;
+}
+
+static int loadable_from_uimage_initrd(struct image_data *data)
+{
+ int ret, num;
+ bool release = false;
+
+ if (streq_ptr(data->os_file, data->initrd_file)) {
+ data->initrd_uimage = data->os_uimage;
+ } else {
+ int is_uimage;
+
+ is_uimage = file_name_detect_type_is_uimage(data->initrd_file, "initrd");
+ if (is_uimage < 0)
+ return is_uimage;
+ if (!is_uimage) {
+ loadable_release(&data->initrd);
+ data->initrd = loadable_from_file(data->initrd_file,
+ LOADABLE_INITRD);
+ return PTR_ERR_OR_ZERO(data->initrd);
+ }
+
data->initrd_uimage = uimage_open(data->initrd_file);
if (!data->initrd_uimage)
return -EINVAL;
@@ -51,88 +70,62 @@ static int bootm_open_initrd_uimage(struct image_data *data)
if (ret) {
pr_err("Checking data crc failed with %pe\n",
ERR_PTR(ret));
+ uimage_close(data->initrd_uimage);
+ data->initrd_uimage = NULL;
return ret;
}
}
uimage_print_contents(data->initrd_uimage);
- } else {
- data->initrd_uimage = data->os_uimage;
- }
-
- return 0;
-}
-
-/*
- * bootm_load_uimage_initrd() - load initrd from uimage to RAM
- *
- * @data: image data context
- * @load_address: The address where the initrd should be loaded to
- *
- * This loads the initrd to a RAM location. load_address must be a valid
- * address. If the image_data doesn't have a initrd specified this function
- * still returns successful as an initrd is optional.
- *
- * Return: initrd resource on success, NULL if no initrd is present or
- * an error pointer if an error occurred.
- */
-struct resource *
-bootm_load_uimage_initrd(struct image_data *data, unsigned long load_address)
-{
- struct resource *res;
- int ret;
-
- int num;
- ret = bootm_open_initrd_uimage(data);
- if (ret) {
- pr_err("loading initrd failed with %pe\n", ERR_PTR(ret));
- return ERR_PTR(ret);
+ release = true;
}
num = uimage_part_num(data->initrd_part);
- res = uimage_load_to_sdram(data->initrd_uimage,
- num, load_address, 0);
- if (!res)
- return ERR_PTR(-ENOMEM);
+ loadable_release(&data->initrd);
+ data->initrd = loadable_from_uimage(data->initrd_uimage, num,
+ LOADABLE_INITRD, release);
- return res;
+ return 0;
}
-int bootm_open_oftree_uimage(struct image_data *data, size_t *size,
- struct fdt_header **fdt)
+static int loadable_from_uimage_oftree(struct image_data *data)
{
- enum filetype ft;
const char *oftree = data->oftree_file;
- int num = uimage_part_num(data->oftree_part);
+ int num;
struct uimage_handle *of_handle;
- int release = 0;
+ bool release = false;
- pr_info("Loading devicetree from '%s'@%d\n", oftree, num);
-
- if (!strcmp(data->os_file, oftree)) {
+ if (data->os_uimage && streq_ptr(data->os_file, oftree)) {
of_handle = data->os_uimage;
- } else if (!strcmp(data->initrd_file, oftree)) {
+ } else if (data->initrd_uimage && streq_ptr(data->initrd_file, oftree)) {
of_handle = data->initrd_uimage;
} else {
+ int is_uimage;
+
+ is_uimage = file_name_detect_type_is_uimage(data->oftree_file, "device tree");
+ if (is_uimage < 0)
+ return is_uimage;
+ if (!is_uimage) {
+ loadable_release(&data->oftree);
+ data->oftree = loadable_from_file(data->oftree_file,
+ LOADABLE_FDT);
+ return PTR_ERR_OR_ZERO(data->oftree);
+ }
+
of_handle = uimage_open(oftree);
if (!of_handle)
return -ENODEV;
uimage_print_contents(of_handle);
- release = 1;
+ release = true;
}
- *fdt = uimage_load_to_buf(of_handle, num, size);
+ num = uimage_part_num(data->oftree_part);
+ pr_info("Loading devicetree from '%s'@%d\n", oftree, num);
- if (release)
- uimage_close(of_handle);
+ data->oftree_uimage = of_handle;
- ft = file_detect_type(*fdt, *size);
- if (ft != filetype_oftree) {
- pr_err("%s is not an oftree but %s\n",
- data->oftree_file, file_type_to_string(ft));
- free(*fdt);
- return -EINVAL;
- }
+ loadable_release(&data->oftree);
+ data->oftree = loadable_from_uimage(data->oftree_uimage, num, LOADABLE_FDT, release);
return 0;
}
@@ -150,7 +143,7 @@ int bootm_open_uimage(struct image_data *data)
if (ret) {
pr_err("Checking data crc failed with %pe\n",
ERR_PTR(ret));
- return ret;
+ goto err_close;
}
}
@@ -159,18 +152,199 @@ int bootm_open_uimage(struct image_data *data)
if (IH_ARCH == IH_ARCH_INVALID || data->os_uimage->header.ih_arch != IH_ARCH) {
pr_err("Unsupported Architecture 0x%x\n",
data->os_uimage->header.ih_arch);
- return -EINVAL;
+ ret = -EINVAL;
+ goto err_close;
}
if (data->os_address == UIMAGE_SOME_ADDRESS)
data->os_address = data->os_uimage->header.ih_load;
return 0;
+
+err_close:
+ uimage_close(data->os_uimage);
+ data->os_uimage = NULL;
+ return ret;
}
-void bootm_close_uimage(struct image_data *data)
+/* === Loadable implementation for uImage === */
+
+struct uimage_loadable_priv {
+ struct uimage_handle *handle;
+ int part_num;
+ bool release_handle;
+};
+
+static int uimage_loadable_get_info(struct loadable *l, struct loadable_info *info)
{
- if (data->initrd_uimage && data->initrd_uimage != data->os_uimage)
- uimage_close(data->initrd_uimage);
- uimage_close(data->os_uimage);
+ struct uimage_loadable_priv *priv = l->priv;
+ struct uimage_handle *handle = priv->handle;
+ ssize_t size;
+
+ /* Get size from uImage header */
+ size = uimage_get_size(handle, priv->part_num);
+ if (size <= 0)
+ return size < 0 ? size : -EINVAL;
+
+ /*
+ * uimage_get_size() returns the compressed (stored) size.
+ * For compressed uImages, the decompressed size is unknown,
+ * so report LOADABLE_SIZE_UNKNOWN to let loadable_extract()
+ * fall through to the extract op which handles decompression.
+ */
+ if (handle->header.ih_comp != IH_COMP_NONE)
+ info->final_size = LOADABLE_SIZE_UNKNOWN;
+ else
+ info->final_size = size;
+
+ return 0;
+}
+
+/**
+ * uimage_loadable_extract_into_buf - load uImage data to target address
+ * @l: loadable representing uImage component
+ * @load_addr: physical address to load data to
+ * @buf_size: size of buffer at load_addr (0 = no limit check)
+ * @offset: how many bytes to skip at the start of the uncompressed input
+ * @flags: A bitmask of OR-ed LOADABLE_EXTRACT_ flags
+ *
+ * Commits the uImage component to the specified memory address. This involves:
+ * 1. Getting size information from loadable
+ * 2. Checking buffer size if buf_size > 0
+ * 3. Calling uimage_load_to_sdram() to decompress and load data
+ * 4. Returning actual bytes written
+ *
+ * The uimage_load_to_sdram() function handles decompression (if needed),
+ * memory allocation with request_sdram_region(), and copying data to the
+ * target address.
+ *
+ * Return: actual number of bytes written on success, negative errno on error
+ * -ENOSPC if buf_size is specified and too small
+ * -ENOMEM if failed to load to SDRAM
+ */
+static ssize_t uimage_loadable_extract_into_buf(struct loadable *l, void *load_addr,
+ size_t buf_size, loff_t offset,
+ unsigned flags)
+{
+ struct uimage_loadable_priv *priv = l->priv;
+ return uimage_load_into_fixed_buf(priv->handle, priv->part_num,
+ load_addr, buf_size, offset,
+ flags & LOADABLE_EXTRACT_PARTIAL);
+}
+
+static void *uimage_loadable_extract(struct loadable *l, size_t *size)
+{
+ struct uimage_loadable_priv *priv = l->priv;
+
+ return uimage_load_to_buf(priv->handle, priv->part_num, size);
+}
+
+static void uimage_loadable_release(struct loadable *l)
+{
+ struct uimage_loadable_priv *priv = l->priv;
+
+ if (priv->release_handle)
+ uimage_close(priv->handle);
+ free(priv);
+}
+
+static const struct loadable_ops uimage_loadable_ops = {
+ .get_info = uimage_loadable_get_info,
+ .extract_into_buf = uimage_loadable_extract_into_buf,
+ .extract = uimage_loadable_extract,
+ /* .mmap is implementable for uncompressed content if anyone cares enough */
+ .release = uimage_loadable_release,
+};
+
+/**
+ * loadable_from_uimage - create a loadable from uImage component
+ * @uimage: opened uImage handle
+ * @part_num: partition/part number within uImage (0 for single-part)
+ * @type: type of loadable (LOADABLE_KERNEL, LOADABLE_INITRD, etc.)
+ * @exclusive: whether the uimage will be owned (and released) by the loadable
+ *
+ * Creates a loadable structure that wraps access to a component within a
+ * uImage. For multi-part uImages, part_num selects which part to load.
+ * The loadable uses the uImage handle to access and potentially decompress
+ * data on demand during commit.
+ *
+ * The created loadable must be freed with loadable_release() when done.
+ * The uImage handle itself is managed by the caller and must remain valid
+ * until the loadable is released.
+ *
+ * Return: pointer to allocated loadable on success, ERR_PTR() on error
+ */
+static struct loadable *loadable_from_uimage(struct uimage_handle *uimage,
+ int part_num,
+ enum loadable_type type,
+ bool exclusive)
+{
+ struct loadable *l;
+ struct uimage_loadable_priv *priv;
+
+ l = xzalloc(sizeof(*l));
+ priv = xzalloc(sizeof(*priv));
+
+ priv->handle = uimage;
+ priv->release_handle = exclusive;
+ priv->part_num = part_num;
+
+ /* Create descriptive name */
+ if (part_num > 0)
+ l->name = xasprintf("uImage(%s, %d)", uimage->filename, part_num);
+ else
+ l->name = xasprintf("uImage(%s)", uimage->filename);
+
+ l->type = type;
+ l->ops = &uimage_loadable_ops;
+ l->priv = priv;
+ loadable_init(l);
+
+ return l;
+}
+
+/**
+ * bootm_collect_uimage_loadables - create loadables from opened uImage
+ * @data: image data context with opened uImage handle
+ *
+ * Creates loadable structures for boot components from opened uImage handles.
+ * This includes:
+ * * Kernel from data->os_uimage (using data->os_part for multi-part selection)
+ * * Initrd from data->initrd_files uImage if specified (opens it if needed)
+ *
+ * For initrd handling:
+ * * If initrd_files matches os_file: uses same uImage handle (multi-part)
+ * * Otherwise: opens separate uImage for initrd and verifies it
+ *
+ * Each loadable is added to data->loadables list and appropriate shortcuts
+ * (data->kernel) are set. The loadables are not yet committed to memory - that
+ * happens later during bootm_load_os/bootm_load_initrd.
+ *
+ * Note: FDT and TEE are not commonly used in uImage format and are not
+ * collected here.
+ *
+ * Requires: data->os_uimage must be already opened by bootm_open_uimage()
+ * Context: Called during boot preparation for uImage boots
+ */
+int bootm_collect_uimage_loadables(struct image_data *data)
+{
+ int ret;
+
+ /* Create kernel loadable from opened uImage */
+ if (data->os_uimage)
+ loadable_from_uimage_os(data);
+
+ if (IS_ENABLED(CONFIG_BOOTM_INITRD) && data->initrd_file) {
+ ret = loadable_from_uimage_initrd(data);
+ if (ret)
+ return ret;
+ }
+
+ if (IS_ENABLED(CONFIG_BOOTM_OFTREE_UIMAGE) && data->oftree_file) {
+ ret = loadable_from_uimage_oftree(data);
+ if (ret)
+ return ret;
+ }
+
+ return 0;
}
diff --git a/common/bootm.c b/common/bootm.c
index 74caa3b13d86..08a8fbbfdcf5 100644
--- a/common/bootm.c
+++ b/common/bootm.c
@@ -202,11 +202,6 @@ static int uimage_part_num(const char *partname)
return simple_strtoul(partname, NULL, 0);
}
-static inline bool image_is_uimage(struct image_data *data)
-{
- return IS_ENABLED(CONFIG_BOOTM_UIMAGE) && data->os_uimage;
-}
-
/**
* bootm_load_os() - load OS to RAM
* @data: image data context
@@ -244,8 +239,6 @@ const struct resource *bootm_load_os(struct image_data *data,
if (data->os_fit)
err = bootm_load_fit_os(data, load_address);
- else if (image_is_uimage(data))
- err = bootm_load_uimage_os(data, load_address);
else
err = -EINVAL;
@@ -278,9 +271,6 @@ const struct resource *
bootm_load_initrd(struct image_data *data, ulong load_address, ulong end_address)
{
struct resource *res = NULL;
- const char *initrd, *initrd_part = NULL;
- enum filetype type = filetype_unknown;
- int ret;
if (!IS_ENABLED(CONFIG_BOOTM_INITRD))
return NULL;
@@ -300,24 +290,8 @@ bootm_load_initrd(struct image_data *data, ulong load_address, ulong end_address
return res;
}
- initrd = data->initrd_file;
- if (initrd) {
- ret = file_name_detect_type(initrd, &type);
- if (ret) {
- pr_err("could not open initrd \"%s\": %pe\n",
- initrd, ERR_PTR(ret));
- return ERR_PTR(ret);
- }
- }
-
- if (type == filetype_uimage) {
- res = bootm_load_uimage_initrd(data, load_address);
- if (data->initrd_uimage->header.ih_type == IH_TYPE_MULTI)
- initrd_part = data->initrd_part;
- } else if (data->os_fit) {
+ if (data->os_fit)
res = bootm_load_fit_initrd(data, load_address);
- type = filetype_fit;
- }
if (IS_ERR_OR_NULL(res))
return res;
@@ -328,11 +302,6 @@ bootm_load_initrd(struct image_data *data, ulong load_address, ulong end_address
if (WARN_ON(res->end > end_address))
return ERR_PTR(-ENOSPC);
- pr_info("Loaded initrd from %s %s%s%s to %pa-%pa\n",
- file_type_to_string(type), initrd ?: "",
- initrd_part ? "@" : "", initrd_part ?: "",
- &res->start, &res->end);
-
data->initrd_res = res;
return data->initrd_res;
}
@@ -351,9 +320,7 @@ bootm_load_initrd(struct image_data *data, ulong load_address, ulong end_address
*/
void *bootm_get_devicetree(struct image_data *data)
{
- enum filetype type;
struct fdt_header *oftree;
- int ret;
if (!IS_ENABLED(CONFIG_OFTREE))
return ERR_PTR(-ENOSYS);
@@ -380,37 +347,6 @@ void *bootm_get_devicetree(struct image_data *data)
} else if (bootm_fit_has_fdt(data)) {
data->of_root_node = bootm_get_fit_devicetree(data);
- } else if (data->oftree_file) {
- size_t size;
-
- /* TODO: There's some duplication here, but that will go away
- * once we switch this over to the loadable API
- */
-
- ret = file_name_detect_type(data->oftree_file, &type);
- if (ret) {
- pr_err("could not open device tree \"%s\": %pe\n", data->oftree_file,
- ERR_PTR(ret));
- return ERR_PTR(ret);
- }
-
- if (type != filetype_uimage)
- return ERR_PTR(-EINVAL);
-
- ret = bootm_open_oftree_uimage(data, &size, &oftree);
- if (ret)
- return ERR_PTR(ret);
-
- data->of_root_node = of_unflatten_dtb(oftree, size);
-
- free(oftree);
-
- if (IS_ERR(data->of_root_node)) {
- data->of_root_node = NULL;
- pr_err("unable to unflatten devicetree\n");
- return ERR_PTR(-EINVAL);
- }
-
} else {
data->of_root_node = of_dup_root_node_for_boot();
if (!data->of_root_node)
@@ -487,8 +423,6 @@ loff_t bootm_get_os_size(struct image_data *data)
if (data->os)
return loadable_get_size(data->os, &size) ?: size;
- if (image_is_uimage(data))
- return uimage_get_size(data->os_uimage, uimage_part_num(data->os_part));
if (data->os_fit)
return data->fit_kernel_size;
@@ -701,6 +635,12 @@ struct image_data *bootm_boot_prep(const struct bootm_data *bootm_data)
goto err_out;
}
+ if (IS_ENABLED(CONFIG_BOOTM_UIMAGE)) {
+ ret = bootm_collect_uimage_loadables(data);
+ if (ret)
+ goto err_out;
+ }
+
if (bootm_data->appendroot) {
const char *root = NULL;
const char *rootopts = NULL;
@@ -862,8 +802,6 @@ void bootm_boot_cleanup(struct image_data *data)
release_sdram_region(data->initrd_res);
release_sdram_region(data->oftree_res);
release_sdram_region(data->tee_res);
- if (image_is_uimage(data))
- bootm_close_uimage(data);
if (data->os_fit)
bootm_close_fit(data);
loadable_release(&data->oftree);
diff --git a/common/uimage.c b/common/uimage.c
index 510f91a26bee..cfa9d600c144 100644
--- a/common/uimage.c
+++ b/common/uimage.c
@@ -339,7 +339,8 @@ EXPORT_SYMBOL(uimage_load);
static void *uimage_buf;
static size_t uimage_size;
static size_t uimage_skip;
-static struct resource *uimage_resource;
+static size_t uimage_maxsize;
+static bool uimage_extract_partial;
static long uimage_sdram_flush(void *buf, unsigned long len)
{
@@ -356,18 +357,14 @@ static long uimage_sdram_flush(void *buf, unsigned long len)
return skip_now;
}
- if (uimage_size + len > resource_size(uimage_resource)) {
- resource_size_t start = uimage_resource->start;
- resource_size_t size = resource_size(uimage_resource) + len;
+ if (!uimage_extract_partial && uimage_size + len > uimage_maxsize)
+ return -ENOSPC;
- release_sdram_region(uimage_resource);
+ /* Buffer full: discard excess data in partial mode */
+ if (uimage_size >= uimage_maxsize)
+ return len + skip_now;
- uimage_resource = request_sdram_region("uimage",
- start, size, MEMTYPE_LOADER_CODE,
- MEMATTRS_RWX);
- if (!uimage_resource)
- return -ENOMEM;
- }
+ len = min_t(unsigned long, len, uimage_maxsize - uimage_size);
if (zero_page_contains((unsigned long)uimage_buf + uimage_size))
zero_page_memcpy(uimage_buf + uimage_size, buf, len);
@@ -380,53 +377,34 @@ static long uimage_sdram_flush(void *buf, unsigned long len)
}
/*
- * Load an uImage to a dynamically allocated sdram resource.
- * the resource must be freed afterwards with release_sdram_region
+ * Load an uImage to a fixed buffer
*
* @handle: uImage handle
* @image_no: image number within the uImage
* @load_address: address to load the image to
* @offset: offset in bytes to skip from the beginning of the decompressed data
*
- * Returns: SDRAM resource on success, NULL on error
+ * Return: number of bytes written on success or negative error code
*/
-struct resource *uimage_load_to_sdram(struct uimage_handle *handle,
- int image_no, unsigned long load_address, loff_t offset)
+int uimage_load_into_fixed_buf(struct uimage_handle *handle, int image_no,
+ void *load_address, size_t size,
+ loff_t offset, bool partial)
{
int ret;
- ssize_t total_size;
- size_t size;
- resource_size_t start = (resource_size_t)load_address;
uimage_buf = (void *)load_address;
+ uimage_maxsize = size;
uimage_size = 0;
uimage_skip = offset;
-
- total_size = uimage_get_size(handle, image_no);
- if (total_size < 0)
- return NULL;
-
- if (offset > total_size)
- return NULL;
-
- /* Allocate for the data after offset: size = total_size - offset */
- size = total_size - offset;
-
- uimage_resource = request_sdram_region("uimage",
- start, size, MEMTYPE_LOADER_CODE,
- MEMATTRS_RWX);
- if (!uimage_resource)
- return NULL;
+ uimage_extract_partial = partial;
ret = uimage_load(handle, image_no, uimage_sdram_flush);
- if (ret) {
- release_sdram_region(uimage_resource);
- return NULL;
- }
+ if (ret)
+ return ret;
- return uimage_resource;
+ return uimage_size;
}
-EXPORT_SYMBOL(uimage_load_to_sdram);
+EXPORT_SYMBOL(uimage_load_into_fixed_buf);
void *uimage_load_to_buf(struct uimage_handle *handle, int image_no,
size_t *outsize)
diff --git a/include/bootm-uimage.h b/include/bootm-uimage.h
index aac2beb35e2a..1676f4fc60cf 100644
--- a/include/bootm-uimage.h
+++ b/include/bootm-uimage.h
@@ -11,45 +11,20 @@ struct resource;
#ifdef CONFIG_BOOTM_UIMAGE
-int bootm_load_uimage_os(struct image_data *data, unsigned long load_address);
-
-struct resource *bootm_load_uimage_initrd(struct image_data *data,
- unsigned long load_address);
-
-int bootm_open_oftree_uimage(struct image_data *data, size_t *size,
- struct fdt_header **fdt);
int bootm_open_uimage(struct image_data *data);
-void bootm_close_uimage(struct image_data *data);
+int bootm_collect_uimage_loadables(struct image_data *data);
#else
-static inline int bootm_load_uimage_os(struct image_data *data,
- unsigned long load_address)
-{
- return -ENOSYS;
-}
-
-static inline struct resource *
-bootm_load_uimage_initrd(struct image_data *data, unsigned long load_address)
-{
- return ERR_PTR(-ENOSYS);
-}
-
-static inline int bootm_open_oftree_uimage(struct image_data *data,
- size_t *size,
- struct fdt_header **fdt)
-{
- return -ENOSYS;
-}
-
static inline int bootm_open_uimage(struct image_data *data)
{
return -ENOSYS;
}
-static inline void bootm_close_uimage(struct image_data *data)
+static inline int bootm_collect_uimage_loadables(struct image_data *data)
{
+ return 0;
}
#endif
diff --git a/include/bootm.h b/include/bootm.h
index 1c3e06f20f47..3ba8402217e3 100644
--- a/include/bootm.h
+++ b/include/bootm.h
@@ -107,6 +107,9 @@ struct image_data {
char *oftree_file;
char *oftree_part;
+ /* if oftree is an uImage this will be provided */
+ struct uimage_handle *oftree_uimage;
+
const void *fit_kernel;
unsigned long fit_kernel_size;
void *fit_config;
diff --git a/include/image.h b/include/image.h
index b37e04f54bae..fa751de74108 100644
--- a/include/image.h
+++ b/include/image.h
@@ -303,8 +303,9 @@ int uimage_load(struct uimage_handle *handle, unsigned int image_no,
long(*flush)(void*, unsigned long));
void uimage_print_contents(struct uimage_handle *handle);
ssize_t uimage_get_size(struct uimage_handle *handle, unsigned int image_no);
-struct resource *uimage_load_to_sdram(struct uimage_handle *handle,
- int image_no, unsigned long load_address, loff_t offset);
+int uimage_load_into_fixed_buf(struct uimage_handle *handle, int image_no,
+ void *load_address, size_t size, loff_t offset,
+ bool partial);
void *uimage_load_to_buf(struct uimage_handle *handle, int image_no,
size_t *size);
#define MAX_MULTI_IMAGE_COUNT 16
--
2.47.3
^ permalink raw reply [flat|nested] 22+ messages in thread* [PATCH 08/16] bootm: fit: switch to new loadable API
2026-03-12 14:44 [PATCH 01/16] lib: add lazy loadable infrastructure for deferred boot component loading Ahmad Fatoum
` (5 preceding siblings ...)
2026-03-12 14:44 ` [PATCH 07/16] bootm: uimage: switch to loadable API Ahmad Fatoum
@ 2026-03-12 14:44 ` Ahmad Fatoum
2026-03-12 14:44 ` [PATCH 09/16] bootm: stash initial OS address/entry in image_data Ahmad Fatoum
` (8 subsequent siblings)
15 siblings, 0 replies; 22+ messages in thread
From: Ahmad Fatoum @ 2026-03-12 14:44 UTC (permalink / raw)
To: barebox; +Cc: Ahmad Fatoum
The new loadable API allows us to remove FIT specific code from
common/bootm.c as can be seen by this commit having a break-even
diff line count.
The work is not over yet though: A lot of architecture specific bootm
handlers access os_file directly and they would need to be adapted to
use loadables, but that's for another day..
Signed-off-by: Ahmad Fatoum <a.fatoum@pengutronix.de>
---
arch/arm/lib32/bootm.c | 42 +----
arch/kvx/lib/bootm.c | 25 ++-
common/bootm-fit.c | 370 +++++++++++++++++++++++++++++----------
common/bootm-overrides.c | 25 +--
common/bootm.c | 75 ++------
common/image-fit.c | 6 +
efi/payload/bootm.c | 164 +++++------------
include/bootm-fit.h | 50 +-----
include/bootm.h | 13 +-
include/image-fit.h | 8 +
10 files changed, 389 insertions(+), 389 deletions(-)
diff --git a/arch/arm/lib32/bootm.c b/arch/arm/lib32/bootm.c
index 7ad2a26fdc2f..4bca29c3fbf8 100644
--- a/arch/arm/lib32/bootm.c
+++ b/arch/arm/lib32/bootm.c
@@ -22,7 +22,6 @@
#include <restart.h>
#include <globalvar.h>
#include <tee/optee.h>
-#include <image-fit.h>
#include <asm/byteorder.h>
#include <asm/setup.h>
#include <asm/barebox-arm.h>
@@ -168,32 +167,6 @@ static int optee_verify_header_request_region(struct image_data *data, struct op
return 0;
}
-static int bootm_load_tee_from_fit(struct image_data *data)
-{
- int ret = 0;
- struct optee_header hdr;
-
- if (data->os_fit &&
- fit_has_image(data->os_fit, data->fit_config, "tee")) {
- const void *tee;
- unsigned long tee_size;
-
- ret = fit_open_image(data->os_fit, data->fit_config, "tee", 0,
- &tee, &tee_size);
- if (ret) {
- pr_err("Error opening tee fit image: %pe\n", ERR_PTR(ret));
- return ret;
- }
- memcpy(&hdr, tee, sizeof(hdr));
- ret = optee_verify_header_request_region(data, &hdr);
- if (ret < 0)
- goto out;
- memcpy((void *)data->tee_res->start, tee + sizeof(hdr), hdr.init_size);
- printf("Read optee image to %pa, size 0x%08x\n", (void *)data->tee_res->start, hdr.init_size);
- }
-out:
- return ret;
-}
static int bootm_load_tee(struct image_data *data)
{
int ret;
@@ -287,15 +260,9 @@ static int __do_bootm_linux(struct image_data *data, unsigned long free_mem,
}
if (IS_ENABLED(CONFIG_BOOTM_OPTEE)) {
- if (data->tee_file && !bootm_signed_images_are_forced()) {
- ret = bootm_load_tee(data);
- if (ret)
- return ret;
- } else if (IS_ENABLED(CONFIG_FITIMAGE)) {
- ret = bootm_load_tee_from_fit(data);
- if (ret)
- return ret;
- }
+ ret = bootm_load_tee(data);
+ if (ret)
+ return ret;
}
@@ -459,7 +426,8 @@ static int do_bootz_linux(struct image_data *data)
unsigned long mem_free;
void *fdt = NULL;
- if (data->os_fit)
+ /* FIXME: whole function should be switched to loadables */
+ if (data->image_type == filetype_fit)
return do_bootm_linux(data);
fd = open(data->os_file, O_RDONLY);
diff --git a/arch/kvx/lib/bootm.c b/arch/kvx/lib/bootm.c
index c464b5006fa2..1bd457f2e7d4 100644
--- a/arch/kvx/lib/bootm.c
+++ b/arch/kvx/lib/bootm.c
@@ -119,20 +119,33 @@ static int do_boot_elf(struct image_data *data, struct elf_image *elf)
static int do_bootm_elf(struct image_data *data)
{
struct elf_image *elf;
+ const void *view = NULL;
+ size_t size;
int ret;
- if (data->fit_kernel)
- elf = elf_open_binary((void *) data->fit_kernel);
- else
- elf = elf_open(data->os_file);
+ /* FIXME: whole function should be switched to loadables */
+ if (data->image_type == filetype_fit) {
+ view = loadable_view(data->os, &size) ?: ERR_PTR(-ENODATA);
+ if (IS_ERR(view))
+ return PTR_ERR(view);
- if (IS_ERR(elf))
- return PTR_ERR(elf);
+ elf = elf_open_binary((void *)view);
+ } else {
+ elf = elf_open(data->os_file);
+ }
+
+ if (IS_ERR(elf)) {
+ ret = PTR_ERR(elf);
+ goto out_view_free;
+ }
ret = do_boot_elf(data, elf);
elf_close(elf);
+out_view_free:
+ loadable_view_free(data->os, view, size);
+
return ret;
}
diff --git a/common/bootm-fit.c b/common/bootm-fit.c
index 70d6ba8edff2..089f376fd7f1 100644
--- a/common/bootm-fit.c
+++ b/common/bootm-fit.c
@@ -6,103 +6,103 @@
#include <memory.h>
#include <zero_page.h>
#include <filetype.h>
+#include <fs.h>
+
+static struct loadable *loadable_from_fit(struct fit_handle *fit,
+ void *config,
+ const char *image_name,
+ int index,
+ enum loadable_type type);
/*
- * bootm_load_fit_os() - load OS from FIT to RAM
- *
+ * loadable_from_fit_os() - create OS loadable from FIT
* @data: image data context
- * @load_address: The address where the OS should be loaded to
+ * @fit: handle of FIT image
+ * @config: config to look up kernel in
*
- * This loads the OS to a RAM location. load_address must be a valid
- * address. If the image_data doesn't have a OS specified it's considered
- * an error.
- *
- * Return: 0 on success, negative error code otherwise
+ * This creates a loadable for the OS.
*/
-int bootm_load_fit_os(struct image_data *data, unsigned long load_address)
+static void loadable_from_fit_os(struct image_data *data,
+ struct fit_handle *fit,
+ void *config)
{
- const void *kernel = data->fit_kernel;
- unsigned long kernel_size = data->fit_kernel_size;
-
- data->os_res = request_sdram_region("kernel",
- load_address, kernel_size,
- MEMTYPE_LOADER_CODE, MEMATTRS_RWX);
- if (!data->os_res)
- return -ENOMEM;
-
- zero_page_memcpy((void *)load_address, kernel, kernel_size);
- return 0;
-}
-
-static bool fitconfig_has_ramdisk(struct image_data *data)
-{
- return fit_has_image(data->os_fit, data->fit_config, "ramdisk");
+ loadable_release(&data->os);
+ data->os = loadable_from_fit(fit, config, "kernel", 0, LOADABLE_KERNEL);
}
/*
- * bootm_load_fit_initrd() - load initrd from FIT to RAM
- *
+ * loadable_from_fit_initrd() - create initrd loadable from FIT
* @data: image data context
- * @load_address: The address where the initrd should be loaded to
+ * @fit: handle of FIT image
+ * @config: config to look up kernel in
*
- * This loads the initrd to a RAM location. load_address must be a valid
- * address. If the image_data doesn't have a initrd specified this function
- * still returns successful as an initrd is optional.
+ * This creates a loadable for the first initial ram disk in the config.
*
- * Return: initrd resource on success, NULL if no initrd is present or
- * an error pointer if an error occurred.
+ * Return: true if initrd booting is supported and a ramdisk exists or
+ * false otherwise.
*/
-struct resource *bootm_load_fit_initrd(struct image_data *data, unsigned long load_address)
+static bool loadable_from_fit_initrd(struct image_data *data,
+ struct fit_handle *fit,
+ void *config)
{
- struct resource *res;
- const void *initrd;
- unsigned long initrd_size;
- int ret;
+ if (!IS_ENABLED(CONFIG_BOOTM_INITRD))
+ return false;
- if (!fitconfig_has_ramdisk(data))
- return NULL;
+ if (!fit_has_image(fit, config, "ramdisk"))
+ return false;
- ret = fit_open_image(data->os_fit, data->fit_config, "ramdisk", 0,
- &initrd, &initrd_size);
- if (ret) {
- pr_err("Cannot open ramdisk image in FIT image: %pe\n",
- ERR_PTR(ret));
- return ERR_PTR(ret);
- }
- res = request_sdram_region("initrd",
- load_address, initrd_size,
- MEMTYPE_LOADER_DATA, MEMATTRS_RW);
- if (!res)
- return ERR_PTR(-ENOMEM);
+ loadable_release(&data->initrd);
- memcpy((void *)load_address, initrd, initrd_size);
- return res;
+ data->initrd = loadable_from_fit(fit, config, "ramdisk", 0, LOADABLE_INITRD);
+
+ return true;
}
/*
- * bootm_get_fit_devicetree() - get devicetree
- *
+ * loadable_from_fit_oftree() - create devicetree loadable from FIT
* @data: image data context
+ * @fit: handle of FIT image
+ * @config: config to look up kernel in
*
- * This gets the fixed devicetree from the various image sources or the internal
- * devicetree. It returns a pointer to the allocated devicetree which must be
- * freed after use.
+ * This creates a loadable for the first fdt in the config.
*
- * Return: pointer to the fixed devicetree, NULL if image_data has an empty DT
- * or a ERR_PTR() on failure.
+ * Return: true if a FDT exists or
+ * false otherwise.
*/
-void *bootm_get_fit_devicetree(struct image_data *data)
+static bool loadable_from_fit_oftree(struct image_data *data,
+ struct fit_handle *fit,
+ void *config)
{
- int ret;
- const void *of_tree;
- unsigned long of_size;
+ if (!fit_has_image(fit, config, "fdt"))
+ return false;
- ret = fit_open_image(data->os_fit, data->fit_config, "fdt", 0,
- &of_tree, &of_size);
- if (ret)
- return ERR_PTR(ret);
+ loadable_release(&data->oftree);
+ data->oftree = loadable_from_fit(fit, config, "fdt", 0, LOADABLE_FDT);
+ return true;
+}
- return of_unflatten_dtb(of_tree, of_size);
+/*
+ * loadable_from_fit_tee() - create tee loadable from FIT
+ * @data: image data context
+ * @fit: handle of FIT image
+ * @config: config to look up kernel in
+ *
+ * This creates a loadable for the first trusted execution environment
+ * in the config.
+ *
+ * Return: true if a TEE exists or
+ * false otherwise.
+ */
+static bool loadable_from_fit_tee(struct image_data *data,
+ struct fit_handle *fit,
+ void *config)
+{
+ if (!fit_has_image(fit, config, "tee"))
+ return false;
+
+ loadable_release(&data->tee);
+ data->tee = loadable_from_fit(fit, config, "tee", 0, LOADABLE_TEE);
+ return true;
}
static bool bootm_fit_config_valid(struct fit_handle *fit,
@@ -117,19 +117,31 @@ static bool bootm_fit_config_valid(struct fit_handle *fit,
static enum filetype bootm_fit_update_os_header(struct image_data *data)
{
- if (data->fit_kernel_size < PAGE_SIZE)
+ size_t size;
+ const void *header;
+ enum filetype os_type;
+
+ header = loadable_view(data->os, &size);
+ if (IS_ERR(header))
return filetype_unknown;
- free(data->os_header);
- data->os_header = xmemdup(data->fit_kernel, PAGE_SIZE);
+ if (size >= PAGE_SIZE)
+ os_type = file_detect_type(header, size);
+ else
+ os_type = filetype_unknown;
- return file_detect_type(data->os_header, PAGE_SIZE);
+ free(data->os_header);
+ data->os_header = xmemdup(header, min_t(size_t, size, PAGE_SIZE));
+
+ loadable_view_free(data->os, header, size);
+
+ return os_type;
}
int bootm_open_fit(struct image_data *data)
{
struct fit_handle *fit;
- static const char *kernel_img = "kernel";
+ void *fit_config;
int ret;
fit = fit_open(data->os_file, data->verbose, data->verify);
@@ -138,47 +150,215 @@ int bootm_open_fit(struct image_data *data)
return PTR_ERR(fit);
}
- data->os_fit = fit;
-
- data->fit_config = fit_open_configuration(data->os_fit,
- data->os_part,
- bootm_fit_config_valid);
- if (IS_ERR(data->fit_config)) {
+ fit_config = fit_open_configuration(fit, data->os_part, bootm_fit_config_valid);
+ if (IS_ERR(fit_config)) {
pr_err("Cannot open FIT image configuration '%s'\n",
- data->os_part ? data->os_part : "default");
- return PTR_ERR(data->fit_config);
+ data->os_part ?: "default");
+ ret = PTR_ERR(fit_config);
+ goto err;
}
- ret = fit_open_image(data->os_fit, data->fit_config, kernel_img, 0,
- &data->fit_kernel, &data->fit_kernel_size);
- if (ret)
- return ret;
+ loadable_from_fit_os(data, fit, fit_config);
+ loadable_from_fit_initrd(data, fit, fit_config);
+ loadable_from_fit_oftree(data, fit, fit_config);
+ loadable_from_fit_tee(data, fit, fit_config);
data->kernel_type = bootm_fit_update_os_header(data);
if (data->os_address == UIMAGE_SOME_ADDRESS) {
- ret = fit_get_image_address(data->os_fit,
- data->fit_config,
- kernel_img,
+ ret = fit_get_image_address(fit, fit_config, "kernel",
"load", &data->os_address);
if (!ret)
pr_info("Load address from FIT '%s': 0x%lx\n",
- kernel_img, data->os_address);
+ "kernel", data->os_address);
/* Note: Error case uses default value. */
}
if (data->os_entry == UIMAGE_SOME_ADDRESS) {
unsigned long entry;
- ret = fit_get_image_address(data->os_fit,
- data->fit_config,
- kernel_img,
+ ret = fit_get_image_address(fit, fit_config, "kernel",
"entry", &entry);
if (!ret) {
data->os_entry = entry - data->os_address;
pr_info("Entry address from FIT '%s': 0x%lx\n",
- kernel_img, entry);
+ "kernel", entry);
}
/* Note: Error case uses default value. */
}
+ /* Each loadable now holds a reference to the FIT, so close our original
+ * reference, so the FIT is completely reclaimed if bootm fails.
+ */
+ fit_close(fit);
+
+ return 0;
+err:
+ fit_close(fit);
+ return ret;
+}
+
+/* === Loadable implementation for FIT images === */
+
+struct fit_loadable_priv {
+ struct fit_handle *fit;
+ struct device_node *config;
+ const char *image_name;
+ int index;
+};
+
+static int fit_loadable_get_info(struct loadable *l, struct loadable_info *info)
+{
+ struct fit_loadable_priv *priv = l->priv;
+ const void *data;
+ unsigned long size;
+ int ret;
+
+ /* Open image to get size */
+ ret = fit_open_image(priv->fit, priv->config, priv->image_name,
+ priv->index, &data, &size);
+ if (ret)
+ return ret;
+
+ /* TODO: This will trigger an uncompression currently.. */
+ info->final_size = size;
+
return 0;
}
+
+static const void *fit_loadable_mmap(struct loadable *l, size_t *size)
+{
+ struct fit_loadable_priv *priv = l->priv;
+ const void *data;
+ unsigned long image_size;
+ int ret;
+
+ ret = fit_open_image(priv->fit, priv->config, priv->image_name,
+ priv->index, &data, &image_size);
+ if (ret)
+ return MAP_FAILED;
+
+ *size = image_size;
+ return data;
+}
+
+/**
+ * fit_loadable_extract_into_buf - load FIT image data to target address
+ * @l: loadable representing FIT image component
+ * @load_addr: physical address to load data to
+ * @buf_size: size of buffer at load_addr (0 = no limit check)
+ * @offset: how many bytes to skip at the start of the uncompressed input
+ * @flags: A bitmask of OR-ed LOADABLE_EXTRACT_ flags
+ *
+ * Commits the FIT image component to the specified memory address. This
+ * involves:
+ * 1. Opening the FIT image to get decompressed data
+ * 2. Checking buffer size
+ * 3. Copying data to target address
+ *
+ * The FIT data is already decompressed by fit_open_image(), so this just
+ * performs a memcpy to the target address.
+ *
+ * Return: actual number of bytes written on success, negative errno on error
+ * -ENOSPC if buf_size is specified and too small
+ * -ENOMEM if failed to register SDRAM region
+ */
+static ssize_t fit_loadable_extract_into_buf(struct loadable *l, void *load_addr,
+ size_t buf_size, loff_t offset,
+ unsigned flags)
+{
+ struct fit_loadable_priv *priv = l->priv;
+ const void *data;
+ unsigned long size;
+ int ret;
+
+ /* TODO: optimize, so it decompresses directly to load address */
+
+ /* Open image to get data */
+ ret = fit_open_image(priv->fit, priv->config, priv->image_name,
+ priv->index, &data, &size);
+ if (ret)
+ return ret;
+
+ /* Check if buffer is large enough */
+ if (offset > size)
+ return 0;
+
+ if (!(flags & LOADABLE_EXTRACT_PARTIAL) && buf_size < size - offset)
+ return -ENOSPC;
+
+ size = min_t(size_t, size - offset, buf_size);
+
+ if (unlikely(zero_page_contains((ulong)load_addr)))
+ zero_page_memcpy(load_addr, data + offset, size);
+ else
+ memcpy(load_addr, data + offset, size);
+
+ return size; /* Return actual bytes written */
+}
+
+static void fit_loadable_release(struct loadable *l)
+{
+ struct fit_loadable_priv *priv = l->priv;
+
+ fit_close(priv->fit);
+ free_const(priv->image_name);
+ free(priv);
+}
+
+static const struct loadable_ops fit_loadable_ops = {
+ .get_info = fit_loadable_get_info,
+ .extract_into_buf = fit_loadable_extract_into_buf,
+ .mmap = fit_loadable_mmap,
+ .release = fit_loadable_release,
+};
+
+/**
+ * loadable_from_fit - create a loadable from FIT image component
+ * @fit: opened FIT image handle
+ * @config: FIT configuration device node
+ * @image_name: name of image in FIT (e.g., "kernel", "ramdisk", "fdt")
+ * @index: index for multi-image types (e.g., ramdisk-0, ramdisk-1)
+ * @type: type of loadable (LOADABLE_KERNEL, LOADABLE_INITRD, etc.)
+ *
+ * Creates a loadable structure that wraps access to a component within a
+ * FIT image. The loadable uses the FIT handle to access decompressed image
+ * data on demand during commit.
+ *
+ * The created loadable must be freed with loadable_release() when done.
+ * The FIT handle itself is managed by the caller and must remain valid
+ * until the loadable is released.
+ *
+ * Return: pointer to allocated loadable on success. Function never fails.
+ */
+static struct loadable *loadable_from_fit(struct fit_handle *fit,
+ void *config,
+ const char *image_name,
+ int index,
+ enum loadable_type type)
+{
+ struct loadable *l;
+ struct fit_loadable_priv *priv;
+
+ l = xzalloc(sizeof(*l));
+ priv = xzalloc(sizeof(*priv));
+
+ priv->fit = fit_open_handle(fit);
+ priv->config = config;
+ priv->image_name = xstrdup_const(image_name);
+ priv->index = index;
+
+ /* Create descriptive name */
+ if (index)
+ l->name = xasprintf("FIT(%s, %s/%s, %d)", fit->filename,
+ fit_config_get_name(fit, config),
+ image_name, index);
+ else
+ l->name = xasprintf("FIT(%s, %s/%s)", fit->filename,
+ fit_config_get_name(fit, config),
+ image_name);
+ l->ops = &fit_loadable_ops;
+ l->type = type;
+ l->priv = priv;
+ loadable_init(l);
+
+ return l;
+}
diff --git a/common/bootm-overrides.c b/common/bootm-overrides.c
index e1cba21e7711..c1f3ee7cade8 100644
--- a/common/bootm-overrides.c
+++ b/common/bootm-overrides.c
@@ -20,23 +20,16 @@ int bootm_apply_overrides(struct image_data *data,
if (bootm_signed_images_are_forced())
return 0;
- /* TODO: As we haven't switched over everything to loadables yet,
- * we need a special marker to mean override to empty.
- * We do this via a 0-byte file (/dev/null) for now..
- */
-
if (overrides->initrd_file) {
loadable_release(&data->initrd);
/* Empty string means to mask the original initrd */
- if (nonempty(overrides->initrd_file))
+ if (nonempty(overrides->initrd_file)) {
data->initrd = loadable_from_file(overrides->initrd_file,
LOADABLE_INITRD);
- else
- data->initrd = loadable_from_file("/dev/null",
- LOADABLE_INITRD);
- if (IS_ERR(data->initrd))
- return PTR_ERR(data->initrd);
+ if (IS_ERR(data->initrd))
+ return PTR_ERR(data->initrd);
+ }
data->is_override.initrd = true;
}
@@ -44,14 +37,12 @@ int bootm_apply_overrides(struct image_data *data,
loadable_release(&data->oftree);
/* Empty string means to mask the original FDT */
- if (nonempty(overrides->oftree_file))
+ if (nonempty(overrides->oftree_file)) {
data->oftree = loadable_from_file(overrides->oftree_file,
LOADABLE_FDT);
- else
- data->oftree = loadable_from_file("/dev/null",
- LOADABLE_FDT);
- if (IS_ERR(data->oftree))
- return PTR_ERR(data->oftree);
+ if (IS_ERR(data->oftree))
+ return PTR_ERR(data->oftree);
+ }
data->is_override.oftree = true;
}
diff --git a/common/bootm.c b/common/bootm.c
index 08a8fbbfdcf5..01d569dd37d4 100644
--- a/common/bootm.c
+++ b/common/bootm.c
@@ -11,7 +11,6 @@
#include <block.h>
#include <libfile.h>
#include <bootm-fit.h>
-#include <image-fit.h>
#include <bootm-uimage.h>
#include <globalvar.h>
#include <init.h>
@@ -218,40 +217,19 @@ const struct resource *bootm_load_os(struct image_data *data,
ulong load_address, ulong end_address)
{
struct resource *res;
- int err;
if (data->os_res)
return data->os_res;
- if (load_address == UIMAGE_INVALID_ADDRESS)
- return ERR_PTR(-EINVAL);
- if (end_address <= load_address)
+ if (load_address == UIMAGE_INVALID_ADDRESS ||
+ end_address <= load_address || !data->os)
return ERR_PTR(-EINVAL);
- if (data->os) {
- res = loadable_extract_into_sdram_all(data->os, load_address, end_address);
- if (!IS_ERR(res))
- data->os_res = res;
- return res;
- }
+ res = loadable_extract_into_sdram_all(data->os, load_address, end_address);
+ if (!IS_ERR(res))
+ data->os_res = res;
- /* TODO: eliminate below special cases */
-
- if (data->os_fit)
- err = bootm_load_fit_os(data, load_address);
- else
- err = -EINVAL;
-
- if (err)
- return ERR_PTR(err);
-
- /* FIXME: We need some more rework to be able to detect this overflow
- * before it happens, but for now, let's at least detect it.
- */
- if (WARN_ON(data->os_res->end > end_address))
- return ERR_PTR(-ENOSPC);
-
- return data->os_res;
+ return res;
}
/**
@@ -280,30 +258,17 @@ bootm_load_initrd(struct image_data *data, ulong load_address, ulong end_address
*/
if (WARN_ON(data->initrd_res))
return data->initrd_res;
+
+ if (!data->initrd)
+ return NULL;
+
if (end_address <= load_address)
return ERR_PTR(-EINVAL);
- if (data->initrd) {
- res = loadable_extract_into_sdram_all(data->initrd, load_address, end_address);
- if (!IS_ERR(res))
- data->initrd_res = res;
- return res;
- }
-
- if (data->os_fit)
- res = bootm_load_fit_initrd(data, load_address);
-
- if (IS_ERR_OR_NULL(res))
- return res;
-
- /* FIXME: We need some more rework to be able to detect this overflow
- * before it happens, but for now, let's at least detect it.
- */
- if (WARN_ON(res->end > end_address))
- return ERR_PTR(-ENOSPC);
-
- data->initrd_res = res;
- return data->initrd_res;
+ res = loadable_extract_into_sdram_all(data->initrd, load_address, end_address);
+ if (!IS_ERR(res))
+ data->initrd_res = res;
+ return res;
}
/*
@@ -345,8 +310,6 @@ void *bootm_get_devicetree(struct image_data *data)
return ERR_PTR(-EINVAL);
}
- } else if (bootm_fit_has_fdt(data)) {
- data->of_root_node = bootm_get_fit_devicetree(data);
} else {
data->of_root_node = of_dup_root_node_for_boot();
if (!data->of_root_node)
@@ -421,12 +384,10 @@ loff_t bootm_get_os_size(struct image_data *data)
{
loff_t size;
- if (data->os)
- return loadable_get_size(data->os, &size) ?: size;
- if (data->os_fit)
- return data->fit_kernel_size;
+ if (!data->os)
+ return -EINVAL;
- return -EINVAL;
+ return loadable_get_size(data->os, &size) ?: size;
}
static void bootm_print_info(struct image_data *data)
@@ -802,8 +763,6 @@ void bootm_boot_cleanup(struct image_data *data)
release_sdram_region(data->initrd_res);
release_sdram_region(data->oftree_res);
release_sdram_region(data->tee_res);
- if (data->os_fit)
- bootm_close_fit(data);
loadable_release(&data->oftree);
loadable_release(&data->initrd);
loadable_release(&data->os);
diff --git a/common/image-fit.c b/common/image-fit.c
index 27e5ec9062c5..40aeee42cd09 100644
--- a/common/image-fit.c
+++ b/common/image-fit.c
@@ -917,6 +917,12 @@ void *fit_open_configuration(struct fit_handle *handle, const char *name,
return conf_node;
}
+const char *fit_config_get_name(struct fit_handle *handle, void *config)
+{
+ struct device_node *node = config;
+ return node->name;
+}
+
static struct fit_handle *fit_get_handle(const char *filename)
{
struct fit_handle *handle;
diff --git a/efi/payload/bootm.c b/efi/payload/bootm.c
index aba643b2c59d..b8e555dab5fa 100644
--- a/efi/payload/bootm.c
+++ b/efi/payload/bootm.c
@@ -27,7 +27,6 @@
#include <libfile.h>
#include <binfmt.h>
#include <wchar.h>
-#include <image-fit.h>
#include <efi/payload.h>
#include <efi/payload/driver.h>
#include <efi/error.h>
@@ -35,73 +34,26 @@
#include "image.h"
-static bool ramdisk_is_fit(struct image_data *data)
-{
- struct stat st;
-
- if (!IS_ENABLED(CONFIG_BOOTM_FITIMAGE))
- return false;
-
- if (bootm_signed_images_are_forced())
- return true;
-
- if (data->initrd_file) {
- if (!stat(data->initrd_file, &st) && st.st_size > 0)
- return false;
- }
-
- return data->os_fit ? fit_has_image(data->os_fit,
- data->fit_config, "ramdisk") > 0 : false;
-}
-
-static bool fdt_is_fit(struct image_data *data)
-{
- struct stat st;
-
- if (!IS_ENABLED(CONFIG_BOOTM_FITIMAGE))
- return false;
-
- if (bootm_signed_images_are_forced())
- return true;
-
- if (data->oftree_file) {
- if (!stat(data->oftree_file, &st) && st.st_size > 0)
- return false;
- }
-
- return data->os_fit ? fit_has_image(data->os_fit,
- data->fit_config, "fdt") > 0 : false;
-}
-
-static bool os_is_fit(struct image_data *data)
-{
- if (!IS_ENABLED(CONFIG_BOOTM_FITIMAGE))
- return false;
-
- if (bootm_signed_images_are_forced())
- return true;
-
- return data->os_fit;
-}
-
static int efi_load_os(struct image_data *data,
struct efi_loaded_image **loaded_image,
efi_handle_t *handle)
{
efi_status_t efiret;
efi_handle_t h;
+ const void *view;
+ size_t size;
- if (!os_is_fit(data))
- return efi_load_image(data->os_file, loaded_image, handle);
-
- if (!data->fit_kernel)
- return -ENOENT;
+ view = loadable_view(data->os, &size) ?: ERR_PTR(-ENODATA);
+ if (IS_ERR(view)) {
+ pr_err("could not view kernel: %pe\n", view);
+ return PTR_ERR(view);
+ }
efiret = BS->load_image(false, efi_parent_image, efi_device_path,
- (void *)data->fit_kernel, data->fit_kernel_size, &h);
+ (void *)view, size, &h);
if (EFI_ERROR(efiret)) {
pr_err("failed to LoadImage: %s\n", efi_strerror(efiret));
- goto out_mem;
+ goto out_view_free;
};
efiret = BS->open_protocol(h, &efi_loaded_image_protocol_guid,
@@ -114,43 +66,33 @@ static int efi_load_os(struct image_data *data,
*handle = h;
+ loadable_view_free(data->os, view, size);
return 0;
out_unload:
BS->unload_image(h);
-out_mem:
+out_view_free:
+ loadable_view_free(data->os, view, size);
return -efi_errno(efiret);
}
-static int efi_load_ramdisk(struct image_data *data, void **initrd)
+static int efi_load_ramdisk(struct image_data *data,
+ const void **initrd,
+ size_t *initrd_size)
{
- unsigned long initrd_size;
- void *initrd_mem;
+ const void *initrd_mem;
int ret;
- if (ramdisk_is_fit(data)) {
- ret = fit_open_image(data->os_fit, data->fit_config, "ramdisk", 0,
- (const void **)&initrd_mem, &initrd_size);
- if (ret) {
- pr_err("Cannot open ramdisk image in FIT image: %m\n");
- return ret;
- }
- } else {
- if (!data->initrd_file)
- return 0;
+ if (!data->initrd)
+ return 0;
- pr_info("Loading ramdisk from '%s'\n", data->initrd_file);
-
- initrd_mem = read_file(data->initrd_file, &initrd_size);
- if (!initrd_mem) {
- ret = -errno;
- pr_err("Failed to read initrd from file '%s': %m\n",
- data->initrd_file);
- return ret;
- }
+ initrd_mem = loadable_view(data->initrd, initrd_size);
+ if (IS_ERR(initrd_mem)) {
+ pr_err("Cannot open ramdisk image: %pe\n", initrd_mem);
+ return PTR_ERR(initrd_mem);
}
- ret = efi_initrd_register(initrd_mem, initrd_size);
+ ret = efi_initrd_register(initrd_mem, *initrd_size);
if (ret) {
pr_err("Failed to register initrd: %pe\n", ERR_PTR(ret));
goto free_mem;
@@ -161,7 +103,7 @@ static int efi_load_ramdisk(struct image_data *data, void **initrd)
return 0;
free_mem:
- free(initrd_mem);
+ loadable_view_free(data->initrd, initrd_mem, *initrd_size);
return ret;
}
@@ -170,45 +112,31 @@ static int efi_load_fdt(struct image_data *data, void **fdt)
{
efi_physical_addr_t mem;
efi_status_t efiret;
- void *of_tree, *vmem;
- unsigned long of_size;
- int ret;
+ void *vmem;
+ size_t bufsize = DIV_ROUND_UP(SZ_2M, EFI_PAGE_SIZE);
+ ssize_t ret;
- if (fdt_is_fit(data)) {
- ret = fit_open_image(data->os_fit, data->fit_config, "fdt", 0,
- (const void **)&of_tree, &of_size);
- if (ret) {
- pr_err("Cannot open FDT image in FIT image: %m\n");
- return ret;
- }
- } else {
- if (!data->oftree_file)
- return 0;
+ if (!data->oftree)
+ return 0;
- pr_info("Loading devicetree from '%s'\n", data->oftree_file);
-
- of_tree = read_file(data->oftree_file, &of_size);
- if (!of_tree) {
- ret = -errno;
- pr_err("Failed to read oftree: %m\n");
- return ret;
- }
- }
-
- efiret = BS->allocate_pages(EFI_ALLOCATE_ANY_PAGES,
- EFI_ACPI_RECLAIM_MEMORY,
- DIV_ROUND_UP(SZ_2M, EFI_PAGE_SIZE), &mem);
+ efiret = BS->allocate_pages(EFI_ALLOCATE_ANY_PAGES, EFI_ACPI_RECLAIM_MEMORY,
+ bufsize, &mem);
if (EFI_ERROR(efiret)) {
pr_err("Failed to allocate pages for FDT: %s\n", efi_strerror(efiret));
- goto free_mem;
+ return -efi_errno(efiret);
}
vmem = efi_phys_to_virt(mem);
- memcpy(vmem, of_tree, of_size);
+
+ ret = loadable_extract_into_buf_full(data->oftree, vmem,
+ bufsize * EFI_PAGE_SIZE);
+ if (ret < 0)
+ goto free_efi_mem;
efiret = BS->install_configuration_table(&efi_fdt_guid, vmem);
if (EFI_ERROR(efiret)) {
pr_err("Failed to install FDT: %s\n", efi_strerror(efiret));
+ ret = -efi_errno(efiret);
goto free_efi_mem;
}
@@ -216,10 +144,8 @@ static int efi_load_fdt(struct image_data *data, void **fdt)
return 0;
free_efi_mem:
- BS->free_pages(mem, DIV_ROUND_UP(SZ_2M, EFI_PAGE_SIZE));
-free_mem:
- free(of_tree);
- return -efi_errno(efiret);
+ BS->free_pages(mem, bufsize);
+ return ret;
}
static void efi_unload_fdt(void *fdt)
@@ -234,8 +160,10 @@ static void efi_unload_fdt(void *fdt)
static int do_bootm_efi_stub(struct image_data *data)
{
struct efi_loaded_image *loaded_image;
- void *fdt = NULL, *initrd = NULL;
- efi_handle_t handle;
+ void *fdt = NULL;
+ const void *initrd = NULL;
+ size_t initrd_size;
+ efi_handle_t handle = NULL; /* silence compiler warning */
enum filetype type;
int ret;
@@ -247,7 +175,7 @@ static int do_bootm_efi_stub(struct image_data *data)
if (ret)
goto unload_os;
- ret = efi_load_ramdisk(data, &initrd);
+ ret = efi_load_ramdisk(data, &initrd, &initrd_size);
if (ret)
goto unload_oftree;
@@ -260,7 +188,7 @@ static int do_bootm_efi_stub(struct image_data *data)
unload_ramdisk:
if (initrd) {
efi_initrd_unregister();
- free(initrd);
+ loadable_view_free(data->initrd, initrd, initrd_size);
}
unload_oftree:
efi_unload_fdt(fdt);
diff --git a/include/bootm-fit.h b/include/bootm-fit.h
index 8deddd62e328..05f4f5acfe9a 100644
--- a/include/bootm-fit.h
+++ b/include/bootm-fit.h
@@ -4,67 +4,21 @@
#include <linux/types.h>
#include <image-fit.h>
-#include <bootm.h>
+#include <linux/errno.h>
-struct resource;
+struct image_data;
#ifdef CONFIG_BOOTM_FITIMAGE
-int bootm_load_fit_os(struct image_data *data, unsigned long load_address);
-
-struct resource *bootm_load_fit_initrd(struct image_data *data,
- unsigned long load_address);
-
-void *bootm_get_fit_devicetree(struct image_data *data);
-
int bootm_open_fit(struct image_data *data);
-static inline void bootm_close_fit(struct image_data *data)
-{
- fit_close(data->os_fit);
-}
-
-static inline bool bootm_fit_has_fdt(struct image_data *data)
-{
- if (!data->os_fit)
- return false;
-
- return fit_has_image(data->os_fit, data->fit_config, "fdt");
-}
-
#else
-static inline int bootm_load_fit_os(struct image_data *data,
- unsigned long load_address)
-{
- return -ENOSYS;
-}
-
-static inline struct resource *bootm_load_fit_initrd(struct image_data *data,
- unsigned long load_address)
-{
- return ERR_PTR(-ENOSYS);
-}
-
-static inline void *bootm_get_fit_devicetree(struct image_data *data)
-{
- return ERR_PTR(-ENOSYS);
-}
-
static inline int bootm_open_fit(struct image_data *data)
{
return -ENOSYS;
}
-static inline void bootm_close_fit(struct image_data *data)
-{
-}
-
-static inline bool bootm_fit_has_fdt(struct image_data *data)
-{
- return false;
-}
-
#endif
#endif
diff --git a/include/bootm.h b/include/bootm.h
index 3ba8402217e3..d3874a0e8ef2 100644
--- a/include/bootm.h
+++ b/include/bootm.h
@@ -64,15 +64,12 @@ struct image_data {
/* simplest case. barebox has already loaded the os here */
struct resource *os_res;
- /* Future default case: A generic loadable object */
+ /* Generic loadable object for OS image */
struct loadable *os;
/* if os is an uImage this will be provided */
struct uimage_handle *os_uimage;
- /* if os is a FIT image this will be provided */
- struct fit_handle *os_fit;
-
char *os_part;
/* otherwise only the filename will be provided */
@@ -92,7 +89,7 @@ struct image_data {
/* if initrd is already loaded this resource will be !NULL */
struct resource *initrd_res;
- /* Future default case: A generic loadable object */
+ /* Generic loadable object for initrd */
struct loadable *initrd;
/* if initrd is an uImage this will be provided */
@@ -110,14 +107,10 @@ struct image_data {
/* if oftree is an uImage this will be provided */
struct uimage_handle *oftree_uimage;
- const void *fit_kernel;
- unsigned long fit_kernel_size;
- void *fit_config;
-
struct device_node *of_root_node;
struct resource *oftree_res;
- /* Future default case: A generic loadable object */
+ /* Generic loadable object for oftree */
struct loadable *oftree;
/*
diff --git a/include/image-fit.h b/include/image-fit.h
index ede43beab12e..1de3468c401d 100644
--- a/include/image-fit.h
+++ b/include/image-fit.h
@@ -27,6 +27,13 @@ struct fit_handle {
struct device_node *configurations;
};
+static inline struct fit_handle *fit_open_handle(struct fit_handle *handle)
+{
+ if (handle)
+ refcount_inc(&handle->users);
+ return handle;
+}
+
struct fit_handle *fit_open(const char *filename, bool verbose,
enum bootm_verify verify);
struct fit_handle *fit_open_buf(const void *buf, size_t len, bool verbose,
@@ -66,6 +73,7 @@ int fit_get_image_address(struct fit_handle *handle, void *configuration,
const char *name, const char *property,
unsigned long *address);
int fit_config_verify_signature(struct fit_handle *handle, struct device_node *conf_node);
+const char *fit_config_get_name(struct fit_handle *handle, void *config);
void fit_close(struct fit_handle *handle);
--
2.47.3
^ permalink raw reply [flat|nested] 22+ messages in thread* [PATCH 09/16] bootm: stash initial OS address/entry in image_data
2026-03-12 14:44 [PATCH 01/16] lib: add lazy loadable infrastructure for deferred boot component loading Ahmad Fatoum
` (6 preceding siblings ...)
2026-03-12 14:44 ` [PATCH 08/16] bootm: fit: switch to new " Ahmad Fatoum
@ 2026-03-12 14:44 ` Ahmad Fatoum
2026-03-12 14:44 ` [PATCH 10/16] bootm: support multiple entries for bootm.initrd Ahmad Fatoum
` (7 subsequent siblings)
15 siblings, 0 replies; 22+ messages in thread
From: Ahmad Fatoum @ 2026-03-12 14:44 UTC (permalink / raw)
To: barebox; +Cc: Ahmad Fatoum
Save the initial os_address and os_entry values that were passed to
bootm_boot() in new os_address_hint and os_entry_hint fields. These
preserve the originally requested values even if os_address/os_entry
are modified during the boot process.
Signed-off-by: Ahmad Fatoum <a.fatoum@pengutronix.de>
---
common/bootm.c | 4 ++--
include/bootm.h | 4 ++++
2 files changed, 6 insertions(+), 2 deletions(-)
diff --git a/common/bootm.c b/common/bootm.c
index 01d569dd37d4..25cbce6ccb3f 100644
--- a/common/bootm.c
+++ b/common/bootm.c
@@ -530,8 +530,8 @@ struct image_data *bootm_boot_prep(const struct bootm_data *bootm_data)
data->force = bootm_data->force;
data->dryrun = bootm_data->dryrun;
data->initrd_address = bootm_data->initrd_address;
- data->os_address = bootm_data->os_address;
- data->os_entry = bootm_data->os_entry;
+ data->os_address = data->os_address_hint = bootm_data->os_address;
+ data->os_entry = data->os_entry_hint = bootm_data->os_entry;
data->efi_boot = bootm_data->efi_boot;
ret = file_read_and_detect_boot_image_type(data->os_file, &data->os_header);
diff --git a/include/bootm.h b/include/bootm.h
index d3874a0e8ef2..570ac4d289f2 100644
--- a/include/bootm.h
+++ b/include/bootm.h
@@ -86,6 +86,10 @@ struct image_data {
/* entry point to the os. relative to the start of the image */
unsigned long os_entry;
+ /* initial os_address/os_entry supplied at entry to bootm_boot */
+ unsigned long os_address_hint;
+ unsigned long os_entry_hint;
+
/* if initrd is already loaded this resource will be !NULL */
struct resource *initrd_res;
--
2.47.3
^ permalink raw reply [flat|nested] 22+ messages in thread* [PATCH 10/16] bootm: support multiple entries for bootm.initrd
2026-03-12 14:44 [PATCH 01/16] lib: add lazy loadable infrastructure for deferred boot component loading Ahmad Fatoum
` (7 preceding siblings ...)
2026-03-12 14:44 ` [PATCH 09/16] bootm: stash initial OS address/entry in image_data Ahmad Fatoum
@ 2026-03-12 14:44 ` Ahmad Fatoum
2026-03-12 14:44 ` [PATCH 11/16] bootm: implement plain and FIT bootm.image override Ahmad Fatoum
` (6 subsequent siblings)
15 siblings, 0 replies; 22+ messages in thread
From: Ahmad Fatoum @ 2026-03-12 14:44 UTC (permalink / raw)
To: barebox; +Cc: Ahmad Fatoum
Linux can extract transparently any number of concatenated CPIOs, even
if individually compressed. This can be useful if we have two CPIOs from
different sources, e.g. an rdinit and a CPIO with the kernel modules.
Teach bootm how to collect multiple initrd entries by leveraging the
loadable chaining support.
Signed-off-by: Ahmad Fatoum <a.fatoum@pengutronix.de>
---
common/bootm-fit.c | 13 +++++++++----
common/bootm-overrides.c | 17 +++++++----------
common/bootm.c | 7 ++++---
3 files changed, 20 insertions(+), 17 deletions(-)
diff --git a/common/bootm-fit.c b/common/bootm-fit.c
index 089f376fd7f1..5b110ad2f19e 100644
--- a/common/bootm-fit.c
+++ b/common/bootm-fit.c
@@ -36,7 +36,7 @@ static void loadable_from_fit_os(struct image_data *data,
* @fit: handle of FIT image
* @config: config to look up kernel in
*
- * This creates a loadable for the first initial ram disk in the config.
+ * This creates loadables for all initial ram disks in the config and chains them.
*
* Return: true if initrd booting is supported and a ramdisk exists or
* false otherwise.
@@ -45,17 +45,22 @@ static bool loadable_from_fit_initrd(struct image_data *data,
struct fit_handle *fit,
void *config)
{
+ int nramdisks;
+
if (!IS_ENABLED(CONFIG_BOOTM_INITRD))
return false;
- if (!fit_has_image(fit, config, "ramdisk"))
+ nramdisks = fit_count_images(fit, config, "ramdisk");
+ if (nramdisks < 0)
return false;
loadable_release(&data->initrd);
- data->initrd = loadable_from_fit(fit, config, "ramdisk", 0, LOADABLE_INITRD);
+ for (int i = 0; i < nramdisks; i++)
+ loadable_chain(&data->initrd, loadable_from_fit(fit, config, "ramdisk",
+ i, LOADABLE_INITRD));
- return true;
+ return nramdisks > 0;
}
/*
diff --git a/common/bootm-overrides.c b/common/bootm-overrides.c
index c1f3ee7cade8..59ca90a58684 100644
--- a/common/bootm-overrides.c
+++ b/common/bootm-overrides.c
@@ -20,16 +20,12 @@ int bootm_apply_overrides(struct image_data *data,
if (bootm_signed_images_are_forced())
return 0;
- if (overrides->initrd_file) {
- loadable_release(&data->initrd);
-
- /* Empty string means to mask the original initrd */
- if (nonempty(overrides->initrd_file)) {
- data->initrd = loadable_from_file(overrides->initrd_file,
- LOADABLE_INITRD);
- if (IS_ERR(data->initrd))
- return PTR_ERR(data->initrd);
- }
+ 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, ":",
+ LOADABLE_INITRD);
+ if (ret)
+ return ret;
data->is_override.initrd = true;
}
@@ -48,3 +44,4 @@ int bootm_apply_overrides(struct image_data *data,
return 0;
}
+
diff --git a/common/bootm.c b/common/bootm.c
index 25cbce6ccb3f..ddc656fb34c8 100644
--- a/common/bootm.c
+++ b/common/bootm.c
@@ -463,9 +463,10 @@ static int bootm_open_files(struct image_data *data)
}
if (data->initrd_file) {
- data->initrd = loadable_from_file(data->initrd_file, LOADABLE_INITRD);
- if (IS_ERR(data->initrd))
- return PTR_ERR(data->initrd);
+ int ret = loadables_from_files(&data->initrd, data->initrd_file, ":",
+ LOADABLE_INITRD);
+ if (ret)
+ return ret;
}
if (data->tee_file) {
--
2.47.3
^ permalink raw reply [flat|nested] 22+ messages in thread* [PATCH 11/16] bootm: implement plain and FIT bootm.image override
2026-03-12 14:44 [PATCH 01/16] lib: add lazy loadable infrastructure for deferred boot component loading Ahmad Fatoum
` (8 preceding siblings ...)
2026-03-12 14:44 ` [PATCH 10/16] bootm: support multiple entries for bootm.initrd Ahmad Fatoum
@ 2026-03-12 14:44 ` Ahmad Fatoum
2026-03-18 9:01 ` Sascha Hauer
2026-03-12 14:44 ` [PATCH 12/16] bootm: overrides: add support for overlays Ahmad Fatoum
` (5 subsequent siblings)
15 siblings, 1 reply; 22+ messages in thread
From: Ahmad Fatoum @ 2026-03-12 14:44 UTC (permalink / raw)
To: barebox; +Cc: Ahmad Fatoum, Claude Opus 4.5
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.
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
^ permalink raw reply [flat|nested] 22+ messages in thread* Re: [PATCH 11/16] bootm: implement plain and FIT bootm.image override
2026-03-12 14:44 ` [PATCH 11/16] bootm: implement plain and FIT bootm.image override Ahmad Fatoum
@ 2026-03-18 9:01 ` Sascha Hauer
2026-03-18 9:17 ` Ahmad Fatoum
0 siblings, 1 reply; 22+ messages in thread
From: Sascha Hauer @ 2026-03-18 9:01 UTC (permalink / raw)
To: Ahmad Fatoum; +Cc: barebox, Claude Opus 4.5
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 |
^ permalink raw reply [flat|nested] 22+ messages in thread* Re: [PATCH 11/16] bootm: implement plain and FIT bootm.image override
2026-03-18 9:01 ` Sascha Hauer
@ 2026-03-18 9:17 ` Ahmad Fatoum
0 siblings, 0 replies; 22+ messages in thread
From: Ahmad Fatoum @ 2026-03-18 9:17 UTC (permalink / raw)
To: Sascha Hauer; +Cc: barebox, Claude Opus 4.5
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 |
^ permalink raw reply [flat|nested] 22+ messages in thread
* [PATCH 12/16] bootm: overrides: add support for overlays
2026-03-12 14:44 [PATCH 01/16] lib: add lazy loadable infrastructure for deferred boot component loading Ahmad Fatoum
` (9 preceding siblings ...)
2026-03-12 14:44 ` [PATCH 11/16] bootm: implement plain and FIT bootm.image override Ahmad Fatoum
@ 2026-03-12 14:44 ` Ahmad Fatoum
2026-03-12 14:44 ` [PATCH 13/16] test: py: add test for initrd concatenation Ahmad Fatoum
` (4 subsequent siblings)
15 siblings, 0 replies; 22+ messages in thread
From: Ahmad Fatoum @ 2026-03-12 14:44 UTC (permalink / raw)
To: barebox; +Cc: Ahmad Fatoum, Claude Opus 4.5
Use loadables_from_files() for the oftree override, matching the initrd
pattern, to support colon-separated multi-file syntax. The first entry
is the base DT and subsequent entries are applied as overlays:
bootm.oftree=a use a as DT (unchanged behavior)
bootm.oftree=a:b use a as DT, apply b as overlay
bootm.oftree=:b keep existing DT, apply b as overlay
bootm.oftree=a:b:c use a as DT, apply b and c as overlays
Override overlays are applied during of_fix_tree() via a fixup registered
at of_populate_initcall level (13), placing them after global overlays
(device_initcall, 11) but before bootargs fixup (late_initcall, 14).
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Signed-off-by: Ahmad Fatoum <a.fatoum@pengutronix.de>
---
common/bootm-overrides.c | 65 +++++++++++++++++++++++++++++++++------
common/bootm.c | 3 ++
include/bootm-overrides.h | 6 ++++
3 files changed, 65 insertions(+), 9 deletions(-)
diff --git a/common/bootm-overrides.c b/common/bootm-overrides.c
index 8c71ceb5f80d..720d5636f331 100644
--- a/common/bootm-overrides.c
+++ b/common/bootm-overrides.c
@@ -3,7 +3,9 @@
#include <bootm.h>
#include <bootm-overrides.h>
#include <bootm-fit.h>
+#include <init.h>
#include <libfile.h>
+#include <of.h>
#include <linux/pagemap.h>
/**
@@ -142,15 +144,11 @@ int bootm_apply_overrides(struct image_data *data,
}
if (overrides->oftree_file) {
- loadable_release(&data->oftree);
-
- /* Empty string means to mask the original FDT */
- if (nonempty(overrides->oftree_file)) {
- data->oftree = loadable_from_file(overrides->oftree_file,
- LOADABLE_FDT);
- if (IS_ERR(data->oftree))
- return PTR_ERR(data->oftree);
- }
+ int ret = loadables_from_files(&data->oftree,
+ overrides->oftree_file, ":",
+ LOADABLE_FDT);
+ if (ret)
+ return ret;
data->is_override.oftree = true;
}
@@ -158,3 +156,52 @@ int bootm_apply_overrides(struct image_data *data,
return 0;
}
+
+static struct loadable *pending_oftree_overlays;
+
+void bootm_set_pending_oftree_overlays(struct loadable *oftree)
+{
+ pending_oftree_overlays = oftree;
+}
+
+void bootm_clear_pending_oftree_overlays(void)
+{
+ pending_oftree_overlays = NULL;
+}
+
+static int bootm_override_overlay_fixup(struct device_node *root, void *ctx)
+{
+ struct loadable *ovl;
+
+ if (!pending_oftree_overlays)
+ return 0;
+
+ list_for_each_entry(ovl, &pending_oftree_overlays->chained_loadables, list) {
+ const void *dtbo;
+ size_t size;
+ int ret;
+
+ dtbo = loadable_view(ovl, &size);
+ if (IS_ERR(dtbo)) {
+ pr_err("could not load overlay \"%s\": %pe\n",
+ ovl->name, dtbo);
+ continue;
+ }
+
+ ret = of_overlay_apply_dtbo(root, dtbo);
+ if (ret)
+ pr_err("failed to apply overlay \"%s\": %pe\n",
+ ovl->name, ERR_PTR(ret));
+ loadable_view_free(ovl, dtbo, size);
+ }
+
+ return 0;
+}
+
+static int bootm_register_override_overlay_fixup(void)
+{
+ if (!IS_ENABLED(CONFIG_OF_OVERLAY))
+ return 0;
+ return of_register_fixup(bootm_override_overlay_fixup, NULL);
+}
+of_populate_initcall(bootm_register_override_overlay_fixup);
diff --git a/common/bootm.c b/common/bootm.c
index ed79c20c0972..d4a3a232743f 100644
--- a/common/bootm.c
+++ b/common/bootm.c
@@ -11,6 +11,7 @@
#include <block.h>
#include <libfile.h>
#include <bootm-fit.h>
+#include <bootm-overrides.h>
#include <bootm-uimage.h>
#include <globalvar.h>
#include <init.h>
@@ -325,7 +326,9 @@ void *bootm_get_devicetree(struct image_data *data)
of_add_reserve_entry(data->initrd_res->start, data->initrd_res->end);
}
+ bootm_set_pending_oftree_overlays(data->oftree);
of_fix_tree(data->of_root_node);
+ bootm_clear_pending_oftree_overlays();
oftree = of_flatten_dtb(data->of_root_node);
if (!oftree)
diff --git a/include/bootm-overrides.h b/include/bootm-overrides.h
index 9b133928a923..0dbf6e7fa823 100644
--- a/include/bootm-overrides.h
+++ b/include/bootm-overrides.h
@@ -9,6 +9,7 @@ struct bootm_overrides {
};
struct image_data;
+struct loadable;
#ifdef CONFIG_BOOT_OVERRIDE
static inline void bootm_merge_overrides(struct bootm_overrides *dst,
@@ -24,6 +25,8 @@ static inline void bootm_merge_overrides(struct bootm_overrides *dst,
int bootm_apply_overrides(struct image_data *data,
const struct bootm_overrides *overrides);
+void bootm_set_pending_oftree_overlays(struct loadable *oftree);
+void bootm_clear_pending_oftree_overlays(void);
#else
static inline void bootm_merge_overrides(struct bootm_overrides *dst,
@@ -36,6 +39,9 @@ static inline int bootm_apply_overrides(struct image_data *data,
{
return 0;
}
+
+static inline void bootm_set_pending_oftree_overlays(struct loadable *o) {}
+static inline void bootm_clear_pending_oftree_overlays(void) {}
#endif
#endif
--
2.47.3
^ permalink raw reply [flat|nested] 22+ messages in thread* [PATCH 13/16] test: py: add test for initrd concatenation
2026-03-12 14:44 [PATCH 01/16] lib: add lazy loadable infrastructure for deferred boot component loading Ahmad Fatoum
` (10 preceding siblings ...)
2026-03-12 14:44 ` [PATCH 12/16] bootm: overrides: add support for overlays Ahmad Fatoum
@ 2026-03-12 14:44 ` Ahmad Fatoum
2026-03-12 14:44 ` [PATCH 14/16] defaultenv: base: add new devboot script Ahmad Fatoum
` (3 subsequent siblings)
15 siblings, 0 replies; 22+ messages in thread
From: Ahmad Fatoum @ 2026-03-12 14:44 UTC (permalink / raw)
To: barebox; +Cc: Ahmad Fatoum
Now that the FIT code supports processing multiple entries in the
ramdisk property, add a test to ensure this doesn't regress.
Signed-off-by: Ahmad Fatoum <a.fatoum@pengutronix.de>
---
test/py/test_fit.py | 38 +++++++++++++-------
test/py/testfs.py | 23 ++++++++++++
test/testdata/multi_v7_defconfig-gzipped.its | 28 +++++++++++++--
test/testdata/multi_v8_defconfig-gzipped.its | 28 +++++++++++++--
4 files changed, 98 insertions(+), 19 deletions(-)
create mode 100644 test/py/testfs.py
diff --git a/test/py/test_fit.py b/test/py/test_fit.py
index 8bcee6a75f23..0fd5a3c5dcc5 100644
--- a/test/py/test_fit.py
+++ b/test/py/test_fit.py
@@ -7,6 +7,7 @@ import shutil
import subprocess
from pathlib import Path
from .helper import of_get_property, filter_errors
+from .testfs import mkcpio
def generate_bootscript(barebox, image, name="test"):
@@ -37,16 +38,9 @@ def fit_testdata(barebox_config, testfs):
input=(builddir / "images" / "barebox-dt-2nd.img").read_bytes(),
stdout=open(builddir / "barebox-dt-2nd.img.gz", "wb"))
- find = subprocess.Popen(["find", "COPYING", "LICENSES/"],
- stdout=subprocess.PIPE)
- cpio = subprocess.Popen(["cpio", "-o", "-H", "newc"],
- stdin=find.stdout, stdout=subprocess.PIPE)
- gzip = subprocess.Popen(["gzip"], stdin=cpio.stdout,
- stdout=open(builddir / "ramdisk.cpio.gz", "wb"))
-
- find.wait()
- cpio.wait()
- gzip.wait()
+ mkcpio("COPYING", outdir / "ramdisk1.cpio.gz")
+ mkcpio("LICENSES/exceptions/", outdir / "ramdisk2.cpio")
+ mkcpio("LICENSES/preferred/", outdir / "ramdisk3.cpio.gz")
run(["mkimage", "-G", "test/self/development_rsa2048.pem", "-r", "-f",
str(builddir / its_name), str(outfile)])
@@ -105,6 +99,15 @@ def test_fit(barebox, strategy, fitimage):
barebox.run_check("global linux.bootargs.testarg=barebox.chainloaded")
+ barebox.run_check("cat -o /tmp/ramdisks.cpio /mnt/9p/testfs/ramdisk*.cpio*")
+ [hashsum1] = barebox.run_check("md5sum /tmp/ramdisks.cpio")
+
+ hashsum1 = re.split("/tmp/ramdisks.cpio", hashsum1, maxsplit=1)[0]
+ # Get the actual size of the concatenated ramdisks file
+ [fileinfo] = barebox.run_check("ls -l /tmp/ramdisks.cpio")
+ # Parse the size from ls -l output (format: permissions links user group size ...)
+ actual_size = int(fileinfo.split()[1])
+
boottarget = generate_bootscript(barebox, fitimage)
with strategy.boot_barebox(boottarget) as barebox:
@@ -118,7 +121,16 @@ def test_fit(barebox, strategy, fitimage):
bootargs = of_get_property(barebox, "/chosen/bootargs")
assert "barebox.chainloaded" in bootargs
- initrd_start = of_get_property(barebox, "/chosen/linux,initrd-start", 0)
- initrd_end = of_get_property(barebox, "/chosen/linux,initrd-end", 0)
+ initrd_start = of_get_property(barebox, "/chosen/linux,initrd-start", ncells=0)
+ initrd_end = of_get_property(barebox, "/chosen/linux,initrd-end", ncells=0)
+ initrd_size = initrd_end - initrd_start
- assert initrd_start < initrd_end
+ # Verify the DT-reported size matches the actual file size
+ assert initrd_size == actual_size, \
+ f"Initrd size mismatch: DT says {initrd_size}, file is {actual_size}"
+
+ [hashsum2] = barebox.run_check(f"md5sum {initrd_start}+{initrd_size}")
+
+ hashsum2 = re.split("/dev/mem", hashsum2, maxsplit=1)[0]
+
+ assert hashsum1 == hashsum2
diff --git a/test/py/testfs.py b/test/py/testfs.py
new file mode 100644
index 000000000000..3ead67c0621b
--- /dev/null
+++ b/test/py/testfs.py
@@ -0,0 +1,23 @@
+# SPDX-License-Identifier: GPL-2.0-or-later
+
+import subprocess
+
+
+def mkcpio(inpath, outname):
+ compress = outname.suffix == ".gz"
+
+ find = subprocess.Popen(["find", inpath], stdout=subprocess.PIPE)
+
+ with open(outname, "wb") as outfile:
+ cpio = subprocess.Popen(["cpio", "-o", "-H", "newc"], stdin=find.stdout,
+ stdout=(subprocess.PIPE if compress else outfile))
+
+ find.stdout.close()
+
+ if compress:
+ gzip = subprocess.Popen(["gzip"], stdin=cpio.stdout, stdout=outfile)
+ cpio.stdout.close()
+ gzip.wait()
+
+ cpio.wait()
+ find.wait()
diff --git a/test/testdata/multi_v7_defconfig-gzipped.its b/test/testdata/multi_v7_defconfig-gzipped.its
index 11595c39baa1..1cb84fd41564 100644
--- a/test/testdata/multi_v7_defconfig-gzipped.its
+++ b/test/testdata/multi_v7_defconfig-gzipped.its
@@ -26,8 +26,30 @@
};
};
ramdisk-1 {
- description = "initramfs";
- data = /incbin/("ramdisk.cpio.gz");
+ description = "initramfs 1 (compressed)";
+ data = /incbin/("testfs/ramdisk1.cpio.gz");
+ type = "ramdisk";
+ arch = "arm";
+ os = "linux";
+ compression = "none";
+ hash-1 {
+ algo = "sha256";
+ };
+ };
+ ramdisk-2 {
+ description = "initramfs 2 (uncompressed)";
+ data = /incbin/("testfs/ramdisk2.cpio");
+ type = "ramdisk";
+ arch = "arm";
+ os = "linux";
+ compression = "none";
+ hash-1 {
+ algo = "sha256";
+ };
+ };
+ ramdisk-3 {
+ description = "initramfs 3 (compressed)";
+ data = /incbin/("testfs/ramdisk3.cpio.gz");
type = "ramdisk";
arch = "arm";
os = "linux";
@@ -44,7 +66,7 @@
description = "Qemu Virt32";
kernel = "kernel-1";
fdt = "fdt-qemu-virt32.dtb";
- ramdisk = "ramdisk-1";
+ ramdisk = "ramdisk-1", "ramdisk-2", "ramdisk-3";
compatible = "linux,dummy-virt";
signature-1 {
algo = "sha256,rsa2048";
diff --git a/test/testdata/multi_v8_defconfig-gzipped.its b/test/testdata/multi_v8_defconfig-gzipped.its
index 5ce678eec9a8..3786d0f12187 100644
--- a/test/testdata/multi_v8_defconfig-gzipped.its
+++ b/test/testdata/multi_v8_defconfig-gzipped.its
@@ -26,8 +26,30 @@
};
};
ramdisk-1 {
- description = "initramfs";
- data = /incbin/("ramdisk.cpio.gz");
+ description = "initramfs 1 (compressed)";
+ data = /incbin/("testfs/ramdisk1.cpio.gz");
+ type = "ramdisk";
+ arch = "arm64";
+ os = "linux";
+ compression = "none";
+ hash-1 {
+ algo = "sha256";
+ };
+ };
+ ramdisk-2 {
+ description = "initramfs 2 (uncompressed)";
+ data = /incbin/("testfs/ramdisk2.cpio");
+ type = "ramdisk";
+ arch = "arm64";
+ os = "linux";
+ compression = "none";
+ hash-1 {
+ algo = "sha256";
+ };
+ };
+ ramdisk-3 {
+ description = "initramfs 3 (compressed)";
+ data = /incbin/("testfs/ramdisk3.cpio.gz");
type = "ramdisk";
arch = "arm64";
os = "linux";
@@ -44,7 +66,7 @@
description = "Qemu Virt64";
kernel = "kernel-1";
fdt = "fdt-qemu-virt64.dtb";
- ramdisk = "ramdisk-1";
+ ramdisk = "ramdisk-1", "ramdisk-2", "ramdisk-3";
compatible = "linux,dummy-virt";
signature-1 {
algo = "sha256,rsa2048";
--
2.47.3
^ permalink raw reply [flat|nested] 22+ messages in thread* [PATCH 14/16] defaultenv: base: add new devboot script
2026-03-12 14:44 [PATCH 01/16] lib: add lazy loadable infrastructure for deferred boot component loading Ahmad Fatoum
` (11 preceding siblings ...)
2026-03-12 14:44 ` [PATCH 13/16] test: py: add test for initrd concatenation Ahmad Fatoum
@ 2026-03-12 14:44 ` Ahmad Fatoum
2026-03-18 9:50 ` Sascha Hauer
2026-03-12 14:44 ` [PATCH 15/16] Documentation: user: devboot: add section on forwarding build dirs Ahmad Fatoum
` (2 subsequent siblings)
15 siblings, 1 reply; 22+ messages in thread
From: Ahmad Fatoum @ 2026-03-12 14:44 UTC (permalink / raw)
To: barebox; +Cc: Ahmad Fatoum
devboot is a new command wrapper that makes it easier to use overrides
with network-provided artifacts:
- On the host side, add a *-devboot-* script that describes which
overrides to use
- On the barebox side, ensure the script can be found at either
${fetchfs}/${global.user}-devboot-${global.hostname} or
${fetchfs}/${global.user}-devboot-${global.arch}
- barebox will source this script and pass the applicable overrides
to the boot command in addition to whatever arguments devboot
was given
Here's an example *-devboot-* script:
devboot_image=afa-fit-rock3a
devboot_oftree= # force use of barebox DT
devboot_initrd=":afa-rsinit-arm64" # append specified CPIO to FIT's
global linux.bootargs.dyn.rsinit=rsinit.bind=/lib/modules
Signed-off-by: Ahmad Fatoum <a.fatoum@pengutronix.de>
---
Documentation/user/booting-linux.rst | 5 +-
Documentation/user/devboot.rst | 204 +++++++++++++++++++++++
Documentation/user/user-manual.rst | 1 +
defaultenv/defaultenv-2-base/bin/devboot | 48 ++++++
defaultenv/defaultenv-2-base/boot/devel | 3 +
5 files changed, 260 insertions(+), 1 deletion(-)
create mode 100644 Documentation/user/devboot.rst
create mode 100644 defaultenv/defaultenv-2-base/bin/devboot
create mode 100755 defaultenv/defaultenv-2-base/boot/devel
diff --git a/Documentation/user/booting-linux.rst b/Documentation/user/booting-linux.rst
index ed1ec3f68a93..3972777f30cf 100644
--- a/Documentation/user/booting-linux.rst
+++ b/Documentation/user/booting-linux.rst
@@ -182,7 +182,10 @@ and configure the overrides as arguments to the ``boot`` command:
.. code-block:: sh
- boot -o bootm.image=/mnt/tftp/oftree mmc
+ boot -o bootm.image=/mnt/tftp/zImage mmc
+
+See :ref:`devboot` for the full override syntax and the ``devboot``
+convenience script for network-based development.
Generic Boot Targets
^^^^^^^^^^^^^^^^^^^^
diff --git a/Documentation/user/devboot.rst b/Documentation/user/devboot.rst
new file mode 100644
index 000000000000..ad1b4c909ab0
--- /dev/null
+++ b/Documentation/user/devboot.rst
@@ -0,0 +1,204 @@
+.. _devboot:
+
+Devboot
+=======
+
+Devboot is a development convenience that builds on top of the
+:ref:`boot override <boot_overrides>` mechanism. It sources a per-user,
+per-board script from the network and translates it into ``boot -o``
+arguments, making it easy to redirect any combination of kernel, device tree
+and initrd to network-hosted files without touching the boot medium.
+
+.. _boot_overrides:
+
+Boot overrides
+--------------
+
+Enable ``CONFIG_BOOT_OVERRIDE`` to allow partial overrides of boot entries.
+This is already enabled in ``multi_v7_defconfig`` and ``multi_v8_defconfig``.
+
+The ``boot`` command then accepts one or more ``-o`` flags:
+
+.. code-block:: sh
+
+ boot -o bootm.image=/mnt/tftp/my-zImage mmc
+ boot -o bootm.oftree=/mnt/tftp/my-board.dtb mmc
+ boot -o bootm.initrd=/mnt/tftp/my-initrd mmc
+
+Multiple overrides can be combined in a single invocation:
+
+.. code-block:: sh
+
+ boot -o bootm.image=/mnt/tftp/zImage \
+ -o bootm.oftree=/mnt/tftp/board.dtb \
+ -o bootm.initrd=/mnt/tftp/initrd \
+ mmc
+
+Overrides are applied after the boot entry has been loaded, so the original
+entry still selects the boot handler, kernel arguments, etc. Only the
+specified components are replaced.
+
+Override rules
+^^^^^^^^^^^^^^
+
+``bootm.image``
+ The override file is probed for its type. If it is a FIT image, the
+ FIT configuration is re-opened and all components (kernel, initrd, device
+ tree) are taken from the override FIT. If it is a plain kernel image
+ (zImage, Image, uImage, ...), only the OS loadable is replaced.
+
+``bootm.oftree``
+ A colon-separated list of files. The first entry is the base device tree;
+ subsequent entries are applied as overlays:
+
+ .. code-block:: sh
+
+ # Use a as the device tree
+ boot -o bootm.oftree=a mmc
+
+ # Use a as the device tree, apply b as overlay
+ boot -o bootm.oftree=a:b mmc
+
+ # Keep the existing device tree, apply b as overlay
+ boot -o bootm.oftree=:b mmc
+
+ # Use a as the device tree, apply b and c as overlays
+ boot -o bootm.oftree=a:b:c mmc
+
+ Setting ``bootm.oftree`` to an empty string (``bootm.oftree=``) discards
+ whatever device tree the boot entry provides. If
+ ``CONFIG_BOOTM_OFTREE_FALLBACK`` is enabled (the default), the
+ barebox-internal device tree is passed to the kernel instead. If the
+ option is disabled, no device tree is passed at all.
+
+``bootm.initrd``
+ A colon-separated list of initrd/CPIO files. Linux can transparently
+ extract any number of concatenated CPIOs, even if individually compressed.
+ A leading colon appends to the initrd that the boot entry already provides:
+
+ .. code-block:: sh
+
+ # Replace with a single initrd
+ boot -o bootm.initrd=/mnt/tftp/initrd mmc
+
+ # Concatenate two initrds
+ boot -o bootm.initrd=initrd1:initrd2 mmc
+
+ # Append an extra CPIO to the existing initrd
+ boot -o bootm.initrd=:extra.cpio mmc
+
+ .. tip::
+
+ The Linux kernel ``make cpio-modules-pkg`` target builds a CPIO archive
+ containing all kernel modules. This is useful for supplementing an existing
+ initramfs with modules without modifying the root filesystem.
+ Combined with initrd concatenation, a devboot script
+ can append it to any boot entry's initrd::
+
+ devboot_initrd=":afa-modules-arm64"
+
+ To make use of the modules, the initramfs init will need to make initramfs
+ /modules available to the rootfs, e.g. via a bind mount:
+
+ mount -n --bind /lib/modules ${ROOT_MOUNT}/lib/modules
+
+.. note::
+
+ When secure boot is enforced (``bootm_signed_images_are_forced()``),
+ overrides are silently ignored.
+
+The devboot script
+------------------
+
+The ``devboot`` command (``/env/bin/devboot``) automates the override
+workflow for network-based development:
+
+1. Brings up the network (``ifup -a1``).
+2. Changes into the fetch directory
+ (:ref:`global.net.fetchdir <magicvar_global_net_fetchdir>`, default
+ ``/mnt/tftp``).
+3. Sources a configuration script named
+ ``${global.user}-devboot-${global.hostname}``. If that file does not
+ exist, it falls back to ``${global.user}-devboot-${global.arch}``.
+4. Translates the variables set by the script into ``boot -o`` arguments.
+5. Passes any extra arguments through to the ``boot`` command.
+
+.. note::
+
+ TFTP is not a real file system, e.g., listing of directories is not
+ possible. Keep that in mind if the devboot script does more than
+ just fetch files by name from TFTP.
+
+Usage
+^^^^^
+
+.. code-block:: sh
+
+ # Boot from MMC with devboot overrides
+ devboot mmc
+
+ # Boot from the default boot entry
+ devboot
+
+ # Make devboot the default for subsequent boots
+ nv.boot.default=devel
+
+Configuration script
+^^^^^^^^^^^^^^^^^^^^
+
+The configuration script lives in the fetch directory and sets up to three
+variables:
+
+``devboot_image``
+ Override for ``bootm.image``. Path is relative to the fetch directory.
+
+``devboot_oftree``
+ Override for ``bootm.oftree``. An empty string discards the boot
+ entry's device tree (see ``bootm.oftree`` rules above).
+
+``devboot_initrd``
+ Override for ``bootm.initrd``. A leading colon appends to the boot
+ entry's existing initrd.
+
+Variables that are not set (using ``[[ -v ... ]]``) are left alone,
+so unset variables do not generate override arguments.
+
+The script can also set arbitrary barebox variables, for example
+kernel command line fragments:
+
+.. code-block:: sh
+
+ # /tftpboot/afa-devboot-rock3a
+ devboot_image=afa-fit-rock3a
+ devboot_oftree=
+ devboot_initrd=":afa-rsinit-arm64"
+
+ global linux.bootargs.dyn.rsinit="rsinit.bind=/lib/modules"
+
+With this script in place and ``global.user=afa``, ``global.hostname=rock3a``,
+running ``devboot mmc`` on the board expands to::
+
+ boot -o bootm.image="afa-fit-rock3a" \
+ -o bootm.oftree="" \
+ -o bootm.initrd=":afa-rsinit-arm64" \
+ mmc
+
+This fetches the FIT image ``afa-fit-rock3a`` from the fetch directory,
+discards the FIT's device tree (falling back to the barebox-internal one
+when ``CONFIG_BOOTM_OFTREE_FALLBACK`` is enabled), and appends the
+``afa-rsinit-arm64`` CPIO archive to whatever initrd the FIT already
+contains.
+
+Setting up the variables
+^^^^^^^^^^^^^^^^^^^^^^^^
+
+The ``global.user`` and ``global.hostname`` variables control which
+script is loaded. Make them persistent with:
+
+.. code-block:: sh
+
+ nv user=afa
+ nv hostname=rock3a
+
+``global.hostname`` is typically derived from the device tree, but can be
+overridden.
diff --git a/Documentation/user/user-manual.rst b/Documentation/user/user-manual.rst
index cb01721863dd..aa55017c69d7 100644
--- a/Documentation/user/user-manual.rst
+++ b/Documentation/user/user-manual.rst
@@ -26,6 +26,7 @@ Contents:
usb
ubi
booting-linux
+ devboot
bootchooser
remote-control
security
diff --git a/defaultenv/defaultenv-2-base/bin/devboot b/defaultenv/defaultenv-2-base/bin/devboot
new file mode 100644
index 000000000000..124bfec01ba3
--- /dev/null
+++ b/defaultenv/defaultenv-2-base/bin/devboot
@@ -0,0 +1,48 @@
+#!/bin/sh
+
+devboot_path="${global.net.fetchdir}"
+
+# global.net.server and global.hostname may be set by DHCP, so trigger it first
+ifup -a1
+
+cd "${devboot_path}" || exit 1
+saved_pwd="$OLDPWD"
+
+devboot_script="${global.user}-devboot-${global.hostname}"
+if [ ! -f "${devboot_script}" ]; then
+ devboot_script2="${global.user}-devboot-${global.arch}"
+ if [ ! -f "${devboot_script2}" ]; then
+ echo "Error: Neither ${devboot_script} nor ${devboot_script2} found"
+ echo "Create one of them and set as needed:"
+ echo " devboot_image, devboot_initrd, devboot_oftree"
+ cd "${saved_pwd}"
+ exit 1
+ fi
+ devboot_script="${devboot_script2}"
+fi
+
+echo Sourcing "${devboot_path}/${devboot_script}"
+source "${devboot_path}/${devboot_script}"
+if [ $? -ne 0 ]; then
+ cd "${saved_pwd}"
+ exit 1
+fi
+
+override_args=""
+
+if [[ -v devboot_image ]]; then
+ override_args="${override_args} -o bootm.image=\"${devboot_image}\""
+fi
+
+if [[ -v devboot_oftree ]]; then
+ override_args="${override_args} -o bootm.oftree=\"${devboot_oftree}\""
+fi
+
+if [[ -v devboot_initrd ]]; then
+ override_args="${override_args} -o bootm.initrd=\"${devboot_initrd}\""
+fi
+
+echo boot ${override_args} $*
+boot ${override_args} $*
+
+cd "${saved_pwd}"
diff --git a/defaultenv/defaultenv-2-base/boot/devel b/defaultenv/defaultenv-2-base/boot/devel
new file mode 100755
index 000000000000..9bcaaffb5870
--- /dev/null
+++ b/defaultenv/defaultenv-2-base/boot/devel
@@ -0,0 +1,3 @@
+#!/bin/sh
+
+devboot
--
2.47.3
^ permalink raw reply [flat|nested] 22+ messages in thread* Re: [PATCH 14/16] defaultenv: base: add new devboot script
2026-03-12 14:44 ` [PATCH 14/16] defaultenv: base: add new devboot script Ahmad Fatoum
@ 2026-03-18 9:50 ` Sascha Hauer
2026-03-18 10:50 ` Ahmad Fatoum
0 siblings, 1 reply; 22+ messages in thread
From: Sascha Hauer @ 2026-03-18 9:50 UTC (permalink / raw)
To: Ahmad Fatoum; +Cc: barebox
On Thu, Mar 12, 2026 at 03:44:57PM +0100, Ahmad Fatoum wrote:
> +The devboot script
> +------------------
> +
> +The ``devboot`` command (``/env/bin/devboot``) automates the override
> +workflow for network-based development:
> +
> +1. Brings up the network (``ifup -a1``).
> +2. Changes into the fetch directory
> + (:ref:`global.net.fetchdir <magicvar_global_net_fetchdir>`, default
> + ``/mnt/tftp``).
Is this default actually set somewhere? I can't find it.
> +3. Sources a configuration script named
> + ``${global.user}-devboot-${global.hostname}``. If that file does not
> + exist, it falls back to ``${global.user}-devboot-${global.arch}``.
> +4. Translates the variables set by the script into ``boot -o`` arguments.
> +5. Passes any extra arguments through to the ``boot`` command.
> +
> +.. note::
> +
> + TFTP is not a real file system, e.g., listing of directories is not
> + possible. Keep that in mind if the devboot script does more than
> + just fetch files by name from TFTP.
> +
> +Usage
> +^^^^^
> +
> +.. code-block:: sh
> +
> + # Boot from MMC with devboot overrides
> + devboot mmc
> +
> + # Boot from the default boot entry
> + devboot
> +
> + # Make devboot the default for subsequent boots
> + nv.boot.default=devel
So that would be equivalent to a permanent "devboot". Is there also a
way to specifiy permanent "devboot mmc"?
Sascha
--
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 |
^ permalink raw reply [flat|nested] 22+ messages in thread* Re: [PATCH 14/16] defaultenv: base: add new devboot script
2026-03-18 9:50 ` Sascha Hauer
@ 2026-03-18 10:50 ` Ahmad Fatoum
2026-03-18 14:49 ` Sascha Hauer
0 siblings, 1 reply; 22+ messages in thread
From: Ahmad Fatoum @ 2026-03-18 10:50 UTC (permalink / raw)
To: Sascha Hauer; +Cc: barebox
On 3/18/26 10:50, Sascha Hauer wrote:
> On Thu, Mar 12, 2026 at 03:44:57PM +0100, Ahmad Fatoum wrote:
>> +The devboot script
>> +------------------
>> +
>> +The ``devboot`` command (``/env/bin/devboot``) automates the override
>> +workflow for network-based development:
>> +
>> +1. Brings up the network (``ifup -a1``).
>> +2. Changes into the fetch directory
>> + (:ref:`global.net.fetchdir <magicvar_global_net_fetchdir>`, default
>> + ``/mnt/tftp``).
>
> Is this default actually set somewhere? I can't find it.
global.net.fetchdir is defined in net/net.c since commit
4f328e47e5c6 ("net: make default netboot artifact directory configurable")
>
>> +3. Sources a configuration script named
>> + ``${global.user}-devboot-${global.hostname}``. If that file does not
>> + exist, it falls back to ``${global.user}-devboot-${global.arch}``.
>> +4. Translates the variables set by the script into ``boot -o`` arguments.
>> +5. Passes any extra arguments through to the ``boot`` command.
>> +
>> +.. note::
>> +
>> + TFTP is not a real file system, e.g., listing of directories is not
>> + possible. Keep that in mind if the devboot script does more than
>> + just fetch files by name from TFTP.
>> +
>> +Usage
>> +^^^^^
>> +
>> +.. code-block:: sh
>> +
>> + # Boot from MMC with devboot overrides
>> + devboot mmc
>> +
>> + # Boot from the default boot entry
>> + devboot
>> +
>> + # Make devboot the default for subsequent boots
>> + nv.boot.default=devel
>
> So that would be equivalent to a permanent "devboot". Is there also a
> way to specifiy permanent "devboot mmc"?
No, but it's clear to me this is a non-sense boot target as boot would
refer to boot.default... I'd just drop it from v2.
Please let me know when you are done with the review and I can resend.
Cheers,
Ahmad
>
> Sascha
>
--
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 |
^ permalink raw reply [flat|nested] 22+ messages in thread* Re: [PATCH 14/16] defaultenv: base: add new devboot script
2026-03-18 10:50 ` Ahmad Fatoum
@ 2026-03-18 14:49 ` Sascha Hauer
0 siblings, 0 replies; 22+ messages in thread
From: Sascha Hauer @ 2026-03-18 14:49 UTC (permalink / raw)
To: Ahmad Fatoum; +Cc: barebox
On Wed, Mar 18, 2026 at 11:50:42AM +0100, Ahmad Fatoum wrote:
> On 3/18/26 10:50, Sascha Hauer wrote:
> > On Thu, Mar 12, 2026 at 03:44:57PM +0100, Ahmad Fatoum wrote:
> >> +The devboot script
> >> +------------------
> >> +
> >> +The ``devboot`` command (``/env/bin/devboot``) automates the override
> >> +workflow for network-based development:
> >> +
> >> +1. Brings up the network (``ifup -a1``).
> >> +2. Changes into the fetch directory
> >> + (:ref:`global.net.fetchdir <magicvar_global_net_fetchdir>`, default
> >> + ``/mnt/tftp``).
> >
> > Is this default actually set somewhere? I can't find it.
>
> global.net.fetchdir is defined in net/net.c since commit
> 4f328e47e5c6 ("net: make default netboot artifact directory configurable")
Ah, I thought this is new and searched for it in this series.
> >
> > So that would be equivalent to a permanent "devboot". Is there also a
> > way to specifiy permanent "devboot mmc"?
>
> No, but it's clear to me this is a non-sense boot target as boot would
> refer to boot.default... I'd just drop it from v2.
>
> Please let me know when you are done with the review and I can resend.
I am done.
Sascha
--
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 |
^ permalink raw reply [flat|nested] 22+ messages in thread
* [PATCH 15/16] Documentation: user: devboot: add section on forwarding build dirs
2026-03-12 14:44 [PATCH 01/16] lib: add lazy loadable infrastructure for deferred boot component loading Ahmad Fatoum
` (12 preceding siblings ...)
2026-03-12 14:44 ` [PATCH 14/16] defaultenv: base: add new devboot script Ahmad Fatoum
@ 2026-03-12 14:44 ` Ahmad Fatoum
2026-03-12 14:44 ` [PATCH 16/16] libfile: remove file_to_sdram Ahmad Fatoum
2026-03-18 10:06 ` [PATCH 01/16] lib: add lazy loadable infrastructure for deferred boot component loading Sascha Hauer
15 siblings, 0 replies; 22+ messages in thread
From: Ahmad Fatoum @ 2026-03-12 14:44 UTC (permalink / raw)
To: barebox; +Cc: Ahmad Fatoum
In case the kernel is built on a remote build server, it can be useful
for devboot to fetch directly from there with the TFTP server running in
the local LAN. Add some documentation about that.
Signed-off-by: Ahmad Fatoum <a.fatoum@pengutronix.de>
---
Documentation/user/devboot.rst | 53 ++++++++++++++++++++++++++++++++++
1 file changed, 53 insertions(+)
diff --git a/Documentation/user/devboot.rst b/Documentation/user/devboot.rst
index ad1b4c909ab0..4425f0ebe91a 100644
--- a/Documentation/user/devboot.rst
+++ b/Documentation/user/devboot.rst
@@ -202,3 +202,56 @@ script is loaded. Make them persistent with:
``global.hostname`` is typically derived from the device tree, but can be
overridden.
+
+Forwarding a remote build directory over the internet
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+If the build server is not reachable from the Device-Under-Test, one
+possibility is to forward the build artifacts to a local TFTP server
+via SSHFS::
+
+ sshfs -o follow_symlinks,allow_other buildserver:/tftpboot /tftpboot
+
+The local development host can then export /tftpboot via TFTP.
+
+If the TFTP server is not running on the local development host, the
+``dpipe`` utility can be used to connect a local SFTP server process to
+an SSH session that runs ``sshfs`` in slave mode on the remote machine:
+
+.. code-block:: sh
+
+ dpipe /usr/lib/openssh/sftp-server = ssh a3f@tftpserver.in-my.lan sshfs -o slave,follow_symlinks,allow_other -o idmap=user -o gid=1001 :/tftpboot /tftpboot
+
+This works as follows:
+
+- ``dpipe`` connects the standard input/output of both sides of ``=``.
+- The left side runs the local SFTP server, giving the remote end access
+ to the local filesystem.
+- The right side runs ``sshfs`` on the TFTP server host in ``slave``
+ mode, reading SFTP protocol directly from stdin instead of spawning its
+ own SSH connection.
+- ``follow_symlinks`` resolves symlinks on the build host, so the TFTP
+ server sees regular files even if the build tree uses symlinks.
+- ``allow_other`` permits the TFTP daemon (which typically runs as a
+ different user) to read the mounted files.
+- ``idmap=user`` maps the remote user's UID to the local user, avoiding
+ permission issues.
+- ``gid=1001`` sets the group ID for all files (adjust to match the
+ group that the TFTP daemon runs as on the server, e.g. ``tftp`` or
+ ``nogroup``).
+- The colon prefix in ``:/tftpboot`` refers to the root of the *local*
+ (build host) filesystem as exported by the SFTP server.
+
+The result is that ``/tftpboot`` on the remote TFTP server mirrors the
+``/tftpboot`` directory on the build host. Build output can be
+symlinked there and the board will fetch it directly over TFTP.
+
+To undo the mount, terminate the ``dpipe`` process and run
+``fusermount -u /tftpboot`` on the TFTP server.
+
+.. note::
+
+ On Debian/Ubuntu, ``dpipe`` can be installed via ``apt install vde2``
+ ``sshfs`` and ``fuse`` must be installed on the TFTP server.
+ ``/etc/fuse.conf`` on the server must have ``user_allow_other``
+ enabled for ``allow_other`` to work.
--
2.47.3
^ permalink raw reply [flat|nested] 22+ messages in thread* [PATCH 16/16] libfile: remove file_to_sdram
2026-03-12 14:44 [PATCH 01/16] lib: add lazy loadable infrastructure for deferred boot component loading Ahmad Fatoum
` (13 preceding siblings ...)
2026-03-12 14:44 ` [PATCH 15/16] Documentation: user: devboot: add section on forwarding build dirs Ahmad Fatoum
@ 2026-03-12 14:44 ` Ahmad Fatoum
2026-03-18 10:06 ` [PATCH 01/16] lib: add lazy loadable infrastructure for deferred boot component loading Sascha Hauer
15 siblings, 0 replies; 22+ messages in thread
From: Ahmad Fatoum @ 2026-03-12 14:44 UTC (permalink / raw)
To: barebox; +Cc: Ahmad Fatoum
All users of file_to_sdram have now been switched to use
loadable_extract_into_sdram_all() or other loadable API, so it's now ok
to remove this function.
Signed-off-by: Ahmad Fatoum <a.fatoum@pengutronix.de>
---
include/libfile.h | 3 ---
lib/libfile.c | 66 -----------------------------------------------
2 files changed, 69 deletions(-)
diff --git a/include/libfile.h b/include/libfile.h
index c1e51a77b169..3f5ea5255af7 100644
--- a/include/libfile.h
+++ b/include/libfile.h
@@ -55,9 +55,6 @@ char *make_temp(const char *template);
int cache_file(const char *path, char **newpath);
-struct resource *file_to_sdram(const char *filename, unsigned long adr,
- enum resource_memtype memtype);
-
int fixup_path_case(int dirfd, const char **path);
int open_fdt(const char *filename, size_t *size);
diff --git a/lib/libfile.c b/lib/libfile.c
index 0670ef0584cb..cf78c70354d9 100644
--- a/lib/libfile.c
+++ b/lib/libfile.c
@@ -830,72 +830,6 @@ int __read_full_anywhere(int fd, void *buf, size_t size)
return now < 0 ? now : now + nbytes;
}
-#define BUFSIZ (PAGE_SIZE * 32)
-
-struct resource *file_to_sdram(const char *filename, unsigned long adr,
- enum resource_memtype memtype)
-{
- struct resource *res;
- unsigned memattrs;
- size_t size = BUFSIZ;
- size_t ofs = 0;
- ssize_t now;
- int fd;
-
- fd = open(filename, O_RDONLY);
- if (fd < 0)
- return NULL;
-
- /* FIXME: EFI payloads are started with MMU enabled, so for now
- * we keep attributes as RWX instead of remapping later on
- */
- memattrs = IS_ENABLED(CONFIG_EFI_LOADER) ? MEMATTRS_RWX : MEMATTRS_RW;
-
- while (1) {
-
- res = request_sdram_region("image", adr, size,
- memtype, memattrs);
- if (!res)
- goto out;
-
- if (zero_page_contains(res->start + ofs)) {
- void *tmp = malloc(BUFSIZ);
- if (!tmp)
- now = -ENOMEM;
- else
- now = read_full(fd, tmp, BUFSIZ);
-
- if (now > 0)
- zero_page_memcpy((void *)(res->start + ofs), tmp, now);
- free(tmp);
- } else {
- now = read_full(fd, (void *)(res->start + ofs), BUFSIZ);
- }
-
- if (now < 0) {
- release_sdram_region(res);
- res = NULL;
- goto out;
- }
-
- if (now < BUFSIZ) {
- release_sdram_region(res);
- res = request_sdram_region("image", adr, ofs + now,
- memtype, memattrs);
- goto out;
- }
-
- release_sdram_region(res);
-
- ofs += BUFSIZ;
- size += BUFSIZ;
- }
-out:
- close(fd);
-
- return res;
-}
-
int fixup_path_case(int fd, const char **path)
{
DIR *dir;
--
2.47.3
^ permalink raw reply [flat|nested] 22+ messages in thread* Re: [PATCH 01/16] lib: add lazy loadable infrastructure for deferred boot component loading
2026-03-12 14:44 [PATCH 01/16] lib: add lazy loadable infrastructure for deferred boot component loading Ahmad Fatoum
` (14 preceding siblings ...)
2026-03-12 14:44 ` [PATCH 16/16] libfile: remove file_to_sdram Ahmad Fatoum
@ 2026-03-18 10:06 ` Sascha Hauer
15 siblings, 0 replies; 22+ messages in thread
From: Sascha Hauer @ 2026-03-18 10:06 UTC (permalink / raw)
To: barebox, Ahmad Fatoum
On Thu, 12 Mar 2026 15:44:44 +0100, Ahmad Fatoum wrote:
> This adds a new "loadable" abstraction that allows boot components (kernel,
> initrd, FDT) to be represented without immediately loading their data.
> Metadata can be queried via get_info() and actual loading happens on
> demand via extract(), extract_into_buf() or mmap().
>
>
Applied, thanks!
[01/16] lib: add lazy loadable infrastructure for deferred boot component loading
https://git.pengutronix.de/cgit/barebox/commit/?id=b4a3f1da19d8 (link may not be stable)
[02/16] bootm: split preparatory step from handler invocation
https://git.pengutronix.de/cgit/barebox/commit/?id=7c5de879f9d0 (link may not be stable)
[03/16] boot: add bootm_boot wrapper that takes struct bootentry
https://git.pengutronix.de/cgit/barebox/commit/?id=797d4cf2115c (link may not be stable)
[04/16] bootchooser: pass along struct bootentry
https://git.pengutronix.de/cgit/barebox/commit/?id=d768a46f9960 (link may not be stable)
[05/16] bootm: switch plain file names case to loadable API
https://git.pengutronix.de/cgit/barebox/commit/?id=6c65dec5f7cc (link may not be stable)
[06/16] uimage: add offset parameter to uimage_load
https://git.pengutronix.de/cgit/barebox/commit/?id=8355a1a55aa3 (link may not be stable)
[07/16] bootm: uimage: switch to loadable API
https://git.pengutronix.de/cgit/barebox/commit/?id=3e6541814a3d (link may not be stable)
[08/16] bootm: fit: switch to new loadable API
https://git.pengutronix.de/cgit/barebox/commit/?id=cd86928a7b4a (link may not be stable)
[09/16] bootm: stash initial OS address/entry in image_data
https://git.pengutronix.de/cgit/barebox/commit/?id=55acd3ee34ec (link may not be stable)
[10/16] bootm: support multiple entries for bootm.initrd
https://git.pengutronix.de/cgit/barebox/commit/?id=d907c0987359 (link may not be stable)
[11/16] bootm: implement plain and FIT bootm.image override
https://git.pengutronix.de/cgit/barebox/commit/?id=10130dd5ff19 (link may not be stable)
[12/16] bootm: overrides: add support for overlays
https://git.pengutronix.de/cgit/barebox/commit/?id=7f66aaf6e6e4 (link may not be stable)
[13/16] test: py: add test for initrd concatenation
https://git.pengutronix.de/cgit/barebox/commit/?id=90a736b917f0 (link may not be stable)
[14/16] defaultenv: base: add new devboot script
https://git.pengutronix.de/cgit/barebox/commit/?id=7901159d712b (link may not be stable)
[15/16] Documentation: user: devboot: add section on forwarding build dirs
https://git.pengutronix.de/cgit/barebox/commit/?id=886de762c869 (link may not be stable)
[16/16] libfile: remove file_to_sdram
https://git.pengutronix.de/cgit/barebox/commit/?id=03d683fe8999 (link may not be stable)
Best regards,
--
Sascha Hauer <s.hauer@pengutronix.de>
^ permalink raw reply [flat|nested] 22+ messages in thread