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
This commit is contained in:
Ad Schellevis 2022-02-09 18:30:09 +01:00 committed by Franco Fichtner
parent fe1d1b42da
commit 56b85fc10c
2 changed files with 26 additions and 0 deletions

View file

@ -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
}

View file

@ -723,6 +723,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
@ -742,6 +751,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;
@ -805,6 +815,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);
}