]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
stub: Determine the correct serial console from the ACPI device path
authorDaan De Meyer <daan@amutable.com>
Wed, 1 Apr 2026 18:24:01 +0000 (18:24 +0000)
committerDaan De Meyer <daan.j.demeyer@gmail.com>
Thu, 2 Apr 2026 12:58:42 +0000 (14:58 +0200)
Instead of requiring exactly one serial device and assuming ttyS0,
extract the COM port index from the ACPI device path and use the
uart I/O port address format for the console= kernel argument.

On x86, the ACPI UID for PNP0501 (16550 UART) maps directly to the
COM port number: UID 0 = COM1 (0x3F8), UID 1 = COM2 (0x2F8), etc.
The I/O port addresses are fixed in the kernel (see
arch/x86/include/asm/serial.h). Using the console=uart,io,<addr>
format (see Documentation/admin-guide/kernel-parameters.txt) addresses
the UART by I/O port directly rather than relying on ttyS naming,
and also provides early console output before the full serial driver
loads.

Restrict the entire serial console auto-detection to x86. On non-x86
(e.g. ARM with PL011 UARTs), displays may be available without GOP
(e.g. simple-framebuffer via device tree), serial device indices are
assigned dynamically during probe rather than being fixed to I/O port
addresses, and the kernel has its own console auto-detection via DT
stdout-path.

When ConOut has no device path (ConSplitter), all text output handles
are enumerated. If multiple handles have PNP0501 UART nodes with
different UIDs, bail out rather than guessing.

Add ACPI_DP device path subtype, ACPI_HID_DEVICE_PATH struct, and
EISA_PNP_ID() macro to device-path.h for parsing ACPI device path
nodes. Remove MSG_UART_DP, device_path_has_uart(), count_serial_devices()
and proto/serial-io.h (no longer needed).

Move all the console logic to console.c as well.

src/boot/console.c
src/boot/console.h
src/boot/proto/device-path.h
src/boot/proto/serial-io.h [deleted file]
src/boot/stub.c

index 81a5641d40579b1ee3699c722b34d53ed3f00f89..8dcd986aa4f157277d620119b520ac77b49ccc5d 100644 (file)
@@ -1,8 +1,13 @@
 /* SPDX-License-Identifier: LGPL-2.1-or-later */
 
 #include "console.h"
+#include "device-path-util.h"
 #include "efi-log.h"
+#include "efi-string.h"
 #include "proto/graphics-output.h"
+#include "proto/pci-io.h"
+#include "string-util-fundamental.h"
+#include "util.h"
 
 #define SYSTEM_FONT_WIDTH 8
 #define SYSTEM_FONT_HEIGHT 19
@@ -347,3 +352,251 @@ EFI_STATUS console_query_mode(size_t *x_max, size_t *y_max) {
 
         return err;
 }
+
+static bool has_virtio_console_pci_device(void) {
+        _cleanup_free_ EFI_HANDLE *handles = NULL;
+        size_t n_handles = 0;
+
+        EFI_STATUS err = BS->LocateHandleBuffer(
+                        ByProtocol,
+                        MAKE_GUID_PTR(EFI_PCI_IO_PROTOCOL),
+                        NULL,
+                        &n_handles,
+                        &handles);
+        if (err != EFI_SUCCESS) {
+                log_debug_status(err, "Failed to locate PCI I/O protocol handles, assuming no VirtIO console: %m");
+                return false;
+        }
+
+        if (n_handles == 0) {
+                log_debug("No PCI devices found, not scanning for VirtIO console.");
+                return false;
+        }
+
+        log_debug("Found %zu PCI devices, scanning for VirtIO console...", n_handles);
+
+        size_t n_virtio_console = 0;
+
+        for (size_t i = 0; i < n_handles; i++) {
+                EFI_PCI_IO_PROTOCOL *pci_io = NULL;
+
+                if (BS->HandleProtocol(handles[i], MAKE_GUID_PTR(EFI_PCI_IO_PROTOCOL), (void **) &pci_io) != EFI_SUCCESS)
+                        continue;
+
+                /* Read PCI vendor ID and device ID (at offsets 0x00 and 0x02 in PCI config space) */
+                uint16_t pci_id[2] = {};
+                if (pci_io->Pci.Read(pci_io, EfiPciIoWidthUint16, /* offset= */ 0x00, /* count= */ 2, pci_id) != EFI_SUCCESS)
+                        continue;
+
+                log_debug("PCI device %zu: vendor=%04x device=%04x", i, pci_id[0], pci_id[1]);
+
+                if (pci_id[0] == PCI_VENDOR_ID_REDHAT && pci_id[1] == PCI_DEVICE_ID_VIRTIO_CONSOLE)
+                        n_virtio_console++;
+
+                if (n_virtio_console > 1) {
+                        log_debug("There is more than one VirtIO console PCI device, cannot determine which one is the console.");
+                        return false;
+                }
+        }
+
+        if (n_virtio_console == 0) {
+                log_debug("No VirtIO console PCI device found.");
+                return false;
+        }
+
+        log_debug("Found exactly one VirtIO console PCI device.");
+        return true;
+}
+
+static bool has_graphics_output(void) {
+        EFI_GRAPHICS_OUTPUT_PROTOCOL *gop = NULL;
+        EFI_STATUS err;
+
+        err = BS->LocateProtocol(MAKE_GUID_PTR(EFI_GRAPHICS_OUTPUT_PROTOCOL), NULL, (void **) &gop);
+        if (err != EFI_SUCCESS) {
+                log_debug_status(err, "No EFI Graphics Output Protocol found: %m");
+                return false;
+        }
+
+        log_debug("EFI Graphics Output Protocol found.");
+        return true;
+}
+
+#if defined(__i386__) || defined(__x86_64__)
+
+/* Walk the device path looking for a UART console and determine the COM port index from the
+ * ACPI device path node. On x86, the Linux kernel assigns fixed ttyS indices based on I/O port
+ * addresses (see arch/x86/include/asm/serial.h):
+ *
+ *   ttyS0=0x3F8, ttyS1=0x2F8, ttyS2=0x3E8, ttyS3=0x2E8
+ *
+ * On standard PC firmware, the ACPI UID for PNP0501 (16550 UART) maps directly to the COM port
+ * index: UID 0 = COM1 (0x3F8) = ttyS0, UID 1 = COM2 (0x2F8) = ttyS1, etc.
+ *
+ * Returns EFI_SUCCESS and sets *ret_index on success, or EFI_NOT_FOUND if no PNP0501 UART
+ * was found. */
+static EFI_STATUS device_path_get_uart_index(const EFI_DEVICE_PATH *dp, uint32_t *ret_index) {
+        assert(ret_index);
+
+        for (const EFI_DEVICE_PATH *node = dp; !device_path_is_end(node); node = device_path_next_node(node))
+                if (node->Type == ACPI_DEVICE_PATH &&
+                    node->SubType == ACPI_DP &&
+                    node->Length >= sizeof(ACPI_HID_DEVICE_PATH)) {
+                        const ACPI_HID_DEVICE_PATH *acpi = (const ACPI_HID_DEVICE_PATH *) node;
+                        if (acpi->HID == EISA_PNP_ID(0x0501)) {
+                                *ret_index = acpi->UID;
+                                return EFI_SUCCESS;
+                        }
+                }
+
+        return EFI_NOT_FOUND;
+}
+
+/* Check if the console output is a serial UART. If so, determine the COM port index from the
+ * ACPI device path so we can pass the correct console= device to the kernel. */
+static EFI_STATUS find_serial_console_index(uint32_t *ret_index) {
+        assert(ret_index);
+
+        /* First try the ConOut handle directly. */
+        EFI_DEVICE_PATH *dp = NULL;
+        if (BS->HandleProtocol(ST->ConsoleOutHandle, MAKE_GUID_PTR(EFI_DEVICE_PATH_PROTOCOL), (void **) &dp) == EFI_SUCCESS) {
+                _cleanup_free_ char16_t *dp_str = NULL;
+                (void) device_path_to_str(dp, &dp_str);
+                log_debug("ConOut device path: %ls", strempty(dp_str));
+
+                if (device_path_get_uart_index(dp, ret_index) == EFI_SUCCESS) {
+                        log_debug("ConOut is a serial console (port index %u).", *ret_index);
+                        return EFI_SUCCESS;
+                }
+
+                log_debug("ConOut device path does not contain a PNP0501 UART node.");
+                return EFI_NOT_FOUND;
+        }
+
+        /* ConOut handle has no device path (e.g. ConSplitter virtual handle). Enumerate all
+         * text output handles and check if any of them is a serial console. */
+        log_debug("ConOut handle has no device path, enumerating text output handles...");
+
+        _cleanup_free_ EFI_HANDLE *handles = NULL;
+        size_t n_handles = 0;
+        if (BS->LocateHandleBuffer(
+                        ByProtocol,
+                        MAKE_GUID_PTR(EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL),
+                        NULL,
+                        &n_handles,
+                        &handles) != EFI_SUCCESS) {
+                log_debug("Failed to enumerate text output handles.");
+                return EFI_NOT_FOUND;
+        }
+
+        bool found = false;
+
+        for (size_t i = 0; i < n_handles; i++) {
+                dp = NULL;
+                if (BS->HandleProtocol(handles[i], MAKE_GUID_PTR(EFI_DEVICE_PATH_PROTOCOL), (void **) &dp) != EFI_SUCCESS)
+                        continue;
+
+                _cleanup_free_ char16_t *dp_str = NULL;
+                (void) device_path_to_str(dp, &dp_str);
+                log_debug("Text output handle %zu device path: %ls", i, strempty(dp_str));
+
+                uint32_t index;
+                if (device_path_get_uart_index(dp, &index) != EFI_SUCCESS)
+                        continue;
+
+                log_debug("Text output handle %zu is a serial console (port index %u).", i, index);
+
+                if (found && *ret_index != index) {
+                        log_debug("Multiple serial consoles with different port indices found, cannot determine which one to use.");
+                        return EFI_NOT_FOUND;
+                }
+
+                *ret_index = index;
+                found = true;
+        }
+
+        if (!found) {
+                log_debug("No serial console found among text output handles.");
+                return EFI_NOT_FOUND;
+        }
+
+        return EFI_SUCCESS;
+}
+
+static const char16_t *serial_console_arg(uint32_t index) {
+        /* Use the uart I/O port address format (see Documentation/admin-guide/kernel-parameters.txt)
+         * instead of ttyS names. This addresses the 8250/16550 UART at the specified I/O port
+         * directly and switches to the matching ttyS device later. The I/O port addresses for
+         * the standard COM ports are fixed (see arch/x86/include/asm/serial.h), and the ACPI UID
+         * for PNP0501 maps directly to the COM port index. */
+        static const char16_t *const table[] = {
+                u"console=uart,io,0x3f8",  /* COM1 */
+                u"console=uart,io,0x2f8",  /* COM2 */
+                u"console=uart,io,0x3e8",  /* COM3 */
+                u"console=uart,io,0x2e8",  /* COM4 */
+        };
+
+        if (index >= ELEMENTSOF(table))
+                return NULL;
+
+        return table[index];
+}
+
+#endif /* __i386__ || __x86_64__ */
+
+/* If there's no console= in the command line yet, try to detect the appropriate console device.
+ *
+ * Detection order:
+ * 1. If exactly one VirtIO console PCI device exists -> console=hvc0
+ * 2. If there's graphical output (GOP) -> don't add console=, the kernel defaults are fine
+ * 3. On x86, if exactly one serial console exists -> console=uart,io,<addr>
+ * 4. Otherwise -> don't add console=, let the user handle it
+ *
+ * VirtIO console takes priority since it's explicitly configured by the VMM. Graphics is
+ * checked before serial to avoid accidentally redirecting output away from a graphical
+ * console by adding a serial console= argument.
+ *
+ * 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.).
+ *
+ * Not TPM-measured because the value is deterministically derived from firmware-reported
+ * hardware state (PCI device enumeration, GOP presence, serial device paths). */
+void cmdline_append_console(char16_t **cmdline) {
+        assert(cmdline);
+
+        if (*cmdline && (efi_fnmatch(u"console=*", *cmdline) || efi_fnmatch(u"* console=*", *cmdline))) {
+                log_debug("Kernel command line already contains console=, not adding one.");
+                return;
+        }
+
+        const char16_t *console_arg = NULL;
+
+        if (has_virtio_console_pci_device())
+                console_arg = u"console=hvc0";
+        else if (has_graphics_output()) {
+                log_debug("Graphical output available, not adding console= to kernel command line.");
+                return;
+        }
+#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);
+        }
+#endif
+
+        if (!console_arg) {
+                log_debug("Cannot determine console type, not adding console= to kernel command line.");
+                return;
+        }
+
+        log_debug("Appending %ls to kernel command line.", console_arg);
+
+        _cleanup_free_ char16_t *old = TAKE_PTR(*cmdline);
+        if (isempty(old))
+                *cmdline = xstrdup16(console_arg);
+        else
+                *cmdline = xasprintf("%ls %ls", old, console_arg);
+}
index 4d0d1364d8fa0ca8b5687934ad9ca428a748df3e..3a2bc6391cdce0034238397f6bda15e2288111ab 100644 (file)
@@ -36,3 +36,4 @@ EFI_STATUS console_key_read(uint64_t *ret_key, uint64_t timeout_usec);
 EFI_STATUS console_set_mode(int64_t mode);
 EFI_STATUS console_query_mode(size_t *x_max, size_t *y_max);
 EFI_STATUS query_screen_resolution(uint32_t *ret_width, uint32_t *ret_height);
