Call xbc_prepend_embedded_cmdline() in setup_arch() right after the
CONFIG_CMDLINE merge and before strscpy(command_line, ...) so the
build-time-rendered embedded bootconfig "kernel" subtree is part of
boot_command_line by the time parse_early_param() runs. early_param()
handlers (mem=, earlycon=, loglevel=, ...) now see values supplied via
CONFIG_BOOT_CONFIG_EMBED_FILE without parsing bootconfig at runtime.

Select ARCH_SUPPORTS_CMDLINE_FROM_BOOTCONFIG so the user-visible
CONFIG_BOOT_CONFIG_EMBED_CMDLINE option becomes selectable on x86.

With this select in place, setup_boot_config() in init/main.c would
otherwise render the embedded "kernel" subtree a second time via
xbc_make_cmdline("kernel") and prepend it to saved_command_line /
static_command_line through extra_command_line, duplicating every
embedded kernel.* key in /proc/cmdline and causing accumulating
handlers (console=, earlycon=, ...) to register the same value twice.
Track whether the bootconfig data came from the embedded source and
skip the duplicate render in that case.

Signed-off-by: Breno Leitao <[email protected]>
---
 arch/x86/Kconfig        |  1 +
 arch/x86/kernel/setup.c |  3 +++
 init/main.c             | 19 ++++++++++++++++---
 3 files changed, 20 insertions(+), 3 deletions(-)

diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig
index f24810015234..f839795692b4 100644
--- a/arch/x86/Kconfig
+++ b/arch/x86/Kconfig
@@ -126,6 +126,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 46882ce79c3a..592c4c79c974 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>
@@ -924,6 +925,8 @@ void __init setup_arch(char **cmdline_p)
        builtin_cmdline_added = true;
 #endif
 
+       xbc_prepend_embedded_cmdline(boot_command_line, COMMAND_LINE_SIZE);
+
        strscpy(command_line, boot_command_line, COMMAND_LINE_SIZE);
        *cmdline_p = command_line;
 
diff --git a/init/main.c b/init/main.c
index e363232b428b..8264bfa97aa2 100644
--- a/init/main.c
+++ b/init/main.c
@@ -378,12 +378,15 @@ static void __init setup_boot_config(void)
        int pos, ret;
        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,
@@ -421,8 +424,18 @@ 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
+                * BOOT_CONFIG_EMBED_CMDLINE is enabled and this bootconfig
+                * came from the embedded source, setup_arch() already
+                * prepended the rendered "kernel" subtree to
+                * boot_command_line; rendering again here would duplicate
+                * the keys in saved_command_line / static_command_line and
+                * cause accumulating handlers (console=, earlycon=, ...) to
+                * re-register the same value.
+                */
+               if (!IS_ENABLED(CONFIG_BOOT_CONFIG_EMBED_CMDLINE) || 
!from_embedded)
+                       extra_command_line = xbc_make_cmdline("kernel");
                /* Also, "init." keys are init arguments */
                extra_init_args = xbc_make_cmdline("init");
        }

-- 
2.54.0


Reply via email to