Skip site navigation (1)Skip section navigation (2)
Date:      Sat, 18 Mar 2023 07:20:33 GMT
From:      Wei Hu <whu@FreeBSD.org>
To:        src-committers@FreeBSD.org, dev-commits-src-all@FreeBSD.org, dev-commits-src-main@FreeBSD.org
Subject:   git: 927358dd98cb - main - amd64 loader: Use efiserialio for Hyper-V booted systems
Message-ID:  <202303180720.32I7KXOc030612@gitrepo.freebsd.org>

next in thread | raw e-mail | index | archive | help
The branch main has been updated by whu:

URL: https://cgit.FreeBSD.org/src/commit/?id=927358dd98cb902160093e0dc0bac002d6b43858

commit 927358dd98cb902160093e0dc0bac002d6b43858
Author:     Wei Hu <whu@FreeBSD.org>
AuthorDate: 2023-03-14 15:13:46 +0000
Commit:     Wei Hu <whu@FreeBSD.org>
CommitDate: 2023-03-18 07:07:35 +0000

    amd64 loader: Use efiserialio for Hyper-V booted systems
    
    UEFI provides ConIn/ConOut handles for consoles that it supports,
    which include the text-video and serial ports. When the serial port
    is available, use the UEFI driver instead of direct io-port accesses
    to avoid conflicts between the firmware and direct hardware access, as
    happens on Hyper-V (Azure) setups.
    
    This change enables efiserialio to be built for efi-amd64 and has
    higher order priority vs comconsole, and only uses efiserialio
    if the hypervisor is Hyper-V. When efiserialio successfully
    probes, it will set efi_comconsole_avail=true which will prevent
    comconsole from probing in this setup.
    
    Tested on Hyper-V, ESXi and Azure VMs.
    
    PR:             264267
    Reviewed by:    kevans, whu
    Tested by:      whu
    Obtained from:  Rubicon Communications, LLC (Netgate)
    MFC after:      2 weeks
    Sponsored by:   Rubicon Communications, LLC (Netgate)
---
 stand/efi/loader/arch/amd64/Makefile.inc |  1 +
 stand/efi/loader/bootinfo.c              | 11 ++++++--
 stand/efi/loader/conf.c                  |  6 +++++
 stand/efi/loader/efiserialio.c           | 43 ++++++++++++++++++++++++++++----
 stand/i386/libi386/comconsole.c          | 14 +++++++++++
 5 files changed, 68 insertions(+), 7 deletions(-)

diff --git a/stand/efi/loader/arch/amd64/Makefile.inc b/stand/efi/loader/arch/amd64/Makefile.inc
index 0d9e2648cb59..bd89044bd6c7 100644
--- a/stand/efi/loader/arch/amd64/Makefile.inc
+++ b/stand/efi/loader/arch/amd64/Makefile.inc
@@ -5,6 +5,7 @@ SRCS+=	amd64_tramp.S \
 	elf64_freebsd.c \
 	trap.c \
 	multiboot2.c \
+	efiserialio.c \
 	exc.S
 
 .PATH:	${BOOTSRC}/i386/libi386
diff --git a/stand/efi/loader/bootinfo.c b/stand/efi/loader/bootinfo.c
index 939f2cf4c3fe..d79f59343af1 100644
--- a/stand/efi/loader/bootinfo.c
+++ b/stand/efi/loader/bootinfo.c
@@ -119,10 +119,17 @@ bi_getboothowto(char *kargs)
 			if (tmp != NULL)
 				speed = strtol(tmp, NULL, 0);
 			tmp = getenv("efi_com_port");
-			if (tmp == NULL)
-				tmp = getenv("comconsole_port");
 			if (tmp != NULL)
 				port = strtol(tmp, NULL, 0);
