diff options
author | Wei Hu <whu@FreeBSD.org> | 2023-03-14 15:13:46 +0000 |
---|---|---|
committer | Wei Hu <whu@FreeBSD.org> | 2023-03-18 07:07:35 +0000 |
commit | 927358dd98cb902160093e0dc0bac002d6b43858 (patch) | |
tree | f9c51f90b157fe51b0c56d41c0cba022b24df061 /stand/efi | |
parent | ab3ff87a333ae586e9a2f779ba323eff8e889791 (diff) | |
download | src-927358dd98cb902160093e0dc0bac002d6b43858.tar.gz src-927358dd98cb902160093e0dc0bac002d6b43858.zip |
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)
Diffstat (limited to 'stand/efi')
-rw-r--r-- | stand/efi/loader/arch/amd64/Makefile.inc | 1 | ||||
-rw-r--r-- | stand/efi/loader/bootinfo.c | 11 | ||||
-rw-r--r-- | stand/efi/loader/conf.c | 6 | ||||
-rw-r--r-- | stand/efi/loader/efiserialio.c | 43 |
4 files changed, 54 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); |