* [PATCH 0/4] Linux bootconfig support
@ 2026-10-27 13:23 Steffen Trumtrar
2026-10-27 13:23 ` [PATCH 1/4] loadable: add loadable_from_buf() Steffen Trumtrar
` (3 more replies)
0 siblings, 4 replies; 5+ messages in thread
From: Steffen Trumtrar @ 2026-10-27 13:23 UTC (permalink / raw)
To: barebox, Sascha Hauer; +Cc: Steffen Trumtrar
Linux reads a boot configuration (bootconfig) from the end of the initrd:
kernel command line parameters (kernel.*), parameters for init (init.*)
and the setup of boot-time tracing (ftrace.*), in a structured text
format. Normally tools/bootconfig appends it to the initrd file when that
is built. This series lets barebox append it at boot time, so it can be
chosen per boot without rebuilding the initrd or changing the boot entry.
The bootconfig is a plain text file, given by global.bootm.bootconfig,
bootm -b, the boot override bootm.bootconfig or devboot_bootconfig.
barebox chains it as the last loadable behind all initrds, adds the
footer (size, checksum, magic) and puts "bootconfig" on the kernel
command line. Without an initrd, the bootconfig alone is passed as one.
For example tracing for a single boot with devboot or a boot override:
# /mnt/tftp/trace.bconf
ftrace.event.sched.sched_switch.enable
kernel.trace_buf_size = 4M
boot -o bootm.bootconfig=/mnt/tftp/trace.bconf mmc
The format follows Linux v7.3, the result is byte-identical to
tools/bootconfig -a. barebox does not parse the bootconfig, the kernel
checks the syntax and reports errors. Importing the parser from Linux
(lib/bootconfig.c) for a command that shows or checks a bootconfig could
follow if that is wanted.
Patch 1 adds loadable_from_buf(), a memory loadable that owns its buffer,
for the bootconfig built at boot time. Patch 2 is the bootm part, patch 3
the boot override, patch 4 the devboot variable.
Tested on QEMU aarch64 virt with dry runs (bootm -d, boot -d, devboot):
with and without an initrd, from global.bootm.bootconfig, bootm -b and
the override, the override replacing the variable and an empty override
removing it; the initrd in memory compared with tools/bootconfig -a of
Linux v7.3 byte for byte. The series builds with and without
CONFIG_BOOTM_BOOTCONFIG.
Example test run:
barebox@ARM QEMU virt64:/ devboot
Sourcing /mnt/tftp/str-devboot-virt64
boot -o bootm.image=str-linux-virt64 -o bootm.bootconfig=str-bootconfig-virt64
Booting entry 'NixOS 26.05.20261021.da6dc0e (virt64) (/mnt/9p/boot/loader/entries/virt64.conf)'
blspec: booting NixOS 26.05.20261021.da6dc0e (virt64) from none
NOTICE: [bootm override active] replacement OS: File(str-linux-virt64)
NOTICE: [bootm override active] replacement bootconfig: str-bootconfig-virt64
Loading ARM aarch64 Linux/EFI image 'str-linux-virt64'
commandline: console=ttyAMA0,115200n8
init=/nix/store/3kb5cxkdbi7w0pzdk5dn5pd97y20b76i-nixos-system-virt64-26.05.20261021.da6dc0e/init
console=ttyAMA0,115200 root=fstab loglevel=7 lsm=landlock,yama,bpf bootconfig
(...)
[ 0.000000] Load bootconfig: 69 bytes 8 nodes
(...)
bash-5.3# cat /proc/bootconfig
ftrace.event.sched.sched_switch.enable = ""
kernel.trace_buf_size = "4M"
# Parameters from bootloader:
# console=ttyAMA0,115200n8 init=/nix/store/71kswz7n3yn5xyhymbvryj4lsds2bqpq-nixos-system-virt64-26.05.20261021.da6dc0e/init
console=ttyAMA0,115200 ip=dhcp root=fstab loglevel=7 lsm=landlock,yama,bpf bootconfig
Signed-off-by: Steffen Trumtrar <s.trumtrar@pengutronix.de>
---
Steffen Trumtrar (4):
loadable: add loadable_from_buf()
bootm: append a Linux bootconfig to the initrd
boot: add bootm.bootconfig override
defaultenv: devboot: add devboot_bootconfig
Documentation/user/booting-linux.rst | 19 +++++
Documentation/user/devboot.rst | 22 ++++++
commands/boot.c | 5 +-
commands/bootm.c | 18 ++++-
common/Kconfig | 15 ++++
common/Makefile | 1 +
common/bootconfig.c | 129 +++++++++++++++++++++++++++++++
common/bootm-overrides.c | 23 +++++-
common/bootm.c | 48 +++++++++++-
defaultenv/defaultenv-2-base/bin/devboot | 6 +-
include/bootconfig.h | 27 +++++++
include/bootm-overrides.h | 3 +
include/bootm.h | 6 ++
include/loadable.h | 5 ++
lib/loadable-mem.c | 24 ++++++
lib/loadable.c | 2 +
16 files changed, 345 insertions(+), 8 deletions(-)
---
base-commit: 5c46c205c8d1a7c57b9dbaa5e516758a6c0a4d80
change-id: 20261027-v2026-10-0-topic-bootconfig-6e815125a5c9
Best regards,
--
Steffen Trumtrar <s.trumtrar@pengutronix.de>
^ permalink raw reply [flat|nested] 5+ messages in thread
* [PATCH 1/4] loadable: add loadable_from_buf()
2026-10-27 13:23 [PATCH 0/4] Linux bootconfig support Steffen Trumtrar
@ 2026-10-27 13:23 ` Steffen Trumtrar
2026-10-27 13:23 ` [PATCH 2/4] bootm: append a Linux bootconfig to the initrd Steffen Trumtrar
` (2 subsequent siblings)
3 siblings, 0 replies; 5+ messages in thread
From: Steffen Trumtrar @ 2026-10-27 13:23 UTC (permalink / raw)
To: barebox, Sascha Hauer; +Cc: Steffen Trumtrar
loadable_from_mem() leaves the memory to the caller, which then has to
keep it until the loadable is released, wherever that happens. Add a
variant that takes ownership of a malloc()ed buffer and frees it on
release, for data generated at boot time.
Assisted-by: Claude:claude-opus-5-5
Signed-off-by: Steffen Trumtrar <s.trumtrar@pengutronix.de>
---
include/loadable.h | 3 +++
lib/loadable-mem.c | 24 ++++++++++++++++++++++++
2 files changed, 27 insertions(+)
diff --git a/include/loadable.h b/include/loadable.h
index 9cc89ea458..6ab1692c5d 100644
--- a/include/loadable.h
+++ b/include/loadable.h
@@ -254,6 +254,9 @@ void loadable_release(struct loadable **l);
__returns_nonnull struct loadable *
loadable_from_mem(const void *mem, size_t size, enum loadable_type type);
+__returns_nonnull struct loadable *
+loadable_from_buf(void *buf, size_t size, enum loadable_type type);
+
__returns_nonnull struct loadable *
loadable_from_file(const char *path, enum loadable_type type);
diff --git a/lib/loadable-mem.c b/lib/loadable-mem.c
index 4e697acc0b..a7f7bca8db 100644
--- a/lib/loadable-mem.c
+++ b/lib/loadable-mem.c
@@ -8,6 +8,7 @@
struct mem_loadable_priv {
const void *start;
size_t size;
+ void *owned;
};
static int mem_loadable_get_info(struct loadable *l, struct loadable_info *info)
@@ -80,6 +81,7 @@ static void mem_loadable_release(struct loadable *l)
{
struct mem_loadable_priv *priv = l->priv;
+ free(priv->owned);
free(priv);
}
@@ -125,3 +127,25 @@ struct loadable *loadable_from_mem(const void *mem, size_t size,
return l;
}
+
+/**
+ * loadable_from_buf - create a loadable owning a buffer
+ * @buf: buffer allocated with malloc()
+ * @size: size of the buffer in bytes
+ * @type: type of loadable (LOADABLE_KERNEL, LOADABLE_INITRD, etc.)
+ *
+ * Like loadable_from_mem(), but the loadable takes ownership of @buf and
+ * frees it in loadable_release().
+ *
+ * Return: pointer to allocated loadable (never fails due to xzalloc)
+ */
+struct loadable *loadable_from_buf(void *buf, size_t size,
+ enum loadable_type type)
+{
+ struct loadable *l = loadable_from_mem(buf, size, type);
+ struct mem_loadable_priv *priv = l->priv;
+
+ priv->owned = buf;
+
+ return l;
+}
--
2.56.0
^ permalink raw reply [flat|nested] 5+ messages in thread
* [PATCH 2/4] bootm: append a Linux bootconfig to the initrd
2026-10-27 13:23 [PATCH 0/4] Linux bootconfig support Steffen Trumtrar
2026-10-27 13:23 ` [PATCH 1/4] loadable: add loadable_from_buf() Steffen Trumtrar
@ 2026-10-27 13:23 ` Steffen Trumtrar
2026-10-27 13:23 ` [PATCH 3/4] boot: add bootm.bootconfig override Steffen Trumtrar
2026-10-27 13:23 ` [PATCH 4/4] defaultenv: devboot: add devboot_bootconfig Steffen Trumtrar
3 siblings, 0 replies; 5+ messages in thread
From: Steffen Trumtrar @ 2026-10-27 13:23 UTC (permalink / raw)
To: barebox, Sascha Hauer; +Cc: Steffen Trumtrar
Linux reads a boot configuration (bootconfig, see
Documentation/admin-guide/bootconfig.rst) from the end of the initrd:
keys for the kernel command line, for init, and for boot-time tracing,
without changing the image or the boot entry. tools/bootconfig appends it
to an initrd file; with this, barebox does that at boot time.
global.bootm.bootconfig or bootm -b names a text file. barebox appends
it with the footer (size, checksum, magic) as the last loadable of the
initrd chain, after all initrds, and adds "bootconfig" to the kernel
command line. It is chained only in bootm_load_initrd(), as FIT, uImage
and overrides may replace the initrd until then. Without an initrd, the
bootconfig alone is passed as one; the kernel removes it and is left
with an empty initrd.
The format follows Linux v7.3 (c03c1a14507d), no code is taken from it:
magic and size limit (XBC_DATA_MAX) from include/linux/bootconfig.h,
checksum and padding as apply_xbc() in tools/bootconfig/main.c writes
them, read by get_boot_config_from_initrd() in init/main.c. As there, the
padding makes the initrd end 4-byte aligned; it depends on the size of
the initrd and is added once that is loaded. Kernels before v7.0 read the
footer as u32, 499f86de4f8c ("init/main: read bootconfig header with
get_unaligned_le32()") made that unaligned. The result is identical to
tools/bootconfig -a of v7.3. The syntax is checked by the kernel, not
here.
Assisted-by: Claude:claude-opus-5-5
Signed-off-by: Steffen Trumtrar <s.trumtrar@pengutronix.de>
---
Documentation/user/booting-linux.rst | 19 ++++++
commands/bootm.c | 18 ++++-
common/Kconfig | 15 ++++
common/Makefile | 1 +
common/bootconfig.c | 129 +++++++++++++++++++++++++++++++++++
common/bootm.c | 48 ++++++++++++-
include/bootconfig.h | 27 ++++++++
include/bootm.h | 5 ++
include/loadable.h | 2 +
lib/loadable.c | 2 +
10 files changed, 262 insertions(+), 4 deletions(-)
diff --git a/Documentation/user/booting-linux.rst b/Documentation/user/booting-linux.rst
index 32a731bfd2..11c26e663c 100644
--- a/Documentation/user/booting-linux.rst
+++ b/Documentation/user/booting-linux.rst
@@ -63,6 +63,25 @@ To use an initramfs, use the ``-r`` option or the
global.bootm.image=/path/to/zImage
bootm
+With ``CONFIG_BOOTM_BOOTCONFIG``, a Linux boot configuration
+(`bootconfig <https://docs.kernel.org/admin-guide/bootconfig.html>`_) can be
+appended to the initrd with the ``-b`` option or the
+:ref:`global.bootm.bootconfig <magicvar_global_bootm_bootconfig>` variable.
+The file is plain text, barebox adds the footer the kernel looks for and
+``bootconfig`` to the kernel command line. Without an initrd, the bootconfig
+alone is passed as one. The kernel needs ``CONFIG_BOOT_CONFIG``:
+
+.. code-block:: sh
+
+ bootm -r /path/to/initrd -b /path/to/bootconfig /path/to/Image
+
+ # same as:
+
+ global.bootm.initrd=/path/to/initrd
+ global.bootm.bootconfig=/path/to/bootconfig
+ global.bootm.image=/path/to/Image
+ bootm
+
FIT image configurations will be matched by comparing the ``compatible`` property
inside the configuration node with the barebox live tree's ``/compatible``.
It's also possible to select a specific configuration explicitly:
diff --git a/commands/bootm.c b/commands/bootm.c
index 44abb953f6..391d51292a 100644
--- a/commands/bootm.c
+++ b/commands/bootm.c
@@ -31,9 +31,15 @@
#define BOOTM_OPTS_COMMON "a:e:vo:fd"
#ifdef CONFIG_BOOTM_INITRD
-#define BOOTM_OPTS BOOTM_OPTS_COMMON "L:r:"
+#define BOOTM_OPTS_INITRD BOOTM_OPTS_COMMON "L:r:"
#else
-#define BOOTM_OPTS BOOTM_OPTS_COMMON
+#define BOOTM_OPTS_INITRD BOOTM_OPTS_COMMON
+#endif
+
+#ifdef CONFIG_BOOTM_BOOTCONFIG
+#define BOOTM_OPTS BOOTM_OPTS_INITRD "b:"
+#else
+#define BOOTM_OPTS BOOTM_OPTS_INITRD
#endif
static unsigned command_attempts;
@@ -62,6 +68,11 @@ static int do_bootm(int argc, char *argv[])
case 'r':
data.initrd_file = optarg;
break;
+#endif
+#ifdef CONFIG_BOOTM_BOOTCONFIG
+ case 'b':
+ data.bootconfig_file = optarg;
+ break;
#endif
case 'a':
data.os_address = simple_strtoul(optarg, NULL, 0);
@@ -112,6 +123,9 @@ BAREBOX_CMD_HELP_OPT ("-f\t", "load images even if type is undetectable")
BAREBOX_CMD_HELP_OPT ("-r INITRD","specify an initrd image")
BAREBOX_CMD_HELP_OPT ("-L ADDR\t","specify initrd load address")
#endif
+#ifdef CONFIG_BOOTM_BOOTCONFIG
+BAREBOX_CMD_HELP_OPT ("-b FILE\t","append Linux bootconfig FILE to the initrd")
+#endif
BAREBOX_CMD_HELP_OPT ("-a ADDR\t","specify os load address")
BAREBOX_CMD_HELP_OPT ("-e OFFS\t","entry point to the image relative to start (0)")
#ifdef CONFIG_OFTREE
diff --git a/common/Kconfig b/common/Kconfig
index 9adecfd2e4..5ae8b4302c 100644
--- a/common/Kconfig
+++ b/common/Kconfig
@@ -706,6 +706,21 @@ config BOOTM_INITRD
-r INITRD specify an initrd image
-L ADDR specify initrd load address
+config BOOTM_BOOTCONFIG
+ bool
+ prompt "Linux boot configuration (bootconfig) support"
+ depends on BOOTM_INITRD
+ help
+ Append a Linux boot configuration (bootconfig, see
+ Documentation/admin-guide/bootconfig.rst in Linux) to the initrd,
+ from global.bootm.bootconfig or the bootm option:
+
+ -b FILE append FILE as bootconfig to the initrd
+
+ Without an initrd, the bootconfig alone is passed as one.
+ "bootconfig" is added to the kernel command line. The kernel needs
+ CONFIG_BOOT_CONFIG.
+
config BOOTM_OFTREE
def_bool y
depends on BOOTM && HAVE_ARCH_BOOTM_OFTREE
diff --git a/common/Makefile b/common/Makefile
index b1045c3acb..31f562c9ea 100644
--- a/common/Makefile
+++ b/common/Makefile
@@ -29,6 +29,7 @@ obj-$(CONFIG_BINFMT) += binfmt.o
obj-$(CONFIG_BLOCK) += block.o
obj-$(CONFIG_BLSPEC) += blspec.o
obj-$(CONFIG_BOOTM) += bootm.o booti.o
+obj-$(CONFIG_BOOTM_BOOTCONFIG) += bootconfig.o
obj-$(CONFIG_BOOTM_AIMAGE) += bootm-android-image.o
obj-$(CONFIG_BOOT_OVERRIDE) += bootm-overrides.o
obj-$(CONFIG_CMD_LOADS) += s_record.o
diff --git a/common/bootconfig.c b/common/bootconfig.c
new file mode 100644
index 0000000000..8c5cab5fb3
--- /dev/null
+++ b/common/bootconfig.c
@@ -0,0 +1,129 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Linux boot configuration (bootconfig): a text file the kernel reads from
+ * the end of the initrd, see Documentation/admin-guide/bootconfig.rst in
+ * Linux. barebox appends it as the last loadable of the initrd chain, so its
+ * footer ends up right at the end of the initrd handed to the kernel. The
+ * kernel only looks for it with "bootconfig" on its command line (or
+ * CONFIG_BOOT_CONFIG_FORCE), bootm adds that.
+ *
+ * The format is the one of Linux v7.3: magic and size limit from
+ * include/linux/bootconfig.h, checksum and padding as apply_xbc() in
+ * tools/bootconfig/main.c writes them, read by get_boot_config_from_initrd()
+ * in init/main.c. No code is taken from there.
+ */
+#define pr_fmt(fmt) "bootconfig: " fmt
+
+#include <common.h>
+#include <bootconfig.h>
+#include <fs.h>
+#include <libfile.h>
+#include <loadable.h>
+#include <linux/ioport.h>
+#include <linux/kernel.h>
+
+#define BOOTCONFIG_MAGIC "#BOOTCONFIG\n"
+#define BOOTCONFIG_MAGIC_LEN 12
+#define BOOTCONFIG_ALIGN 4
+/* XBC_DATA_MAX in Linux: largest size in the footer, padding included */
+#define BOOTCONFIG_DATA_MAX 32767
+
+struct bootconfig_footer {
+ __le32 size;
+ __le32 csum;
+ char magic[BOOTCONFIG_MAGIC_LEN];
+} __packed;
+
+/**
+ * bootconfig_loadable - read a boot configuration for the initrd
+ * @path: file with the boot configuration (text)
+ *
+ * Builds what tools/bootconfig in Linux appends to an initrd: the text with
+ * a terminating NUL, then size, checksum and magic. The padding depends on
+ * the size of the initrd, bootconfig_align() adds it once loaded behind it.
+ * The syntax is checked by the kernel, not here.
+ *
+ * Return: loadable for loadable_chain() onto the initrd, or an error pointer
+ */
+struct loadable *bootconfig_loadable(const char *path)
+{
+ struct bootconfig_footer *footer;
+ struct loadable *l;
+ size_t len, size;
+ char *buf;
+ u32 csum = 0;
+ int ret, i;
+
+ ret = read_file_2(path, &len, (void **)&buf, FILESIZE_MAX);
+ if (ret) {
+ pr_err("%s: %pe\n", path, ERR_PTR(ret));
+ return ERR_PTR(ret);
+ }
+
+ /* read_file_2() zeroes behind the data: buf[len] is the NUL */
+ len = strnlen(buf, len);
+ size = len + 1;
+ /* room for the padding bootconfig_align() may add */
+ if (size + BOOTCONFIG_ALIGN - 1 > BOOTCONFIG_DATA_MAX) {
+ pr_err("%s: %zu bytes, the kernel accepts at most %d\n",
+ path, size, BOOTCONFIG_DATA_MAX - (BOOTCONFIG_ALIGN - 1));
+ free(buf);
+ return ERR_PTR(-E2BIG);
+ }
+
+ buf = xrealloc(buf, size + sizeof(*footer));
+
+ for (i = 0; i < size; i++)
+ csum += (u8)buf[i];
+
+ footer = (void *)buf + size;
+ footer->size = cpu_to_le32(size);
+ footer->csum = cpu_to_le32(csum);
+ memcpy(footer->magic, BOOTCONFIG_MAGIC, BOOTCONFIG_MAGIC_LEN);
+
+ l = loadable_from_buf(buf, size + sizeof(*footer), LOADABLE_BOOTCONFIG);
+ free(l->name);
+ l->name = xstrdup(path);
+
+ return l;
+}
+
+/**
+ * bootconfig_align - align the bootconfig loaded at the end of an initrd
+ * @res: initrd in SDRAM, ending with the bootconfig
+ * @end_address: last address the initrd may use
+ *
+ * tools/bootconfig in Linux pads the bootconfig so that the initrd ends
+ * 4-byte aligned: kernels before v7.0 read the footer as u32 (since
+ * 499f86de4f8c "init/main: read bootconfig header with get_unaligned_le32()"
+ * they also take it unaligned). The size of the initrd before it is only
+ * known now: add the padding by moving the footer up to 3 bytes further.
+ * The size in the footer includes the padding, the checksum does not change
+ * (the padding is zero).
+ *
+ * Return: 0 on success, negative error code otherwise
+ */
+int bootconfig_align(struct resource *res, unsigned long end_address)
+{
+ void *end = (void *)(unsigned long)(res->end + 1);
+ struct bootconfig_footer *footer = end - sizeof(*footer);
+ unsigned int pad = -(res->end + 1) & (BOOTCONFIG_ALIGN - 1);
+ int ret;
+
+ if (!pad)
+ return 0;
+
+ if (res->end + pad > end_address)
+ return -ENOSPC;
+
+ ret = resize_region(res, resource_size(res) + pad);
+ if (ret)
+ return ret;
+
+ memmove((void *)footer + pad, footer, sizeof(*footer));
+ memset(footer, 0, pad);
+ footer = (void *)footer + pad;
+ footer->size = cpu_to_le32(le32_to_cpu(footer->size) + pad);
+
+ return 0;
+}
diff --git a/common/bootm.c b/common/bootm.c
index 27da1a590b..a8ac6bea21 100644
--- a/common/bootm.c
+++ b/common/bootm.c
@@ -3,6 +3,7 @@
#include <common.h>
#include <bootargs.h>
#include <bootm.h>
+#include <bootconfig.h>
#include <fs.h>
#include <fcntl.h>
#include <efi/mode.h>
@@ -101,6 +102,8 @@ void bootm_data_init_defaults(struct bootm_data *data)
getenv_ul("global.bootm.initrd.loadaddr", &data->initrd_address);
data->initrd_file = getenv_nonempty("global.bootm.initrd");
}
+ if (IS_ENABLED(CONFIG_BOOTM_BOOTCONFIG))
+ data->bootconfig_file = getenv_nonempty("global.bootm.bootconfig");
data->root_dev = getenv_nonempty("global.bootm.root_dev");
data->root_param = getenv_nonempty("global.bootm.root_param");
data->verify = bootm_get_verify_mode();
@@ -122,6 +125,8 @@ void bootm_data_restore_defaults(const struct bootm_data *data)
pr_setenv("global.bootm.initrd.loadaddr", "0x%lx", data->initrd_address);
globalvar_set("bootm.initrd", data->initrd_file);
}
+ if (IS_ENABLED(CONFIG_BOOTM_BOOTCONFIG))
+ globalvar_set("bootm.bootconfig", data->bootconfig_file);
globalvar_set("bootm.root_dev", data->root_dev);
globalvar_set("bootm.root_param", data->root_param);
bootm_set_verify_mode(data->verify);
@@ -265,6 +270,7 @@ const struct resource *
bootm_load_initrd(struct image_data *data, ulong load_address, ulong end_address)
{
struct resource *res = NULL;
+ bool bootconfig = false;
if (!IS_ENABLED(CONFIG_BOOTM_INITRD))
return NULL;
@@ -275,6 +281,18 @@ bootm_load_initrd(struct image_data *data, ulong load_address, ulong end_address
if (WARN_ON(data->initrd_res))
return data->initrd_res;
+ /*
+ * Last in the chain, after all initrds: the kernel looks for the
+ * bootconfig footer at the end of the initrd. Chained only now, as
+ * FIT, uImage and overrides may replace the initrd until here.
+ */
+ if (data->bootconfig) {
+ loadable_chain(&data->initrd, data->bootconfig);
+ data->bootconfig = NULL;
+ bootconfig = true;
+ globalvar_add_simple(LINUX_BOOTARGS_BOOTM_LATE "bootconfig", "bootconfig");
+ }
+
if (!data->initrd)
return NULL;
@@ -282,8 +300,19 @@ bootm_load_initrd(struct image_data *data, ulong load_address, ulong end_address
return ERR_PTR(-EINVAL);
res = loadable_extract_into_sdram_all(data->initrd, load_address, end_address);
- if (!IS_ERR(res))
- data->initrd_res = res;
+ if (IS_ERR_OR_NULL(res))
+ return res;
+
+ if (bootconfig) {
+ int ret = bootconfig_align(res, end_address);
+
+ if (ret) {
+ release_sdram_region(res);
+ return ERR_PTR(ret);
+ }
+ }
+
+ data->initrd_res = res;
return res;
}
@@ -623,6 +652,16 @@ struct image_data *bootm_boot_prep(const struct bootm_data *bootm_data)
goto err_out;
}
+ if (IS_ENABLED(CONFIG_BOOTM_BOOTCONFIG) && bootm_data->bootconfig_file) {
+ data->bootconfig_file = xstrdup(bootm_data->bootconfig_file);
+ data->bootconfig = bootconfig_loadable(data->bootconfig_file);
+ if (IS_ERR(data->bootconfig)) {
+ ret = PTR_ERR(data->bootconfig);
+ data->bootconfig = NULL;
+ goto err_out;
+ }
+ }
+
if (bootm_data->appendroot) {
const char *root = NULL;
const char *rootopts = NULL;
@@ -798,6 +837,7 @@ void bootm_boot_cleanup(struct image_data *data)
release_sdram_region(data->initrd_res);
release_sdram_region(data->oftree_res);
loadable_release(&data->oftree);
+ loadable_release(&data->bootconfig);
loadable_release(&data->initrd);
loadable_release(&data->os);
if (data->of_root_node)
@@ -808,6 +848,7 @@ void bootm_boot_cleanup(struct image_data *data)
free(data->os_file);
free(data->oftree_file);
free(data->initrd_file);
+ free(data->bootconfig_file);
free(data);
}
@@ -879,6 +920,8 @@ static int bootm_init(void)
globalvar_add_simple("bootm.initrd", NULL);
globalvar_add_simple("bootm.initrd.loadaddr", NULL);
}
+ if (IS_ENABLED(CONFIG_BOOTM_BOOTCONFIG))
+ globalvar_add_simple("bootm.bootconfig", NULL);
globalvar_add_simple_bool("bootm.dryrun", &bootm_dryrun);
globalvar_add_simple_int("bootm.verbose", &bootm_verbosity, "%u");
@@ -911,6 +954,7 @@ BAREBOX_MAGICVAR(global.bootm.image, "bootm default boot image");
BAREBOX_MAGICVAR(global.bootm.image.loadaddr, "bootm default boot image loadaddr");
BAREBOX_MAGICVAR(global.bootm.initrd, "bootm default initrd");
BAREBOX_MAGICVAR(global.bootm.initrd.loadaddr, "bootm default initrd loadaddr");
+BAREBOX_MAGICVAR(global.bootm.bootconfig, "bootm default Linux bootconfig, appended to the initrd");
BAREBOX_MAGICVAR(global.bootm.oftree, "bootm default oftree");
BAREBOX_MAGICVAR(global.bootm.dryrun, "bootm default dryrun level");
BAREBOX_MAGICVAR(global.bootm.verify, "bootm default verify level");
diff --git a/include/bootconfig.h b/include/bootconfig.h
new file mode 100644
index 0000000000..37ef8e0580
--- /dev/null
+++ b/include/bootconfig.h
@@ -0,0 +1,27 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+#ifndef __BOOTCONFIG_H
+#define __BOOTCONFIG_H
+
+#include <linux/err.h>
+#include <linux/types.h>
+
+struct loadable;
+struct resource;
+
+#ifdef CONFIG_BOOTM_BOOTCONFIG
+struct loadable *bootconfig_loadable(const char *path);
+int bootconfig_align(struct resource *res, unsigned long end_address);
+#else
+static inline struct loadable *bootconfig_loadable(const char *path)
+{
+ return ERR_PTR(-ENOSYS);
+}
+
+static inline int bootconfig_align(struct resource *res,
+ unsigned long end_address)
+{
+ return -ENOSYS;
+}
+#endif
+
+#endif /* __BOOTCONFIG_H */
diff --git a/include/bootm.h b/include/bootm.h
index 946713971e..134b01d453 100644
--- a/include/bootm.h
+++ b/include/bootm.h
@@ -24,6 +24,7 @@ struct bootm_data {
const char *os_file;
const char *initrd_file;
const char *oftree_file;
+ const char *bootconfig_file;
const char *root_dev;
const char *root_param;
int verbose;
@@ -111,6 +112,10 @@ struct image_data {
unsigned long initrd_address;
+ /* Linux bootconfig, appended to the initrd by bootm_load_initrd() */
+ char *bootconfig_file;
+ struct loadable *bootconfig;
+
char *oftree_file;
char *oftree_part;
diff --git a/include/loadable.h b/include/loadable.h
index 6ab1692c5d..489c0ef7d8 100644
--- a/include/loadable.h
+++ b/include/loadable.h
@@ -17,12 +17,14 @@ struct loadable;
* @LOADABLE_KERNEL: kernel image
* @LOADABLE_INITRD: initial ramdisk
* @LOADABLE_FDT: flattened device tree
+ * @LOADABLE_BOOTCONFIG: Linux boot configuration, appended to the initrd
*/
enum loadable_type {
LOADABLE_UNSPECIFIED,
LOADABLE_KERNEL,
LOADABLE_INITRD,
LOADABLE_FDT,
+ LOADABLE_BOOTCONFIG,
};
/**
diff --git a/lib/loadable.c b/lib/loadable.c
index 8c016c125d..b410ef477c 100644
--- a/lib/loadable.c
+++ b/lib/loadable.c
@@ -31,6 +31,8 @@ const char *loadable_type_tostr(enum loadable_type type)
return "initrd";
case LOADABLE_FDT:
return "fdt";
+ case LOADABLE_BOOTCONFIG:
+ return "bootconfig";
default:
return NULL;
}
--
2.56.0
^ permalink raw reply [flat|nested] 5+ messages in thread
* [PATCH 3/4] boot: add bootm.bootconfig override
2026-10-27 13:23 [PATCH 0/4] Linux bootconfig support Steffen Trumtrar
2026-10-27 13:23 ` [PATCH 1/4] loadable: add loadable_from_buf() Steffen Trumtrar
2026-10-27 13:23 ` [PATCH 2/4] bootm: append a Linux bootconfig to the initrd Steffen Trumtrar
@ 2026-10-27 13:23 ` Steffen Trumtrar
2026-10-27 13:23 ` [PATCH 4/4] defaultenv: devboot: add devboot_bootconfig Steffen Trumtrar
3 siblings, 0 replies; 5+ messages in thread
From: Steffen Trumtrar @ 2026-10-27 13:23 UTC (permalink / raw)
To: barebox, Sascha Hauer; +Cc: Steffen Trumtrar
boot -o bootm.bootconfig=FILE replaces the bootconfig a boot entry would
get from global.bootm.bootconfig, an empty value removes it. Together
with the other overrides this changes kernel parameters, init options or
tracing for one boot of an existing entry.
Assisted-by: Claude:claude-opus-5-5
Signed-off-by: Steffen Trumtrar <s.trumtrar@pengutronix.de>
---
Documentation/user/devboot.rst | 17 +++++++++++++++++
commands/boot.c | 5 ++++-
common/bootm-overrides.c | 23 +++++++++++++++++++++--
include/bootm-overrides.h | 3 +++
include/bootm.h | 1 +
5 files changed, 46 insertions(+), 3 deletions(-)
diff --git a/Documentation/user/devboot.rst b/Documentation/user/devboot.rst
index e319636994..fce8398b22 100644
--- a/Documentation/user/devboot.rst
+++ b/Documentation/user/devboot.rst
@@ -105,6 +105,23 @@ Override rules
mount -n --bind /lib/modules ${ROOT_MOUNT}/lib/modules
+``bootm.bootconfig``
+ A Linux bootconfig file (``CONFIG_BOOTM_BOOTCONFIG``), appended to the
+ initrd after all initrds, or passed alone as the initrd if there is
+ none, see :ref:`global.bootm.bootconfig
+ <magicvar_global_bootm_bootconfig>`. It replaces the bootconfig the boot
+ entry would get from the variable; an empty string removes it. This
+ configures the kernel and init without touching the boot entry's
+ command line or the root filesystem, e.g. tracing for one boot:
+
+ .. code-block:: sh
+
+ # /mnt/tftp/trace.bconf
+ ftrace.event.sched.sched_switch.enable
+ kernel.trace_buf_size = 4M
+
+ boot -o bootm.bootconfig=/mnt/tftp/trace.bconf mmc
+
.. note::
When secure boot is enforced (``bootm_signed_images_are_forced()``),
diff --git a/commands/boot.c b/commands/boot.c
index cc7a64bcca..bd09b90901 100644
--- a/commands/boot.c
+++ b/commands/boot.c
@@ -49,6 +49,9 @@ static int boot_add_override(struct bootm_overrides *overrides, char *var)
overrides->oftree_file = val;
} else if (!strcmp(var, "bootm.initrd")) {
overrides->initrd_file = val;
+ } else if (IS_ENABLED(CONFIG_BOOTM_BOOTCONFIG) &&
+ !strcmp(var, "bootm.bootconfig")) {
+ overrides->bootconfig_file = val;
} else {
return -EINVAL;
}
@@ -241,7 +244,7 @@ BAREBOX_CMD_HELP_OPT ("-m","Show a menu with boot options")
BAREBOX_CMD_HELP_OPT ("-M DEFAULT","Show a menu with boot options with entry DEFAULT preselected")
BAREBOX_CMD_HELP_OPT ("-w SECS","Start watchdog with timeout SECS before booting")
#ifdef CONFIG_BOOT_OVERRIDE
-BAREBOX_CMD_HELP_OPT ("-o VAR[=VAL]","override VAR (bootm.{oftree,initrd}) with VAL")
+BAREBOX_CMD_HELP_OPT ("-o VAR[=VAL]","override VAR (bootm.{oftree,initrd,bootconfig}) with VAL")
BAREBOX_CMD_HELP_OPT (" ","if VAL is not specified, the value of VAR is taken")
#endif
BAREBOX_CMD_HELP_OPT ("-t SECS","specify timeout in SECS")
diff --git a/common/bootm-overrides.c b/common/bootm-overrides.c
index 720d5636f3..f02a037b13 100644
--- a/common/bootm-overrides.c
+++ b/common/bootm-overrides.c
@@ -3,6 +3,7 @@
#include <bootm.h>
#include <bootm-overrides.h>
#include <bootm-fit.h>
+#include <bootconfig.h>
#include <init.h>
#include <libfile.h>
#include <of.h>
@@ -107,6 +108,8 @@ static void report_active_overrides(const struct image_data *data)
report_active_override("initrd", data->initrd);
if (data->is_override.oftree)
report_active_override("FDT", data->oftree);
+ if (data->is_override.bootconfig)
+ report_active_override("bootconfig", data->bootconfig);
}
/**
@@ -114,8 +117,9 @@ static void report_active_overrides(const struct image_data *data)
* @data: image data context
* @overrides: overrides to apply
*
- * Applies bootm.image, bootm.initrd, and bootm.oftree overrides by translating
- * them into file-based loadables or FIT image replacements.
+ * Applies bootm.image, bootm.initrd, bootm.oftree and bootm.bootconfig
+ * 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
@@ -143,6 +147,21 @@ int bootm_apply_overrides(struct image_data *data,
data->is_override.initrd = true;
}
+ if (IS_ENABLED(CONFIG_BOOTM_BOOTCONFIG) && overrides->bootconfig_file) {
+ /* an empty bootconfig_file removes the bootconfig */
+ loadable_release(&data->bootconfig);
+ if (nonempty(overrides->bootconfig_file)) {
+ data->bootconfig = bootconfig_loadable(overrides->bootconfig_file);
+ if (IS_ERR(data->bootconfig)) {
+ ret = PTR_ERR(data->bootconfig);
+
+ data->bootconfig = NULL;
+ return ret;
+ }
+ }
+ data->is_override.bootconfig = true;
+ }
+
if (overrides->oftree_file) {
int ret = loadables_from_files(&data->oftree,
overrides->oftree_file, ":",
diff --git a/include/bootm-overrides.h b/include/bootm-overrides.h
index 0dbf6e7fa8..fde543a8e4 100644
--- a/include/bootm-overrides.h
+++ b/include/bootm-overrides.h
@@ -6,6 +6,7 @@ struct bootm_overrides {
const char *os_file;
const char *oftree_file;
const char *initrd_file;
+ const char *bootconfig_file;
};
struct image_data;
@@ -21,6 +22,8 @@ static inline void bootm_merge_overrides(struct bootm_overrides *dst,
dst->oftree_file = src->oftree_file;
if (src->initrd_file)
dst->initrd_file = src->initrd_file;
+ if (src->bootconfig_file)
+ dst->bootconfig_file = src->bootconfig_file;
}
int bootm_apply_overrides(struct image_data *data,
diff --git a/include/bootm.h b/include/bootm.h
index 134b01d453..9038ba7300 100644
--- a/include/bootm.h
+++ b/include/bootm.h
@@ -148,6 +148,7 @@ struct image_data {
u8 os:1;
u8 initrd:1;
u8 oftree:1;
+ u8 bootconfig:1;
} is_override;
enum bootm_efi_mode efi_boot;
};
--
2.56.0
^ permalink raw reply [flat|nested] 5+ messages in thread
* [PATCH 4/4] defaultenv: devboot: add devboot_bootconfig
2026-10-27 13:23 [PATCH 0/4] Linux bootconfig support Steffen Trumtrar
` (2 preceding siblings ...)
2026-10-27 13:23 ` [PATCH 3/4] boot: add bootm.bootconfig override Steffen Trumtrar
@ 2026-10-27 13:23 ` Steffen Trumtrar
3 siblings, 0 replies; 5+ messages in thread
From: Steffen Trumtrar @ 2026-10-27 13:23 UTC (permalink / raw)
To: barebox, Sascha Hauer; +Cc: Steffen Trumtrar
Passed on as -o bootm.bootconfig, like devboot_initrd.
Assisted-by: Claude:claude-opus-5-5
Signed-off-by: Steffen Trumtrar <s.trumtrar@pengutronix.de>
---
Documentation/user/devboot.rst | 5 +++++
defaultenv/defaultenv-2-base/bin/devboot | 6 +++++-
2 files changed, 10 insertions(+), 1 deletion(-)
diff --git a/Documentation/user/devboot.rst b/Documentation/user/devboot.rst
index fce8398b22..ec676f2998 100644
--- a/Documentation/user/devboot.rst
+++ b/Documentation/user/devboot.rst
@@ -177,6 +177,11 @@ variables:
Override for ``bootm.initrd``. A leading colon appends to the boot
entry's existing initrd.
+``devboot_bootconfig``
+ Override for ``bootm.bootconfig``: a Linux bootconfig file, appended to
+ the initrd or, without one, passed alone as the initrd
+ (``CONFIG_BOOTM_BOOTCONFIG``). An empty string removes it.
+
Variables that are not set (using ``[[ -v ... ]]``) are left alone,
so unset variables do not generate override arguments.
diff --git a/defaultenv/defaultenv-2-base/bin/devboot b/defaultenv/defaultenv-2-base/bin/devboot
index 1a43246337..92f98c6f00 100644
--- a/defaultenv/defaultenv-2-base/bin/devboot
+++ b/defaultenv/defaultenv-2-base/bin/devboot
@@ -14,7 +14,7 @@ if [ ! -f "${devboot_script}" ]; then
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"
+ echo " devboot_image, devboot_initrd, devboot_oftree, devboot_bootconfig"
cd "${saved_pwd}"
exit 1
fi
@@ -42,6 +42,10 @@ if [[ -v devboot_initrd ]]; then
override_args="${override_args} -o bootm.initrd=\"${devboot_initrd}\""
fi
+if [[ -v devboot_bootconfig ]]; then
+ override_args="${override_args} -o bootm.bootconfig=\"${devboot_bootconfig}\""
+fi
+
echo boot ${override_args} $*
boot ${override_args} $*
ret=$?
--
2.56.0
^ permalink raw reply [flat|nested] 5+ messages in thread
end of thread, other threads:[~2026-10-27 13:47 UTC | newest]
Thread overview: 5+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2026-10-27 13:23 [PATCH 0/4] Linux bootconfig support Steffen Trumtrar
2026-10-27 13:23 ` [PATCH 1/4] loadable: add loadable_from_buf() Steffen Trumtrar
2026-10-27 13:23 ` [PATCH 2/4] bootm: append a Linux bootconfig to the initrd Steffen Trumtrar
2026-10-27 13:23 ` [PATCH 3/4] boot: add bootm.bootconfig override Steffen Trumtrar
2026-10-27 13:23 ` [PATCH 4/4] defaultenv: devboot: add devboot_bootconfig Steffen Trumtrar
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox