Thanks,

Let me update the diff.

On Tue, 30 May 2017 13:58:29 +0200
Patrick Wildt <patr...@blueri.se> wrote:
> On Tue, May 30, 2017 at 12:58:48PM +0200, YASUOKA Masahiko wrote:
>> The following diff is to support serial console on efiboot.
> 
> Nice.
>> 
>> It uses ACPI UID to identify the port number (com0, com1 and so on) of
>> probed serial interface.  But I'm not sure wether com0-com3 are always
>> mapped UID 0-3 as expected.  Though I think this is good enough.
>> 
>> Comment?

diff --git a/sys/arch/amd64/stand/efiboot/conf.c 
b/sys/arch/amd64/stand/efiboot/conf.c
index 0b2933d4cff..913a33e77a6 100644
--- a/sys/arch/amd64/stand/efiboot/conf.c
+++ b/sys/arch/amd64/stand/efiboot/conf.c
@@ -85,6 +85,7 @@ int ndevs = nitems(devsw);
 
 struct consdev constab[] = {
        { efi_cons_probe, efi_cons_init, efi_cons_getc, efi_cons_putc },
+       { efi_com_probe, efi_com_init, efi_com_getc, efi_com_putc },
        { NULL }
 };
 struct consdev *cn_tab = constab;
diff --git a/sys/arch/amd64/stand/efiboot/efiboot.c 
b/sys/arch/amd64/stand/efiboot/efiboot.c
index d668258989f..fb7587fd50e 100644
--- a/sys/arch/amd64/stand/efiboot/efiboot.c
+++ b/sys/arch/amd64/stand/efiboot/efiboot.c
@@ -501,10 +501,177 @@ efi_cons_getshifts(dev_t dev)
        return (0);
 }
 
-/* XXX: serial console is not supported yet */
 int com_addr = -1;
 int com_speed = -1;
 
+static SERIAL_IO_INTERFACE     *serios[4];
+
+void
+efi_com_probe(struct consdev *cn)
+{
+       EFI_GUID                 serio_guid = SERIAL_IO_PROTOCOL;
+       EFI_HANDLE              *handles = NULL;
+       SERIAL_IO_INTERFACE     *serio;
+       EFI_STATUS               status;
+       EFI_DEVICE_PATH         *dp, *dp0;
+       EFI_DEV_PATH_PTR         dpp;
+       UINTN                    sz;
+       int                      i, uid = -1;
+
+       sz = 0;
+       status = EFI_CALL(BS->LocateHandle, ByProtocol, &serio_guid, 0, &sz, 0);
+       if (status == EFI_BUFFER_TOO_SMALL) {
+               handles = alloc(sz);
+               status = EFI_CALL(BS->LocateHandle, ByProtocol, &serio_guid,
+                   0, &sz, handles);
+       }
+       if (handles == NULL || EFI_ERROR(status))
+               panic("could not get handles of serial i/o");
+
+       for (i = 0; i < sz / sizeof(EFI_HANDLE); i++) {
+               /*
+                * Identify port number of the handle.  This assumes ACPI
+                * UID 0-3 map to legacy COM[1-4] and they use the legacy
+                * port address.
+                */
+               status = EFI_CALL(BS->HandleProtocol, handles[i], &devp_guid,
+                   (void **)&dp0);
+               if (EFI_ERROR(status))
+                       continue;
+               uid = -1;
+               for (dp = dp0; !IsDevicePathEnd(dp);
+                   dp = NextDevicePathNode(dp)) {
+                       dpp = (EFI_DEV_PATH_PTR)dp;
+                       if (DevicePathType(dp) == ACPI_DEVICE_PATH &&
+                           DevicePathSubType(dp) == ACPI_DP)
+                               if (dpp.Acpi->HID == EFI_PNP_ID(0x0501)) {
+                                       uid = dpp.Acpi->UID;
+                                       break;
+                               }
+               }
+               if (uid < 0)
+                       continue;
+
+               /* Prepare SERIAL_IO_INTERFACE */
+               status = EFI_CALL(BS->HandleProtocol, handles[i], &serio_guid,
+                   (void **)&serio);
+               if (EFI_ERROR(status))
+                       continue;
+               if (uid < nitems(serios))
+                       serios[uid] = serio;
+       }
+       free(handles, sz);
+
+       for (i = 0; i < nitems(serios); i++) {
+               if (serios[i] != NULL)
+                       printf(" com%d", i);
+       }
+       cn->cn_pri = CN_LOWPRI;
+       cn->cn_dev = makedev(8, 0);
+}
+
+int
+efi_valid_com(dev_t dev)
+{
+       return (0 <= minor(dev) && minor(dev) < nitems(serios) &&
+           serios[minor(dev)] != NULL);
+}
+
+int
+comspeed(dev_t dev, int sp)
+{
+       EFI_STATUS               status;
+       SERIAL_IO_INTERFACE     *serio = serios[minor(dev)];
+       int                      newsp;
+
+       if (sp <= 0)
+               return com_speed;
+
+       if (!efi_valid_com(dev))
+               return (-1);
+
+       if (serio->Mode->BaudRate != sp) {
+               status = EFI_CALL(serio->SetAttributes, serio,
+                   sp, serio->Mode->ReceiveFifoDepth,
+                   serio->Mode->Timeout, serio->Mode->Parity,
+                   serio->Mode->DataBits, serio->Mode->StopBits);
+               if (EFI_ERROR(status)) {
+                       printf("com%d: SetAttribute() failed with status=%d\n",
+                           minor(dev), status);
+                       return (-1);
+               }
+               if (com_speed != -1)
+                       printf("\ncom%d: %d baud\n", minor(dev), sp);
+       }
+
+       /* same as comspeed() in libsa/bioscons.c */
+       newsp = com_speed;
+       com_speed = sp;
+
+       return (newsp);
+}
+
+void
+efi_com_init(struct consdev *cn)
+{
+       if (!efi_valid_com(cn->cn_dev))
+               panic("com%d is not probed", minor(cn->cn_dev));
+
+       if (com_speed == -1)
+               comspeed(cn->cn_dev, 9600); /* default speed is 9600 baud */
+}
+
+int
+efi_com_getc(dev_t dev)
+{
+       EFI_STATUS               status;
+       SERIAL_IO_INTERFACE     *serio;
+       UINTN                    sz;
+       u_char                   buf;
+       static u_char            lastchar = 0;
+
+       if (!efi_valid_com(dev & 0x7f))
+               panic("com%d is not probed", minor(dev));
+       serio = serios[minor(dev & 0x7f)];
+
+       if (lastchar != 0) {
+               int r = lastchar;
+               if ((dev & 0x80) == 0)
+                       lastchar = 0;
+               return (r);
+       }
+
+       for (;;) {
+               sz = 1;
+               status = EFI_CALL(serio->Read, serio, &sz, &buf);
+               if (status == EFI_SUCCESS && sz > 0)
+                       break;
+               if (status != EFI_TIMEOUT && EFI_ERROR(status))
+                       panic("Error reading from serial status=%d", status);
+               if (dev & 0x80)
+                       return (0);
+       }
+
+       if (dev & 0x80)
+               lastchar = buf;
+
+       return (buf);
+}
+
+void
+efi_com_putc(dev_t dev, int c)
+{
+       SERIAL_IO_INTERFACE     *serio;
+       UINTN                    sz = 1;
+       u_char                   buf;
+
+       if (!efi_valid_com(dev))
+               panic("com%d is not probed", minor(dev));
+       serio = serios[minor(dev)];
+       buf = c;
+       EFI_CALL(serio->Write, serio, &sz, &buf);
+}
+
 /***********************************************************************
  * Miscellaneous
  ***********************************************************************/
