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 <[email protected]>
@@ -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 <[email protected]>
@@ -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 <[email protected]>
@@ -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 <[email protected]>
@@ -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 <[email protected]>
@@ -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 <[email protected]>
@@ -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 <[email protected]>
@@ -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 <[email protected]>
@@ -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 <[email protected]>
@@ -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;
+}