diff options
| author | Mark Brown <broonie@kernel.org> | 2026-08-21 14:07:47 +0100 |
|---|---|---|
| committer | Mark Brown <broonie@kernel.org> | 2026-08-21 14:07:47 +0100 |
| commit | 52f605e669a545a78e5294d42259b8cd7b85bbcb (patch) | |
| tree | 8c690650a03d33799e1062850854257603568389 | |
| parent | eead08c618c1c1bda9622461ced111b585f8f84b (diff) | |
| parent | 3df3ae98c30c249c4bbf3d74559cc6972898052c (diff) | |
| download | linux-next-52f605e669a545a78e5294d42259b8cd7b85bbcb.tar.gz linux-next-52f605e669a545a78e5294d42259b8cd7b85bbcb.zip | |
Merge branch 'for-next' of https://git.kernel.org/pub/scm/linux/kernel/git/trace/linux-trace.git
| -rw-r--r-- | Documentation/admin-guide/bootconfig.rst | 81 | ||||
| -rw-r--r-- | MAINTAINERS | 1 | ||||
| -rw-r--r-- | Makefile | 27 | ||||
| -rw-r--r-- | arch/x86/Kconfig | 1 | ||||
| -rw-r--r-- | arch/x86/kernel/setup.c | 14 | ||||
| -rw-r--r-- | include/linux/bootconfig.h | 14 | ||||
| -rw-r--r-- | init/Kconfig | 36 | ||||
| -rw-r--r-- | init/main.c | 52 | ||||
| -rw-r--r-- | lib/Makefile | 16 | ||||
| -rw-r--r-- | lib/bootconfig.c | 139 | ||||
| -rw-r--r-- | lib/embedded-cmdline.S | 16 | ||||
| -rw-r--r-- | tools/bootconfig/Makefile | 4 |
12 files changed, 372 insertions, 29 deletions
diff --git a/Documentation/admin-guide/bootconfig.rst b/Documentation/admin-guide/bootconfig.rst index f712758472d5..3d6412458c8b 100644 --- a/Documentation/admin-guide/bootconfig.rst +++ b/Documentation/admin-guide/bootconfig.rst @@ -234,6 +234,87 @@ Kconfig option selected. Note that even if you set this option, you can override the embedded bootconfig by another bootconfig which attached to the initrd. +Rendering Embedded kernel.* Keys at Build Time +---------------------------------------------- + +By default, the embedded bootconfig (``CONFIG_BOOT_CONFIG_EMBED=y``) is +parsed at runtime, after ``parse_early_param()`` has already run. Early +parameter handlers (``mem=``, ``earlycon=``, ``loglevel=``, ...) therefore +cannot see values supplied via the embedded ``kernel`` subtree. + +``CONFIG_CMDLINE_FROM_BOOTCONFIG`` resolves this by rendering the +``kernel`` subtree of ``CONFIG_BOOT_CONFIG_EMBED_FILE`` into a flat cmdline +string at kernel build time (via ``tools/bootconfig -C``) and prepending +it to ``boot_command_line`` during early architecture setup, so the keys +are visible to ``parse_early_param()``. + +The option requires ``CONFIG_BOOT_CONFIG_EMBED=y``, a non-empty +``CONFIG_BOOT_CONFIG_EMBED_FILE``, ``CONFIG_CMDLINE`` to be empty, and +an architecture that selects ``CONFIG_ARCH_SUPPORTS_CMDLINE_FROM_BOOTCONFIG``. +Currently only x86 selects it; on other architectures the embedded +bootconfig still works, but only through the late runtime parser. + +The same ``bootconfig`` opt-in applies as elsewhere: the rendered keys +are prepended only when ``bootconfig`` (in any form) appears on the +kernel command line, or when ``CONFIG_BOOT_CONFIG_FORCE`` is set, which +defaults to ``y`` when ``CONFIG_BOOT_CONFIG_EMBED`` is set. + +For example, given:: + + kernel { + loglevel = 7 + mem = 4G + } + +the kernel boots as if ``loglevel=7 mem=4G`` had been prepended to the +bootloader command line, with the values visible to early-parsed +handlers. Comma-separated values are still expanded into multiple +cmdline entries per the bootconfig array convention -- the embedded +``kernel.earlycon = "uart8250,io,0x3f8"`` must be quoted to land as a +single ``earlycon=`` entry, exactly as for the runtime parser. + +If the rendered string would not fit in ``COMMAND_LINE_SIZE`` together +with the existing command line, the prepend is skipped and an error is +logged, so an oversized embedded bootconfig cannot brick a boot. + +Interaction with other command line and bootconfig sources +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +With ``CONFIG_CMDLINE_FROM_BOOTCONFIG=y`` the rendered ``kernel`` +subtree behaves like a build-time command line (similar to +``CONFIG_CMDLINE``), not like a bootconfig source. It is prepended to +``boot_command_line`` in ``setup_arch()``, before ``parse_early_param()`` +and long before the runtime parser looks at an initrd. Options can reach +the kernel from up to four places: + +- Bootloader command line: the arguments the boot loader passes. The + embedded cmdline is prepended in front of them, so for last-one-wins + parameters a bootloader option still overrides the embedded value. + Visible in /proc/cmdline. +- Embedded cmdline (this option): the rendered ``kernel`` subtree, + prepended early so it is seen by ``parse_early_param()``. Visible in + /proc/cmdline. +- Initrd bootconfig: parsed late in ``setup_boot_config()``; its + ``kernel`` keys are placed ahead of ``boot_command_line``, i.e. before + the embedded cmdline, so last-wins favors the embedded values. As a + bootconfig source, an initrd bootconfig still replaces the embedded + bootconfig. Visible in /proc/cmdline and /proc/bootconfig. +- Embedded bootconfig (runtime): parsed late, only when no initrd + bootconfig is present. Visible in /proc/cmdline and /proc/bootconfig. + +So with this option the embedded ``kernel.*`` values take precedence +over an initrd bootconfig's ``kernel.*`` values: for early parameters +the initrd is not parsed yet, and for ordinary parameters the embedded +keys land later in the command line. If you need an initrd bootconfig to +override the embedded ``kernel.*`` keys, leave this option off and rely +on the runtime parser. + +The rendered string is part of the command line, so it appears in +/proc/cmdline. It is deliberately not shown in /proc/bootconfig: that +file keeps reporting the parsed bootconfig tree -- the initrd bootconfig +if present, otherwise the embedded bootconfig -- independent of whether +build-time cmdline rendering is enabled. + Kernel parameters via Boot Config ================================= diff --git a/MAINTAINERS b/MAINTAINERS index d3fe5444c627..d590d85d09af 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -9889,6 +9889,7 @@ F: fs/proc/bootconfig.c F: include/linux/bootconfig.h F: lib/bootconfig-data.S F: lib/bootconfig.c +F: lib/embedded-cmdline.S F: tools/bootconfig/* F: tools/bootconfig/scripts/* @@ -1561,6 +1561,22 @@ prepare: tools/bpf/resolve_btfids endif endif +# tools/bootconfig renders the embedded bootconfig into a cmdline at build time. +ifdef CONFIG_CMDLINE_FROM_BOOTCONFIG +prepare: tools/bootconfig +endif + +# tools/bootconfig is run on the build host during prepare, so force a host +# binary here; its own Makefile keeps $(CC) for standalone and cross builds. +# CROSS_COMPILE= is cleared so tools/scripts/Makefile.include does not inject +# the target's --target=/--sysroot= flags into the host clang invocation under +# LLVM=1 cross builds (which would produce a target binary that fails to exec). +tools/bootconfig: export CC := $(HOSTCC) +tools/bootconfig: FORCE + $(Q)mkdir -p $(objtree)/tools + $(Q)$(MAKE) O=$(abspath $(objtree)) subdir=tools -C $(srctree)/tools/ \ + bootconfig CROSS_COMPILE= + # The tools build system is not a part of Kbuild and tends to introduce # its own unique issues. If you need to integrate a new tool into Kbuild, # please consider locating that tool outside the tools/ tree and using the @@ -1587,6 +1603,15 @@ ifneq ($(wildcard $(objtool_O)),) $(Q)$(MAKE) -sC $(abs_srctree)/tools/objtool O=$(objtool_O) srctree=$(abs_srctree) $(patsubst objtool_%,%,$@) endif +PHONY += bootconfig_clean + +bootconfig_O = $(abspath $(objtree))/tools/bootconfig + +bootconfig_clean: +ifneq ($(wildcard $(bootconfig_O)),) + $(Q)$(MAKE) -sC $(srctree)/tools/bootconfig O=$(bootconfig_O) clean +endif + tools/: FORCE $(Q)mkdir -p $(objtree)/tools $(Q)$(MAKE) O=$(abspath $(objtree)) subdir=tools -C $(srctree)/tools/ @@ -1762,7 +1787,7 @@ vmlinuxclean: $(Q)$(CONFIG_SHELL) $(srctree)/scripts/link-vmlinux.sh clean $(Q)$(if $(ARCH_POSTLINK), $(MAKE) -f $(ARCH_POSTLINK) clean) -clean: archclean vmlinuxclean resolve_btfids_clean objtool_clean +clean: archclean vmlinuxclean resolve_btfids_clean objtool_clean bootconfig_clean # mrproper - Delete all generated files, including .config # diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig index 4c9afaf3e194..15fd9ec5ecac 100644 --- a/arch/x86/Kconfig +++ b/arch/x86/Kconfig @@ -129,6 +129,7 @@ config X86 select ARCH_SUPPORTS_NUMA_BALANCING if X86_64 select ARCH_SUPPORTS_KMAP_LOCAL_FORCE_MAP if NR_CPUS <= 4096 select ARCH_SUPPORTS_CFI if X86_64 + select ARCH_SUPPORTS_CMDLINE_FROM_BOOTCONFIG select ARCH_USES_CFI_TRAPS if X86_64 && CFI select ARCH_SUPPORTS_LTO_CLANG select ARCH_SUPPORTS_LTO_CLANG_THIN diff --git a/arch/x86/kernel/setup.c b/arch/x86/kernel/setup.c index a8c873356f17..cda6adb9f69c 100644 --- a/arch/x86/kernel/setup.c +++ b/arch/x86/kernel/setup.c @@ -6,6 +6,7 @@ * parts of early kernel initialization. */ #include <linux/acpi.h> +#include <linux/bootconfig.h> #include <linux/console.h> #include <linux/cpu.h> #include <linux/crash_dump.h> @@ -880,7 +881,6 @@ static void __init x86_report_nx(void) * * Note: On x86_64, fixmaps are ready for use even before this is called. */ - void __init setup_arch(char **cmdline_p) { #ifdef CONFIG_X86_32 @@ -924,6 +924,18 @@ void __init setup_arch(char **cmdline_p) builtin_cmdline_added = true; #endif +#ifdef CONFIG_CMDLINE_FROM_BOOTCONFIG + /* + * Prepend the build-time-rendered embedded "kernel" keys here so + * parse_early_param() below sees them, using the same opt-in as the + * runtime parser, plus the build-time CONFIG_BOOT_CONFIG_FORCE. + */ + if (bootconfig_cmdline_requested(boot_command_line, NULL) || + IS_ENABLED(CONFIG_BOOT_CONFIG_FORCE)) + xbc_prepend_embedded_cmdline(boot_command_line, + COMMAND_LINE_SIZE); +#endif + strscpy(command_line, boot_command_line, COMMAND_LINE_SIZE); *cmdline_p = command_line; diff --git a/include/linux/bootconfig.h b/include/linux/bootconfig.h index 1c7f3b74ffcf..deda507500da 100644 --- a/include/linux/bootconfig.h +++ b/include/linux/bootconfig.h @@ -308,4 +308,18 @@ static inline const char *xbc_get_embedded_bootconfig(size_t *size) } #endif +/* Bootconfig opt-in detection, shared by setup_arch() and setup_boot_config() */ +#ifdef CONFIG_BOOT_CONFIG +bool __init bootconfig_cmdline_requested(const char *boot_cmdline, int *end_offset); +#endif + +/* Build-time-rendered bootconfig cmdline prepended in setup_arch() */ +#ifdef CONFIG_CMDLINE_FROM_BOOTCONFIG +void __init xbc_prepend_embedded_cmdline(char *dst, size_t size); +bool __init xbc_embedded_cmdline_applied(void); +#else +static inline void xbc_prepend_embedded_cmdline(char *dst, size_t size) { } +static inline bool xbc_embedded_cmdline_applied(void) { return false; } +#endif + #endif diff --git a/init/Kconfig b/init/Kconfig index f63bf5e05e79..8583d9f06c52 100644 --- a/init/Kconfig +++ b/init/Kconfig @@ -1578,6 +1578,42 @@ config BOOT_CONFIG_EMBED_FILE This bootconfig will be used if there is no initrd or no other bootconfig in the initrd. +config ARCH_SUPPORTS_CMDLINE_FROM_BOOTCONFIG + bool + help + Silent symbol; no C code reads it directly. Architectures + select it once their setup_arch() calls + xbc_prepend_embedded_cmdline() before parse_early_param(). + Its only role is to gate the user-visible + CMDLINE_FROM_BOOTCONFIG option per-arch, the same + ARCH_SUPPORTS_* idiom used by ARCH_SUPPORTS_CFI, etc. + +config CMDLINE_FROM_BOOTCONFIG + bool "Render embedded bootconfig as kernel cmdline at build time" + depends on BOOT_CONFIG_EMBED_FILE != "" + depends on ARCH_SUPPORTS_CMDLINE_FROM_BOOTCONFIG + depends on CMDLINE = "" + default n + help + Render the "kernel" subtree of the embedded bootconfig file into a + flat cmdline string at kernel build time and prepend it to + boot_command_line during early architecture setup. This makes + early_param() handlers (e.g. mem=, earlycon=, loglevel=) see the + values supplied via the embedded bootconfig. + + The runtime bootconfig parser is unaffected, so tree-structured + consumers such as ftrace boot-time tracing keep working. + + Note: when an initrd also carries a bootconfig, its "kernel" + subtree is still parsed at runtime, but the embedded "kernel" + keys remain in boot_command_line for parse_early_param() and + end up later than the initrd keys in saved_command_line, so + parse_args() last-wins favors the embedded values. If you need + initrd to override embedded kernel.* keys, leave this option + off. + + If unsure, say N. + config CMDLINE_LOG_WRAP_IDEAL_LEN int "Length to try to wrap the cmdline when logged at boot" default 1021 diff --git a/init/main.c b/init/main.c index 92d34e496a33..2613d3f9b3ce 100644 --- a/init/main.c +++ b/init/main.c @@ -357,45 +357,33 @@ static char * __init xbc_make_cmdline(const char *key) return new_cmdline; } -static int __init bootconfig_params(char *param, char *val, - const char *unused, void *arg) -{ - if (strcmp(param, "bootconfig") == 0) { - bootconfig_found = true; - } - return 0; -} - static int __init warn_bootconfig(char *str) { - /* The 'bootconfig' has been handled by bootconfig_params(). */ + /* The 'bootconfig' option is handled by setup_boot_config(). */ return 0; } static void __init setup_boot_config(void) { - static char tmp_cmdline[COMMAND_LINE_SIZE] __initdata; const char *msg, *data; - int pos, ret; + int pos, ret, offs; size_t size; - char *err; + bool from_embedded = false; /* 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) + if (!data) { data = xbc_get_embedded_bootconfig(&size); + from_embedded = true; + } - strscpy(tmp_cmdline, boot_command_line, COMMAND_LINE_SIZE); - err = parse_args("bootconfig", tmp_cmdline, NULL, 0, 0, 0, NULL, - bootconfig_params); - - if (IS_ERR(err) || !(bootconfig_found || IS_ENABLED(CONFIG_BOOT_CONFIG_FORCE))) + bootconfig_found = bootconfig_cmdline_requested(boot_command_line, &offs); + if (!(bootconfig_found || IS_ENABLED(CONFIG_BOOT_CONFIG_FORCE))) return; - /* parse_args() stops at the next param of '--' and returns an address */ - if (err) - initargs_offs = err - tmp_cmdline; + /* Offset of the init arguments after a "--", located by the helper. */ + initargs_offs = offs; if (!data) { /* If user intended to use bootconfig, show an error level message */ @@ -422,8 +410,24 @@ static void __init setup_boot_config(void) } else { 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"); + /* + * keys starting with "kernel." are passed via cmdline. When + * this bootconfig came from the embedded source and + * setup_arch() already prepended the rendered "kernel" subtree + * to boot_command_line, rendering again here would duplicate + * the keys in saved_command_line and make accumulating handlers + * (console=, earlycon=, ...) re-register the same value. Skip + * only when the prepend really happened. + * + * On arches that do not select ARCH_SUPPORTS_CMDLINE_FROM_BOOTCONFIG, + * CONFIG_CMDLINE_FROM_BOOTCONFIG is unselectable and + * xbc_embedded_cmdline_applied() collapses to a stub returning + * false, so this path still runs and the embedded "kernel" + * keys reach the cmdline via the runtime parser exactly as + * before this series. + */ + if (!from_embedded || !xbc_embedded_cmdline_applied()) + extra_command_line = xbc_make_cmdline("kernel"); /* Also, "init." keys are init arguments */ extra_init_args = xbc_make_cmdline("init"); } diff --git a/lib/Makefile b/lib/Makefile index dee4cee03e2d..dfab958327c5 100644 --- a/lib/Makefile +++ b/lib/Makefile @@ -273,6 +273,22 @@ filechk_defbconf = cat $(or $(real-prereqs), /dev/null) $(obj)/default.bconf: $(CONFIG_BOOT_CONFIG_EMBED_FILE) FORCE $(call filechk,defbconf) +obj-$(CONFIG_CMDLINE_FROM_BOOTCONFIG) += embedded-cmdline.o +$(obj)/embedded-cmdline.o: $(obj)/embedded_cmdline.bin + +# Render the bootconfig "kernel" subtree to a flat cmdline string using +# the userspace tools/bootconfig parser (-C mode). The runtime prepend +# helper enforces COMMAND_LINE_SIZE at boot, so no build-time size +# check is performed here (COMMAND_LINE_SIZE is an arch header +# constant, not a Kconfig value). +quiet_cmd_render_cmdline = BCONF2C $@ + cmd_render_cmdline = \ + $(objtree)/tools/bootconfig/bootconfig -C $< > $@ + +targets += embedded_cmdline.bin +$(obj)/embedded_cmdline.bin: $(obj)/default.bconf $(objtree)/tools/bootconfig/bootconfig FORCE + $(call if_changed,render_cmdline) + obj-$(CONFIG_RBTREE_TEST) += rbtree_test.o obj-$(CONFIG_INTERVAL_TREE_TEST) += interval_tree_test.o diff --git a/lib/bootconfig.c b/lib/bootconfig.c index 2ed9ee3dc81c..89c88e359179 100644 --- a/lib/bootconfig.c +++ b/lib/bootconfig.c @@ -19,9 +19,13 @@ #include <linux/errno.h> #include <linux/cache.h> #include <linux/compiler.h> +#include <linux/init.h> +#include <linux/moduleparam.h> +#include <linux/printk.h> #include <linux/sprintf.h> #include <linux/memblock.h> #include <linux/string.h> +#include <asm/setup.h> /* COMMAND_LINE_SIZE */ #ifdef CONFIG_BOOT_CONFIG_EMBED /* embedded_bootconfig_data is defined in bootconfig-data.S */ @@ -34,7 +38,129 @@ const char * __init xbc_get_embedded_bootconfig(size_t *size) return (*size) ? embedded_bootconfig_data : NULL; } #endif -#endif + +#ifdef CONFIG_CMDLINE_FROM_BOOTCONFIG +/* embedded_kernel_cmdline is defined in embedded-cmdline.S */ +extern __visible const char embedded_kernel_cmdline[]; +extern __visible const char embedded_kernel_cmdline_end[]; + +/* Set once the embedded cmdline has actually been prepended. */ +static bool xbc_cmdline_applied __initdata; + +/* + * str_prepend() - Prepend @src in front of the string in @dst, in place + * @dst: NUL-terminated destination buffer, currently @dst_len bytes long + * @dst_len: length of the current @dst string (excluding its NUL) + * @src: bytes to prepend (not NUL-terminated) + * @src_len: number of bytes from @src to prepend + * + * The caller must guarantee @dst has room for src_len + dst_len + 1 bytes. + * Moving dst_len + 1 bytes carries @dst's NUL terminator too, so an empty + * @dst needs no special case. + */ +static void __init str_prepend(char *dst, size_t dst_len, + const char *src, size_t src_len) +{ + memmove(dst + src_len, dst, dst_len + 1); + memcpy(dst, src, src_len); +} + +/** + * xbc_prepend_embedded_cmdline() - Prepend embedded bootconfig cmdline + * @dst: cmdline buffer to prepend into (must already contain a NUL byte) + * @size: total capacity of @dst in bytes + * + * Prepend the build-time-rendered "kernel" subtree of the embedded + * bootconfig to @dst. The rendered string already ends with a single + * space (the xbc_snprint_cmdline() invariant), which serves as the + * separator between the embedded keys and any existing content of @dst. + * On overflow, log an error and leave @dst untouched rather than + * silently truncating: booting without the embedded values is better + * than refusing to boot, and the error message tells the user why + * their embedded keys are missing. + * + * Intended to be called from setup_arch() before parse_early_param() so + * that early_param() handlers see the embedded values. + */ +void __init xbc_prepend_embedded_cmdline(char *dst, size_t size) +{ + size_t embed_len = embedded_kernel_cmdline_end - embedded_kernel_cmdline; + size_t dst_len; + + if (!size || embed_len <= 1) /* trailing NUL only */ + return; + embed_len--; /* exclude trailing NUL byte */ + + dst_len = strnlen(dst, size); + if (embed_len + dst_len + 1 > size) { + pr_err("embedded bootconfig cmdline (%zu bytes) does not fit in COMMAND_LINE_SIZE with %zu bytes already used; ignoring embedded values\n", + embed_len, dst_len); + return; + } + + str_prepend(dst, dst_len, embedded_kernel_cmdline, embed_len); + xbc_cmdline_applied = true; +} + +/** + * xbc_embedded_cmdline_applied() - Did the embedded cmdline get prepended? + * + * Return true if xbc_prepend_embedded_cmdline() actually prepended the + * embedded "kernel" subtree. setup_boot_config() uses this to avoid + * rendering the same keys a second time. + */ +bool __init xbc_embedded_cmdline_applied(void) +{ + return xbc_cmdline_applied; +} +#endif /* CONFIG_CMDLINE_FROM_BOOTCONFIG */ + +/* parse_args() callback: flag when the "bootconfig" parameter is present. */ +static int __init bootconfig_optin(char *param, char *val, + const char *unused, void *arg) +{ + if (!strcmp(param, "bootconfig")) + *(bool *)arg = true; + return 0; +} + +/** + * bootconfig_cmdline_requested() - Was "bootconfig" passed on the cmdline? + * @boot_cmdline: kernel command line to inspect (not modified) + * @end_offset: if non-NULL, set to the offset of the init arguments that + * follow a "--" separator, or 0 when there is none + * + * Parse a private copy of @boot_cmdline (parse_args() is destructive) and + * report whether "bootconfig" is present before the "--" separator. + * setup_arch() uses this to gate prepending the build-time embedded cmdline; + * setup_boot_config() uses it for the runtime opt-in and to locate the init + * arguments via @end_offset. Sharing one parser keeps the early and late + * paths agreeing on what counts as opt-in. CONFIG_BOOT_CONFIG_FORCE is not + * folded in here; callers apply it where they need it. + */ +bool __init bootconfig_cmdline_requested(const char *boot_cmdline, int *end_offset) +{ + static char tmp_cmdline[COMMAND_LINE_SIZE] __initdata; + bool found = false; + char *err; + + if (end_offset) + *end_offset = 0; + + strscpy(tmp_cmdline, boot_cmdline, COMMAND_LINE_SIZE); + err = parse_args("bootconfig", tmp_cmdline, NULL, 0, 0, 0, + &found, bootconfig_optin); + if (IS_ERR(err)) + return false; + + /* parse_args() stops at "--" and returns the address of the rest. */ + if (end_offset && err) + *end_offset = err - tmp_cmdline; + + return found; +} + +#endif /* __KERNEL__ */ /* * Extra Boot Config (XBC) is given as tree-structured ascii text of @@ -440,6 +566,17 @@ int __init xbc_snprint_cmdline(char *buf, size_t size, struct xbc_node *root) * itself is well defined and returns the would-be length. */ xbc_node_for_each_key_value(root, knode, val) { + /* + * An empty or value-only @root (e.g. "kernel {}" or + * "kernel = x", possibly alongside "kernel.foo = bar") + * yields @root itself here. Skip it: composing a key for it + * would fail with -EINVAL, yet any real descendant keys must + * still be rendered. An entirely empty subtree then renders + * nothing and returns 0 rather than an error. + */ + if (knode == root) + continue; + ret = xbc_node_compose_key_after(root, knode, xbc_namebuf, XBC_KEYLEN_MAX); if (ret < 0) diff --git a/lib/embedded-cmdline.S b/lib/embedded-cmdline.S new file mode 100644 index 000000000000..bda81b4a42be --- /dev/null +++ b/lib/embedded-cmdline.S @@ -0,0 +1,16 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Embed the build-time-rendered bootconfig "kernel" subtree as a flat + * cmdline string. setup_arch() prepends this to boot_command_line on + * architectures that select ARCH_SUPPORTS_CMDLINE_FROM_BOOTCONFIG. + * + * Copyright (c) 2026 Meta Platforms, Inc. and affiliates + * Copyright (c) 2026 Breno Leitao <leitao@debian.org> + */ + .section .init.rodata.embed_cmdline, "a", %progbits + .global embedded_kernel_cmdline +embedded_kernel_cmdline: + .incbin "lib/embedded_cmdline.bin" + .byte 0 + .global embedded_kernel_cmdline_end +embedded_kernel_cmdline_end: diff --git a/tools/bootconfig/Makefile b/tools/bootconfig/Makefile index 90eb47c9d8de..3cb8066d5141 100644 --- a/tools/bootconfig/Makefile +++ b/tools/bootconfig/Makefile @@ -15,7 +15,7 @@ override CFLAGS += -Wall -g -I$(CURDIR)/include ALL_TARGETS := bootconfig ALL_PROGRAMS := $(patsubst %,$(OUTPUT)%,$(ALL_TARGETS)) -all: $(ALL_PROGRAMS) test +all: $(ALL_PROGRAMS) $(OUTPUT)bootconfig: main.c include/linux/bootconfig.h $(LIBSRC) $(CC) $(filter %.c,$^) $(CFLAGS) $(LDFLAGS) -o $@ @@ -27,4 +27,4 @@ install: $(ALL_PROGRAMS) install $(OUTPUT)bootconfig $(DESTDIR)$(bindir) clean: - $(RM) -f $(OUTPUT)*.o $(ALL_PROGRAMS) + rm -f $(OUTPUT)*.o $(ALL_PROGRAMS) |
