Module Name: src Committed By: martin Date: Mon Apr 2 08:50:33 UTC 2018
Modified Files: src/sys/arch/i386/stand/efiboot [netbsd-8]: Makefile.efiboot boot.c efiboot.c efiboot.h eficons.c efidelay.c efidisk.c efimemory.c src/sys/arch/i386/stand/efiboot/bootia32 [netbsd-8]: efibootia32.c src/sys/arch/i386/stand/efiboot/bootx64 [netbsd-8]: efibootx64.c Added Files: src/sys/arch/i386/stand/efiboot [netbsd-8]: efichar.c Log Message: Pull up following revision(s) (requested by nonaka in ticket #685): sys/arch/i386/stand/efiboot/efidisk.c: revision 1.4 sys/arch/i386/stand/efiboot/bootx64/efibootx64.c: revision 1.4 sys/arch/i386/stand/efiboot/eficons.c: revision 1.5 sys/arch/i386/stand/efiboot/efichar.c: revision 1.1 sys/arch/i386/stand/efiboot/bootia32/efibootia32.c: revision 1.4 sys/arch/i386/stand/efiboot/boot.c: revision 1.8 sys/arch/i386/stand/efiboot/efimemory.c: revision 1.5 sys/arch/i386/stand/efiboot/efiboot.c: revision 1.6 sys/arch/i386/stand/efiboot/efidelay.c: revision 1.2 sys/arch/i386/stand/efiboot/efiboot.h: revision 1.7 sys/arch/i386/stand/efiboot/Makefile.efiboot: revision 1.11 efiboot: Added serial console support. To generate a diff of this commit: cvs rdiff -u -r1.9.2.1 -r1.9.2.2 \ src/sys/arch/i386/stand/efiboot/Makefile.efiboot cvs rdiff -u -r1.5.2.2 -r1.5.2.3 src/sys/arch/i386/stand/efiboot/boot.c cvs rdiff -u -r1.4.10.1 -r1.4.10.2 src/sys/arch/i386/stand/efiboot/efiboot.c cvs rdiff -u -r1.5.2.1 -r1.5.2.2 src/sys/arch/i386/stand/efiboot/efiboot.h cvs rdiff -u -r0 -r1.1.4.2 src/sys/arch/i386/stand/efiboot/efichar.c cvs rdiff -u -r1.4 -r1.4.2.1 src/sys/arch/i386/stand/efiboot/eficons.c cvs rdiff -u -r1.1 -r1.1.12.1 src/sys/arch/i386/stand/efiboot/efidelay.c cvs rdiff -u -r1.1.12.2 -r1.1.12.3 src/sys/arch/i386/stand/efiboot/efidisk.c cvs rdiff -u -r1.4 -r1.4.10.1 src/sys/arch/i386/stand/efiboot/efimemory.c cvs rdiff -u -r1.3 -r1.3.2.1 \ src/sys/arch/i386/stand/efiboot/bootia32/efibootia32.c cvs rdiff -u -r1.3 -r1.3.2.1 \ src/sys/arch/i386/stand/efiboot/bootx64/efibootx64.c Please note that diffs are not public domain; they are subject to the copyright notices on the relevant files.
Modified files: Index: src/sys/arch/i386/stand/efiboot/Makefile.efiboot diff -u src/sys/arch/i386/stand/efiboot/Makefile.efiboot:1.9.2.1 src/sys/arch/i386/stand/efiboot/Makefile.efiboot:1.9.2.2 --- src/sys/arch/i386/stand/efiboot/Makefile.efiboot:1.9.2.1 Tue Mar 13 14:54:52 2018 +++ src/sys/arch/i386/stand/efiboot/Makefile.efiboot Mon Apr 2 08:50:33 2018 @@ -1,4 +1,4 @@ -# $NetBSD: Makefile.efiboot,v 1.9.2.1 2018/03/13 14:54:52 martin Exp $ +# $NetBSD: Makefile.efiboot,v 1.9.2.2 2018/04/02 08:50:33 martin Exp $ S= ${.CURDIR}/../../../../.. @@ -12,7 +12,7 @@ SOURCES?= start.S conf.c devopen.c efibo LIBI386SRCS= boot.c biosdisk.c bootinfo.c bootinfo_biosgeom.c LIBI386SRCS+= bootmenu.c diskbuf.c exec.c menuutils.c LIBI386SRCS+= panic.c parseutils.c pread.c -LIBI386SRCS+= eficons.c efidelay.c efidev.c efidisk.c efidisk_ll.c +LIBI386SRCS+= efichar.c eficons.c efidelay.c efidev.c efidisk.c efidisk_ll.c LIBI386SRCS+= efigetsecs.c efimemory.c SRCS= ${SOURCES} ${EXTRA_SOURCES} ${LIBI386SRCS} Index: src/sys/arch/i386/stand/efiboot/boot.c diff -u src/sys/arch/i386/stand/efiboot/boot.c:1.5.2.2 src/sys/arch/i386/stand/efiboot/boot.c:1.5.2.3 --- src/sys/arch/i386/stand/efiboot/boot.c:1.5.2.2 Wed Mar 21 10:50:49 2018 +++ src/sys/arch/i386/stand/efiboot/boot.c Mon Apr 2 08:50:33 2018 @@ -1,4 +1,4 @@ -/* $NetBSD: boot.c,v 1.5.2.2 2018/03/21 10:50:49 martin Exp $ */ +/* $NetBSD: boot.c,v 1.5.2.3 2018/04/02 08:50:33 martin Exp $ */ /*- * Copyright (c) 2016 Kimihiro Nonaka <non...@netbsd.org> @@ -463,11 +463,16 @@ command_consdev(char *arg) char *sep, *sep2 = NULL; int ioport, speed = 0; + if (*arg == '\0') { + efi_cons_show(); + return; + } + sep = strchr(arg, ','); if (sep != NULL) { *sep++ = '\0'; sep2 = strchr(sep, ','); - if (sep != NULL) + if (sep2 != NULL) *sep2++ = '\0'; } @@ -555,6 +560,8 @@ void command_version(char *arg) { CHAR16 *path; + char *upath, *ufirmware; + int rv; if (strcmp(arg, "full") == 0) { printf("ImageBase: 0x%" PRIxPTR "\n", @@ -562,12 +569,24 @@ command_version(char *arg) printf("Stack: 0x%" PRIxPTR "\n", efi_main_sp); printf("EFI version: %d.%02d\n", ST->Hdr.Revision >> 16, ST->Hdr.Revision & 0xffff); - Print(L"EFI Firmware: %s (rev %d.%02d)\n", ST->FirmwareVendor, - ST->FirmwareRevision >> 16, ST->FirmwareRevision & 0xffff); + ufirmware = NULL; + rv = ucs2_to_utf8(ST->FirmwareVendor, &ufirmware); + if (rv == 0) { + printf("EFI Firmware: %s (rev %d.%02d)\n", ufirmware, + ST->FirmwareRevision >> 16, + ST->FirmwareRevision & 0xffff); + FreePool(ufirmware); + } path = DevicePathToStr(efi_bootdp); - Print(L"Boot DevicePath: %d:%d:%s\n", DevicePathType(efi_bootdp), - DevicePathSubType(efi_bootdp), path); + upath = NULL; + rv = ucs2_to_utf8(path, &upath); FreePool(path); + if (rv == 0) { + printf("Boot DevicePath: %d:%d:%s\n", + DevicePathType(efi_bootdp), + DevicePathSubType(efi_bootdp), upath); + FreePool(upath); + } } printf("\n" @@ -603,7 +622,9 @@ command_devpath(char *arg) EFI_HANDLE *handles; EFI_DEVICE_PATH *dp0, *dp; CHAR16 *path; + char *upath; UINTN cols, rows, row = 0; + int rv; status = uefi_call_wrapper(ST->ConOut->QueryMode, 4, ST->ConOut, ST->ConOut->Mode->Mode, &cols, &rows); @@ -626,41 +647,54 @@ command_devpath(char *arg) if (EFI_ERROR(status)) break; - Print(L"DevicePathType %d\n", DevicePathType(dp0)); + printf("DevicePathType %d\n", DevicePathType(dp0)); if (++row >= rows) { row = 0; - Print(L"Press Any Key to continue :"); + printf("Press Any Key to continue :"); (void) awaitkey(-1, 0); - Print(L"\n"); + printf("\n"); } for (dp = dp0; !IsDevicePathEnd(dp); dp = NextDevicePathNode(dp)) { + path = DevicePathToStr(dp); - Print(L"%d:%d:%s\n", DevicePathType(dp), DevicePathSubType(dp), path); + upath = NULL; + rv = ucs2_to_utf8(path, &upath); FreePool(path); + if (rv) { + printf("convert failed\n"); + break; + } + + printf("%d:%d:%s\n", DevicePathType(dp), + DevicePathSubType(dp), upath); + FreePool(upath); if (++row >= rows) { row = 0; - Print(L"Press Any Key to continue :"); + printf("Press Any Key to continue :"); (void) awaitkey(-1, 0); - Print(L"\n"); + printf("\n"); } } } } + void command_efivar(char *arg) { - static const CHAR16 header[] = - L"GUID Variable Name Value\n" - L"=================================== ==================== ========\n"; + static const char header[] = + "GUID Variable Name Value\n" + "==================================== ==================== ========\n"; EFI_STATUS status; UINTN sz = 64, osz; - CHAR16 *name = NULL, *tmp, *val; + CHAR16 *name = NULL, *tmp, *val, guid[128]; + char *uname, *uval, *uguid; EFI_GUID vendor; UINTN cols, rows, row = 0; + int rv; status = uefi_call_wrapper(ST->ConOut->QueryMode, 4, ST->ConOut, ST->ConOut->Mode->Mode, &cols, &rows); @@ -671,15 +705,15 @@ command_efivar(char *arg) name = AllocatePool(sz); if (name == NULL) { - Print(L"memory allocation failed: %ld bytes\n", - (UINT64)sz); + printf("memory allocation failed: %" PRIuMAX" bytes\n", + (uintmax_t)sz); return; } SetMem(name, sz, 0); vendor = NullGuid; - Print(L"%s", header); + printf("%s", header); for (;;) { osz = sz; status = uefi_call_wrapper(RT->GetNextVariableName, 3, @@ -688,15 +722,15 @@ command_efivar(char *arg) if (status == EFI_NOT_FOUND) break; if (status != EFI_BUFFER_TOO_SMALL) { - Print(L"GetNextVariableName failed: %r\n", - status); + printf("GetNextVariableName failed: %" PRIxMAX "\n", + (uintmax_t)status); break; } tmp = AllocatePool(sz); if (tmp == NULL) { - Print(L"memory allocation failed: %ld bytes\n", - (UINT64)sz); + printf("memory allocation failed: %" PRIuMAX + "bytes\n", (uintmax_t)sz); break; } SetMem(tmp, sz, 0); @@ -707,15 +741,43 @@ command_efivar(char *arg) } val = LibGetVariable(name, &vendor); - Print(L"%.-35g %.-20s %s\n", &vendor, name, - val ? val : L"(null)"); - FreePool(val); + if (val != NULL) { + uval = NULL; + rv = ucs2_to_utf8(val, &uval); + FreePool(val); + if (rv) { + printf("value convert failed\n"); + break; + } + } else + uval = NULL; + uname = NULL; + rv = ucs2_to_utf8(name, &uname); + if (rv) { + printf("name convert failed\n"); + FreePool(uval); + break; + } + GuidToString(guid, &vendor); + uguid = NULL; + rv = ucs2_to_utf8(guid, &uguid); + if (rv) { + printf("GUID convert failed\n"); + FreePool(uval); + FreePool(uname); + break; + } + printf("%-35s %-20s %s\n", uguid, uname, uval ? uval : "(null)"); + FreePool(uguid); + FreePool(uname); + if (uval != NULL) + FreePool(uval); if (++row >= rows) { row = 0; - Print(L"Press Any Key to continue :"); + printf("Press Any Key to continue :"); (void) awaitkey(-1, 0); - Print(L"\n"); + printf("\n"); } } Index: src/sys/arch/i386/stand/efiboot/efiboot.c diff -u src/sys/arch/i386/stand/efiboot/efiboot.c:1.4.10.1 src/sys/arch/i386/stand/efiboot/efiboot.c:1.4.10.2 --- src/sys/arch/i386/stand/efiboot/efiboot.c:1.4.10.1 Tue Mar 13 14:54:52 2018 +++ src/sys/arch/i386/stand/efiboot/efiboot.c Mon Apr 2 08:50:33 2018 @@ -1,4 +1,4 @@ -/* $NetBSD: efiboot.c,v 1.4.10.1 2018/03/13 14:54:52 martin Exp $ */ +/* $NetBSD: efiboot.c,v 1.4.10.2 2018/04/02 08:50:33 martin Exp $ */ /*- * Copyright (c) 2016 Kimihiro Nonaka <non...@netbsd.org> @@ -68,11 +68,13 @@ efi_main(EFI_HANDLE imageHandle, EFI_SYS status = uefi_call_wrapper(BS->HandleProtocol, 3, IH, &LoadedImageProtocol, (void **)&efi_li); if (EFI_ERROR(status)) - Panic(L"HandleProtocol(LoadedImageProtocol): %r", status); + panic("HandleProtocol(LoadedImageProtocol): %" PRIxMAX, + (uintmax_t)status); status = uefi_call_wrapper(BS->HandleProtocol, 3, efi_li->DeviceHandle, &DevicePathProtocol, (void **)&dp0); if (EFI_ERROR(status)) - Panic(L"HandleProtocol(DevicePathProtocol): %r", status); + panic("HandleProtocol(DevicePathProtocol): %" PRIxMAX, + (uintmax_t)status); efi_bootdp = dp0; for (dp = dp0; !IsDevicePathEnd(dp); dp = NextDevicePathNode(dp)) { if (DevicePathType(dp) == MEDIA_DEVICE_PATH && @@ -86,7 +88,7 @@ efi_main(EFI_HANDLE imageHandle, EFI_SYS status = uefi_call_wrapper(BS->SetWatchdogTimer, 4, 0, 0, 0, NULL); if (EFI_ERROR(status)) - Panic(L"SetWatchdogTimer: %r", status); + panic("SetWatchdogTimer: %" PRIxMAX, (uintmax_t)status); boot(); @@ -122,7 +124,7 @@ efi_cleanup(void) &DescriptorVersion, true); status = uefi_call_wrapper(BS->ExitBootServices, 2, IH, MapKey); if (EFI_ERROR(status)) - Panic(L"ExitBootServices failed"); + panic("ExitBootServices failed"); } efi_cleanuped = true; Index: src/sys/arch/i386/stand/efiboot/efiboot.h diff -u src/sys/arch/i386/stand/efiboot/efiboot.h:1.5.2.1 src/sys/arch/i386/stand/efiboot/efiboot.h:1.5.2.2 --- src/sys/arch/i386/stand/efiboot/efiboot.h:1.5.2.1 Tue Mar 13 14:54:52 2018 +++ src/sys/arch/i386/stand/efiboot/efiboot.h Mon Apr 2 08:50:33 2018 @@ -1,4 +1,4 @@ -/* $NetBSD: efiboot.h,v 1.5.2.1 2018/03/13 14:54:52 martin Exp $ */ +/* $NetBSD: efiboot.h,v 1.5.2.2 2018/04/02 08:50:33 martin Exp $ */ /*- * Copyright (c) 2016 Kimihiro Nonaka <non...@netbsd.org> @@ -54,9 +54,15 @@ extern u_long efi_kernel_size; extern bool efi_cleanuped; void efi_cleanup(void); +/* efichar.c */ +size_t ucs2len(const CHAR16 *); +int ucs2_to_utf8(const CHAR16 *, char **); +int utf8_to_ucs2(const char *, CHAR16 **, size_t *); + /* eficons.c */ int cninit(void); void consinit(int, int, int); +void efi_cons_show(void); void command_text(char *); void command_gop(char *); Index: src/sys/arch/i386/stand/efiboot/eficons.c diff -u src/sys/arch/i386/stand/efiboot/eficons.c:1.4 src/sys/arch/i386/stand/efiboot/eficons.c:1.4.2.1 --- src/sys/arch/i386/stand/efiboot/eficons.c:1.4 Mon May 1 13:03:01 2017 +++ src/sys/arch/i386/stand/efiboot/eficons.c Mon Apr 2 08:50:33 2018 @@ -1,4 +1,4 @@ -/* $NetBSD: eficons.c,v 1.4 2017/05/01 13:03:01 nonaka Exp $ */ +/* $NetBSD: eficons.c,v 1.4.2.1 2018/04/02 08:50:33 martin Exp $ */ /*- * Copyright (c) 2016 Kimihiro Nonaka <non...@netbsd.org> @@ -40,14 +40,43 @@ struct btinfo_console btinfo_console; static EFI_GRAPHICS_OUTPUT_PROTOCOL *efi_gop; static int efi_gop_mode = -1; - static CHAR16 keybuf[16]; static int keybuf_read = 0; static int keybuf_write = 0; +static SERIAL_IO_INTERFACE *serios[4]; +static int default_comspeed = +#if defined(CONSPEED) + CONSPEED; +#else + 9600; +#endif +static u_char serbuf[16]; +static int serbuf_read = 0; +static int serbuf_write = 0; + static void eficons_init_video(void); static void efi_switch_video_to_text_mode(void); +static int efi_cons_getc(void); +static int efi_cons_putc(int); +static int efi_cons_iskey(int); +static int efi_cons_waitforinputevent(uint64_t); + +static void efi_com_probe(void); +static bool efi_valid_com(int); +static int efi_com_init(int, int); +static int efi_com_getc(void); +static int efi_com_putc(int); +static int efi_com_status(int); +static int efi_com_waitforinputevent(uint64_t); + +static int iodev; +static int (*internal_getchar)(void) = efi_cons_getc; +static int (*internal_putchar)(int) = efi_cons_putc; +static int (*internal_iskey)(int) = efi_cons_iskey; +static int (*internal_waitforinputevent)(uint64_t) = efi_cons_waitforinputevent; + static int getcomaddr(int idx) { @@ -64,33 +93,48 @@ getcomaddr(int idx) void consinit(int dev, int ioport, int speed) { - int iodev; + int i; -#if defined(CONSPEED) - btinfo_console.speed = CONSPEED; -#else - btinfo_console.speed = 9600; -#endif + btinfo_console.speed = default_comspeed; switch (dev) { case CONSDEV_AUTO: - /* XXX comport */ + for (i = 0; i < __arraycount(serios); i++) { + iodev = CONSDEV_COM0 + i; + if (!efi_valid_com(iodev)) + continue; + btinfo_console.addr = getcomaddr(i); + + efi_cons_putc('0' + i); + efi_com_init(btinfo_console.addr, btinfo_console.speed); + /* check for: + * 1. successful output + * 2. optionally, keypress within 7s + */ + if (efi_com_putc(':') && + efi_com_putc('-') && + efi_com_putc('(') && + awaitkey(7, 0)) + goto ok; + } goto nocom; +ok: + break; case CONSDEV_COM0: case CONSDEV_COM1: case CONSDEV_COM2: case CONSDEV_COM3: iodev = dev; -comport: btinfo_console.addr = ioport; if (btinfo_console.addr == 0) { - btinfo_console.addr = getcomaddr(iodev - CONSDEV_COM0); - if (btinfo_console.addr == 0) + if (!efi_valid_com(iodev)) goto nocom; + btinfo_console.addr = getcomaddr(iodev - CONSDEV_COM0); } if (speed != 0) btinfo_console.speed = speed; + efi_com_init(btinfo_console.addr, btinfo_console.speed); break; case CONSDEV_COM0KBD: @@ -98,12 +142,33 @@ comport: case CONSDEV_COM2KBD: case CONSDEV_COM3KBD: iodev = dev - CONSDEV_COM0KBD + CONSDEV_COM0; - goto comport; /* XXX kbd */ - + if (!efi_valid_com(iodev)) + goto nocom; + btinfo_console.addr = getcomaddr(iodev - CONSDEV_COM0); + + efi_cons_putc('0' + iodev - CONSDEV_COM0); + efi_com_init(btinfo_console.addr, btinfo_console.speed); + /* check for: + * 1. successful output + * 2. optionally, keypress within 7s + */ + if (efi_com_putc(':') && + efi_com_putc('-') && + efi_com_putc('(') && + awaitkey(7, 0)) + goto kbd; + /*FALLTHROUGH*/ case CONSDEV_PC: default: nocom: iodev = CONSDEV_PC; + internal_putchar = efi_cons_putc; +kbd: + internal_getchar = efi_cons_getc; + internal_iskey = efi_cons_iskey; + internal_waitforinputevent = efi_cons_waitforinputevent; + memset(keybuf, 0, sizeof(keybuf)); + keybuf_read = keybuf_write = 0; break; } @@ -116,6 +181,7 @@ cninit(void) efi_switch_video_to_text_mode(); eficons_init_video(); + efi_com_probe(); consinit(boot_params.bp_consdev, boot_params.bp_consaddr, boot_params.bp_conspeed); @@ -123,8 +189,50 @@ cninit(void) return 0; } -int -getchar(void) +void +efi_cons_show(void) +{ + const bool pc_is_console = strcmp(btinfo_console.devname, "pc") == 0; + const bool com_is_console = strcmp(btinfo_console.devname, "com") == 0; + bool first = true; + bool found = false; + int i; + + if (efi_gop != NULL) { + printf("pc"); + if (pc_is_console) + printf("*"); + first = false; + } + + for (i = 0; i < __arraycount(serios); i++) { + if (serios[i] != NULL) { + if (!first) + printf(" "); + first = false; + + printf("com%d", i); + if (com_is_console && + btinfo_console.addr == getcomaddr(i)) { + printf(",%d*", btinfo_console.speed); + found = true; + } + } + } + if (!found && com_is_console) { + if (!first) + printf(" "); + first = false; + + printf("com,0x%x,%d*", btinfo_console.addr, + btinfo_console.speed); + } + + printf("\n"); +} + +static int +efi_cons_getc(void) { EFI_STATUS status; EFI_INPUT_KEY key; @@ -146,23 +254,21 @@ getchar(void) return key.UnicodeChar; } -void -putchar(int c) +static int +efi_cons_putc(int c) { CHAR16 buf[2]; - buf[1] = 0; - if (c == '\n') { - buf[0] = '\r'; - Output(buf); - } buf[0] = c; + buf[1] = 0; Output(buf); + + return 1; } /*ARGSUSED*/ -int -iskey(int intr) +static int +efi_cons_iskey(int intr) { EFI_STATUS status; EFI_INPUT_KEY key; @@ -180,13 +286,49 @@ iskey(int intr) return 1; } +static int +efi_cons_waitforinputevent(uint64_t timeout) +{ + EFI_STATUS status; + + status = WaitForSingleEvent(ST->ConIn->WaitForKey, timeout); + if (!EFI_ERROR(status)) + return 0; + if (status == EFI_TIMEOUT) + return ETIMEDOUT; + return EINVAL; +} + +int +getchar(void) +{ + + return internal_getchar(); +} + +void +putchar(int c) +{ + + if (c == '\n') + internal_putchar('\r'); + internal_putchar(c); +} + +int +iskey(int intr) +{ + + return internal_iskey(intr); +} + char awaitkey(int timeout, int tell) { char c = 0; for (;;) { - if (tell) { + if (tell && timeout) { char numbuf[32]; int len; @@ -210,7 +352,7 @@ awaitkey(int timeout, int tell) goto out; } if (timeout--) - WaitForSingleEvent(ST->ConIn->WaitForKey, 10000000); + internal_waitforinputevent(10000000); else break; } @@ -307,7 +449,8 @@ bi_framebuffer(void) status = uefi_call_wrapper(efi_gop->SetMode, 2, efi_gop, bestmode); if (EFI_ERROR(status) || efi_gop->Mode->Mode != bestmode) - Print(L"GOP setmode failed: %r\n", status); + printf("GOP setmode failed: %" PRIxMAX "\n", + (uintmax_t)status); } info = efi_gop->Mode->Info; @@ -350,7 +493,7 @@ bi_framebuffer(void) case PixelBltOnly: case PixelFormatMax: - Panic(L"Error: invalid pixel format (%d)", info->PixelFormat); + panic("Error: invalid pixel format (%d)", info->PixelFormat); break; } @@ -378,8 +521,8 @@ print_text_modes(void) ST->ConOut, i, &cols, &rows); if (EFI_ERROR(status)) continue; - Print(L"%c%d: %dx%d\n", i == curmode ? '*' : ' ', - i, cols, rows); + printf("%c%d: %" PRIxMAX "x%" PRIxMAX "\n", + i == curmode ? '*' : ' ', i, (uintmax_t)cols, (uintmax_t)rows); } } @@ -396,7 +539,8 @@ efi_find_text_mode(char *arg) ST->ConOut, i, &cols, &rows); if (EFI_ERROR(status)) continue; - snprintf(mode, sizeof(mode), "%lux%lu", (long)cols, (long)rows); + snprintf(mode, sizeof(mode), "%" PRIuMAX "x%" PRIuMAX, + (uintmax_t)cols, (uintmax_t)rows); if (strcmp(arg, mode) == 0) return i; } @@ -456,36 +600,36 @@ print_gop_modes(void) if (EFI_ERROR(status)) continue; - Print(L"%c%d: %dx%d ", + printf("%c%d: %dx%d ", memcmp(info, efi_gop->Mode->Info, sizeof(*info)) == 0 ? '*' : ' ', i, info->HorizontalResolution, info->VerticalResolution); switch (info->PixelFormat) { case PixelRedGreenBlueReserved8BitPerColor: - Print(L"RGBR"); + printf("RGBR"); break; case PixelBlueGreenRedReserved8BitPerColor: - Print(L"BGRR"); + printf("BGRR"); break; case PixelBitMask: - Print(L"R:%08x G:%08x B:%08x X:%08x", + printf("R:%08x G:%08x B:%08x X:%08x", info->PixelInformation.RedMask, info->PixelInformation.GreenMask, info->PixelInformation.BlueMask, info->PixelInformation.ReservedMask); break; case PixelBltOnly: - Print(L"(blt only)"); + printf("(blt only)"); break; default: - Print(L"(Invalid pixel format)"); + printf("(Invalid pixel format)"); break; } - Print(L" pitch %d", info->PixelsPerScanLine); + printf(" pitch %d", info->PixelsPerScanLine); depth = getdepth(info); if (depth > 0) - Print(L" bpp %d", depth); - Print(L"\n"); + printf(" bpp %d", depth); + printf("\n"); } return 0; @@ -623,3 +767,246 @@ efi_switch_video_to_text_mode(void) EfiConsoleControlScreenText); } } + +/* + * serial port + */ +static void +efi_com_probe(void) +{ + EFI_STATUS status; + UINTN i, nhandles; + EFI_HANDLE *handles; + EFI_DEVICE_PATH *dp, *dp0; + EFI_DEV_PATH_PTR dpp; + SERIAL_IO_INTERFACE *serio; + int uid = -1; + + status = LibLocateHandle(ByProtocol, &SerialIoProtocol, NULL, + &nhandles, &handles); + if (EFI_ERROR(status)) + return; + + for (i = 0; i < nhandles; 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 = uefi_call_wrapper(BS->HandleProtocol, 3, handles[i], + &DevicePathProtocol, (void **)&dp0); + if (EFI_ERROR(status)) + continue; + + for (uid = -1, dp = dp0; + !IsDevicePathEnd(dp); + dp = NextDevicePathNode(dp)) { + + if (DevicePathType(dp) == ACPI_DEVICE_PATH && + DevicePathSubType(dp) == ACPI_DP) { + dpp = (EFI_DEV_PATH_PTR)dp; + if (dpp.Acpi->HID == EISA_PNP_ID(0x0501)) { + uid = dpp.Acpi->UID; + break; + } + } + } + if (uid < 0 || __arraycount(serios) <= uid) + continue; + + /* Prepare SERIAL_IO_INTERFACE */ + status = uefi_call_wrapper(BS->HandleProtocol, 3, handles[i], + &SerialIoProtocol, (void **)&serio); + if (EFI_ERROR(status)) + continue; + + serios[uid] = serio; + } + + FreePool(handles); + +} + +static bool +efi_valid_com(int dev) +{ + int idx; + + switch (dev) { + default: + case CONSDEV_PC: + return false; + + case CONSDEV_COM0: + case CONSDEV_COM1: + case CONSDEV_COM2: + case CONSDEV_COM3: + idx = dev - CONSDEV_COM0; + break; + } + + return idx < __arraycount(serios) && + serios[idx] != NULL && + getcomaddr(idx) != 0; +} + +static int +efi_com_init(int addr, int speed) +{ + EFI_STATUS status; + SERIAL_IO_INTERFACE *serio; + + if (speed <= 0) + return 0; + + if (!efi_valid_com(iodev)) + return 0; + + serio = serios[iodev - CONSDEV_COM0]; + + if (serio->Mode->BaudRate != btinfo_console.speed) { + status = uefi_call_wrapper(serio->SetAttributes, 7, serio, + speed, 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=%" PRIxMAX + "\n", iodev - CONSDEV_COM0, (uintmax_t)status); + return 0; + } + } + + default_comspeed = speed; + internal_getchar = efi_com_getc; + internal_putchar = efi_com_putc; + internal_iskey = efi_com_status; + internal_waitforinputevent = efi_com_waitforinputevent; + memset(serbuf, 0, sizeof(serbuf)); + serbuf_read = serbuf_write = 0; + + return speed; +} + +static int +efi_com_getc(void) +{ + EFI_STATUS status; + SERIAL_IO_INTERFACE *serio; + UINTN sz; + u_char c; + + if (!efi_valid_com(iodev)) + panic("Invalid serial port: iodev=%d", iodev); + + if (serbuf_read != serbuf_write) { + c = serbuf[serbuf_read]; + serbuf_read = (serbuf_read + 1) % __arraycount(serbuf); + return c; + } + + serio = serios[iodev - CONSDEV_COM0]; + + for (;;) { + sz = 1; + status = uefi_call_wrapper(serio->Read, 3, serio, &sz, &c); + if (!EFI_ERROR(status) && sz > 0) + break; + if (status != EFI_TIMEOUT && EFI_ERROR(status)) + panic("Error reading from serial status=%"PRIxMAX, + (uintmax_t)status); + } + return c; +} + +static int +efi_com_putc(int c) +{ + EFI_STATUS status; + SERIAL_IO_INTERFACE *serio; + UINTN sz = 1; + u_char buf; + + if (!efi_valid_com(iodev)) + return 0; + + serio = serios[iodev - CONSDEV_COM0]; + buf = c; + status = uefi_call_wrapper(serio->Write, 3, serio, &sz, &buf); + if (EFI_ERROR(status) || sz < 1) + return 0; + return 1; +} + +/*ARGSUSED*/ +static int +efi_com_status(int intr) +{ + EFI_STATUS status; + SERIAL_IO_INTERFACE *serio; + UINTN sz; + u_char c; + + if (!efi_valid_com(iodev)) + panic("Invalid serial port: iodev=%d", iodev); + + if (serbuf_read != serbuf_write) + return 1; + + serio = serios[iodev - CONSDEV_COM0]; + sz = 1; + status = uefi_call_wrapper(serio->Read, 3, serio, &sz, &c); + if (EFI_ERROR(status) || sz < 1) + return 0; + + serbuf[serbuf_write] = c; + serbuf_write = (serbuf_write + 1) % __arraycount(serbuf); + return 1; +} + +static void +efi_com_periodic_event(EFI_EVENT event, void *ctx) +{ + EFI_EVENT timer = ctx; + + if (efi_com_status(0)) { + uefi_call_wrapper(BS->SetTimer, 3, event, TimerCancel, 0); + uefi_call_wrapper(BS->SignalEvent, 1, timer); + } +} + +static int +efi_com_waitforinputevent(uint64_t timeout) +{ + EFI_STATUS status; + EFI_EVENT timer, periodic; + + status = uefi_call_wrapper(BS->CreateEvent, 5, EVT_TIMER, 0, NULL, NULL, + &timer); + if (EFI_ERROR(status)) + return EINVAL; + + status = uefi_call_wrapper(BS->CreateEvent, 5, + EVT_TIMER | EVT_NOTIFY_SIGNAL, TPL_CALLBACK, efi_com_periodic_event, + timer, &periodic); + if (EFI_ERROR(status)) { + uefi_call_wrapper(BS->CloseEvent, 1, timer); + return EINVAL; + } + + status = uefi_call_wrapper(BS->SetTimer, 3, periodic, TimerPeriodic, + 1000000); /* 100ms */ + if (EFI_ERROR(status)) { + uefi_call_wrapper(BS->CloseEvent, 1, periodic); + uefi_call_wrapper(BS->CloseEvent, 1, timer); + return EINVAL; + } + status = WaitForSingleEvent(&timer, timeout); + uefi_call_wrapper(BS->SetTimer, 3, periodic, TimerCancel, 0); + uefi_call_wrapper(BS->CloseEvent, 1, periodic); + uefi_call_wrapper(BS->CloseEvent, 1, timer); + if (!EFI_ERROR(status)) + return 0; + if (status == EFI_TIMEOUT) + return ETIMEDOUT; + return EINVAL; +} Index: src/sys/arch/i386/stand/efiboot/efidelay.c diff -u src/sys/arch/i386/stand/efiboot/efidelay.c:1.1 src/sys/arch/i386/stand/efiboot/efidelay.c:1.1.12.1 --- src/sys/arch/i386/stand/efiboot/efidelay.c:1.1 Tue Jan 24 11:09:14 2017 +++ src/sys/arch/i386/stand/efiboot/efidelay.c Mon Apr 2 08:50:33 2018 @@ -1,4 +1,4 @@ -/* $NetBSD: efidelay.c,v 1.1 2017/01/24 11:09:14 nonaka Exp $ */ +/* $NetBSD: efidelay.c,v 1.1.12.1 2018/04/02 08:50:33 martin Exp $ */ /*- * Copyright (c) 2016 Kimihiro Nonaka <non...@netbsd.org> @@ -32,10 +32,22 @@ void delay(int us) { EFI_STATUS status; + CHAR16 errmsg[128]; + char *uerrmsg; + int rv; status = uefi_call_wrapper(BS->Stall, 1, us); - if (EFI_ERROR(status)) - Panic(L"%a: couldn't delay %d us: %r\n", __func__, us, status); + if (EFI_ERROR(status)) { + StatusToString(errmsg, status); + uerrmsg = NULL; + rv = ucs2_to_utf8(errmsg, &uerrmsg); + if (rv) + uerrmsg = ""; + panic("couldn't delay %d us: %s(%" PRIxMAX ")\n", us, uerrmsg, + (uintmax_t)status); + if (rv == 0) + FreePool(uerrmsg); + } } void Index: src/sys/arch/i386/stand/efiboot/efidisk.c diff -u src/sys/arch/i386/stand/efiboot/efidisk.c:1.1.12.2 src/sys/arch/i386/stand/efiboot/efidisk.c:1.1.12.3 --- src/sys/arch/i386/stand/efiboot/efidisk.c:1.1.12.2 Wed Mar 21 10:50:49 2018 +++ src/sys/arch/i386/stand/efiboot/efidisk.c Mon Apr 2 08:50:33 2018 @@ -1,4 +1,4 @@ -/* $NetBSD: efidisk.c,v 1.1.12.2 2018/03/21 10:50:49 martin Exp $ */ +/* $NetBSD: efidisk.c,v 1.1.12.3 2018/04/02 08:50:33 martin Exp $ */ /*- * Copyright (c) 2016 Kimihiro Nonaka <non...@netbsd.org> @@ -57,7 +57,8 @@ efi_disk_probe(void) status = LibLocateHandle(ByProtocol, &BlockIoProtocol, NULL, &nhandles, &handles); if (EFI_ERROR(status)) - Panic(L"LocateHandle(BlockIoProtocol): %r", status); + panic("LocateHandle(BlockIoProtocol): %" PRIxMAX, + (uintmax_t)status); if (efi_bootdp != NULL) depth = efi_device_path_depth(efi_bootdp, MEDIA_DEVICE_PATH); @@ -75,7 +76,8 @@ efi_disk_probe(void) status = uefi_call_wrapper(BS->HandleProtocol, 3, handles[i], &BlockIoProtocol, (void **)&bio); if (EFI_ERROR(status)) - Panic(L"HandleProtocol(BlockIoProtocol): %r", status); + panic("HandleProtocol(BlockIoProtocol): %" PRIxMAX, + (uintmax_t)status); media = bio->Media; if (media->LogicalPartition || !media->MediaPresent) Index: src/sys/arch/i386/stand/efiboot/efimemory.c diff -u src/sys/arch/i386/stand/efiboot/efimemory.c:1.4 src/sys/arch/i386/stand/efiboot/efimemory.c:1.4.10.1 --- src/sys/arch/i386/stand/efiboot/efimemory.c:1.4 Tue Feb 14 13:29:09 2017 +++ src/sys/arch/i386/stand/efiboot/efimemory.c Mon Apr 2 08:50:33 2018 @@ -1,4 +1,4 @@ -/* $NetBSD: efimemory.c,v 1.4 2017/02/14 13:29:09 nonaka Exp $ */ +/* $NetBSD: efimemory.c,v 1.4.10.1 2018/04/02 08:50:33 martin Exp $ */ /*- * Copyright (c) 2016 Kimihiro Nonaka <non...@netbsd.org> @@ -110,7 +110,7 @@ efi_memory_get_map(UINTN *NoEntries, UIN desc = LibMemoryMap(NoEntries, MapKey, DescriptorSize, DescriptorVersion); if (desc == NULL) - Panic(L"efi_memory_get_map failed"); + panic("efi_memory_get_map failed"); if (!sorted) return desc; @@ -238,7 +238,7 @@ efi_memory_probe(void) mdtop = efi_memory_get_map(&NoEntries, &MapKey, &DescriptorSize, &DescriptorVersion, false); - Print(L" mem["); + printf(" mem["); for (i = 0, n = 0, md = mdtop; i < NoEntries; i++, md = next) { next = NextMemoryDescriptor(md, DescriptorSize); @@ -251,11 +251,11 @@ efi_memory_probe(void) continue; if (n++ > 0) - Print(L" "); - Print(L"0x%lx-0x%lx", md->PhysicalStart, - md->PhysicalStart + MappingSize - 1); + printf(" "); + printf("0x%" PRIxMAX "-0x%" PRIxMAX, (uintmax_t)md->PhysicalStart, + (uintmax_t)(md->PhysicalStart + MappingSize - 1)); } - Print(L"]"); + printf("]\n"); FreePool(mdtop); } @@ -302,9 +302,9 @@ efi_memory_show_map(bool sorted) if (++row >= rows) { row = 0; - Print(L"Press Any Key to continue :"); + printf("Press Any Key to continue :"); (void) awaitkey(-1, 0); - Print(L"\n"); + printf("\n"); } } Index: src/sys/arch/i386/stand/efiboot/bootia32/efibootia32.c diff -u src/sys/arch/i386/stand/efiboot/bootia32/efibootia32.c:1.3 src/sys/arch/i386/stand/efiboot/bootia32/efibootia32.c:1.3.2.1 --- src/sys/arch/i386/stand/efiboot/bootia32/efibootia32.c:1.3 Sat Apr 29 00:05:35 2017 +++ src/sys/arch/i386/stand/efiboot/bootia32/efibootia32.c Mon Apr 2 08:50:33 2018 @@ -1,4 +1,4 @@ -/* $NetBSD: efibootia32.c,v 1.3 2017/04/29 00:05:35 nonaka Exp $ */ +/* $NetBSD: efibootia32.c,v 1.3.2.1 2018/04/02 08:50:33 martin Exp $ */ /*- * Copyright (c) 2016 Kimihiro Nonaka <non...@netbsd.org> @@ -46,8 +46,8 @@ efi_md_init(void) status = uefi_call_wrapper(BS->AllocatePages, 4, AllocateMaxAddress, EfiLoaderData, sz, &addr); if (EFI_ERROR(status)) - Panic(L"%a: AllocatePages() failed: %d page(s): %r", - __func__, sz, status); + panic("%s: AllocatePages() failed: %d page(s): %" PRIxMAX, + __func__, sz, (uintmax_t)status); startprog32 = (void *)(u_long)addr; CopyMem(startprog32, startprog32_start, startprog32_size); } @@ -67,5 +67,5 @@ startprog(physaddr_t entry, uint32_t arg void multiboot(physaddr_t entry, physaddr_t header, physaddr_t sp) { - Panic(L"%a: not implemented", __func__); + panic("%s: not implemented", __func__); } Index: src/sys/arch/i386/stand/efiboot/bootx64/efibootx64.c diff -u src/sys/arch/i386/stand/efiboot/bootx64/efibootx64.c:1.3 src/sys/arch/i386/stand/efiboot/bootx64/efibootx64.c:1.3.2.1 --- src/sys/arch/i386/stand/efiboot/bootx64/efibootx64.c:1.3 Sat Apr 29 00:05:35 2017 +++ src/sys/arch/i386/stand/efiboot/bootx64/efibootx64.c Mon Apr 2 08:50:33 2018 @@ -1,4 +1,4 @@ -/* $NetBSD: efibootx64.c,v 1.3 2017/04/29 00:05:35 nonaka Exp $ */ +/* $NetBSD: efibootx64.c,v 1.3.2.1 2018/04/02 08:50:33 martin Exp $ */ /*- * Copyright (c) 2016 Kimihiro Nonaka <non...@netbsd.org> @@ -46,8 +46,8 @@ efi_md_init(void) status = uefi_call_wrapper(BS->AllocatePages, 4, AllocateMaxAddress, EfiLoaderData, sz, &addr); if (EFI_ERROR(status)) - Panic(L"%a: AllocatePages() failed: %d page(s): %r", - __func__, sz, status); + panic("%s: AllocatePages() failed: %d page(s): %" PRIxMAX, + __func__, sz, (uintmax_t)status); startprog64 = (void *)addr; CopyMem(startprog64, startprog64_start, startprog64_size); } @@ -72,5 +72,5 @@ startprog(physaddr_t entry, uint32_t arg void multiboot(physaddr_t entry, physaddr_t header, physaddr_t sp) { - Panic(L"%a: not implemented", __func__); + panic("%s: not implemented", __func__); } Added files: Index: src/sys/arch/i386/stand/efiboot/efichar.c diff -u /dev/null src/sys/arch/i386/stand/efiboot/efichar.c:1.1.4.2 --- /dev/null Mon Apr 2 08:50:33 2018 +++ src/sys/arch/i386/stand/efiboot/efichar.c Mon Apr 2 08:50:33 2018 @@ -0,0 +1,195 @@ +/* $NetBSD: efichar.c,v 1.1.4.2 2018/04/02 08:50:33 martin Exp $ */ + +/*- + * Copyright (c) 2010 Marcel Moolenaar + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include <sys/cdefs.h> +#if 0 +__FBSDID("$FreeBSD: head/stand/efi/libefi/efichar.c 328061 2018-01-16 20:35:54Z tsoome $"); +#endif + +#include "efiboot.h" + +size_t +ucs2len(const CHAR16 *str) +{ + size_t i; + + i = 0; + while (*str++) + i++; + return i; +} + +/* + * If nm were converted to utf8, what what would strlen + * return on the resulting string? + */ +static size_t +utf8_len_of_ucs2(const CHAR16 *nm) +{ + size_t len; + CHAR16 c; + + len = 0; + while (*nm) { + c = *nm++; + if (c > 0x7ff) + len += 3; + else if (c > 0x7f) + len += 2; + else + len++; + } + + return len; +} + +int +ucs2_to_utf8(const CHAR16 *nm, char **name) +{ + size_t len, sz; + CHAR16 c; + char *cp; + int freeit = *name == NULL; + + sz = utf8_len_of_ucs2(nm) + 1; + len = 0; + if (*name != NULL) + cp = *name; + else + cp = *name = AllocatePool(sz); + if (*name == NULL) + return ENOMEM; + + while (*nm) { + c = *nm++; + if (c > 0x7ff) { + if (len++ < sz) + *cp++ = (char)(0xE0 | (c >> 12)); + if (len++ < sz) + *cp++ = (char)(0x80 | ((c >> 6) & 0x3f)); + if (len++ < sz) + *cp++ = (char)(0x80 | (c & 0x3f)); + } else if (c > 0x7f) { + if (len++ < sz) + *cp++ = (char)(0xC0 | ((c >> 6) & 0x1f)); + if (len++ < sz) + *cp++ = (char)(0x80 | (c & 0x3f)); + } else { + if (len++ < sz) + *cp++ = (char)(c & 0x7f); + } + } + + if (len >= sz) { + /* Absent bugs, we'll never return EOVERFLOW */ + if (freeit) { + FreePool(*name); + *name = NULL; + } + return EOVERFLOW; + } + *cp++ = '\0'; + + return 0; +} + +int +utf8_to_ucs2(const char *name, CHAR16 **nmp, size_t *len) +{ + CHAR16 *nm; + size_t sz; + uint32_t ucs4; + int c, bytes; + int freeit = *nmp == NULL; + + sz = strlen(name) * 2 + 2; + if (*nmp == NULL) + *nmp = AllocatePool(sz); + if (*nmp == NULL) + return ENOMEM; + nm = *nmp; + *len = sz; + + ucs4 = 0; + bytes = 0; + while (sz > 1 && *name != '\0') { + c = *name++; + /* + * Conditionalize on the two major character types: + * initial and followup characters. + */ + if ((c & 0xc0) != 0x80) { + /* Initial characters. */ + if (bytes != 0) + goto ilseq; + if ((c & 0xf8) == 0xf0) { + ucs4 = c & 0x07; + bytes = 3; + } else if ((c & 0xf0) == 0xe0) { + ucs4 = c & 0x0f; + bytes = 2; + } else if ((c & 0xe0) == 0xc0) { + ucs4 = c & 0x1f; + bytes = 1; + } else { + ucs4 = c & 0x7f; + bytes = 0; + } + } else { + /* Followup characters. */ + if (bytes > 0) { + ucs4 = (ucs4 << 6) + (c & 0x3f); + bytes--; + } else if (bytes == 0) + goto ilseq; + } + if (bytes == 0) { + if (ucs4 > 0xffff) + goto ilseq; + *nm++ = (CHAR16)ucs4; + sz -= 2; + } + } + if (sz < 2) { + if (freeit) { + FreePool(nm); + *nmp = NULL; + } + return EINVAL; + } + sz -= 2; + *nm = 0; + *len -= sz; + return 0; +ilseq: + if (freeit) { + FreePool(nm); + *nmp = NULL; + } + return EILSEQ; +}