> Date: Thu, 14 Mar 2019 19:17:42 +1100
> From: Jonathan Gray <[email protected]>
>
> 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.
ok kettenis@
> 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
>
>