mirror of
https://github.com/torvalds/linux.git
synced 2026-09-12 12:34:02 +02:00
Bootconfig updates for v7.3:
- bootconfig: Support build-time command line rendering for embedded bootconfig
. bootconfig: render descendant keys when xbc_snprint_cmdline() root has a
value. Fix xbc_snprint_cmdline() to render descendant keys when the root
has both a value and subkeys, and treats empty subtrees correctly.
. bootconfig: render embedded bootconfig as a kernel cmdline at build time.
Add build-time pipeline using tools/bootconfig -C to render the embedded
bootconfig "kernel" subtree into .init.rodata as a cmdline string.
. bootconfig: clean build-time tools/bootconfig from make clean.
. bootconfig: add xbc_prepend_embedded_cmdline() helper.
Add helper to prepend embedded bootconfig cmdline into boot_command_line
early before parse_early_param().
. x86/setup: prepend embedded bootconfig cmdline before parse_early_param.
Wire early prepend helper in x86 setup_arch() so early_param handlers see
values from the embedded bootconfig. (So this feature is currently x86 only)
. bootconfig: skip runtime kernel.* render once prepended early.
Avoid duplicating "kernel" keys in setup_boot_config().
. init/main.c: use bootconfig_cmdline_requested() for the runtime opt-in.
Refactor setup_boot_config() to share bootconfig_cmdline_requested().
. Documentation: bootconfig: document build-time cmdline rendering.
Document CONFIG_CMDLINE_FROM_BOOTCONFIG usage, requirements, and precedence.
-----BEGIN PGP SIGNATURE-----
iQFPBAABCgA5FiEEh7BulGwFlgAOi5DV2/sHvwUrPxsFAmqNQwAbHG1hc2FtaS5o
aXJhbWF0c3VAZ21haWwuY29tAAoJENv7B78FKz8bcLcH/1GHYfxZHrl1aA112j60
YqBgn98hnCiH+Q1wMhqgDIF7ks1qePT9pq0zC2vJawVa1BM6OM5RpnC4BW+YSpCa
7tRf209Hrr5sd2i0vmsnYpmd9SV9JWKsuyz6VJjFjPsfEFtI9Nj7d3jm7WfGypUc
aNEAjf3sntEaFB44MoKekHlLzTXDFrgBaUaAcdw3aGjUU1CE9ltdT+QooQGv6CHe
7Z+UlmGhg+jkQa1tNNpRnKZErD5OBLnTkoMU5ca3M7PQLlPjIcOTf62SInm47Ma/
viOyzkSYIXC/yq2U4Je4qKcZaKhNIL61jtQGFI8EbbZ0x1BzVbPjbr0DB3iq2YW4
4Xk=
=8++3
-----END PGP SIGNATURE-----
Merge tag 'bootconfig-v7.3' of git://git.kernel.org/pub/scm/linux/kernel/git/trace/linux-trace
Pull bootconfig updates from Masami Hiramatsu:
- Support build-time command line building for embedded bootconfig
- Fix xbc_snprint_cmdline() to render descendant keys when the root has
both a value and subkeys, and treats empty subtrees correctly.
- Add build-time pipeline using tools/bootconfig -C to render the
embedded bootconfig "kernel" subtree into .init.rodata as a cmdline
string.
- Clean build-time tools/bootconfig from make clean
- Add helper to prepend embedded bootconfig cmdline into
boot_command_line early before parse_early_param()
- Wire early prepend helper in x86 setup_arch() so early_param handlers
see values from the embedded bootconfig (currently x86 only)
- Avoid duplicating "kernel" keys in setup_boot_config()
- Refactor setup_boot_config() to share bootconfig_cmdline_requested()
- Document CONFIG_CMDLINE_FROM_BOOTCONFIG usage, requirements, and
precedence
* tag 'bootconfig-v7.3' of git://git.kernel.org/pub/scm/linux/kernel/git/trace/linux-trace:
init/main.c: use bootconfig_cmdline_requested() for the runtime opt-in
bootconfig: skip runtime kernel.* render once prepended early
x86/setup: prepend embedded bootconfig cmdline before parse_early_param
Documentation: bootconfig: document build-time cmdline rendering
bootconfig: add xbc_prepend_embedded_cmdline() helper
bootconfig: clean build-time tools/bootconfig from make clean
bootconfig: render embedded bootconfig as a kernel cmdline at build time
bootconfig: render descendant keys when xbc_snprint_cmdline() root has a value
This commit is contained in:
commit
5f5ef9c407
|
|
@ -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
|
||||
=================================
|
||||
|
||||
|
|
|
|||
|
|
@ -9898,6 +9898,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/*
|
||||
|
||||
|
|
|
|||
27
Makefile
27
Makefile
|
|
@ -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
|
||||
#
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
36
init/Kconfig
36
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
|
||||
|
|
|
|||
52
init/main.c
52
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");
|
||||
}
|
||||
|
|
|
|||
16
lib/Makefile
16
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
|
||||
|
||||
|
|
|
|||
139
lib/bootconfig.c
139
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)
|
||||
|
|
|
|||
16
lib/embedded-cmdline.S
Normal file
16
lib/embedded-cmdline.S
Normal file
|
|
@ -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:
|
||||
|
|
@ -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)
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user