Index: lib/libefivar/Makefile =================================================================== --- lib/libefivar/Makefile +++ lib/libefivar/Makefile @@ -33,7 +33,7 @@ PACKAGE=lib${LIB} LIB= efivar -SRCS= efivar.c efichar.c efivar-dp-format.c \ +SRCS= efivar.c efichar.c string16.c efivar-dp-format.c \ efivar-dp-parse.c \ uefi-guid.c uefi-dputil.c INCS= efivar.h efivar-dp.h @@ -41,6 +41,7 @@ MAN= efivar.3 CFLAGS+= -I${EFIBOOT}/include +CFLAGS+= -I${EFIBOOT}/include/${MACHINE} CFLAGS+= -I${.CURDIR} -I${EDK2INC} CFLAGS.efivar-dp-format.c=-Wno-unused-parameter Index: sys/boot/efi/include/efichar.h =================================================================== --- sys/boot/efi/include/efichar.h +++ sys/boot/efi/include/efichar.h @@ -29,7 +29,10 @@ #ifndef _BOOT_EFI_EFICHAR_H_ #define _BOOT_EFI_EFICHAR_H_ -int ucs2_to_utf8(const efi_char *, char **); -int utf8_to_ucs2(const char *, efi_char **, size_t *); +#include +#include + +extern int ucs2_to_utf8(const efi_char *, char **); +extern int utf8_to_ucs2(const char *, efi_char **, size_t *); #endif /* _BOOT_EFI_EFICHAR_H_ */ Index: sys/boot/efi/include/efidef.h =================================================================== --- sys/boot/efi/include/efidef.h +++ sys/boot/efi/include/efidef.h @@ -70,11 +70,11 @@ // A GUID // -typedef struct { +typedef struct { UINT32 Data1; UINT16 Data2; UINT16 Data3; - UINT8 Data4[8]; + UINT8 Data4[8]; } EFI_GUID; @@ -82,7 +82,7 @@ // Time // -typedef struct { +typedef struct { UINT16 Year; // 1998 - 20XX UINT8 Month; // 1 - 12 UINT8 Day; // 1 - 31 @@ -165,9 +165,9 @@ #define EFI_MEMORY_WC 0x0000000000000002 #define EFI_MEMORY_WT 0x0000000000000004 #define EFI_MEMORY_WB 0x0000000000000008 -#define EFI_MEMORY_UCE 0x0000000000000010 +#define EFI_MEMORY_UCE 0x0000000000000010 -// physical memory protection on range +// physical memory protection on range #define EFI_MEMORY_WP 0x0000000000001000 #define EFI_MEMORY_RP 0x0000000000002000 #define EFI_MEMORY_XP 0x0000000000004000 @@ -195,9 +195,15 @@ // // +#ifndef EFI_PAGE_SIZE #define EFI_PAGE_SIZE 4096 +#endif +#ifndef EFI_PAGE_MASK #define EFI_PAGE_MASK 0xFFF +#endif +#ifndef EFI_PAGE_SHIFT #define EFI_PAGE_SHIFT 12 +#endif #define EFI_SIZE_TO_PAGES(a) \ ( ((a) >> EFI_PAGE_SHIFT) + (((a) & EFI_PAGE_MASK) ? 1 : 0) ) Index: sys/boot/efi/include/efilib.h =================================================================== --- sys/boot/efi/include/efilib.h +++ sys/boot/efi/include/efilib.h @@ -90,9 +90,4 @@ /* EFI environment initialization. */ void efi_init_environment(void); -/* CHAR16 utility functions. */ -int wcscmp(CHAR16 *, CHAR16 *); -void cpy8to16(const char *, CHAR16 *, size_t); -void cpy16to8(const CHAR16 *, char *, size_t); - #endif /* _LOADER_EFILIB_H */ Index: sys/boot/efi/include/string16.h =================================================================== --- sys/boot/efi/include/string16.h +++ sys/boot/efi/include/string16.h @@ -1,5 +1,6 @@ /*- - * Copyright 2016 Netflix, Inc. All Rights Reserved. + * Copyright (c) 2016 Eric McCorkle + * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -21,53 +22,29 @@ * 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. + * + * $FreeBSD$ */ -#include -__FBSDID("$FreeBSD$"); +#ifndef _STRING16_H_ +#define _STRING16_H_ +#include #include -#include +#include /* - * CHAR16 related functions moved from loader. - * Perhaps we should move those to libstand afterall, but they are - * needed only by UEFI. + * These are 16-bit variants of string.h functions for use with EFI code. */ -int -wcscmp(CHAR16 *a, CHAR16 *b) -{ - - while (*a && *b && *a == *b) { - a++; - b++; - } - return *a - *b; -} - -/* - * cpy8to16 copies a traditional C string into a CHAR16 string and - * 0 terminates it. len is the size of *dst in bytes. - */ -void -cpy8to16(const char *src, CHAR16 *dst, size_t len) -{ - len <<= 1; /* Assume CHAR16 is 2 bytes */ - while (len > 0 && *src) { - *dst++ = *src++; - len--; - } - *dst++ = (CHAR16)0; -} - -void -cpy16to8(const CHAR16 *src, char *dst, size_t len) -{ - size_t i; - - for (i = 0; i < len && src[i]; i++) - dst[i] = (char)src[i]; - if (i < len) - dst[i] = '\0'; -} +extern size_t strlen16(const CHAR16 *str); +extern CHAR16* strdup16(CHAR16 *str); +extern CHAR16* strcpy16(CHAR16 *dst, const CHAR16 *src); +extern CHAR16* stpcpy16(CHAR16 *dst, const CHAR16 *src); +extern CHAR16* strncpy_to_16(CHAR16 *dst, const char *src, size_t len); +extern char* strncpy_from_16(char *dst, const CHAR16 *src, size_t len); +extern CHAR16* stpncpy_to_16(CHAR16 *dst, const char *src, size_t len); +extern char* stpncpy_from_16(char *dst, const CHAR16 *src, size_t len); +extern int strcmp16(const CHAR16 *a, const CHAR16 *b); + +#endif Index: sys/boot/efi/libefi/Makefile =================================================================== --- sys/boot/efi/libefi/Makefile +++ sys/boot/efi/libefi/Makefile @@ -12,7 +12,7 @@ WARNS?= 2 SRCS= delay.c devpath.c efi_console.c efinet.c efipart.c env.c errno.c \ - handles.c wchar.c libefi.c + handles.c string16.c libefi.c .if ${MACHINE_CPUARCH} == "amd64" || ${MACHINE_CPUARCH} == "i386" SRCS+= time.c Index: sys/boot/efi/libefi/efichar.c =================================================================== --- sys/boot/efi/libefi/efichar.c +++ sys/boot/efi/libefi/efichar.c @@ -33,10 +33,9 @@ #include #include #include -#include -#include #include "efichar.h" +#include "string16.h" /* * If nm were converted to utf8, what what would strlen @@ -65,13 +64,10 @@ int ucs2_to_utf8(const efi_char *nm, char **name) { - size_t len, sz; - efi_char c; + size_t sz; char *cp; - int freeit = *name == NULL; sz = utf8_len_of_ucs2(nm) + 1; - len = 0; if (*name != NULL) cp = *name; else @@ -79,33 +75,7 @@ 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) - free(*name); - return (EOVERFLOW); - } - *cp++ = '\0'; + strncpy_from_16(cp, nm, sz); return (0); } @@ -115,72 +85,13 @@ { efi_char *nm; size_t sz; - uint32_t ucs4; - int c, bytes; - int freeit = *nmp == NULL; sz = strlen(name) * 2 + 2; if (*nmp == NULL) *nmp = malloc(sz); - 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) { - if (freeit) - free(nm); - return (EILSEQ); - } - 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) { - if (freeit) - free(nm); - return (EILSEQ); - } - } - if (bytes == 0) { - if (ucs4 > 0xffff) { - if (freeit) - free(nm); - return (EILSEQ); - } - *nm++ = (efi_char)ucs4; - sz -= 2; - } - } - if (sz < 2) { - if (freeit) - free(nm); - return (EDOOFUS); - } - sz -= 2; - *nm = 0; - *len -= sz; + nm = stpncpy_to_16(*nmp, name, sz); + + *len = (nm - *nmp) * 2; return (0); } Index: sys/boot/efi/libefi/efipart.c =================================================================== --- sys/boot/efi/libefi/efipart.c +++ sys/boot/efi/libefi/efipart.c @@ -41,6 +41,8 @@ #include #include +#include "string16.h" + static EFI_GUID blkio_guid = BLOCK_IO_PROTOCOL; static int efipart_initfd(void); @@ -460,7 +462,7 @@ free(pd); return (ENOMEM); } - cpy16to8(node->PathName, pathname, len + 1); + strncpy_from_16(pathname, node->PathName, len + 1); p = strchr(pathname, ':'); /* Index: sys/boot/efi/libefi/env.c =================================================================== --- sys/boot/efi/libefi/env.c +++ sys/boot/efi/libefi/env.c @@ -33,6 +33,7 @@ #include #include #include +#include #include "bootstrap.h" #ifdef BOOT_FORTH #include "ficl.h" @@ -291,7 +292,7 @@ continue; } if (vflag) { - if (wcscmp(varnamearg, varname) == 0) { + if (strcmp16(varnamearg, varname) == 0) { if (efi_print_var(varname, &varguid, lflag) != CMD_OK) break; continue; @@ -334,7 +335,8 @@ printf("Invalid uuid %s %d\n", uuid, status); return (CMD_ERROR); } - cpy8to16(var, wvar, sizeof(wvar)); + + strncpy_to_16(wvar, var, sizeof(wvar)); err = RS->SetVariable(wvar, &guid, EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS, strlen(val) + 1, val); @@ -367,7 +369,7 @@ printf("Invalid uuid %s\n", uuid); return (CMD_ERROR); } - cpy8to16(var, wvar, sizeof(wvar)); + strncpy_to_16(wvar, var, sizeof(wvar)); err = RS->SetVariable(wvar, &guid, 0, 0, NULL); if (EFI_ERROR(err)) { printf("Failed to unset variable: error %lu\n", EFI_ERROR_CODE(err)); Index: sys/boot/efi/libefi/string16.c =================================================================== --- /dev/null +++ sys/boot/efi/libefi/string16.c @@ -0,0 +1,185 @@ +/*- + * Copyright (c) 2016 Eric McCorkle + * 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. + * + * $FreeBSD$ + */ + +#include + +#include "string16.h" +#include "efichar.h" + +size_t +strlen16(const CHAR16 *str) +{ + size_t i; + + for (i = 0; str[i] != 0; i++); + + return i; +} + +CHAR16 * +strcpy16(CHAR16 *dst, const CHAR16 *src) +{ + stpcpy16(dst, src); + + return (dst); +} + +CHAR16 * +stpcpy16(CHAR16 *dst, const CHAR16 *src) +{ + for (; *src != 0; src++, dst++) { + *dst = *src; + } + + *dst = *src; + + return dst; +} + +char * +strncpy_from_16(char *dst, const CHAR16 *src, size_t len) +{ + stpncpy_from_16(dst, src, len); + + return (dst); +} + +CHAR16 * +strncpy_to_16(CHAR16 *dst, const char *src, size_t len) +{ + stpncpy_to_16(dst, src, len); + + return (dst); +} + +char * +stpncpy_from_16(char *dst, const CHAR16 *src, size_t sz) +{ + size_t len = 0; + efi_char c; + char *cp = dst; + + while (*src) { + c = *src++; + if (c > 0x7ff) { + if (len + 3 <= sz) { + *cp++ = (char)(0xE0 | (c >> 12)); + *cp++ = (char)(0x80 | ((c >> 6) & 0x3f)); + *cp++ = (char)(0x80 | (c & 0x3f)); + len += 3; + } else { + break; + } + } else if (c > 0x7f) { + if (len + 2 <= sz) { + *cp++ = (char)(0xC0 | ((c >> 6) & 0x1f)); + *cp++ = (char)(0x80 | (c & 0x3f)); + len += 2; + } else { + break; + } + } else { + if (len + 1 <= sz) { + *cp++ = (char)(c & 0x7f); + len++; + } else { + break; + } + } + } + + *cp = '\0'; + + return (cp); +} + +CHAR16 * +stpncpy_to_16(CHAR16 *dst, const char *src, size_t sz) +{ + uint32_t ucs4; + int c, bytes; + + ucs4 = 0; + bytes = 0; + while (sz > 1 && *src != '\0') { + c = *src++; + /* + * Conditionalize on the two major character types: + * initial and followup characters. + */ + if ((c & 0xc0) != 0x80) { + /* Initial characters. */ + if (bytes != 0) { + break; + } + 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) { + break; + } + } + if (bytes == 0) { + if (ucs4 > 0xffff) { + break; + } + *dst++ = (efi_char)ucs4; + sz -= 2; + } + } + + *dst = '\0'; + + return (dst); +} + +int +strcmp16(const CHAR16 *a, const CHAR16 *b) +{ + + while (*a && *b && *a == *b) { + a++; + b++; + } + return *a - *b; +} Index: sys/boot/efi/loader/main.c =================================================================== --- sys/boot/efi/loader/main.c +++ sys/boot/efi/loader/main.c @@ -49,6 +49,7 @@ #include #endif +#include "string16.h" #include "loader_efi.h" extern char bootprog_info[]; @@ -82,7 +83,7 @@ EFI_HANDLE *hin, *hin_end, *walker; UINTN sz; int retval = 0; - + /* * Find all the handles that support the SIMPLE_TEXT_INPUT_PROTOCOL and * do the typical dance to get the right sized buffer. @@ -139,7 +140,7 @@ } else if (DevicePathType(path) == MESSAGING_DEVICE_PATH && DevicePathSubType(path) == MSG_USB_CLASS_DP) { USB_CLASS_DEVICE_PATH *usb; - + usb = (USB_CLASS_DEVICE_PATH *)(void *)path; if (usb->DeviceClass == 3 && /* HID */ usb->DeviceSubClass == 1 && /* Boot devices */ @@ -387,14 +388,14 @@ if (i + 1 == argc) { setenv("comconsole_speed", "115200", 1); } else { - cpy16to8(&argv[i + 1][0], var, + strncpy_from_16(var, &argv[i + 1][0], sizeof(var)); setenv("comconsole_speedspeed", var, 1); } i++; break; } else { - cpy16to8(&argv[i][j + 1], var, + strncpy_from_16(var, &argv[i][j + 1], sizeof(var)); setenv("comconsole_speed", var, 1); break; Index: sys/sys/efi.h =================================================================== --- sys/sys/efi.h +++ sys/sys/efi.h @@ -32,9 +32,15 @@ #include #include +#ifndef EFI_PAGE_SHIFT #define EFI_PAGE_SHIFT 12 +#endif +#ifndef EFI_PAGE_SIZE #define EFI_PAGE_SIZE (1 << EFI_PAGE_SHIFT) +#endif +#ifndef EFI_PAGE_MASK #define EFI_PAGE_MASK (EFI_PAGE_SIZE - 1) +#endif #define EFI_TABLE_ACPI20 \ {0x8868e871,0xe4f1,0x11d3,0xbc,0x22,{0x00,0x80,0xc7,0x3c,0x88,0x81}}