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;