A large number of machines ship uefi firmware which does not have
the serial io protcol. When using shell.efi 'dh -p serialio' and
'sermode' indicate it is not present.
To handle this fallback to pio access with code derived from
amd64/stand/libsa/bioscons.c minus the init code which resulted in
nothing showing up on serial.
I've not found any hardware which implements the serial io protocol,
but it is present with edk2 ovmf with qemu and still seems fine with
these changes.
Index: efiboot/conf.c
===================================================================
RCS file: /cvs/src/sys/arch/amd64/stand/efiboot/conf.c,v
retrieving revision 1.16
diff -u -p -r1.16 conf.c
--- efiboot/conf.c 10 Aug 2018 16:43:54 -0000 1.16
+++ efiboot/conf.c 14 Mar 2019 07:51:51 -0000
@@ -39,7 +39,7 @@
#include "efidev.h"
#include "efipxe.h"
-const char version[] = "3.40";
+const char version[] = "3.41";
#ifdef EFI_DEBUG
int debug = 0;
Index: efiboot/efiboot.c
===================================================================
RCS file: /cvs/src/sys/arch/amd64/stand/efiboot/efiboot.c,v
retrieving revision 1.32
diff -u -p -r1.32 efiboot.c
--- efiboot/efiboot.c 20 Nov 2018 03:10:47 -0000 1.32
+++ efiboot/efiboot.c 14 Mar 2019 08:11:17 -0000
@@ -20,9 +20,11 @@
#include <sys/queue.h>
#include <dev/cons.h>
#include <dev/isa/isareg.h>
+#include <dev/ic/comreg.h>
#include <sys/disklabel.h>
#include <cmd.h>
#include <stand/boot/bootarg.h>
+#include <machine/pio.h>
#include "libsa.h"
#include "disk.h"
@@ -533,6 +535,87 @@ int com_addr = -1;
int com_speed = -1;
static SERIAL_IO_INTERFACE *serios[4];
+const int comports[4] = { 0x3f8, 0x2f8, 0x3e8, 0x2e8 };
+
+/* call with sp == 0 to query the current speed */
+int
+pio_comspeed(dev_t dev, int sp)
+{
+ int port = (com_addr == -1) ? comports[minor(dev)] : com_addr;
+ int i, newsp;
+ int err;
+
+ if (sp <= 0)
+ return com_speed;
+ /* valid baud rate? */
+ if (115200 < sp || sp < 75)
+ return -1;
+
+ /*
+ * Accepted speeds:
+ * 75 150 300 600 1200 2400 4800 9600 19200 38400 76800 and
+ * 14400 28800 57600 115200
+ */
+ for (i = sp; i != 75 && i != 14400; i >>= 1)
+ if (i & 1)
+ return -1;
+
+/* ripped screaming from dev/ic/com.c */
+#define divrnd(n, q) (((n)*2/(q)+1)/2) /* divide and round off */
+ newsp = divrnd((COM_FREQ / 16), sp);
+ if (newsp <= 0)
+ return -1;
+ err = divrnd((COM_FREQ / 16) * 1000, sp * newsp) - 1000;
+ if (err < 0)
+ err = -err;
+ if (err > COM_TOLERANCE)
+ return -1;
+#undef divrnd
+
+ if (com_speed != -1 && cn_tab && cn_tab->cn_dev == dev &&
+ com_speed != sp) {
+ printf("com%d: changing speed to %d baud in 5 seconds, "
+ "change your terminal to match!\n\a",
+ minor(dev), sp);
+ sleep(5);
+ }
+
+ outb(port + com_cfcr, LCR_DLAB);
+ outb(port + com_dlbl, newsp);
+ outb(port + com_dlbh, newsp>>8);
+ outb(port + com_cfcr, LCR_8BITS);
+ if (com_speed != -1)
+ printf("\ncom%d: %d baud\n", minor(dev), sp);
+
+ newsp = com_speed;
+ com_speed = sp;
+ return newsp;
+}
+
+int
+pio_com_getc(dev_t dev)
+{
+ int port = (com_addr == -1) ? comports[minor(dev & 0x7f)] : com_addr;
+
+ if (dev & 0x80)
+ return (inb(port + com_lsr) & LSR_RXRDY);
+
+ while ((inb(port + com_lsr) & LSR_RXRDY) == 0)
+ ;
+
+ return (inb(port + com_data) & 0xff);
+}
+
+void
+pio_com_putc(dev_t dev, int c)
+{
+ int port = (com_addr == -1) ? comports[minor(dev)] : com_addr;
+
+ while ((inb(port + com_lsr) & LSR_TXRDY) == 0)
+ ;
+
+ outb(port + com_data, c);
+}
void
efi_com_probe(struct consdev *cn)
@@ -545,6 +628,9 @@ efi_com_probe(struct consdev *cn)
UINTN sz;
int i, uid = -1;
+ cn->cn_pri = CN_LOWPRI;
+ cn->cn_dev = makedev(8, 0);
+
sz = 0;
status = EFI_CALL(BS->LocateHandle, ByProtocol, &serio_guid, 0, &sz, 0);
if (status == EFI_BUFFER_TOO_SMALL) {
@@ -594,8 +680,6 @@ efi_com_probe(struct consdev *cn)
if (serios[i] != NULL)
printf(" com%d", i);
}
- cn->cn_pri = CN_LOWPRI;
- cn->cn_dev = makedev(8, 0);
}
int
@@ -615,7 +699,7 @@ comspeed(dev_t dev, int sp)
return com_speed;
if (!efi_valid_com(dev))
- return (-1);
+ return pio_comspeed(dev, sp);
if (serio->Mode->BaudRate != sp) {
status = EFI_CALL(serio->SetAttributes, serio,
@@ -659,7 +743,7 @@ efi_com_getc(dev_t dev)
static u_char lastchar = 0;
if (!efi_valid_com(dev & 0x7f))
- return (0) ;
+ return pio_com_getc(dev);
serio = serios[minor(dev & 0x7f)];
if (lastchar != 0) {
@@ -693,8 +777,10 @@ efi_com_putc(dev_t dev, int c)
UINTN sz = 1;
u_char buf;
- if (!efi_valid_com(dev))
+ if (!efi_valid_com(dev)) {
+ pio_com_putc(dev, c);
return;
+ }
serio = serios[minor(dev)];
buf = c;
EFI_CALL(serio->Write, serio, &sz, &buf);
@@ -854,6 +940,21 @@ getsecs(void)
r += t.TimeZone * 60;
return (r);
+}
+
+u_int
+sleep(u_int i)
+{
+ time_t t;
+
+ /*
+ * Loop for the requested number of seconds, polling,
+ * so that it may handle interrupts.
+ */
+ for (t = getsecs() + i; getsecs() < t; cnischar())
+ ;
+
+ return 0;
}
/***********************************************************************
Index: libsa/cmd_i386.c
===================================================================
RCS file: /cvs/src/sys/arch/amd64/stand/libsa/cmd_i386.c,v
retrieving revision 1.12
diff -u -p -r1.12 cmd_i386.c
--- libsa/cmd_i386.c 11 Oct 2017 04:07:50 -0000 1.12
+++ libsa/cmd_i386.c 13 Mar 2019 23:32:19 -0000
@@ -56,8 +56,8 @@ int bootbuf(void *, int);
const struct cmd_table cmd_machine[] = {
#ifndef EFIBOOT
{ "boot", CMDT_CMD, Xboot },
- { "comaddr", CMDT_CMD, Xcomaddr },
#endif
+ { "comaddr", CMDT_CMD, Xcomaddr },
{ "diskinfo", CMDT_CMD, Xdiskinfo },
{ "memory", CMDT_CMD, Xmemory },
#ifdef EFIBOOT
@@ -226,7 +226,6 @@ Xmemory(void)
return 0;
}
-#ifndef EFIBOOT
int
Xcomaddr(void)
{
@@ -237,4 +236,3 @@ Xcomaddr(void)
return 0;
}
-#endif