From: Kai Lüke Date: Thu, 9 Jul 2026 08:35:42 +0000 (+0900) Subject: stub: Set up all detected consoles X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=924552cfbacd51be0229ac6ce95fe3b69c7b7923;p=thirdparty%2Fsystemd.git stub: Set up all detected consoles With no console= given the kernel will use the graphical console and if we give one console= then that will be used instead. But sometimes we want both a serial console and a graphical one to work. This would be consistent with the EFI menu and sd-boot showing on both already. It also makes the impact of a wrongly detected-but-missing VirtIO console lower when we emit it alongside of the other consoles we detect. Collect all detected consoles and emit them via console= with the same priority we used before to select them. This means for the main console there is no change but we get additional ones enabled. This helps with boot output and having a login presented, yet the main console is still special and gets the emergency output at boot (we should somehow surface that on the additional consoles but that's another topic). If we only see the graphical console (or none), we don't need to emit anything a the kernel already selects it itself. This also avoids suppressing the non-x86 kernel serial console detection. As mentioned above, the VirtIO console being wrongly added is now also less impactful. But for non-x86 ACPI case we could detect the serial so that console=hvc0 won't stop the kernel serial auto-detection. --- diff --git a/src/boot/console.c b/src/boot/console.c index 95f1d112476..06070347e38 100644 --- a/src/boot/console.c +++ b/src/boot/console.c @@ -544,24 +544,32 @@ static const char16_t *serial_console_arg(uint32_t index) { #endif /* __i386__ || __x86_64__ */ -/* If there's no console= in the command line yet, try to detect the appropriate console device. +/* If there's no console= in the command line yet, try to detect the appropriate console devices. * - * Detection order: - * 1. If there's graphical output (GOP) -> don't add console=, the kernel defaults are fine + * The kernel enables all consoles listed on the command line and the last console= becomes + * /dev/console, so entries are appended in ascending priority: + * 1. On x86, if exactly one serial console exists -> console=uart,io, * 2. If exactly one VirtIO console PCI device exists -> console=hvc0 - * 3. On x86, if exactly one serial console exists -> console=uart,io, + * 3. If there's graphical output (GOP) -> console=tty0, but only if 1. or 2. matched * 4. Otherwise -> don't add console=, let the user handle it * - * Graphics is checked first to avoid redirecting output away from a graphical console. + * Graphics takes priority to avoid redirecting (possibly interactive) main-console output away from a + * graphical console. If we only have a graphical one, we don't need to set console= because the kernel + * defaults to it anyway (and it would suppress non-x86 kernel auto-detection). * The VirtIO console takes priority over serial since it's explicitly configured by the VMM but detection * by PCI ID also triggers for non-console ports, so its presence alone doesn't imply that a hvc0 console * actually exists. For example, for qemu-guest-agent the PCI device is present but only a traditional - * serial console is used. In this case we wrongly prefer hvc0 for now. + * serial console is used. In this case we wrongly prefer hvc0 for now but this is mostly fine because a + * console= entry whose device never shows up is skipped by the kernel. The VMM can also be changed to make + * an explicit selection through a SMBIOS kernel-cmdline-extra or switch to using the virtio console + * instead of serial. * * Serial console auto-detection is restricted to x86 where ACPI PNP0501 UIDs map to fixed * I/O port addresses for 8250/16550 UARTs. On non-x86 (e.g. ARM), serial device indices are * assigned dynamically, and the kernel has its own console auto-detection mechanisms - * (DT stdout-path, etc.). + * (DT stdout-path, etc.). This case is problematic with VirtIO because we could emit console=hvc0 + * wrongly and then the kernel will never do its detection. TODO: For non-x86 ACPI we could do the SPCR + * lookup here. * * Not TPM-measured because the value is deterministically derived from firmware-reported * hardware state (PCI device enumeration, GOP presence, serial device paths). */ @@ -573,33 +581,43 @@ void cmdline_append_console(char16_t **cmdline) { return; } - if (has_graphics_output()) { - log_debug("Graphical output available, not adding console= to kernel command line."); - return; - } + const char16_t *console_args[3]; + size_t n_console_args = 0; - const char16_t *console_arg = NULL; - - if (has_virtio_console_pci_device()) - console_arg = u"console=hvc0"; #if defined(__i386__) || defined(__x86_64__) - else { - uint32_t serial_index; - if (find_serial_console_index(&serial_index) == EFI_SUCCESS) - console_arg = serial_console_arg(serial_index); + uint32_t serial_index; + if (find_serial_console_index(&serial_index) == EFI_SUCCESS) { + const char16_t *serial_arg = serial_console_arg(serial_index); + if (serial_arg) { + assert(n_console_args < ELEMENTSOF(console_args)); + console_args[n_console_args++] = serial_arg; + } } #endif - if (!console_arg) { - log_debug("Cannot determine console type, not adding console= to kernel command line."); + if (has_virtio_console_pci_device()) { + assert(n_console_args < ELEMENTSOF(console_args)); + console_args[n_console_args++] = u"console=hvc0"; + } + + if (n_console_args == 0) { + log_debug("No serial or VirtIO console found, not adding console= to kernel command line."); return; } - log_debug("Appending %ls to kernel command line.", console_arg); + /* Keep the graphical console enabled, as the main one, when adding other consoles. */ + if (has_graphics_output()) { + assert(n_console_args < ELEMENTSOF(console_args)); + console_args[n_console_args++] = u"console=tty0"; + } - _cleanup_free_ char16_t *old = TAKE_PTR(*cmdline); - if (isempty(old)) - *cmdline = xstrdup16(console_arg); - else - *cmdline = xasprintf("%ls %ls", old, console_arg); + FOREACH_ARRAY(arg, console_args, n_console_args) { + log_debug("Appending %ls to kernel command line.", *arg); + + _cleanup_free_ char16_t *old = TAKE_PTR(*cmdline); + if (isempty(old)) + *cmdline = xstrdup16(*arg); + else + *cmdline = xasprintf("%ls %ls", old, *arg); + } }