diff --git a/sys/arch/amd64/stand/efiboot/efiboot.h 
b/sys/arch/amd64/stand/efiboot/efiboot.h
index 84cbcb537a4..fb7abb7c5f4 100644
--- a/sys/arch/amd64/stand/efiboot/efiboot.h
+++ b/sys/arch/amd64/stand/efiboot/efiboot.h
@@ -17,14 +17,18 @@
  */
 
 void    efi_cleanup(void);
-void    efi_cons_probe (struct consdev *);
-void    efi_memprobe (void);
-void    efi_hardprobe (void);
-void    efi_diskprobe (void);
-void    efi_cons_init (struct consdev *);
-int     efi_cons_getc (dev_t);
-void    efi_cons_putc (dev_t, int);
+void    efi_cons_probe(struct consdev *);
+void    efi_memprobe(void);
+void    efi_hardprobe(void);
+void    efi_diskprobe(void);
+void    efi_cons_init(struct consdev *);
+int     efi_cons_getc(dev_t);
+void    efi_cons_putc(dev_t, int);
 int     efi_cons_getshifts(dev_t dev);
+void    efi_com_probe(struct consdev *);
+void    efi_com_init(struct consdev *);
+int     efi_com_getc(dev_t);
+void    efi_com_putc(dev_t, int);
 int     Xvideo_efi(void);
 int     Xexit_efi(void);
 void    efi_makebootargs(void);
diff --git a/sys/arch/amd64/stand/libsa/bioscons.c 
b/sys/arch/amd64/stand/libsa/bioscons.c
index 9e8ec24ac42..8c86525ccb7 100644
--- a/sys/arch/amd64/stand/libsa/bioscons.c
+++ b/sys/arch/amd64/stand/libsa/bioscons.c
@@ -228,6 +228,7 @@ comspeed(dev_t dev, int sp)
 
        newsp = com_speed;
        com_speed = sp;
+
        return newsp;
 }
 
diff --git a/sys/arch/amd64/stand/libsa/dev_i386.c 
b/sys/arch/amd64/stand/libsa/dev_i386.c
index ee1a11ca6b0..a2b55ec556d 100644
--- a/sys/arch/amd64/stand/libsa/dev_i386.c
+++ b/sys/arch/amd64/stand/libsa/dev_i386.c
@@ -182,10 +182,8 @@ ttydev(char *name)
 int
 cnspeed(dev_t dev, int sp)
 {
-#ifndef EFIBOOT
        if (major(dev) == 8)    /* comN */
                return comspeed(dev, sp);
-#endif
 
        /* pc0 and anything else */
        return 9600;

Reply via email to