Index: stand/efi/include/efidevp.h =================================================================== --- stand/efi/include/efidevp.h +++ stand/efi/include/efidevp.h @@ -141,6 +141,9 @@ UINT32 CID; } ACPI_EXTENDED_HID_DEVICE_PATH; +#define ACPI_ADR_DP 0x03 +/* ACPI_ADR_DEVICE_PATH not defined */ + // // EISA ID Macro // EISA ID Definition 32-bits Index: stand/efi/loader/bootinfo.c =================================================================== --- stand/efi/loader/bootinfo.c +++ stand/efi/loader/bootinfo.c @@ -68,10 +68,11 @@ static int bi_getboothowto(char *kargs) { - const char *sw; + const char *sw, *tmp; char *opts; char *console; - int howto; + int howto, speed, port; + char buf[50]; howto = bootenv_flags(); @@ -81,6 +82,35 @@ howto |= RB_SERIAL; if (strcmp(console, "nullconsole") == 0) howto |= RB_MUTE; + if (strcmp(console, "efi") == 0) { + /* + * If we found a com port and com speed, we need to tell + * the kernel where the serial port is, and how + * fast. Ideally, we'd get the port from ACPI, but that + * isn't running in the loader. Do the next best thing + * by allowing it to be set by a loader.conf variable, + * either a EFI specific one, or the compatible + * comconsole_port if not. PCI support is needed, but + * for that we'd ideally refactor the + * libi386/comconsole.c code to have identical behavior. + */ + tmp = getenv("efi_com_speed"); + if (tmp != NULL) { + speed = strtol(tmp, NULL, 0); + tmp = getenv("efi_com_port"); + if (tmp == NULL) + tmp = getenv("comconsole_port"); + /* XXX fallback to EFI variable set in rc.d? */ + if (tmp != NULL) + port = strtol(tmp, NULL, 0); + else + port = 0x3f8; + snprintf(buf, sizeof(buf), "io:%d,br:%d", port, + speed); + env_setenv("hw.uart.console", EV_VOLATILE, buf, + NULL, NULL); + } + } } /* Parse kargs */ Index: stand/efi/loader/main.c =================================================================== --- stand/efi/loader/main.c +++ stand/efi/loader/main.c @@ -72,6 +72,8 @@ EFI_GUID fdtdtb = FDT_TABLE_GUID; EFI_GUID inputid = SIMPLE_TEXT_INPUT_PROTOCOL; +static bool uefi_boot_mgr; + /* * Number of seconds to wait for a keystroke before exiting with failure * in the event no currdev is found. -2 means always break, -1 means @@ -496,12 +498,67 @@ return (howto); } +/* + * 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 + * ACPI name space to map the UID for the serial port to a port. The + * latter is especially hard. + */ +static int +parse_uefi_con_out(void) +{ + int how, rv; + bool vid_seen = false, com_seen = false; + size_t sz; + char buf[4096], *ep; + EFI_DEVICE_PATH *node; + ACPI_HID_DEVICE_PATH *acpi; + UART_DEVICE_PATH *uart; + + how = 0; + sz = sizeof(buf); + rv = efi_global_getenv("ConOut", buf, &sz); + if (rv != EFI_SUCCESS) + goto out; + ep = buf + sz; + node = (EFI_DEVICE_PATH *)buf; + while ((char *)node < ep) { + if (DevicePathType(node) == ACPI_DEVICE_PATH && + DevicePathSubType(node) == ACPI_DP) { + /* Check for Serial node */ + acpi = (void *)node; + if (EISA_ID_TO_NUM(acpi->HID) == 0x501) + com_seen = true; + } else if (DevicePathType(node) == MESSAGING_DEVICE_PATH && + DevicePathSubType(node) == MSG_UART_DP) { + char bd[16]; + + uart = (void *)node; + snprintf(bd, sizeof(bd), "%d", uart->BaudRate); + setenv("efi_com_speed", bd, 1); + printf("Console speed is %d\n", uart->BaudRate); + } else if (DevicePathType(node) == ACPI_DEVICE_PATH && + DevicePathSubType(node) == ACPI_ADR_DP) { + /* Check for AcpiAdr() Node for video */ + vid_seen = true; + } + node = NextDevicePathNode(node); /* Skip the end node */ + } + if (vid_seen && com_seen) + how = RB_MULTIPLE | RB_SERIAL; + else if (com_seen) + how = RB_SERIAL; + else if (vid_seen) + how = RB_RESERVED1; +out: + return (how); +} EFI_STATUS main(int argc, CHAR16 *argv[]) { EFI_GUID *guid; - int howto, i; + int howto, i, uhowto; UINTN k; bool has_kbd; char *s; @@ -550,21 +607,37 @@ howto = parse_args(argc, argv, has_kbd); - bootenv_set(howto); - - /* - * XXX we need fallback to this stuff after looking at the ConIn, ConOut and ConErr variables - */ - if (howto & RB_MULTIPLE) { - if (howto & RB_SERIAL) - setenv("console", "comconsole efi" , 1); - else - setenv("console", "efi comconsole" , 1); - } else if (howto & RB_SERIAL) { - setenv("console", "comconsole" , 1); - } else + uhowto = parse_uefi_con_out(); + + printf("howto is %#x and uhowto is %#x\n", howto, uhowto); + if (uhowto == 0) { + /* + * Couldn't figure it out from the ConOut env var, so fall back to + * the command line stuff passed in. + */ + bootenv_set(howto); + + /* + * If there's no ConOut, then we have to set things, though it's + * not clear how efi would work without it. + */ + if (howto & RB_MULTIPLE) { + if (howto & RB_SERIAL) + setenv("console", "comconsole efi" , 1); + else + setenv("console", "efi comconsole" , 1); + } else if (howto & RB_SERIAL) { + setenv("console", "comconsole" , 1); + } else + setenv("console", "efi", 1); + } else { + /* + * ConOut found something, so blend the command line args with what we found. + */ + uhowto &= ~RB_RESERVED1; + bootenv_set(uhowto | (howto & ~(RB_MULTIPLE | RB_SERIAL))); setenv("console", "efi", 1); - + } if (efi_copy_init()) { printf("failed to allocate staging area\n"); return (EFI_BUFFER_TOO_SMALL); @@ -651,7 +724,6 @@ return (EFI_NOT_FOUND); efi_init_environment(); - setenv("LINES", "24", 1); /* optional */ #if !defined(__arm__) for (k = 0; k < ST->NumberOfTableEntries; k++) {