* [PATCH 0/3] bootconfig: break dependency from memblock
@ 2026-04-15 10:51 Breno Leitao
2026-04-15 10:51 ` [PATCH 1/3] bootconfig: use static buffers instead of memblock allocation Breno Leitao
` (2 more replies)
0 siblings, 3 replies; 6+ messages in thread
From: Breno Leitao @ 2026-04-15 10:51 UTC (permalink / raw)
To: Andrew Morton, Masami Hiramatsu
Cc: oss, paulmck, linux-trace-kernel, linux-kernel,
linux-trace-kernel, kernel-team, Breno Leitao
This series moves embedded bootconfig (CONFIG_BOOT_CONFIG_EMBED) parsing
before setup_arch() in start_kernel(). The goal is to prepare for a
follow-up change that will allow bootconfig to provide early_param()
parameters (e.g. memblock=debug, loglevel) that are consumed during
architecture-specific setup.
Currently, bootconfig depends on memblock for memory allocation, which
is not available until setup_arch() initializes it. This series removes
that dependency by replacing memblock allocations with static __initdata
buffers (~96KB total, freed after init), then splits the bootconfig
loading into an early embedded path and a late initrd path.
The static buffers are used by both the kernel and the userspace
tools/bootconfig parser, which simplifies the code by removing the
These patches alone do not change user-visible behavior. Bootconfig
parameters are still stored in extra_command_line, which gets merged
into boot_command_line by setup_command_line() after setup_arch().
Making parse_early_param() see bootconfig values during setup_arch()
is a separate change that will follow once this infrastructure is
accepted.
Keeping the two efforts separate simplifies review, since the
early_param() integration is a non-trivial change on its own.
Some discussion that led to this decision:
1) It is not trivial to parse early param after setup_arch()
https://lore.kernel.org/all/20260325-early_bootconfig-v2-1-6b05a36fbfb5@debian.org/
2) An similar proposal from Petr 3 years ago:
https://lore.kernel.org/all/20231121231342.193646-2-oss@malat.biz/
---
Breno Leitao (3):
bootconfig: use static buffers instead of memblock allocation
init: use static buffers for bootconfig extra command line
init: move embedded bootconfig parsing before setup_arch()
init/main.c | 91 +++++++++++++++++++++++++++++++++++++++++---------------
lib/bootconfig.c | 56 +++++++---------------------------
2 files changed, 77 insertions(+), 70 deletions(-)
---
base-commit: 1c7cc4904160c6fc6377564140062d68a3dc93a0
change-id: 20260414-bootconfig_earlier-9e185ceb71ae
Best regards,
--
Breno Leitao <leitao@debian.org>
^ permalink raw reply [flat|nested] 6+ messages in thread
* [PATCH 1/3] bootconfig: use static buffers instead of memblock allocation
2026-04-15 10:51 [PATCH 0/3] bootconfig: break dependency from memblock Breno Leitao
@ 2026-04-15 10:51 ` Breno Leitao
2026-04-15 10:51 ` [PATCH 2/3] init: use static buffers for bootconfig extra command line Breno Leitao
2026-04-15 10:51 ` [PATCH 3/3] init: move embedded bootconfig parsing before setup_arch() Breno Leitao
2 siblings, 0 replies; 6+ messages in thread
From: Breno Leitao @ 2026-04-15 10:51 UTC (permalink / raw)
To: Andrew Morton, Masami Hiramatsu
Cc: oss, paulmck, linux-trace-kernel, linux-kernel,
linux-trace-kernel, kernel-team, Breno Leitao
Replace dynamic allocations in the bootconfig parser with static
__initdata buffers. This removes the dependency on memblock being
available when bootconfig is parsed, which is a prerequisite for
moving embedded bootconfig parsing earlier in the boot sequence.
The static buffers are:
- xbc_data_buf[XBC_DATA_MAX + 1] (~32KB) for bootconfig text data
- xbc_nodes_buf[XBC_NODE_MAX] (64KB) for the parse tree nodes
Both are __initdata and freed after init in the kernel. The userspace
tools path (tools/bootconfig) also uses the same static buffers,
which simplifies the code by removing all #ifdef __KERNEL__ blocks
from the parser.
Signed-off-by: Breno Leitao <leitao@debian.org>
---
lib/bootconfig.c | 56 ++++++++++----------------------------------------------
1 file changed, 10 insertions(+), 46 deletions(-)
diff --git a/lib/bootconfig.c b/lib/bootconfig.c
index c470b93d5dbc2..3e529325c90ac 100644
--- a/lib/bootconfig.c
+++ b/lib/bootconfig.c
@@ -15,12 +15,11 @@
#ifdef __KERNEL__
#include <linux/bug.h>
-#include <linux/ctype.h>
-#include <linux/errno.h>
#include <linux/cache.h>
#include <linux/compiler.h>
+#include <linux/ctype.h>
+#include <linux/errno.h>
#include <linux/sprintf.h>
-#include <linux/memblock.h>
#include <linux/string.h>
#ifdef CONFIG_BOOT_CONFIG_EMBED
@@ -54,33 +53,12 @@ static const char *xbc_err_msg __initdata;
static int xbc_err_pos __initdata;
static int open_brace[XBC_DEPTH_MAX] __initdata;
static int brace_index __initdata;
-
-#ifdef __KERNEL__
-static inline void * __init xbc_alloc_mem(size_t size)
-{
- return memblock_alloc(size, SMP_CACHE_BYTES);
-}
-
-static inline void __init xbc_free_mem(void *addr, size_t size, bool early)
-{
- if (early)
- memblock_free(addr, size);
- else if (addr)
- memblock_free(addr, size);
-}
-
-#else /* !__KERNEL__ */
-
-static inline void *xbc_alloc_mem(size_t size)
-{
- return calloc(1, size);
-}
-
-static inline void xbc_free_mem(void *addr, size_t size, bool early)
-{
- free(addr);
-}
-#endif
+/*
+ * Static buffers for bootconfig data and nodes. Avoids dynamic allocation
+ * so bootconfig can be parsed before memblock is available in the kernel.
+ */
+static char xbc_data_buf[XBC_DATA_MAX + 1] __initdata;
+static struct xbc_node xbc_nodes_buf[XBC_NODE_MAX] __initdata;
/**
* xbc_get_info() - Get the information of loaded boot config
@@ -930,11 +908,9 @@ static int __init xbc_parse_tree(void)
*/
void __init _xbc_exit(bool early)
{
- xbc_free_mem(xbc_data, xbc_data_size, early);
xbc_data = NULL;
xbc_data_size = 0;
xbc_node_num = 0;
- xbc_free_mem(xbc_nodes, sizeof(struct xbc_node) * XBC_NODE_MAX, early);
xbc_nodes = NULL;
brace_index = 0;
}
@@ -973,24 +949,12 @@ int __init xbc_init(const char *data, size_t size, const char **emsg, int *epos)
return -ERANGE;
}
- xbc_data = xbc_alloc_mem(size + 1);
- if (!xbc_data) {
- if (emsg)
- *emsg = "Failed to allocate bootconfig data";
- return -ENOMEM;
- }
+ xbc_data = xbc_data_buf;
+ xbc_nodes = xbc_nodes_buf;
memcpy(xbc_data, data, size);
xbc_data[size] = '\0';
xbc_data_size = size + 1;
- xbc_nodes = xbc_alloc_mem(sizeof(struct xbc_node) * XBC_NODE_MAX);
- if (!xbc_nodes) {
- if (emsg)
- *emsg = "Failed to allocate bootconfig nodes";
- _xbc_exit(true);
- return -ENOMEM;
- }
-
ret = xbc_parse_tree();
if (!ret)
ret = xbc_verify_tree();
--
2.52.0
^ permalink raw reply related [flat|nested] 6+ messages in thread
* [PATCH 2/3] init: use static buffers for bootconfig extra command line
2026-04-15 10:51 [PATCH 0/3] bootconfig: break dependency from memblock Breno Leitao
2026-04-15 10:51 ` [PATCH 1/3] bootconfig: use static buffers instead of memblock allocation Breno Leitao
@ 2026-04-15 10:51 ` Breno Leitao
2026-04-17 1:44 ` Masami Hiramatsu
2026-04-15 10:51 ` [PATCH 3/3] init: move embedded bootconfig parsing before setup_arch() Breno Leitao
2 siblings, 1 reply; 6+ messages in thread
From: Breno Leitao @ 2026-04-15 10:51 UTC (permalink / raw)
To: Andrew Morton, Masami Hiramatsu
Cc: oss, paulmck, linux-trace-kernel, linux-kernel,
linux-trace-kernel, kernel-team, Breno Leitao
Replace memblock_alloc/memblock_free in xbc_make_cmdline() with
static __initdata buffers. This removes the last memblock dependency
from the bootconfig loading path, completing the prerequisite for
running bootconfig parsing before memblock is available.
Signed-off-by: Breno Leitao <leitao@debian.org>
---
init/main.c | 24 ++++++++++++------------
1 file changed, 12 insertions(+), 12 deletions(-)
diff --git a/init/main.c b/init/main.c
index 96f93bb06c490..b9feca55e01f9 100644
--- a/init/main.c
+++ b/init/main.c
@@ -369,11 +369,18 @@ static int __init xbc_snprint_cmdline(char *buf, size_t size,
}
#undef rest
+/*
+ * Static buffers for bootconfig-generated command line parameters.
+ * Two separate buffers are needed because both "kernel" and "init"
+ * parameters are stored simultaneously.
+ */
+static char extra_cmdline_buf[COMMAND_LINE_SIZE] __initdata;
+static char extra_initargs_buf[COMMAND_LINE_SIZE] __initdata;
+
/* Make an extra command line under given key word */
-static char * __init xbc_make_cmdline(const char *key)
+static char * __init xbc_make_cmdline(const char *key, char *new_cmdline)
{
struct xbc_node *root;
- char *new_cmdline;
int ret, len = 0;
root = xbc_find_node(key);
@@ -382,19 +389,12 @@ static char * __init xbc_make_cmdline(const char *key)
/* Count required buffer size */
len = xbc_snprint_cmdline(NULL, 0, root);
- if (len <= 0)
+ if (len <= 0 || len >= COMMAND_LINE_SIZE)
return NULL;
- new_cmdline = memblock_alloc(len + 1, SMP_CACHE_BYTES);
- if (!new_cmdline) {
- pr_err("Failed to allocate memory for extra kernel cmdline.\n");
- return NULL;
- }
-
ret = xbc_snprint_cmdline(new_cmdline, len + 1, root);
if (ret < 0 || ret > len) {
pr_err("Failed to print extra kernel cmdline.\n");
- memblock_free(new_cmdline, len + 1);
return NULL;
}
@@ -467,9 +467,9 @@ static void __init setup_boot_config(void)
xbc_get_info(&ret, NULL);
pr_info("Load bootconfig: %ld bytes %d nodes\n", (long)size, ret);
/* keys starting with "kernel." are passed via cmdline */
- extra_command_line = xbc_make_cmdline("kernel");
+ extra_command_line = xbc_make_cmdline("kernel", extra_cmdline_buf);
/* Also, "init." keys are init arguments */
- extra_init_args = xbc_make_cmdline("init");
+ extra_init_args = xbc_make_cmdline("init", extra_initargs_buf);
}
return;
}
--
2.52.0
^ permalink raw reply related [flat|nested] 6+ messages in thread
* [PATCH 3/3] init: move embedded bootconfig parsing before setup_arch()
2026-04-15 10:51 [PATCH 0/3] bootconfig: break dependency from memblock Breno Leitao
2026-04-15 10:51 ` [PATCH 1/3] bootconfig: use static buffers instead of memblock allocation Breno Leitao
2026-04-15 10:51 ` [PATCH 2/3] init: use static buffers for bootconfig extra command line Breno Leitao
@ 2026-04-15 10:51 ` Breno Leitao
2 siblings, 0 replies; 6+ messages in thread
From: Breno Leitao @ 2026-04-15 10:51 UTC (permalink / raw)
To: Andrew Morton, Masami Hiramatsu
Cc: oss, paulmck, linux-trace-kernel, linux-kernel,
linux-trace-kernel, kernel-team, Breno Leitao
Split setup_boot_config() into setup_boot_config_from_embedded() for
embedded bootconfig and setup_boot_config_from_initrd() for initrd
bootconfig.
The embedded bootconfig data lives in .init.rodata (compiled into the
kernel via bootconfig-data.S), so it requires no memory allocation to
access. Combined with the previous patches that replaced memblock
allocations with static buffers, this allows embedded bootconfig to
be parsed before setup_arch(), making bootconfig parameters available
during architecture-specific setup.
The initrd bootconfig path remains at its original position since it
needs initrd_start/initrd_end set up by setup_arch().
Signed-off-by: Breno Leitao <leitao@debian.org>
---
init/main.c | 67 ++++++++++++++++++++++++++++++++++++++++++++++++++-----------
1 file changed, 55 insertions(+), 12 deletions(-)
diff --git a/init/main.c b/init/main.c
index b9feca55e01f9..20fded9bfbdd0 100644
--- a/init/main.c
+++ b/init/main.c
@@ -416,20 +416,17 @@ static int __init warn_bootconfig(char *str)
return 0;
}
-static void __init setup_boot_config(void)
+/*
+ * Parse bootconfig data and extract kernel/init command line parameters.
+ * Shared by both the early embedded path and the late initrd path.
+ */
+static void __init __boot_config_load(const char *data, size_t size)
{
static char tmp_cmdline[COMMAND_LINE_SIZE] __initdata;
- const char *msg, *data;
+ const char *msg;
int pos, ret;
- size_t size;
char *err;
- /* Cut out the bootconfig data even if we have no bootconfig option */
- data = get_boot_config_from_initrd(&size);
- /* If there is no bootconfig in initrd, try embedded one. */
- if (!data)
- data = xbc_get_embedded_bootconfig(&size);
-
strscpy(tmp_cmdline, boot_command_line, COMMAND_LINE_SIZE);
err = parse_args("bootconfig", tmp_cmdline, NULL, 0, 0, 0, NULL,
bootconfig_params);
@@ -471,7 +468,50 @@ static void __init setup_boot_config(void)
/* Also, "init." keys are init arguments */
extra_init_args = xbc_make_cmdline("init", extra_initargs_buf);
}
- return;
+}
+
+/*
+ * Load embedded bootconfig before setup_arch(). This runs before memblock
+ * is available, relying on static buffers in the bootconfig parser.
+ * The embedded data lives in .init.rodata so no allocation is needed
+ * to access it.
+ */
+static void __init setup_boot_config_from_embedded(void)
+{
+ const char *data;
+ size_t size;
+
+ data = xbc_get_embedded_bootconfig(&size);
+ if (!data)
+ return;
+
+ pr_info("Load embedded bootconfig early\n");
+ __boot_config_load(data, size);
+}
+
+/*
+ * Load bootconfig from initrd. This MUST run after setup_arch() when initrd
+ * boundaries are known. If initrd bootconfig exists, it overrides any embedded
+ * bootconfig that was loaded early, preserving the original priority (initrd
+ * > embedded).
+ */
+static void __init setup_boot_config_from_initrd(void)
+{
+ const char *data;
+ size_t size;
+
+ /* Cut out the bootconfig data even if we have no bootconfig option */
+ data = get_boot_config_from_initrd(&size);
+
+ /* No initrd bootconfig — keep embedded if already loaded */
+ if (!data)
+ return;
+
+ /* Initrd overrides embedded — tear down and re-parse */
+ if (xbc_get_info(NULL, NULL) == 0)
+ _xbc_exit(true);
+
+ __boot_config_load(data, size);
}
static void __init exit_boot_config(void)
@@ -481,7 +521,9 @@ static void __init exit_boot_config(void)
#else /* !CONFIG_BOOT_CONFIG */
-static void __init setup_boot_config(void)
+static void __init setup_boot_config_from_embedded(void) { }
+
+static void __init setup_boot_config_from_initrd(void)
{
/* Remove bootconfig data from initrd */
get_boot_config_from_initrd(NULL);
@@ -1036,13 +1078,14 @@ void start_kernel(void)
boot_cpu_init();
page_address_init();
pr_notice("%s", linux_banner);
+ setup_boot_config_from_embedded();
setup_arch(&command_line);
mm_core_init_early();
/* Static keys and static calls are needed by LSMs */
jump_label_init();
static_call_init();
early_security_init();
- setup_boot_config();
+ setup_boot_config_from_initrd();
setup_command_line(command_line);
setup_nr_cpu_ids();
setup_per_cpu_areas();
--
2.52.0
^ permalink raw reply related [flat|nested] 6+ messages in thread
* Re: [PATCH 2/3] init: use static buffers for bootconfig extra command line
2026-04-15 10:51 ` [PATCH 2/3] init: use static buffers for bootconfig extra command line Breno Leitao
@ 2026-04-17 1:44 ` Masami Hiramatsu
2026-04-17 15:38 ` Breno Leitao
0 siblings, 1 reply; 6+ messages in thread
From: Masami Hiramatsu @ 2026-04-17 1:44 UTC (permalink / raw)
To: Breno Leitao
Cc: Andrew Morton, oss, paulmck, linux-trace-kernel, linux-kernel,
kernel-team
On Wed, 15 Apr 2026 03:51:11 -0700
Breno Leitao <leitao@debian.org> wrote:
> Replace memblock_alloc/memblock_free in xbc_make_cmdline() with
> static __initdata buffers. This removes the last memblock dependency
> from the bootconfig loading path, completing the prerequisite for
> running bootconfig parsing before memblock is available.
>
> Signed-off-by: Breno Leitao <leitao@debian.org>
> ---
> init/main.c | 24 ++++++++++++------------
> 1 file changed, 12 insertions(+), 12 deletions(-)
>
> diff --git a/init/main.c b/init/main.c
> index 96f93bb06c490..b9feca55e01f9 100644
> --- a/init/main.c
> +++ b/init/main.c
> @@ -369,11 +369,18 @@ static int __init xbc_snprint_cmdline(char *buf, size_t size,
> }
> #undef rest
>
> +/*
> + * Static buffers for bootconfig-generated command line parameters.
> + * Two separate buffers are needed because both "kernel" and "init"
> + * parameters are stored simultaneously.
> + */
> +static char extra_cmdline_buf[COMMAND_LINE_SIZE] __initdata;
> +static char extra_initargs_buf[COMMAND_LINE_SIZE] __initdata;
This is not good to me, since bootconfig supports bigger config file
than COMMAND_LINE_SIZE. Even if we limits the size for embedded
bootconfig file, it should depends on CONFIG_BOOT_CONFIG_EMBED.
Please use XBC_DATA_MAX instead of COMMAND_LINE_SIZE, or calculate
expected data length when compiling kernel.
But if we can do it, should we continue using bootconfig? I mean
it is easy to make a tool (or add a feature in tools/bootconfig)
which converts bootconfig file to command line string and embeds
it in the kernel. Hmm.
Thanks,
> +
> /* Make an extra command line under given key word */
> -static char * __init xbc_make_cmdline(const char *key)
> +static char * __init xbc_make_cmdline(const char *key, char *new_cmdline)
> {
> struct xbc_node *root;
> - char *new_cmdline;
> int ret, len = 0;
>
> root = xbc_find_node(key);
> @@ -382,19 +389,12 @@ static char * __init xbc_make_cmdline(const char *key)
>
> /* Count required buffer size */
> len = xbc_snprint_cmdline(NULL, 0, root);
> - if (len <= 0)
> + if (len <= 0 || len >= COMMAND_LINE_SIZE)
> return NULL;
>
> - new_cmdline = memblock_alloc(len + 1, SMP_CACHE_BYTES);
> - if (!new_cmdline) {
> - pr_err("Failed to allocate memory for extra kernel cmdline.\n");
> - return NULL;
> - }
> -
> ret = xbc_snprint_cmdline(new_cmdline, len + 1, root);
> if (ret < 0 || ret > len) {
> pr_err("Failed to print extra kernel cmdline.\n");
> - memblock_free(new_cmdline, len + 1);
> return NULL;
> }
>
> @@ -467,9 +467,9 @@ static void __init setup_boot_config(void)
> xbc_get_info(&ret, NULL);
> pr_info("Load bootconfig: %ld bytes %d nodes\n", (long)size, ret);
> /* keys starting with "kernel." are passed via cmdline */
> - extra_command_line = xbc_make_cmdline("kernel");
> + extra_command_line = xbc_make_cmdline("kernel", extra_cmdline_buf);
> /* Also, "init." keys are init arguments */
> - extra_init_args = xbc_make_cmdline("init");
> + extra_init_args = xbc_make_cmdline("init", extra_initargs_buf);
> }
> return;
> }
>
> --
> 2.52.0
>
--
Masami Hiramatsu (Google) <mhiramat@kernel.org>
^ permalink raw reply [flat|nested] 6+ messages in thread
* Re: [PATCH 2/3] init: use static buffers for bootconfig extra command line
2026-04-17 1:44 ` Masami Hiramatsu
@ 2026-04-17 15:38 ` Breno Leitao
0 siblings, 0 replies; 6+ messages in thread
From: Breno Leitao @ 2026-04-17 15:38 UTC (permalink / raw)
To: Masami Hiramatsu
Cc: Andrew Morton, oss, paulmck, linux-trace-kernel, linux-kernel,
kernel-team
On Fri, Apr 17, 2026 at 10:44:36AM +0900, Masami Hiramatsu wrote:
> On Wed, 15 Apr 2026 03:51:11 -0700
> Breno Leitao <leitao@debian.org> wrote:
>
> But if we can do it, should we continue using bootconfig? I mean
> it is easy to make a tool (or add a feature in tools/bootconfig)
> which converts bootconfig file to command line string and embeds
> it in the kernel. Hmm.
Sure, you are talking about a a tool that embeddeds it in the kernel binary,
something like:
0) Get a kernel and define CONFIG_BOOT_CONFIG_EMBED_FILE=".bootconfig"
1) Add an option in tools/bootconfig to convert bootconfig (.bootconfig)
to a cmdline string ($ bootconfig -C kernel .bootconfig).
Something like:
# tools/bootconfig/bootconfig -C kernel .bootconfig
mem=2G loglevel=7 debug nokaslr %
2) At kernel build time, run that tool on .bootconfig and embed the
resulting string into the kernel image as a .init.rodata symbol
(embedded_kernel_cmdline[]).
# gdb -batch -ex 'x/s &embedded_kernel_cmdline' vmlinux
0xffffffff87e108f8: "mem=2G loglevel=7 debug nokaslr "
3) At boot, the arch's setup_arch() prepends that symbol to
boot_command_line right before parse_early_param() — so early_param()
handlers (mem=, earlycon=, loglevel=, ...) actually see kernel.*
keys from the embedded bootconfig.
This needs to be architecture by architecture. Something like:
@@ -924,6 +925,13 @@ void __init setup_arch(char **cmdline_p)
builtin_cmdline_added = true;
#endif
+ /*
+ * Prepend kernel.* keys from the embedded bootconfig (rendered at
+ * build time by tools/bootconfig) so parse_early_param() below sees
+ * them. No-op when CONFIG_BOOT_CONFIG_EMBED=n.
+ */
+ xbc_prepend_embedded_cmdline(boot_command_line, COMMAND_LINE_SIZE);
+
strscpy(command_line, boot_command_line, COMMAND_LINE_SIZE);
*cmdline_p = command_line;
Am I describing your suggestion accordingly?
Thanks!
--breno
^ permalink raw reply [flat|nested] 6+ messages in thread
end of thread, other threads:[~2026-04-17 15:38 UTC | newest]
Thread overview: 6+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-04-15 10:51 [PATCH 0/3] bootconfig: break dependency from memblock Breno Leitao
2026-04-15 10:51 ` [PATCH 1/3] bootconfig: use static buffers instead of memblock allocation Breno Leitao
2026-04-15 10:51 ` [PATCH 2/3] init: use static buffers for bootconfig extra command line Breno Leitao
2026-04-17 1:44 ` Masami Hiramatsu
2026-04-17 15:38 ` Breno Leitao
2026-04-15 10:51 ` [PATCH 3/3] init: move embedded bootconfig parsing before setup_arch() Breno Leitao
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox