From cbee2bc03fbfbfc4e1239bd406628992c9b99872 Mon Sep 17 00:00:00 2001 From: Ad Schellevis Date: Wed, 9 Feb 2022 18:30:09 +0100 Subject: [PATCH] stand: add EFI support for mmio serial consoles When no legacy serial is found, we may be looking at a non-legacy mmio serial device mapping, in which case the efi_devpath_name() for name ConOutDev looks like this: VenHw(XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX,0090DCFE00000000)/Uart(115200,8,N,1)/VenVt100() Which should tell the kernel to attach a console to 0xfedc9000 (little endian 64 bit value). The value is stored behind the VENDOR_DEVICE_PATH struct as a byte stream hence we need to check if said address is appended behind the node. Also enforce use for uart by requiring the console speed read from the same device. There is no scientific process for "rs:2" derivation, but evidence would indicate that this is the correct setting for existing MMIO EFI consoles. See also: http://bsdimp.blogspot.com/2018/07/how-to-get-memory-mapped-serial-console.html --- stand/efi/loader/bootinfo.c | 8 ++++++++ stand/efi/loader/main.c | 18 ++++++++++++++++++ 2 files changed, 26 insertions(+) diff --git a/stand/efi/loader/bootinfo.c b/stand/efi/loader/bootinfo.c index b55c2184d9f..611fa6c89a3 100644 --- a/stand/efi/loader/bootinfo.c +++ b/stand/efi/loader/bootinfo.c @@ -134,6 +134,14 @@ bi_getboothowto(char *kargs) NULL, NULL); } } + if (getenv("efi_com_mmio") != NULL && + getenv("efi_com_speed") != NULL && /* verifies uart mode */ + getenv("hw.uart.console") == NULL) { + snprintf(buf, sizeof(buf), "mm:%s,rs:2", + getenv("efi_com_mmio")); + env_setenv("hw.uart.console", EV_VOLATILE, buf, NULL, + NULL); + } #endif #endif } diff --git a/stand/efi/loader/main.c b/stand/efi/loader/main.c index e4d62f2e940..d39314e7a3f 100644 --- a/stand/efi/loader/main.c +++ b/stand/efi/loader/main.c @@ -719,6 +719,15 @@ setenv_int(const char *key, int val) setenv(key, buf, 1); } +static void +setenv_addr(const char *key, uint64_t addr) +{ + char buf[30]; + + snprintf(buf, sizeof(buf), "0x%llx", addr); + setenv(key, buf, 1); +} + /* * Parse ConOut (the list of consoles active) and see if we can find a * serial port and/or a video port. It would be nice to also walk the @@ -738,6 +747,7 @@ parse_uefi_con_out(void) EFI_DEVICE_PATH *node; ACPI_HID_DEVICE_PATH *acpi; UART_DEVICE_PATH *uart; + VENDOR_DEVICE_PATH *hw; bool pci_pending; how = 0; @@ -801,6 +811,14 @@ parse_uefi_con_out(void) * so only match it if it's last. */ pci_pending = true; + } else if (DevicePathType(node) == HARDWARE_DEVICE_PATH && + DevicePathSubType(node) == HW_VENDOR_DP) { + hw = (void *)node; + + if (DevicePathNodeLength(&hw->Header) == + sizeof(*hw) + sizeof(uint64_t)) { + setenv_addr("efi_com_mmio", *(uint64_t *)(hw + 1)); + } } node = NextDevicePathNode(node); }