+void cmdline_append_console(char16_t **cmdline);
index 531ff3d003bdc2e1a63ce9fcb83d7216da051966..d81c0e1f8dd17c285ffb773a70414515e54c53b6 100644 (file)
@@ -27,13 +27,14 @@ enum {
 
         HW_MEMMAP_DP                     = 0x03,
 
+        ACPI_DP                          = 0x01,
+
         MEDIA_HARDDRIVE_DP               = 0x01,
         MEDIA_VENDOR_DP                  = 0x03,
         MEDIA_FILEPATH_DP                = 0x04,
         MEDIA_PIWG_FW_FILE_DP            = 0x06,
         MEDIA_PIWG_FW_VOL_DP             = 0x07,
 
-        MSG_UART_DP                      = 0x0e,
         MSG_URI_DP                       = 24,
 };
 
@@ -48,6 +49,15 @@ typedef struct {
         EFI_GUID Guid;
 } _packed_ VENDOR_DEVICE_PATH;
 
+/* EISA PNP ID encoding: compressed 3-letter vendor + 16-bit product ID. */
+#define EISA_PNP_ID(Id) ((uint32_t) (((Id) << 16) | 0x41D0))
+
+typedef struct {
+        EFI_DEVICE_PATH Header;
+        uint32_t HID;
+        uint32_t UID;
+} _packed_ ACPI_HID_DEVICE_PATH;
+
 typedef struct {
         EFI_DEVICE_PATH Header;
         uint32_t MemoryType;
diff --git a/src/boot/proto/serial-io.h b/src/boot/proto/serial-io.h
deleted file mode 100644 (file)
index 98690c1..0000000
+++ /dev/null
@@ -1,7 +0,0 @@
-/* SPDX-License-Identifier: LGPL-2.1-or-later */
-#pragma once
-
-#include "efi.h"
-
-#define EFI_SERIAL_IO_PROTOCOL_GUID \
-        GUID_DEF(0xbb25cf6f, 0xf1d4, 0x11d2, 0x9a, 0x0c, 0x00, 0x90, 0x27, 0x3f, 0xc1, 0xfd)
index 02621b68bb928fcd457e7ae689074d7f33180dae..3c8318a2adfe4311c45ae5a435dbb4a3dd0fd9b6 100644 (file)
@@ -1,6 +1,7 @@
 /* SPDX-License-Identifier: LGPL-2.1-or-later */
 
 #include "boot-secret.h"
+#include "console.h"
 #include "cpio.h"
 #include "device-path-util.h"
 #include "devicetree.h"
@@ -15,9 +16,6 @@
 #include "memory-util-fundamental.h"
 #include "part-discovery.h"
 #include "pe.h"
-#include "proto/graphics-output.h"
-#include "proto/pci-io.h"
-#include "proto/serial-io.h"            /* IWYU pragma: keep */
 #include "proto/shell-parameters.h"
 #include "random-seed.h"
 #include "sbat.h"
@@ -1246,219 +1244,6 @@ static void measure_profile(unsigned profile, int *parameters_measured) {
         combine_measured_flag(parameters_measured, m);
 }
 
-static bool has_virtio_console_pci_device(void) {
-        _cleanup_free_ EFI_HANDLE *handles = NULL;
-        size_t n_handles = 0;
-
-        EFI_STATUS err = BS->LocateHandleBuffer(
-                        ByProtocol,
-                        MAKE_GUID_PTR(EFI_PCI_IO_PROTOCOL),
-                        NULL,
-                        &n_handles,
-                        &handles);
-        if (err != EFI_SUCCESS) {
-                log_debug_status(err, "Failed to locate PCI I/O protocol handles, assuming no VirtIO console: %m");
-                return false;
-        }
-
-        if (n_handles == 0) {
-                log_debug("No PCI devices found, not scanning for VirtIO console.");
-                return false;
-        }
-
-        log_debug("Found %zu PCI devices, scanning for VirtIO console...", n_handles);
-
-        size_t n_virtio_console = 0;
-
-        for (size_t i = 0; i < n_handles; i++) {
-                EFI_PCI_IO_PROTOCOL *pci_io = NULL;
-
-                if (BS->HandleProtocol(handles[i], MAKE_GUID_PTR(EFI_PCI_IO_PROTOCOL), (void **) &pci_io) != EFI_SUCCESS)
-                        continue;
-
-                /* Read PCI vendor ID and device ID (at offsets 0x00 and 0x02 in PCI config space) */
-                uint16_t pci_id[2] = {};
-                if (pci_io->Pci.Read(pci_io, EfiPciIoWidthUint16, /* offset= */ 0x00, /* count= */ 2, pci_id) != EFI_SUCCESS)
-                        continue;
-
-                log_debug("PCI device %zu: vendor=%04x device=%04x", i, pci_id[0], pci_id[1]);
-
-                if (pci_id[0] == PCI_VENDOR_ID_REDHAT && pci_id[1] == PCI_DEVICE_ID_VIRTIO_CONSOLE)
-                        n_virtio_console++;
-
-                if (n_virtio_console > 1) {
-                        log_debug("There is more than one VirtIO console PCI device, cannot determine which one is the console.");
-                        return false;
-                }
-        }
-
-        if (n_virtio_console == 0) {
-                log_debug("No VirtIO console PCI device found.");
-                return false;
-        }
-
-        log_debug("Found exactly one VirtIO console PCI device.");
-        return true;
-}
-
-static bool device_path_has_uart(const EFI_DEVICE_PATH *dp) {
-        for (const EFI_DEVICE_PATH *node = dp; !device_path_is_end(node); node = device_path_next_node(node))
-                if (node->Type == MESSAGING_DEVICE_PATH && node->SubType == MSG_UART_DP)
-                        return true;
-
-        return false;
-}
-
-static size_t count_serial_devices(void) {
-        _cleanup_free_ EFI_HANDLE *handles = NULL;
-        size_t n_handles = 0;
-
-        if (BS->LocateHandleBuffer(
-                        ByProtocol,
-                        MAKE_GUID_PTR(EFI_SERIAL_IO_PROTOCOL),
-                        NULL,
-                        &n_handles,
-                        &handles) != EFI_SUCCESS)
-                return 0;
-
-        log_debug("Found %zu serial I/O devices in total.", n_handles);
-        return n_handles;
-}
-
-static bool has_single_serial_console(void) {
-        /* Even if we find exactly one serial console, we can only confidently map it to ttyS0
-         * if there's only one serial device in the entire system. With multiple UARTs, the
-         * kernel assigns ttyS indices based on its own discovery order, so the console UART
-         * might end up as ttyS1 or higher. */
-        size_t n_serial_devices = count_serial_devices();
-        if (n_serial_devices == 0) {
-                log_debug("No serial I/O devices found.");
-                return false;
-        }
-        if (n_serial_devices > 1) {
-                log_debug("Found %zu serial I/O devices, cannot determine ttyS index.", n_serial_devices);
-                return false;
-        }
-
-        /* Exactly one serial device in the system. Verify it's actually used as a console
-         * by checking if ConOut or any text output handle has a UART device path. */
-
-        /* First try the ConOut handle directly */
-        EFI_DEVICE_PATH *dp = NULL;
-        if (BS->HandleProtocol(ST->ConsoleOutHandle, MAKE_GUID_PTR(EFI_DEVICE_PATH_PROTOCOL), (void **) &dp) == EFI_SUCCESS) {
-                _cleanup_free_ char16_t *dp_str = NULL;
-                (void) device_path_to_str(dp, &dp_str);
-                log_debug("ConOut device path: %ls", strempty(dp_str));
-
-                if (device_path_has_uart(dp)) {
-                        log_debug("ConOut device path contains UART node.");
-                        return true;
-                }
-
-                log_debug("ConOut device path does not contain UART node.");
-                return false;
-        }
-
-        /* ConOut handle has no device path (e.g. ConSplitter virtual handle). Enumerate all
-         * text output handles and check if any of them is a serial console. */
-        log_debug("ConOut handle has no device path, enumerating text output handles...");
-
-        _cleanup_free_ EFI_HANDLE *handles = NULL;
-        size_t n_handles = 0;
-        if (BS->LocateHandleBuffer(
-                        ByProtocol,
-                        MAKE_GUID_PTR(EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL),
-                        NULL,
-                        &n_handles,
-                        &handles) != EFI_SUCCESS) {
-                log_debug("Failed to enumerate text output handles.");
-                return false;
-        }
-
-        for (size_t i = 0; i < n_handles; i++) {
-                dp = NULL;
-                if (BS->HandleProtocol(handles[i], MAKE_GUID_PTR(EFI_DEVICE_PATH_PROTOCOL), (void **) &dp) != EFI_SUCCESS)
-                        continue;
-
-                _cleanup_free_ char16_t *dp_str = NULL;
-                (void) device_path_to_str(dp, &dp_str);
-                log_debug("Text output handle %zu device path: %ls", i, strempty(dp_str));
-
-                if (device_path_has_uart(dp)) {
-                        log_debug("Text output handle %zu is a serial console.", i);
-                        return true;
-                }
-        }
-
-        log_debug("No serial console found among text output handles.");
-        return false;
-}
-
-static bool has_graphics_output(void) {
-        EFI_GRAPHICS_OUTPUT_PROTOCOL *gop = NULL;
-        EFI_STATUS err;
-
-        err = BS->LocateProtocol(MAKE_GUID_PTR(EFI_GRAPHICS_OUTPUT_PROTOCOL), NULL, (void **) &gop);
-        if (err != EFI_SUCCESS) {
-                log_debug_status(err, "No EFI Graphics Output Protocol found: %m");
-                return false;
-        }
-
-        log_debug("EFI Graphics Output Protocol found.");
-        return true;
-}
-
-static const char16_t *serial_console_arg(void) {
-#if defined(__arm__) || defined(__aarch64__)
-        return u"console=ttyAMA0";
-#else
-        return u"console=ttyS0";
-#endif
-}
-
-/* If there's no console= in the command line yet, try to detect the appropriate console device.
- *
- * Detection order:
- * 1. If exactly one VirtIO console PCI device exists → console=hvc0
- * 2. If there's graphical output (GOP) → don't add console=, the kernel defaults are fine
- * 3. If exactly one serial console exists → arch-specific serial (ttyS0, ttyAMA0, etc.)
- * 4. Otherwise → don't add console=, let the user handle it
- *
- * VirtIO console takes priority since it's explicitly configured by the VMM. Graphics is
- * checked before serial to avoid accidentally redirecting output away from a graphical
- * console by adding a serial console= argument. */
-static void cmdline_append_console(char16_t **cmdline) {
-        assert(cmdline);
-
-        if (*cmdline && (efi_fnmatch(u"console=*", *cmdline) || efi_fnmatch(u"* console=*", *cmdline))) {
-                log_debug("Kernel command line already contains console=, not adding one.");
-                return;
-        }
-
-        const char16_t *console_arg = NULL;
-
-        if (has_virtio_console_pci_device())
-                console_arg = u"console=hvc0";
-        else if (has_graphics_output()) {
-                log_debug("Graphical output available, not adding console= to kernel command line.");
-                return;
-        } else if (has_single_serial_console())
-                console_arg = serial_console_arg();
-
-        if (!console_arg) {
-                log_debug("Cannot determine console type, not adding console= to kernel command line.");
-                return;
-        }
-
-        log_debug("Appending %ls to kernel command line.", console_arg);
-
-        _cleanup_free_ char16_t *old = TAKE_PTR(*cmdline);
-        if (isempty(old))
-                *cmdline = xstrdup16(console_arg);
-        else
-                *cmdline = xasprintf("%ls %ls", old, console_arg);
-}
-
 static EFI_STATUS run(EFI_HANDLE image) {
         int sections_measured = -1, parameters_measured = -1, sysext_measured = -1, confext_measured = -1;
         _cleanup_(devicetree_cleanup) struct devicetree_state dt_state = {};
@@ -1521,10 +1306,6 @@ static EFI_STATUS run(EFI_HANDLE image) {
         cmdline_append_and_measure_addons(cmdline_addons, &cmdline, &parameters_measured);
         cmdline_append_and_measure_smbios(&cmdline, &parameters_measured);
 
-        /* Console auto-detection is intentionally not TPM-measured. The value is deterministically
-         * derived from firmware-reported hardware state (PCI device enumeration, GOP presence, serial
-         * device paths), so it doesn't represent an independent input that could be manipulated
-         * without also changing the firmware environment that TPM already captures. */
         cmdline_append_console(&cmdline);
 
         export_common_variables(loaded_image);