On Tue, May 30, 2017 at 12:58:48PM +0200, YASUOKA Masahiko wrote: > Hi, > > 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..613ede425b6 100644 > --- a/sys/arch/amd64/stand/efiboot/efiboot.c > +++ b/sys/arch/amd64/stand/efiboot/efiboot.c > @@ -501,10 +501,171 @@ 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]; > +const int comports[4] = { 0x3f8, 0x2f8, 0x3e8, 0x2e8 }; > + > +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-4 map to legacy COM[1-4] and they use the legacy I think youy meant UID 0-3. > + * 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 == 0x50141d0 /* PNP0501 */) { There is a macro for that. EFI_PNP_ID(0x0501) should do. > + 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); Before the printf are 4 spaces instead of a tab. > + } > + 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)]; > + > + if (!efi_valid_com(dev)) > + return (-1); > + > + if (sp > 0 && 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)) { > + painc("com%d: SetAttribute() failed with status=%d\n", > + minor(dev), status); > + } > + com_speed = serio->Mode->BaudRate; > + } > + com_speed = sp; > + > + return (serio->Mode->BaudRate); > +} > + > +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 */ > + > + com_addr = comports[minor(cn->cn_dev)]; > +} > + > +int > +efi_com_getc(dev_t dev) > +{ > + EFI_STATUS status; > + SERIAL_IO_INTERFACE *serio; > + UINTN sz; > + u_char buf[1]; Wouldn't it be enough to define u_char buf; and pass &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[0]; > + > + return (buf[0]); > +} > + > +void > +efi_com_putc(dev_t dev, int c) > +{ > + SERIAL_IO_INTERFACE *serio; > + UINTN sz = 1; > + u_char buf[1]; Same question here. > + > + if (!efi_valid_com(dev)) > + panic("com%d is not probed", minor(dev)); > + serio = serios[minor(dev)]; > + buf[0] = 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/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; >