diff options
author | YASUOKA Masahiko <yasuoka@cvs.openbsd.org> | 2017-05-31 08:40:33 +0000 |
---|---|---|
committer | YASUOKA Masahiko <yasuoka@cvs.openbsd.org> | 2017-05-31 08:40:33 +0000 |
commit | cdc0ab9a7a8dc68133bdef38e8523797657a3715 (patch) | |
tree | 5ad1a7b4db32e8a558f9eb8399745bcdce70b17f /sys | |
parent | f71dd1005880fe3168775ee7df12a5a3439917f8 (diff) |
Add serial console support for efiboot.
Diffstat (limited to 'sys')
-rw-r--r-- | sys/arch/amd64/stand/efiboot/conf.c | 3 | ||||
-rw-r--r-- | sys/arch/amd64/stand/efiboot/efiboot.c | 170 | ||||
-rw-r--r-- | sys/arch/amd64/stand/efiboot/efiboot.h | 20 | ||||
-rw-r--r-- | sys/arch/amd64/stand/libsa/dev_i386.c | 4 |
4 files changed, 183 insertions, 14 deletions
diff --git a/sys/arch/amd64/stand/efiboot/conf.c b/sys/arch/amd64/stand/efiboot/conf.c index 0b2933d4cff..c02719d1327 100644 --- a/sys/arch/amd64/stand/efiboot/conf.c +++ b/sys/arch/amd64/stand/efiboot/conf.c @@ -1,4 +1,4 @@ -/* $OpenBSD: conf.c,v 1.6 2016/09/18 16:36:09 jsing Exp $ */ +/* $OpenBSD: conf.c,v 1.7 2017/05/31 08:40:32 yasuoka Exp $ */ /* * Copyright (c) 1996 Michael Shalayeff @@ -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..25e34c1a93b 100644 --- a/sys/arch/amd64/stand/efiboot/efiboot.c +++ b/sys/arch/amd64/stand/efiboot/efiboot.c @@ -1,4 +1,4 @@ -/* $OpenBSD: efiboot.c,v 1.18 2017/05/16 02:53:28 yasuoka Exp $ */ +/* $OpenBSD: efiboot.c,v 1.19 2017/05/31 08:40:32 yasuoka Exp $ */ /* * Copyright (c) 2015 YASUOKA Masahiko <yasuoka@yasuoka.net> @@ -387,6 +387,8 @@ static EFI_GUID con_guid = EFI_CONSOLE_CONTROL_PROTOCOL_GUID; static EFI_GUID gop_guid = EFI_GRAPHICS_OUTPUT_PROTOCOL_GUID; +static EFI_GUID serio_guid + = SERIAL_IO_PROTOCOL; struct efi_video { int cols; int rows; @@ -501,10 +503,174 @@ 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_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 || nitems(serios) <= uid) + continue; + + /* Prepare SERIAL_IO_INTERFACE */ + status = EFI_CALL(BS->HandleProtocol, handles[i], &serio_guid, + (void **)&serio); + if (EFI_ERROR(status)) + continue; + 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 (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..8a07d5b46b3 100644 --- a/sys/arch/amd64/stand/efiboot/efiboot.h +++ b/sys/arch/amd64/stand/efiboot/efiboot.h @@ -1,4 +1,4 @@ -/* $OpenBSD: efiboot.h,v 1.1 2015/09/02 01:52:25 yasuoka Exp $ */ +/* $OpenBSD: efiboot.h,v 1.2 2017/05/31 08:40:32 yasuoka Exp $ */ /* * Copyright (c) 2015 YASUOKA Masahiko <yasuoka@yasuoka.net> @@ -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..5d8e389bf82 100644 --- a/sys/arch/amd64/stand/libsa/dev_i386.c +++ b/sys/arch/amd64/stand/libsa/dev_i386.c @@ -1,4 +1,4 @@ -/* $OpenBSD: dev_i386.c,v 1.19 2017/03/01 12:43:07 patrick Exp $ */ +/* $OpenBSD: dev_i386.c,v 1.20 2017/05/31 08:40:32 yasuoka Exp $ */ /* * Copyright (c) 1996-1999 Michael Shalayeff @@ -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; |