From owner-svn-src-all@freebsd.org Thu Feb 21 02:28:05 2019 Return-Path: Delivered-To: svn-src-all@mailman.ysv.freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2610:1c1:1:606c::19:1]) by mailman.ysv.freebsd.org (Postfix) with ESMTP id CB79014EA022; Thu, 21 Feb 2019 02:28:05 +0000 (UTC) (envelope-from kevans@FreeBSD.org) Received: from mxrelay.nyi.freebsd.org (mxrelay.nyi.freebsd.org [IPv6:2610:1c1:1:606c::19:3]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) server-signature RSA-PSS (4096 bits) client-signature RSA-PSS (4096 bits) client-digest SHA256) (Client CN "mxrelay.nyi.freebsd.org", Issuer "Let's Encrypt Authority X3" (verified OK)) by mx1.freebsd.org (Postfix) with ESMTPS id 6853884ECF; Thu, 21 Feb 2019 02:28:05 +0000 (UTC) (envelope-from kevans@FreeBSD.org) Received: from repo.freebsd.org (repo.freebsd.org [IPv6:2610:1c1:1:6068::e6a:0]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (Client did not present a certificate) by mxrelay.nyi.freebsd.org (Postfix) with ESMTPS id 53294EE34; Thu, 21 Feb 2019 02:28:05 +0000 (UTC) (envelope-from kevans@FreeBSD.org) Received: from repo.freebsd.org ([127.0.1.37]) by repo.freebsd.org (8.15.2/8.15.2) with ESMTP id x1L2S5dg075577; Thu, 21 Feb 2019 02:28:05 GMT (envelope-from kevans@FreeBSD.org) Received: (from kevans@localhost) by repo.freebsd.org (8.15.2/8.15.2/Submit) id x1L2S4dn075574; Thu, 21 Feb 2019 02:28:04 GMT (envelope-from kevans@FreeBSD.org) Message-Id: <201902210228.x1L2S4dn075574@repo.freebsd.org> X-Authentication-Warning: repo.freebsd.org: kevans set sender to kevans@FreeBSD.org using -f From: Kyle Evans Date: Thu, 21 Feb 2019 02:28:04 +0000 (UTC) To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-stable@freebsd.org, svn-src-stable-11@freebsd.org Subject: svn commit: r344403 - in stable/11/stand/efi: include loader X-SVN-Group: stable-11 X-SVN-Commit-Author: kevans X-SVN-Commit-Paths: in stable/11/stand/efi: include loader X-SVN-Commit-Revision: 344403 X-SVN-Commit-Repository: base MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit X-Rspamd-Queue-Id: 6853884ECF X-Spamd-Bar: -- Authentication-Results: mx1.freebsd.org X-Spamd-Result: default: False [-2.94 / 15.00]; local_wl_from(0.00)[FreeBSD.org]; NEURAL_HAM_MEDIUM(-1.00)[-0.999,0]; NEURAL_HAM_LONG(-1.00)[-0.999,0]; NEURAL_HAM_SHORT(-0.95)[-0.947,0]; ASN(0.00)[asn:11403, ipnet:2610:1c1:1::/48, country:US] X-BeenThere: svn-src-all@freebsd.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: "SVN commit messages for the entire src tree \(except for " user" and " projects" \)" List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Thu, 21 Feb 2019 02:28:06 -0000 Author: kevans Date: Thu Feb 21 02:28:04 2019 New Revision: 344403 URL: https://svnweb.freebsd.org/changeset/base/344403 Log: MFC r336264, r336270-r336272, r336464, r336627: UEFI Console Improvements r336264: Define ADR subtype of ACPI type for a device path. r336270: uefi stand: Guess the console better For server machines, ComOut is set to the set of devices that the efi console suppots. Parse it to see if we have serial, video or both. Make that take precidence over the command line args. boot1.efi parses them, but loader.efi doesn't. It's not clear where to read boot.conf from, so we don't do that. The command line args can still be set via efibootmgr, which is more inline with the UEFI boot manager to replace that. These args are typically used only to set serial vs video and the com speed line. We can infer that from ComOut, so do so. Remember the com speed and hw.uart.console to match. r336271: Add reporting of whether or not a keyboard is detected. In addition, note that r336270's commit message was slightly incorrect. It changed the default setting of the console to honor the ConOut variable. Overrides via the command line are still possible, and we use the devices in ConOut to set the proper console. If, for example, serial cosnole is specified, we'll set console to "efi" if ConOut has a serial port list and to either "efi comconsole" or "comconsole efi" if not depending on whether -D or -D -h was specified. r336272: Minor adjustments: o Fix the parsing of the device path. a last minute change terminated it too soon. o Kill setting LINES. We don't need to do it, and even if we did hard coding it to 24 is wrong. o Now that the console is working again for the loader, adjust the printfs to be more in line with other platforms. r336464: If the console is already set, don't override it. If console=X is specified on the command line, it's effectively overridden by the current code. It shouldn't do that. r336627: Fix the attempt to see if we're overriding the console in the command line args. I had thought console would be NULL, but it's efi. Set it to efi (as a clue) before we initialize the console, then test it to see if it changed on the command line to do the automatic override. This gets my serial console back. RelNotes: yes Modified: stable/11/stand/efi/include/efidevp.h stable/11/stand/efi/loader/bootinfo.c stable/11/stand/efi/loader/main.c Directory Properties: stable/11/ (props changed) Modified: stable/11/stand/efi/include/efidevp.h ============================================================================== --- stable/11/stand/efi/include/efidevp.h Thu Feb 21 01:30:37 2019 (r344402) +++ stable/11/stand/efi/include/efidevp.h Thu Feb 21 02:28:04 2019 (r344403) @@ -141,6 +141,9 @@ typedef struct _ACPI_EXTENDED_HID_DEVICE_PATH { 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 Modified: stable/11/stand/efi/loader/bootinfo.c ============================================================================== --- stable/11/stand/efi/loader/bootinfo.c Thu Feb 21 01:30:37 2019 (r344402) +++ stable/11/stand/efi/loader/bootinfo.c Thu Feb 21 02:28:04 2019 (r344403) @@ -67,10 +67,11 @@ extern EFI_SYSTEM_TABLE *ST; 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 = boot_parse_cmdline(kargs); howto |= boot_env_to_howto(); @@ -81,6 +82,35 @@ bi_getboothowto(char *kargs) 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); + } + } } return (howto); Modified: stable/11/stand/efi/loader/main.c ============================================================================== --- stable/11/stand/efi/loader/main.c Thu Feb 21 01:30:37 2019 (r344402) +++ stable/11/stand/efi/loader/main.c Thu Feb 21 02:28:04 2019 (r344403) @@ -316,11 +316,6 @@ find_currdev(EFI_LOADED_IMAGE *img) if (dp->pd_parent != NULL) { dp = dp->pd_parent; STAILQ_FOREACH(pp, &dp->pd_part, pd_link) { - text = efi_devpath_name(pp->pd_devpath); - if (text != NULL) { - printf("And now the part: %S\n", text); - efi_free_devpath_name(text); - } /* * Roll up the ZFS special case * for those partitions that have @@ -400,8 +395,8 @@ interactive_interrupt(const char *msg) return (false); } -int -parse_args(int argc, CHAR16 *argv[], bool has_kbd) +static int +parse_args(int argc, CHAR16 *argv[]) { int i, j, howto; bool vargood; @@ -429,12 +424,97 @@ parse_args(int argc, CHAR16 *argv[], bool has_kbd) 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; + int vid_seen = 0, com_seen = 0, seen = 0; + size_t sz; + char buf[4096], *ep; + EFI_DEVICE_PATH *node; + ACPI_HID_DEVICE_PATH *acpi; + UART_DEVICE_PATH *uart; + bool pci_pending; + 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) { + pci_pending = false; + 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 = ++seen; + } 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); + } else if (DevicePathType(node) == ACPI_DEVICE_PATH && + DevicePathSubType(node) == ACPI_ADR_DP) { + /* Check for AcpiAdr() Node for video */ + vid_seen = ++seen; + } else if (DevicePathType(node) == HARDWARE_DEVICE_PATH && + DevicePathSubType(node) == HW_PCI_DP) { + /* + * Note, vmware fusion has a funky console device + * PciRoot(0x0)/Pci(0xf,0x0) + * which we can only detect at the end since we also + * have to cope with: + * PciRoot(0x0)/Pci(0x1f,0x0)/Serial(0x1) + * so only match it if it's last. + */ + pci_pending = true; + } + node = NextDevicePathNode(node); /* Skip the end node */ + } + if (pci_pending && vid_seen == 0) + vid_seen = ++seen; + + /* + * Truth table for RB_MULTIPLE | RB_SERIAL + * Value Result + * 0 Use only video console + * RB_SERIAL Use only serial console + * RB_MULTIPLE Use both video and serial console + * (but video is primary so gets rc messages) + * both Use both video and serial console + * (but serial is primary so gets rc messages) + * + * Try to honor this as best we can. If only one of serial / video + * found, then use that. Otherwise, use the first one we found. + * This also implies if we found nothing, default to video. + */ + how = 0; + if (vid_seen && com_seen) { + how |= RB_MULTIPLE; + if (com_seen < vid_seen) + how |= RB_SERIAL; + } else if (com_seen) + how |= RB_SERIAL; +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; @@ -474,6 +554,7 @@ main(int argc, CHAR16 *argv[]) * eg. the boot device, which we can't do yet. We can use * printf() etc. once this is done. */ + setenv("console", "efi", 1); cons_probe(); /* @@ -481,23 +562,61 @@ main(int argc, CHAR16 *argv[]) */ bcache_init(32768, 512); - howto = parse_args(argc, argv, has_kbd); + howto = parse_args(argc, argv); + if (!has_kbd && (howto & RB_PROBE)) + howto |= RB_SERIAL | RB_MULTIPLE; + howto &= ~RB_PROBE; + uhowto = parse_uefi_con_out(); - boot_howto_to_env(howto); - /* - * XXX we need fallback to this stuff after looking at the ConIn, ConOut and ConErr variables + * We now have two notions of console. howto should be viewed as + * overrides. If console is already set, don't set it again. */ - 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); - +#define VIDEO_ONLY 0 +#define SERIAL_ONLY RB_SERIAL +#define VID_SER_BOTH RB_MULTIPLE +#define SER_VID_BOTH (RB_SERIAL | RB_MULTIPLE) +#define CON_MASK (RB_SERIAL | RB_MULTIPLE) + if (strcmp(getenv("console"), "efi") == 0) { + if ((howto & CON_MASK) == 0) { + /* No override, uhowto is controlling and efi cons is perfect */ + howto = howto | (uhowto & CON_MASK); + setenv("console", "efi", 1); + } else if ((howto & CON_MASK) == (uhowto & CON_MASK)) { + /* override matches what UEFI told us, efi console is perfect */ + setenv("console", "efi", 1); + } else if ((uhowto & (CON_MASK)) != 0) { + /* + * We detected a serial console on ConOut. All possible + * overrides include serial. We can't really override what efi + * gives us, so we use it knowing it's the best choice. + */ + setenv("console", "efi", 1); + } else { + /* + * We detected some kind of serial in the override, but ConOut + * has no serial, so we have to sort out which case it really is. + */ + switch (howto & CON_MASK) { + case SERIAL_ONLY: + setenv("console", "comconsole", 1); + break; + case VID_SER_BOTH: + setenv("console", "efi comconsole", 1); + break; + case SER_VID_BOTH: + setenv("console", "comconsole efi", 1); + break; + /* case VIDEO_ONLY can't happen -- it's the first if above */ + } + } + } + /* + * howto is set now how we want to export the flags to the kernel, so + * set the env based on it. + */ + boot_howto_to_env(howto); + if (efi_copy_init()) { printf("failed to allocate staging area\n"); return (EFI_BUFFER_TOO_SMALL); @@ -517,18 +636,17 @@ main(int argc, CHAR16 *argv[]) } else printf("efipart_inithandles failed %d, expect failures", i); - printf("Command line arguments:"); + printf("%s\n", bootprog_info); + printf(" Command line arguments:"); for (i = 0; i < argc; i++) printf(" %S", argv[i]); printf("\n"); - printf("Image base: 0x%lx\n", (u_long)img->ImageBase); - printf("EFI version: %d.%02d\n", ST->Hdr.Revision >> 16, + printf(" EFI version: %d.%02d\n", ST->Hdr.Revision >> 16, ST->Hdr.Revision & 0xffff); - printf("EFI Firmware: %S (rev %d.%02d)\n", ST->FirmwareVendor, + printf(" EFI Firmware: %S (rev %d.%02d)\n", ST->FirmwareVendor, ST->FirmwareRevision >> 16, ST->FirmwareRevision & 0xffff); - printf("\n%s", bootprog_info); /* Determine the devpath of our image so we can prefer it. */ text = efi_devpath_name(img->FilePath); @@ -584,7 +702,6 @@ main(int argc, CHAR16 *argv[]) return (EFI_NOT_FOUND); efi_init_environment(); - setenv("LINES", "24", 1); /* optional */ #if !defined(__arm__) for (k = 0; k < ST->NumberOfTableEntries; k++) {