+			if (port <= 0) {
+				tmp = getenv("comconsole_port");
+				if (tmp != NULL)
+					port = strtol(tmp, NULL, 0);
+				else {
+					if (port == 0)
+						port = 0x3f8;
+				}
+			}
 			if (speed != -1 && port != -1) {
 				snprintf(buf, sizeof(buf), "io:%d,br:%d", port,
 				    speed);
diff --git a/stand/efi/loader/conf.c b/stand/efi/loader/conf.c
index 863c9188c72c..051e1a3381d1 100644
--- a/stand/efi/loader/conf.c
+++ b/stand/efi/loader/conf.c
@@ -81,6 +81,9 @@ struct netif_driver *netif_drivers[] = {
 
 extern struct console efi_console;
 extern struct console comconsole;
+#if defined(__amd64__)
+extern struct console eficomconsole;
+#endif
 #if defined(__amd64__) || defined(__i386__)
 extern struct console nullconsole;
 extern struct console spinconsole;
@@ -88,6 +91,9 @@ extern struct console spinconsole;
 
 struct console *consoles[] = {
 	&efi_console,
+#if defined(__amd64__)
+	&eficomconsole,
+#endif
 	&comconsole,
 #if defined(__amd64__) || defined(__i386__)
 	&nullconsole,
diff --git a/stand/efi/loader/efiserialio.c b/stand/efi/loader/efiserialio.c
index 375e679d2590..5fbc700f6ac2 100644
--- a/stand/efi/loader/efiserialio.c
+++ b/stand/efi/loader/efiserialio.c
@@ -69,6 +69,11 @@ static int	comc_speed_set(struct env_var *, int, const void *);
 
 static struct serial	*comc_port;
 extern struct console efi_console;
+bool efi_comconsole_avail = false;
+
+#if defined(__amd64__)
+#define comconsole eficomconsole
+#endif
 
 struct console comconsole = {
 	.c_name = "comconsole",
@@ -254,11 +259,22 @@ comc_probe(struct console *sc)
 	char *env, *buf, *ep;
 	size_t sz;
 
+#if defined(__amd64__)
+	/*
+	 * For x86-64, don't use this driver if not running in Hyper-V.
+	 */
+	env = getenv("smbios.bios.version");
+	if (env == NULL || strncmp(env, "Hyper-V", 7) != 0) {
+		return;
+	}
+#endif
+
 	if (comc_port == NULL) {
 		comc_port = calloc(1, sizeof (struct serial));
 		if (comc_port == NULL)
 			return;
 	}
+
 	/* Use defaults from firmware */
 	comc_port->databits = 8;
 	comc_port->parity = DefaultParity;
@@ -308,6 +324,10 @@ comc_probe(struct console *sc)
 	    comc_port_set, env_nounset);
 
 	env = getenv("efi_com_speed");
+	if (env == NULL)
+		/* fallback to comconsole setting */
+		env = getenv("comconsole_speed");
+
 	if (comc_parse_intval(env, &val) == CMD_OK)
 		comc_port->baudrate = val;
 
@@ -318,8 +338,13 @@ comc_probe(struct console *sc)
 	    comc_speed_set, env_nounset);
 
 	comconsole.c_flags = 0;
-	if (comc_setup())
+	if (comc_setup()) {
 		sc->c_flags = C_PRESENTIN | C_PRESENTOUT;
+		efi_comconsole_avail = true;
+	} else {
+		/* disable being seen as "comconsole" */
+		comconsole.c_name = "efiserialio";
+	}
 }
 
 static int
@@ -489,6 +514,7 @@ comc_setup(void)
 {
 	EFI_STATUS status;
 	UINT32 control;
+	char *ev;
 
 	/* port is not usable */
 	if (comc_port->sio == NULL)
@@ -498,10 +524,17 @@ comc_setup(void)
 	if (EFI_ERROR(status))
 		return (false);
 
-	status = comc_port->sio->SetAttributes(comc_port->sio,
-	    comc_port->baudrate, comc_port->receivefifodepth,
-	    comc_port->timeout, comc_port->parity,
-	    comc_port->databits, comc_port->stopbits);
+	ev = getenv("smbios.bios.version");
+	if (ev != NULL && strncmp(ev, "Hyper-V", 7) == 0) {
+		status = comc_port->sio->SetAttributes(comc_port->sio,
+	            0, 0, 0, DefaultParity, 0, DefaultStopBits);
+	} else {
+		status = comc_port->sio->SetAttributes(comc_port->sio,
+		    comc_port->baudrate, comc_port->receivefifodepth,
+		    comc_port->timeout, comc_port->parity,
+		    comc_port->databits, comc_port->stopbits);
+	}
+
 	if (EFI_ERROR(status))
 		return (false);
 
diff --git a/stand/i386/libi386/comconsole.c b/stand/i386/libi386/comconsole.c
index ed1f1aa08ed7..3fbb6a292c19 100644
--- a/stand/i386/libi386/comconsole.c
+++ b/stand/i386/libi386/comconsole.c
@@ -85,6 +85,20 @@ comc_probe(struct console *cp)
 	int speed, port;
 	uint32_t locator;
 
+#if defined(__amd64__)
+	extern bool efi_comconsole_avail;
+
+	if (efi_comconsole_avail) {
+		/*
+		 * If EFI provides serial I/O, then don't use this legacy
+		 * com driver to avoid conflicts with the firmware's driver.
+		 * Change c_name so that it cannot be found in the lookup.
+		 */
+		comconsole.c_name = "xcomconsole";
+		return;
+	}
+#endif
+
 	if (comc_curspeed == 0) {
 		comc_curspeed = COMSPEED;
 		/*



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?202303180720.32I7KXOc030612>