From nobody Tue Oct 15 11:14:05 2024 X-Original-To: dev-commits-src-main@mlmmj.nyi.freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2610:1c1:1:606c::19:1]) by mlmmj.nyi.freebsd.org (Postfix) with ESMTP id 4XSWgy2X4Lz5YmvP; Tue, 15 Oct 2024 11:14:06 +0000 (UTC) (envelope-from git@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) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256 client-signature RSA-PSS (4096 bits) client-digest SHA256) (Client CN "mxrelay.nyi.freebsd.org", Issuer "R11" (verified OK)) by mx1.freebsd.org (Postfix) with ESMTPS id 4XSWgy17mKz4ZJx; Tue, 15 Oct 2024 11:14:06 +0000 (UTC) (envelope-from git@FreeBSD.org) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=freebsd.org; s=dkim; t=1728990846; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding; bh=TBKRpMIdp/FE+Ul+tbA5PDcxL++stTH4gYyiRDfpu/4=; b=FtnbT/pYj2UItDi4ACwgKRYOPwqhhvP7wjX0Z4HzznAILae2mlzGRexRMl4gWYHc6gM2Ls JAFTLWakWihwWyP8taWXEV/wcghoNqESHtbZG8Ogn3dChQY/x/A29v5kyLLk03mDrZGr0E bpJ6/C34QyhbS9PRUXq/PvVrrD77TGwVQ72maY8o67FdCPUghntrWBmPCnxjrCbUHtXIlA l6PvNvzMjWvljvp0cmzCdEL45tlNci3nZJaAbI5/8KqzMJNoWXlOubr4iQ4qbqdxtepAO1 +ROnD1buPQwSe7miFw1TmX5hQwXWyNIhn+FpfLXuod/PR5foUCl58aA4ljIA4g== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=freebsd.org; s=dkim; t=1728990846; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding; bh=TBKRpMIdp/FE+Ul+tbA5PDcxL++stTH4gYyiRDfpu/4=; b=YYyUntjrgEoc1B/8LE0PXiesXjvhC3uf4x7RtQeRjVkitrq2dMUWIE6ggpckeV7eVfcBM7 0bHRJJndG1pRoDxNQ6o33Qf5g7bYcl0Lk73UH+RHpnFJRfu3NU3I3kSzhru3lx2NMBEZ5M oO3vTUa/UhoY9a+DVwu+DOob5YYT7MkgQS5iAdVrWXnrBZ4M7nMsCSZ6nza8ghOXQ0Fudn geIRZvVzFfMzyfL5HJeMBadjE7v8zThXSdJ6wE8mnmXxuRiJgG4Zw8mCPXa04bF1CNKbjq qJlqln7OC4klEewYasUKqWcPSe4r8USuRLxkBxptAmW1C+CrI8LDlqEW2ZBzCQ== ARC-Authentication-Results: i=1; mx1.freebsd.org; none ARC-Seal: i=1; s=dkim; d=freebsd.org; t=1728990846; a=rsa-sha256; cv=none; b=mPS2qnId80bPSMfiKFqgd4z0rjbbswVTKy4UkuKUUsQ/jORHhBWoEgTLTtoWq2JLACo86h k/nQ9e2S3D9Wp/EphibAEi6aGvtbZlFN5aWUq4IqU9IeikmI08YTk6CO4BTLHwc2Fl1i9F O0Qz7fpH/k4qv18lb2nzjRMMwsYh7yM106dImYQkArBp4mvxAstLejZ/zuOdkBvOqYgVbx M8PPXXNUDq+A7H3DCLyreqqmXH5/qDo9BEAL9W3cHb9I8ZimSRJSAcmFMexd9vMED8sLar riIbfP5OA+n7jUpvV61kCvk7tbyj4puh5wcUp/LZv6eUx32+xxoQKeNr5xCLjw== Received: from gitrepo.freebsd.org (gitrepo.freebsd.org [IPv6:2610:1c1:1:6068::e6a:5]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256) (Client did not present a certificate) by mxrelay.nyi.freebsd.org (Postfix) with ESMTPS id 4XSWgy0jkczKl2; Tue, 15 Oct 2024 11:14:06 +0000 (UTC) (envelope-from git@FreeBSD.org) Received: from gitrepo.freebsd.org ([127.0.1.44]) by gitrepo.freebsd.org (8.18.1/8.18.1) with ESMTP id 49FBE5pk098085; Tue, 15 Oct 2024 11:14:05 GMT (envelope-from git@gitrepo.freebsd.org) Received: (from git@localhost) by gitrepo.freebsd.org (8.18.1/8.18.1/Submit) id 49FBE5F7098082; Tue, 15 Oct 2024 11:14:05 GMT (envelope-from git) Date: Tue, 15 Oct 2024 11:14:05 GMT Message-Id: <202410151114.49FBE5F7098082@gitrepo.freebsd.org> To: src-committers@FreeBSD.org, dev-commits-src-all@FreeBSD.org, dev-commits-src-main@FreeBSD.org From: Warner Losh Subject: git: 70253b538f68 - main - loader.efi: Parse SPCR table entry in ACPI tables List-Id: Commit messages for the main branch of the src repository List-Archive: https://lists.freebsd.org/archives/dev-commits-src-main List-Help: List-Post: List-Subscribe: List-Unsubscribe: X-BeenThere: dev-commits-src-main@freebsd.org Sender: owner-dev-commits-src-main@FreeBSD.org MIME-Version: 1.0 Content-Type: text/plain; charset=utf-8 Content-Transfer-Encoding: 8bit X-Git-Committer: imp X-Git-Repository: src X-Git-Refname: refs/heads/main X-Git-Reftype: branch X-Git-Commit: 70253b538f68f2787d5913702337eb600799a3c3 Auto-Submitted: auto-generated The branch main has been updated by imp: URL: https://cgit.FreeBSD.org/src/commit/?id=70253b538f68f2787d5913702337eb600799a3c3 commit 70253b538f68f2787d5913702337eb600799a3c3 Author: Warner Losh AuthorDate: 2024-10-15 11:12:16 +0000 Commit: Warner Losh CommitDate: 2024-10-15 11:12:16 +0000 loader.efi: Parse SPCR table entry in ACPI tables If there's a SPCR, then use it to create and pass the right values to the uart. We pass xo=0 in to calcuate the xo from the baud rate. We try to be smart about what we set. We either set io or mm or pv/pd. Old kernels will still work, despite pb/pd not being supported, because we'll fall back to the SPCR parsing in the kernel. We don't support Rev3 or Rev4 SPCR yet. It's too new to be in real hardware yet. Sponsored by: Netflix Differential Revision: https://reviews.freebsd.org/D47085 --- stand/efi/loader/main.c | 220 ++++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 205 insertions(+), 15 deletions(-) diff --git a/stand/efi/loader/main.c b/stand/efi/loader/main.c index 13ef90795d4b..e8db72bf4c8a 100644 --- a/stand/efi/loader/main.c +++ b/stand/efi/loader/main.c @@ -728,14 +728,199 @@ setenv_int(const char *key, int val) setenv(key, buf, 1); } +static void * +acpi_map_sdt(vm_offset_t addr) +{ + /* PA == VA */ + return ((void *)addr); +} + +static int +acpi_checksum(void *p, size_t length) +{ + uint8_t *bp; + uint8_t sum; + + bp = p; + sum = 0; + while (length--) + sum += *bp++; + + return (sum); +} + +static void * +acpi_find_table(uint8_t *sig) +{ + int entries, i, addr_size; + ACPI_TABLE_HEADER *sdp; + ACPI_TABLE_RSDT *rsdt; + ACPI_TABLE_XSDT *xsdt; + vm_offset_t addr; + + if (rsdp == NULL) + return (NULL); + + rsdt = (ACPI_TABLE_RSDT *)(uintptr_t)rsdp->RsdtPhysicalAddress; + xsdt = (ACPI_TABLE_XSDT *)(uintptr_t)rsdp->XsdtPhysicalAddress; + if (rsdp->Revision < 2) { + sdp = (ACPI_TABLE_HEADER *)rsdt; + addr_size = sizeof(uint32_t); + } else { + sdp = (ACPI_TABLE_HEADER *)xsdt; + addr_size = sizeof(uint64_t); + } + entries = (sdp->Length - sizeof(ACPI_TABLE_HEADER)) / addr_size; + for (i = 0; i < entries; i++) { + if (addr_size == 4) + addr = le32toh(rsdt->TableOffsetEntry[i]); + else + addr = le64toh(xsdt->TableOffsetEntry[i]); + if (addr == 0) + continue; + sdp = (ACPI_TABLE_HEADER *)acpi_map_sdt(addr); + if (acpi_checksum(sdp, sdp->Length)) { + printf("RSDT entry %d (sig %.4s) is corrupt", i, + sdp->Signature); + continue; + } + if (memcmp(sig, sdp->Signature, 4) == 0) + return (sdp); + } + return (NULL); +} + +/* + * Convert the InterfaceType in the SPCR. These are encoded the same for DBG2 + * tables as well (though we don't parse those here). + */ +static const char * +acpi_uart_type(UINT8 t) +{ + static const char *types[] = { + [0] = "ns8250", /* Full 16550 */ + [1] = "ns8250", /* DBGP Rev 1 16550 subset */ + [3] = "pl011", /* Arm PL011 */ + [5] = "ns8250", /* Nvidia 16550 */ + [0x12] = "ns8250", /* 16550 defined in SerialPort */ + }; + + if (t >= nitems(types)) + return (NULL); + return (types[t]); +} + +static int +acpi_uart_baud(UINT8 b) +{ + static int baud[] = { 0, -1, -1, 9600, 19200, -1, 57600, 115200 }; + + if (b > 7) + return (-1); + return (baud[b]); +} + +static int +acpi_uart_regionwidth(UINT8 rw) +{ + if (rw == 0) + return (1); + if (rw > 4) + return (-1); + return (1 << (rw - 1)); +} + +static const char * +acpi_uart_parity(UINT8 p) +{ + /* Some of these SPCR entires get this wrong, hard wire none */ + return ("none"); +} + /* - * 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. Also check for ConIn as well. This will - * be enough to determine if we have serial, and if we don't, we default - * to video. If there's a dual-console situation with ConIn, this will - * currently fail. + * See if we can find a SPCR ACPI table in the static tables. If so, then it + * describes the serial console that's been redirected to, so we know that at + * least there's a serial console. this is most important for embedded systems + * that don't have traidtional PC serial ports. + * + * All the two letter variables in this function correspond to their usage in + * the uart(4) console string. We use io == -1 to select between I/O ports and + * memory mapped addresses. Set both hw.uart.console and hw.uart.consol.extra + * to communicate settings from SPCR to the kernel. + */ +static int +check_acpi_spcr(void) +{ + ACPI_TABLE_SPCR *spcr; + int br, db, io, rs, rw, sb, xo, pv, pd; + uintmax_t mm; + const char *dt, *pa; + char *val = NULL; + + spcr = acpi_find_table(ACPI_SIG_SPCR); + if (spcr == NULL) + return (0); + dt = acpi_uart_type(spcr->InterfaceType); + if (dt == NULL) { /* Kernel can't use unknown types */ + printf("UART Type %d not known\n", spcr->InterfaceType); + return (0); + } + + /* I/O vs Memory mapped vs PCI device */ + io = -1; + pv = spcr->PciVendorId; + pd = spcr->PciDeviceId; + if (pv == 0xffff && pd == 0xffff) { + if (spcr->SerialPort.SpaceId == 1) + io = spcr->SerialPort.Address; + else { + mm = spcr->SerialPort.Address; + rs = ffs(spcr->SerialPort.BitWidth) - 4; + rw = acpi_uart_regionwidth(spcr->SerialPort.AccessWidth); + } + } else { + /* XXX todo: bus:device:function + flags and segment */ + } + + /* Uart settings */ + pa = acpi_uart_parity(spcr->Parity); + sb = spcr->StopBits; + db = 8; + + /* + * Note: We don't support SPCR Rev3 or Rev4 so use Rev2 values, if we + * did we wouldn't have to do this weird dances with baud or xtal rates. + * Rev 3 and 4 are too new to have seen any deployment, and aren't in + * the system's actblX.h files yet. This will fail for newer high-speed + * consoles until acpica catches up with Microsoft's new definitions. + */ + xo = 0; + br = acpi_uart_baud(spcr->BaudRate); + + if (io != -1) { + asprintf(&val, "db:%d,dt:%s,io:%#x,pa:%s,br:%d,xo=%d", + db, dt, io, pa, br, xo); + } else if (pv != 0xffff && pd != 0xffff) { + asprintf(&val, "db:%d,dt:%s,pv:%#x,pd:%#x,pa:%s,br:%d,xo=%d", + db, dt, pv, pd, pa, br, xo); + } else { + asprintf(&val, "db:%d,dt:%s,mm:%#jx,rs:%d,rw:%d,pa:%s,br:%d,xo=%d", + db, dt, mm, rs, rw, pa, br, xo); + } + env_setenv("hw.uart.console", EV_VOLATILE, val, NULL, NULL); + free(val); + + return (RB_SERIAL); +} + + +/* + * 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 DSDT to map + * the UID for the serial port to a port since there's no standard mapping. Also + * check for ConIn as well. This will be enough to determine if we have serial, + * and if we don't, we default to video. If there's a dual-console situation + * with only ConIn defined, this will currently fail. */ int parse_uefi_con_out(void) @@ -749,7 +934,12 @@ parse_uefi_con_out(void) UART_DEVICE_PATH *uart; bool pci_pending; - how = 0; + /* + * A SPCR in the ACPI fixed tables documents a serial port used for the + * console. It may mirror a video console, or may be stand alone. If it + * is present, we return RB_SERIAL and will use it for the kernel. + */ + how = check_acpi_spcr(); sz = sizeof(buf); rv = efi_global_getenv("ConOut", buf, &sz); if (rv != EFI_SUCCESS) @@ -758,13 +948,13 @@ parse_uefi_con_out(void) rv = efi_global_getenv("ConIn", buf, &sz); if (rv != EFI_SUCCESS) { /* - * If we don't have any ConOut default to both. If we have GOP - * make video primary, otherwise just make serial primary. In - * either case, try to use both the 'efi' console which will use - * the GOP, if present and serial. If there's an EFI BIOS that - * omits this, but has a serial port redirect, we'll - * unavioidably get doubled characters (but we'll be right in - * all the other more common cases). + * If we don't have any Con* variable use both. If we have GOP + * make video primary, otherwise set serial primary. In either + * case, try to use both the 'efi' console which will use the + * GOP, if present and serial. If there's an EFI BIOS that omits + * this, but has a serial port redirect, we'll unavioidably get + * doubled characters, but we'll be right in all the other more + * common cases. */ if (efi_has_gop()) how |= RB_MULTIPLE;