bootm: Fix Linux silent console on newer kernels
authorSean Anderson <sean.anderson@seco.com>
Thu, 19 May 2022 22:26:05 +0000 (18:26 -0400)
committerTom Rini <trini@konsulko.com>
Mon, 6 Jun 2022 22:01:21 +0000 (18:01 -0400)
Linux determines its console based on several sources:

1. the console command line parameter
2. device tree (e.g. /chosen/stdout-path)
3. various other board- and arch-specific sources

If the console parameter specifies a real console (e.g. ttyS0) then that is
used as /dev/console. However, if it does not specify a real console (e.g.
ttyDoesntExist) then *nothing* will be used as /dev/console.
Reading/writing it will return ENODEV. Additionally, no other source will
be used as a console source.

Linux commit ab4af56ae250 ("printk/console: Allow to disable console output
by using console="" or console=null") recently changed the semantics of the
parameter. Previously, specifying console="" would be treated like
specifying some other bad console. This commit changed things so that it
added /dev/ttynull as a console (if available).  However, it also allows
for other console sources. If the device tree specifies a console (such as
if U-Boot and Linux share a device tree), then it will be used in addition
to /dev/ttynull. This can result in a non-silent console.

To avoid this, explicitly set ttynull as the console. This will disable
other console sources. If CONFIG_NULL_TTY is disabled, then this will have
the same behavior as in the past (no output, and writing /dev/console
returns ENODEV).

[1] and [2] have additional background on this kernel change.

[1] https://lore.kernel.org/all/20201006025935.GA597@jagdpanzerIV.localdomain/
[2] https://lore.kernel.org/all/20201111135450.11214-1-pmladek@suse.com/

Signed-off-by: Sean Anderson <sean.anderson@seco.com>
boot/bootm.c
test/bootm.c

index 714406a..dfa65f1 100644 (file)
@@ -498,7 +498,8 @@ ulong bootm_disable_interrupts(void)
 }
 
 #define CONSOLE_ARG            "console="
-#define CONSOLE_ARG_SIZE       sizeof(CONSOLE_ARG)
+#define NULL_CONSOLE           (CONSOLE_ARG "ttynull")
+#define CONSOLE_ARG_SIZE       sizeof(NULL_CONSOLE)
 
 /**
  * fixup_silent_linux() - Handle silencing the linux boot if required
@@ -550,21 +551,22 @@ static int fixup_silent_linux(char *buf, int maxlen)
                        char *end = strchr(start, ' ');
                        int start_bytes;
 
-                       start_bytes = start - cmdline + CONSOLE_ARG_SIZE - 1;
+                       start_bytes = start - cmdline;
                        strncpy(buf, cmdline, start_bytes);
+                       strncpy(buf + start_bytes, NULL_CONSOLE, CONSOLE_ARG_SIZE);
                        if (end)
-                               strcpy(buf + start_bytes, end);
+                               strcpy(buf + start_bytes + CONSOLE_ARG_SIZE - 1, end);
                        else
-                               buf[start_bytes] = '\0';
+                               buf[start_bytes + CONSOLE_ARG_SIZE] = '\0';
                } else {
-                       sprintf(buf, "%s %s", cmdline, CONSOLE_ARG);
+                       sprintf(buf, "%s %s", cmdline, NULL_CONSOLE);
                }
                if (buf + strlen(buf) >= cmdline)
                        return -ENOSPC;
        } else {
-               if (maxlen < sizeof(CONSOLE_ARG))
+               if (maxlen < CONSOLE_ARG_SIZE)
                        return -ENOSPC;
-               strcpy(buf, CONSOLE_ARG);
+               strcpy(buf, NULL_CONSOLE);
        }
        debug("after silent fix-up: %s\n", buf);
 
index 8528982..7d03e1e 100644 (file)
@@ -83,12 +83,12 @@ static int bootm_test_silent(struct unit_test_state *uts)
 
        ut_assertok(env_set("silent_linux", "yes"));
        ut_assertok(bootm_process_cmdline(buf, BUF_SIZE, BOOTM_CL_SILENT));
-       ut_asserteq_str("console=", buf);
+       ut_asserteq_str("console=ttynull", buf);
 
        /* Empty buffer should still add the string */
        *buf = '\0';
        ut_assertok(bootm_process_cmdline(buf, BUF_SIZE, BOOTM_CL_SILENT));
-       ut_asserteq_str("console=", buf);
+       ut_asserteq_str("console=ttynull", buf);
 
        /* Check nothing happens when do_silent is false */
        *buf = '\0';
@@ -97,21 +97,21 @@ static int bootm_test_silent(struct unit_test_state *uts)
 
        /* Not enough space */
        *buf = '\0';
-       ut_asserteq(-ENOSPC, bootm_process_cmdline(buf, 8, BOOTM_CL_SILENT));
+       ut_asserteq(-ENOSPC, bootm_process_cmdline(buf, 15, BOOTM_CL_SILENT));
 
        /* Just enough space */
        *buf = '\0';
-       ut_assertok(bootm_process_cmdline(buf, 9, BOOTM_CL_SILENT));
+       ut_assertok(bootm_process_cmdline(buf, 16, BOOTM_CL_SILENT));
 
        /* add at end */
        strcpy(buf, "something");
        ut_assertok(bootm_process_cmdline(buf, BUF_SIZE, BOOTM_CL_SILENT));
-       ut_asserteq_str("something console=", buf);
+       ut_asserteq_str("something console=ttynull", buf);
 
        /* change at start */
        strcpy(buf, CONSOLE_STR " something");
        ut_assertok(bootm_process_cmdline(buf, BUF_SIZE, BOOTM_CL_SILENT));
-       ut_asserteq_str("console= something", buf);
+       ut_asserteq_str("console=ttynull something", buf);
 
        return 0;
 }
@@ -210,12 +210,12 @@ static int bootm_test_subst_var(struct unit_test_state *uts)
 {
        env_set("bootargs", NULL);
        ut_assertok(bootm_process_cmdline_env(BOOTM_CL_SILENT));
-       ut_asserteq_str("console=", env_get("bootargs"));
+       ut_asserteq_str("console=ttynull", env_get("bootargs"));
 
        ut_assertok(env_set("var", "abc"));
        ut_assertok(env_set("bootargs", "some${var}thing"));
        ut_assertok(bootm_process_cmdline_env(BOOTM_CL_SILENT));
-       ut_asserteq_str("some${var}thing console=", env_get("bootargs"));
+       ut_asserteq_str("some${var}thing console=ttynull", env_get("bootargs"));
 
        return 0;
 }
@@ -227,12 +227,12 @@ static int bootm_test_subst_both(struct unit_test_state *uts)
        ut_assertok(env_set("silent_linux", "yes"));
        env_set("bootargs", NULL);
        ut_assertok(bootm_process_cmdline_env(BOOTM_CL_ALL));
-       ut_asserteq_str("console=", env_get("bootargs"));
+       ut_asserteq_str("console=ttynull", env_get("bootargs"));
 
        ut_assertok(env_set("bootargs", "some${var}thing " CONSOLE_STR));
        ut_assertok(env_set("var", "1234567890"));
        ut_assertok(bootm_process_cmdline_env(BOOTM_CL_ALL));
-       ut_asserteq_str("some1234567890thing console=", env_get("bootargs"));
+       ut_asserteq_str("some1234567890thing console=ttynull", env_get("bootargs"));
 
        return 0;
 }