> 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
> 
> 

Reply via email to