aboutsummaryrefslogtreecommitdiff
path: root/stand/efi/libefi
diff options
context:
space:
mode:
authorWarner Losh <imp@FreeBSD.org>2017-11-14 23:02:19 +0000
committerWarner Losh <imp@FreeBSD.org>2017-11-14 23:02:19 +0000
commitca987d4641cdcd7f27e153db17c5bf064934faf5 (patch)
tree6c3860e3ba8949be9528d644fbb7fa88d8bbbb79 /stand/efi/libefi
parent6eac7115560381ce5c9e2939ab3fce82bb9b6a95 (diff)
downloadsrc-ca987d4641cdcd7f27e153db17c5bf064934faf5.tar.gz
src-ca987d4641cdcd7f27e153db17c5bf064934faf5.zip
Move sys/boot to stand. Fix all references to new location
Sponsored by: Netflix
Notes
Notes: svn path=/head/; revision=325834
Diffstat (limited to 'stand/efi/libefi')
-rw-r--r--stand/efi/libefi/Makefile57
-rw-r--r--stand/efi/libefi/Makefile.depend13
-rw-r--r--stand/efi/libefi/delay.c47
-rw-r--r--stand/efi/libefi/devicename.c219
-rw-r--r--stand/efi/libefi/devpath.c197
-rw-r--r--stand/efi/libefi/efi_console.c518
-rw-r--r--stand/efi/libefi/efi_driver_utils.c91
-rw-r--r--stand/efi/libefi/efichar.c201
-rw-r--r--stand/efi/libefi/efinet.c390
-rw-r--r--stand/efi/libefi/efipart.c984
-rw-r--r--stand/efi/libefi/efizfs.c122
-rw-r--r--stand/efi/libefi/env.c534
-rw-r--r--stand/efi/libefi/errno.c157
-rw-r--r--stand/efi/libefi/handles.c118
-rw-r--r--stand/efi/libefi/libefi.c52
-rw-r--r--stand/efi/libefi/time.c283
-rw-r--r--stand/efi/libefi/time_event.c82
-rw-r--r--stand/efi/libefi/wchar.c73
18 files changed, 4138 insertions, 0 deletions
diff --git a/stand/efi/libefi/Makefile b/stand/efi/libefi/Makefile
new file mode 100644
index 000000000000..e0ffd7b80f62
--- /dev/null
+++ b/stand/efi/libefi/Makefile
@@ -0,0 +1,57 @@
+# $FreeBSD$
+
+.include <bsd.init.mk>
+
+.if ${MK_FORTH} != "no"
+.include "${BOOTSRC}/ficl.mk"
+.endif
+
+LIB= efi
+INTERNALLIB=
+WARNS?= 2
+
+SRCS= delay.c devpath.c efi_console.c efichar.c efinet.c efipart.c env.c errno.c \
+ handles.c wchar.c libefi.c efi_driver_utils.c efizfs.c devicename.c
+
+.if ${MACHINE_CPUARCH} == "amd64" || ${MACHINE_CPUARCH} == "i386"
+SRCS+= time.c
+.elif ${MACHINE_CPUARCH} == "aarch64" || ${MACHINE_CPUARCH} == "arm"
+SRCS+= time_event.c
+.endif
+
+# We implement a slightly non-standard %S in that it always takes a
+# CHAR16 that's common in UEFI-land instead of a wchar_t. This only
+# seems to matter on arm64 where wchar_t defaults to an int instead
+# of a short. There's no good cast to use here so just ignore the
+# warnings for now.
+CWARNFLAGS.efinet.c+= -Wno-format
+CWARNFLAGS.efipart.c+= -Wno-format
+CWARNFLAGS.env.c+= -Wno-format
+
+.if ${MACHINE_CPUARCH} == "aarch64"
+CFLAGS+= -mgeneral-regs-only
+.endif
+.if ${MACHINE_ARCH} == "amd64"
+CFLAGS+= -fPIC -mno-red-zone
+.endif
+CFLAGS+= -I${EFIINC}
+CFLAGS+= -I${EFIINCMD}
+.if ${MK_ZFS} != "no"
+CFLAGS+= -I${ZFSSRC}
+CFLAGS+= -DEFI_ZFS_BOOT
+.endif
+
+# Pick up the bootstrap header for some interface items
+CFLAGS+= -I${LDRSRC}
+
+# Handle FreeBSD specific %b and %D printf format specifiers
+CFLAGS+= ${FORMAT_EXTENSIONS}
+
+# Do not use TERM_EMU on arm and arm64 as it doesn't behave well with serial console
+.if ${MACHINE_CPUARCH} != "arm" && ${MACHINE_CPUARCH} != "aarch64"
+CFLAGS+= -DTERM_EMU
+.endif
+
+CFLAGS+= -DLIBEFI
+
+.include <bsd.lib.mk>
diff --git a/stand/efi/libefi/Makefile.depend b/stand/efi/libefi/Makefile.depend
new file mode 100644
index 000000000000..18be76b0cb6f
--- /dev/null
+++ b/stand/efi/libefi/Makefile.depend
@@ -0,0 +1,13 @@
+# $FreeBSD$
+# Autogenerated - do NOT edit!
+
+DIRDEPS = \
+ include \
+ include/xlocale \
+
+
+.include <dirdeps.mk>
+
+.if ${DEP_RELDIR} == ${_DEP_RELDIR}
+# local dependencies - needed for -jN in clean tree
+.endif
diff --git a/stand/efi/libefi/delay.c b/stand/efi/libefi/delay.c
new file mode 100644
index 000000000000..723f681c5286
--- /dev/null
+++ b/stand/efi/libefi/delay.c
@@ -0,0 +1,47 @@
+/*-
+ * Copyright (c) 2001 Doug Rabson
+ * 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>
+__FBSDID("$FreeBSD$");
+
+#include <efi.h>
+#include <efilib.h>
+
+void
+delay(int usecs)
+{
+ static EFI_EVENT ev = 0;
+ UINTN junk;
+
+ if (!ev) {
+ if (BS->CreateEvent(EVT_TIMER, TPL_APPLICATION, 0, 0, &ev)
+ != EFI_SUCCESS)
+ return;
+ }
+
+ BS->SetTimer(ev, TimerRelative, usecs * 10);
+ BS->WaitForEvent(1, &ev, &junk);
+}
diff --git a/stand/efi/libefi/devicename.c b/stand/efi/libefi/devicename.c
new file mode 100644
index 000000000000..52e4799c8f3d
--- /dev/null
+++ b/stand/efi/libefi/devicename.c
@@ -0,0 +1,219 @@
+/*-
+ * Copyright (c) 1998 Michael Smith <msmith@freebsd.org>
+ * Copyright (c) 2006 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>
+__FBSDID("$FreeBSD$");
+
+#include <stand.h>
+#include <string.h>
+#include <sys/disklabel.h>
+#include <sys/param.h>
+#include <bootstrap.h>
+#include <disk.h>
+#ifdef EFI_ZFS_BOOT
+#include <libzfs.h>
+#endif
+
+#include <efi.h>
+#include <efilib.h>
+
+static int efi_parsedev(struct devdesc **, const char *, const char **);
+
+/*
+ * Point (dev) at an allocated device specifier for the device matching the
+ * path in (devspec). If it contains an explicit device specification,
+ * use that. If not, use the default device.
+ */
+int
+efi_getdev(void **vdev, const char *devspec, const char **path)
+{
+ struct devdesc **dev = (struct devdesc **)vdev;
+ int rv;
+
+ /*
+ * If it looks like this is just a path and no device, then
+ * use the current device instead.
+ */
+ if (devspec == NULL || *devspec == '/' || !strchr(devspec, ':')) {
+ rv = efi_parsedev(dev, getenv("currdev"), NULL);
+ if (rv == 0 && path != NULL)
+ *path = devspec;
+ return (rv);
+ }
+
+ /* Parse the device name off the beginning of the devspec. */
+ return (efi_parsedev(dev, devspec, path));
+}
+
+/*
+ * Point (dev) at an allocated device specifier matching the string version
+ * at the beginning of (devspec). Return a pointer to the remaining
+ * text in (path).
+ *
+ * In all cases, the beginning of (devspec) is compared to the names
+ * of known devices in the device switch, and then any following text
+ * is parsed according to the rules applied to the device type.
+ *
+ * For disk-type devices, the syntax is:
+ *
+ * fs<unit>:
+ */
+static int
+efi_parsedev(struct devdesc **dev, const char *devspec, const char **path)
+{
+ struct devdesc *idev;
+ struct devsw *dv;
+ int i, unit, err;
+ char *cp;
+ const char *np;
+
+ /* minimum length check */
+ if (strlen(devspec) < 2)
+ return (EINVAL);
+
+ /* look for a device that matches */
+ for (i = 0; devsw[i] != NULL; i++) {
+ dv = devsw[i];
+ if (!strncmp(devspec, dv->dv_name, strlen(dv->dv_name)))
+ break;
+ }
+ if (devsw[i] == NULL)
+ return (ENOENT);
+
+ np = devspec + strlen(dv->dv_name);
+ idev = NULL;
+ err = 0;
+
+ switch (dv->dv_type) {
+ case DEVT_NONE:
+ break;
+
+ case DEVT_DISK:
+ idev = malloc(sizeof(struct disk_devdesc));
+ if (idev == NULL)
+ return (ENOMEM);
+
+ err = disk_parsedev((struct disk_devdesc *)idev, np, path);
+ if (err != 0)
+ goto fail;
+ break;
+
+#ifdef EFI_ZFS_BOOT
+ case DEVT_ZFS:
+ idev = malloc(sizeof(struct zfs_devdesc));
+ if (idev == NULL)
+ return (ENOMEM);
+
+ err = zfs_parsedev((struct zfs_devdesc*)idev, np, path);
+ if (err != 0)
+ goto fail;
+ break;
+#endif
+ default:
+ idev = malloc(sizeof(struct devdesc));
+ if (idev == NULL)
+ return (ENOMEM);
+
+ unit = 0;
+ cp = (char *)np;
+
+ if (*np != '\0' && *np != ':') {
+ errno = 0;
+ unit = strtol(np, &cp, 0);
+ if (errno != 0 || cp == np) {
+ err = EUNIT;
+ goto fail;
+ }
+ }
+ if (*cp != '\0' && *cp != ':') {
+ err = EINVAL;
+ goto fail;
+ }
+
+ idev->d_unit = unit;
+ if (path != NULL)
+ *path = (*cp == 0) ? cp : cp + 1;
+ break;
+ }
+
+ idev->d_dev = dv;
+ idev->d_type = dv->dv_type;
+
+ if (dev != NULL)
+ *dev = idev;
+ else
+ free(idev);
+ return (0);
+
+fail:
+ free(idev);
+ return (err);
+}
+
+char *
+efi_fmtdev(void *vdev)
+{
+ struct devdesc *dev = (struct devdesc *)vdev;
+ static char buf[SPECNAMELEN + 1];
+
+ switch(dev->d_type) {
+ case DEVT_NONE:
+ strcpy(buf, "(no device)");
+ break;
+
+ case DEVT_DISK:
+ return (disk_fmtdev(vdev));
+
+#ifdef EFI_ZFS_BOOT
+ case DEVT_ZFS:
+ return (zfs_fmtdev(dev));
+#endif
+ default:
+ sprintf(buf, "%s%d:", dev->d_dev->dv_name, dev->d_unit);
+ break;
+ }
+
+ return (buf);
+}
+
+/*
+ * Set currdev to suit the value being supplied in (value)
+ */
+int
+efi_setcurrdev(struct env_var *ev, int flags, const void *value)
+{
+ struct devdesc *ncurr;
+ int rv;
+
+ rv = efi_parsedev(&ncurr, value, NULL);
+ if (rv != 0)
+ return (rv);
+
+ free(ncurr);
+ env_setenv(ev->ev_name, flags | EV_NOHOOK, value, NULL, NULL);
+ return (0);
+}
diff --git a/stand/efi/libefi/devpath.c b/stand/efi/libefi/devpath.c
new file mode 100644
index 000000000000..f881cfce9896
--- /dev/null
+++ b/stand/efi/libefi/devpath.c
@@ -0,0 +1,197 @@
+/*-
+ * Copyright (c) 2016 John Baldwin <jhb@FreeBSD.org>
+ * 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>
+__FBSDID("$FreeBSD$");
+
+#include <efi.h>
+#include <efilib.h>
+
+static EFI_GUID ImageDevicePathGUID =
+ EFI_LOADED_IMAGE_DEVICE_PATH_PROTOCOL_GUID;
+static EFI_GUID DevicePathGUID = DEVICE_PATH_PROTOCOL;
+static EFI_GUID DevicePathToTextGUID = EFI_DEVICE_PATH_TO_TEXT_PROTOCOL_GUID;
+static EFI_DEVICE_PATH_TO_TEXT_PROTOCOL *textProtocol;
+
+EFI_DEVICE_PATH *
+efi_lookup_image_devpath(EFI_HANDLE handle)
+{
+ EFI_DEVICE_PATH *devpath;
+ EFI_STATUS status;
+
+ status = BS->HandleProtocol(handle, &ImageDevicePathGUID,
+ (VOID **)&devpath);
+ if (EFI_ERROR(status))
+ devpath = NULL;
+ return (devpath);
+}
+
+EFI_DEVICE_PATH *
+efi_lookup_devpath(EFI_HANDLE handle)
+{
+ EFI_DEVICE_PATH *devpath;
+ EFI_STATUS status;
+
+ status = BS->HandleProtocol(handle, &DevicePathGUID, (VOID **)&devpath);
+ if (EFI_ERROR(status))
+ devpath = NULL;
+ return (devpath);
+}
+
+CHAR16 *
+efi_devpath_name(EFI_DEVICE_PATH *devpath)
+{
+ static int once = 1;
+ EFI_STATUS status;
+
+ if (devpath == NULL)
+ return (NULL);
+ if (once) {
+ status = BS->LocateProtocol(&DevicePathToTextGUID, NULL,
+ (VOID **)&textProtocol);
+ if (EFI_ERROR(status))
+ textProtocol = NULL;
+ once = 0;
+ }
+ if (textProtocol == NULL)
+ return (NULL);
+
+ return (textProtocol->ConvertDevicePathToText(devpath, TRUE, TRUE));
+}
+
+void
+efi_free_devpath_name(CHAR16 *text)
+{
+
+ BS->FreePool(text);
+}
+
+EFI_DEVICE_PATH *
+efi_devpath_last_node(EFI_DEVICE_PATH *devpath)
+{
+
+ if (IsDevicePathEnd(devpath))
+ return (NULL);
+ while (!IsDevicePathEnd(NextDevicePathNode(devpath)))
+ devpath = NextDevicePathNode(devpath);
+ return (devpath);
+}
+
+EFI_DEVICE_PATH *
+efi_devpath_trim(EFI_DEVICE_PATH *devpath)
+{
+ EFI_DEVICE_PATH *node, *copy;
+ size_t prefix, len;
+
+ if ((node = efi_devpath_last_node(devpath)) == NULL)
+ return (NULL);
+ prefix = (UINT8 *)node - (UINT8 *)devpath;
+ if (prefix == 0)
+ return (NULL);
+ len = prefix + DevicePathNodeLength(NextDevicePathNode(node));
+ copy = malloc(len);
+ if (copy != NULL) {
+ memcpy(copy, devpath, prefix);
+ node = (EFI_DEVICE_PATH *)((UINT8 *)copy + prefix);
+ SetDevicePathEndNode(node);
+ }
+ return (copy);
+}
+
+EFI_HANDLE
+efi_devpath_handle(EFI_DEVICE_PATH *devpath)
+{
+ EFI_STATUS status;
+ EFI_HANDLE h;
+
+ /*
+ * There isn't a standard way to locate a handle for a given
+ * device path. However, querying the EFI_DEVICE_PATH protocol
+ * for a given device path should give us a handle for the
+ * closest node in the path to the end that is valid.
+ */
+ status = BS->LocateDevicePath(&DevicePathGUID, &devpath, &h);
+ if (EFI_ERROR(status))
+ return (NULL);
+ return (h);
+}
+
+bool
+efi_devpath_match(EFI_DEVICE_PATH *devpath1, EFI_DEVICE_PATH *devpath2)
+{
+ size_t len;
+
+ if (devpath1 == NULL || devpath2 == NULL)
+ return (false);
+
+ while (true) {
+ if (DevicePathType(devpath1) != DevicePathType(devpath2) ||
+ DevicePathSubType(devpath1) != DevicePathSubType(devpath2))
+ return (false);
+
+ len = DevicePathNodeLength(devpath1);
+ if (len != DevicePathNodeLength(devpath2))
+ return (false);
+
+ if (memcmp(devpath1, devpath2, len) != 0)
+ return (false);
+
+ if (IsDevicePathEnd(devpath1))
+ break;
+ devpath1 = NextDevicePathNode(devpath1);
+ devpath2 = NextDevicePathNode(devpath2);
+ }
+ return (true);
+}
+
+bool
+efi_devpath_is_prefix(EFI_DEVICE_PATH *prefix, EFI_DEVICE_PATH *path)
+{
+ size_t len;
+
+ if (prefix == NULL || path == NULL)
+ return (false);
+
+ while (1) {
+ if (IsDevicePathEnd(prefix))
+ break;
+
+ if (DevicePathType(prefix) != DevicePathType(path) ||
+ DevicePathSubType(prefix) != DevicePathSubType(path))
+ return (false);
+
+ len = DevicePathNodeLength(prefix);
+ if (len != DevicePathNodeLength(path))
+ return (false);
+
+ if (memcmp(prefix, path, len) != 0)
+ return (false);
+
+ prefix = NextDevicePathNode(prefix);
+ path = NextDevicePathNode(path);
+ }
+ return (true);
+}
diff --git a/stand/efi/libefi/efi_console.c b/stand/efi/libefi/efi_console.c
new file mode 100644
index 000000000000..450ed46a23f5
--- /dev/null
+++ b/stand/efi/libefi/efi_console.c
@@ -0,0 +1,518 @@
+/*-
+ * Copyright (c) 2000 Doug Rabson
+ * 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>
+__FBSDID("$FreeBSD$");
+
+#include <efi.h>
+#include <efilib.h>
+
+#include "bootstrap.h"
+
+static SIMPLE_TEXT_OUTPUT_INTERFACE *conout;
+static SIMPLE_INPUT_INTERFACE *conin;
+
+#ifdef TERM_EMU
+#define DEFAULT_FGCOLOR EFI_LIGHTGRAY
+#define DEFAULT_BGCOLOR EFI_BLACK
+
+#define MAXARGS 8
+static int args[MAXARGS], argc;
+static int fg_c, bg_c, curx, cury;
+static int esc;
+
+void get_pos(int *x, int *y);
+void curs_move(int *_x, int *_y, int x, int y);
+static void CL(int);
+void HO(void);
+void end_term(void);
+#endif
+
+static EFI_INPUT_KEY key_cur;
+static int key_pending;
+
+static void efi_cons_probe(struct console *);
+static int efi_cons_init(int);
+void efi_cons_putchar(int);
+int efi_cons_getchar(void);
+void efi_cons_efiputchar(int);
+int efi_cons_poll(void);
+
+struct console efi_console = {
+ "efi",
+ "EFI console",
+ C_WIDEOUT,
+ efi_cons_probe,
+ efi_cons_init,
+ efi_cons_putchar,
+ efi_cons_getchar,
+ efi_cons_poll
+};
+
+#ifdef TERM_EMU
+
+/* Get cursor position. */
+void
+get_pos(int *x, int *y)
+{
+ *x = conout->Mode->CursorColumn;
+ *y = conout->Mode->CursorRow;
+}
+
+/* Move cursor to x rows and y cols (0-based). */
+void
+curs_move(int *_x, int *_y, int x, int y)
+{
+ conout->SetCursorPosition(conout, x, y);
+ if (_x != NULL)
+ *_x = conout->Mode->CursorColumn;
+ if (_y != NULL)
+ *_y = conout->Mode->CursorRow;
+}
+
+/* Clear internal state of the terminal emulation code. */
+void
+end_term(void)
+{
+ esc = 0;
+ argc = -1;
+}
+
+#endif
+
+static void
+efi_cons_probe(struct console *cp)
+{
+ conout = ST->ConOut;
+ conin = ST->ConIn;
+ cp->c_flags |= C_PRESENTIN | C_PRESENTOUT;
+}
+
+static int
+efi_cons_init(int arg)
+{
+#ifdef TERM_EMU
+ conout->SetAttribute(conout, EFI_TEXT_ATTR(DEFAULT_FGCOLOR,
+ DEFAULT_BGCOLOR));
+ end_term();
+ get_pos(&curx, &cury);
+ curs_move(&curx, &cury, curx, cury);
+ fg_c = DEFAULT_FGCOLOR;
+ bg_c = DEFAULT_BGCOLOR;
+#endif
+ conout->EnableCursor(conout, TRUE);
+ return 0;
+}
+
+static void
+efi_cons_rawputchar(int c)
+{
+ int i;
+ UINTN x, y;
+ conout->QueryMode(conout, conout->Mode->Mode, &x, &y);
+
+ if (c == '\t')
+ /* XXX lame tab expansion */
+ for (i = 0; i < 8; i++)
+ efi_cons_rawputchar(' ');
+ else {
+#ifndef TERM_EMU
+ if (c == '\n')
+ efi_cons_efiputchar('\r');
+ efi_cons_efiputchar(c);
+#else
+ switch (c) {
+ case '\r':
+ curx = 0;
+ curs_move(&curx, &cury, curx, cury);
+ return;
+ case '\n':
+ cury++;
+ if (cury >= y) {
+ efi_cons_efiputchar('\n');
+ cury--;
+ } else
+ curs_move(&curx, &cury, curx, cury);
+ return;
+ case '\b':
+ if (curx > 0) {
+ curx--;
+ curs_move(&curx, &cury, curx, cury);
+ }
+ return;
+ default:
+ efi_cons_efiputchar(c);
+ curx++;
+ if (curx > x-1) {
+ curx = 0;
+ cury++;
+ }
+ if (cury > y-1) {
+ curx = 0;
+ cury--;
+ }
+ }
+ curs_move(&curx, &cury, curx, cury);
+#endif
+ }
+}
+
+#ifdef TERM_EMU
+/* Gracefully exit ESC-sequence processing in case of misunderstanding. */
+static void
+bail_out(int c)
+{
+ char buf[16], *ch;
+ int i;
+
+ if (esc) {
+ efi_cons_rawputchar('\033');
+ if (esc != '\033')
+ efi_cons_rawputchar(esc);
+ for (i = 0; i <= argc; ++i) {
+ sprintf(buf, "%d", args[i]);
+ ch = buf;
+ while (*ch)
+ efi_cons_rawputchar(*ch++);
+ }
+ }
+ efi_cons_rawputchar(c);
+ end_term();
+}
+
+/* Clear display from current position to end of screen. */
+static void
+CD(void) {
+ int i;
+ UINTN x, y;
+
+ get_pos(&curx, &cury);
+ if (curx == 0 && cury == 0) {
+ conout->ClearScreen(conout);
+ end_term();
+ return;
+ }
+
+ conout->QueryMode(conout, conout->Mode->Mode, &x, &y);
+ CL(0); /* clear current line from cursor to end */
+ for (i = cury + 1; i < y-1; i++) {
+ curs_move(NULL, NULL, 0, i);
+ CL(0);
+ }
+ curs_move(NULL, NULL, curx, cury);
+ end_term();
+}
+
+/*
+ * Absolute cursor move to args[0] rows and args[1] columns
+ * (the coordinates are 1-based).
+ */
+static void
+CM(void)
+{
+ if (args[0] > 0)
+ args[0]--;
+ if (args[1] > 0)
+ args[1]--;
+ curs_move(&curx, &cury, args[1], args[0]);
+ end_term();
+}
+
+/* Home cursor (left top corner), also called from mode command. */
+void
+HO(void)
+{
+ argc = 1;
+ args[0] = args[1] = 1;
+ CM();
+}
+
+/* Clear line from current position to end of line */
+static void
+CL(int direction)
+{
+ int i, len;
+ UINTN x, y;
+ CHAR16 *line;
+
+ conout->QueryMode(conout, conout->Mode->Mode, &x, &y);
+ switch (direction) {
+ case 0: /* from cursor to end */
+ len = x - curx + 1;
+ break;
+ case 1: /* from beginning to cursor */
+ len = curx;
+ break;
+ case 2: /* entire line */
+ len = x;
+ break;
+ default: /* NOTREACHED */
+ __unreachable();
+ }
+
+ if (cury == y - 1)
+ len--;
+
+ line = malloc(len * sizeof (CHAR16));
+ if (line == NULL) {
+ printf("out of memory\n");
+ return;
+ }
+ for (i = 0; i < len; i++)
+ line[i] = ' ';
+ line[len-1] = 0;
+
+ if (direction != 0)
+ curs_move(NULL, NULL, 0, cury);
+
+ conout->OutputString(conout, line);
+ /* restore cursor position */
+ curs_move(NULL, NULL, curx, cury);
+ free(line);
+ end_term();
+}
+
+static void
+get_arg(int c)
+{
+ if (argc < 0)
+ argc = 0;
+ args[argc] *= 10;
+ args[argc] += c - '0';
+}
+
+/* Emulate basic capabilities of cons25 terminal */
+static void
+efi_term_emu(int c)
+{
+ static int ansi_col[] = {
+ 0, 4, 2, 6, 1, 5, 3, 7
+ };
+ int t, i;
+
+ switch (esc) {
+ case 0:
+ switch (c) {
+ case '\033':
+ esc = c;
+ break;
+ default:
+ efi_cons_rawputchar(c);
+ break;
+ }
+ break;
+ case '\033':
+ switch (c) {
+ case '[':
+ esc = c;
+ args[0] = 0;
+ argc = -1;
+ break;
+ default:
+ bail_out(c);
+ break;
+ }
+ break;
+ case '[':
+ switch (c) {
+ case ';':
+ if (argc < 0)
+ argc = 0;
+ else if (argc + 1 >= MAXARGS)
+ bail_out(c);
+ else
+ args[++argc] = 0;
+ break;
+ case 'H': /* ho = \E[H */
+ if (argc < 0)
+ HO();
+ else if (argc == 1)
+ CM();
+ else
+ bail_out(c);
+ break;
+ case 'J': /* cd = \E[J */
+ if (argc < 0)
+ CD();
+ else
+ bail_out(c);
+ break;
+ case 'm':
+ if (argc < 0) {
+ fg_c = DEFAULT_FGCOLOR;
+ bg_c = DEFAULT_BGCOLOR;
+ }
+ for (i = 0; i <= argc; ++i) {
+ switch (args[i]) {
+ case 0: /* back to normal */
+ fg_c = DEFAULT_FGCOLOR;
+ bg_c = DEFAULT_BGCOLOR;
+ break;
+ case 1: /* bold */
+ fg_c |= 0x8;
+ break;
+ case 4: /* underline */
+ case 5: /* blink */
+ bg_c |= 0x8;
+ break;
+ case 7: /* reverse */
+ t = fg_c;
+ fg_c = bg_c;
+ bg_c = t;
+ break;
+ case 30: case 31: case 32: case 33:
+ case 34: case 35: case 36: case 37:
+ fg_c = ansi_col[args[i] - 30];
+ break;
+ case 39: /* normal */
+ fg_c = DEFAULT_FGCOLOR;
+ break;
+ case 40: case 41: case 42: case 43:
+ case 44: case 45: case 46: case 47:
+ bg_c = ansi_col[args[i] - 40];
+ break;
+ case 49: /* normal */
+ bg_c = DEFAULT_BGCOLOR;
+ break;
+ }
+ }
+ conout->SetAttribute(conout, EFI_TEXT_ATTR(fg_c, bg_c));
+ end_term();
+ break;
+ default:
+ if (isdigit(c))
+ get_arg(c);
+ else
+ bail_out(c);
+ break;
+ }
+ break;
+ default:
+ bail_out(c);
+ break;
+ }
+}
+#else
+void
+HO(void)
+{
+}
+#endif
+
+void
+efi_cons_putchar(int c)
+{
+#ifdef TERM_EMU
+ efi_term_emu(c);
+#else
+ efi_cons_rawputchar(c);
+#endif
+}
+
+int
+efi_cons_getchar()
+{
+ EFI_INPUT_KEY key;
+ EFI_STATUS status;
+ UINTN junk;
+
+ if (key_pending) {
+ key = key_cur;
+ key_pending = 0;
+ } else {
+ /* Try to read a key stroke. We wait for one if none is pending. */
+ status = conin->ReadKeyStroke(conin, &key);
+ while (status == EFI_NOT_READY) {
+ /* Some EFI implementation (u-boot for example) do not support WaitForKey */
+ if (conin->WaitForKey != NULL)
+ BS->WaitForEvent(1, &conin->WaitForKey, &junk);
+ status = conin->ReadKeyStroke(conin, &key);
+ }
+ }
+
+ switch (key.ScanCode) {
+ case 0x17: /* ESC */
+ return (0x1b); /* esc */
+ }
+
+ /* this can return */
+ return (key.UnicodeChar);
+}
+
+int
+efi_cons_poll()
+{
+ EFI_INPUT_KEY key;
+ EFI_STATUS status;
+
+ if (conin->WaitForKey == NULL) {
+ if (key_pending)
+ return (1);
+ status = conin->ReadKeyStroke(conin, &key);
+ if (status == EFI_SUCCESS) {
+ key_cur = key;
+ key_pending = 1;
+ }
+ return (key_pending);
+ }
+
+ /* This can clear the signaled state. */
+ return (BS->CheckEvent(conin->WaitForKey) == EFI_SUCCESS);
+}
+
+/* Plain direct access to EFI OutputString(). */
+void
+efi_cons_efiputchar(int c)
+{
+ CHAR16 buf[2];
+
+ /*
+ * translate box chars to unicode
+ */
+ switch (c) {
+ /* single frame */
+ case 0xb3: buf[0] = BOXDRAW_VERTICAL; break;
+ case 0xbf: buf[0] = BOXDRAW_DOWN_LEFT; break;
+ case 0xc0: buf[0] = BOXDRAW_UP_RIGHT; break;
+ case 0xc4: buf[0] = BOXDRAW_HORIZONTAL; break;
+ case 0xda: buf[0] = BOXDRAW_DOWN_RIGHT; break;
+ case 0xd9: buf[0] = BOXDRAW_UP_LEFT; break;
+
+ /* double frame */
+ case 0xba: buf[0] = BOXDRAW_DOUBLE_VERTICAL; break;
+ case 0xbb: buf[0] = BOXDRAW_DOUBLE_DOWN_LEFT; break;
+ case 0xbc: buf[0] = BOXDRAW_DOUBLE_UP_LEFT; break;
+ case 0xc8: buf[0] = BOXDRAW_DOUBLE_UP_RIGHT; break;
+ case 0xc9: buf[0] = BOXDRAW_DOUBLE_DOWN_RIGHT; break;
+ case 0xcd: buf[0] = BOXDRAW_DOUBLE_HORIZONTAL; break;
+
+ default:
+ buf[0] = c;
+ }
+ buf[1] = 0; /* terminate string */
+
+ conout->OutputString(conout, buf);
+}
diff --git a/stand/efi/libefi/efi_driver_utils.c b/stand/efi/libefi/efi_driver_utils.c
new file mode 100644
index 000000000000..0edea5c1e0d8
--- /dev/null
+++ b/stand/efi/libefi/efi_driver_utils.c
@@ -0,0 +1,91 @@
+/*-
+ * Copyright (c) 2017 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 <stdbool.h>
+
+#include <efi.h>
+#include <efilib.h>
+
+#include "efi_driver_utils.h"
+
+static EFI_GUID DriverBindingProtocolGUID = DRIVER_BINDING_PROTOCOL;
+
+EFI_STATUS
+connect_controllers(EFI_GUID *filter)
+{
+ EFI_STATUS status;
+ EFI_HANDLE *handles;
+ UINTN nhandles, i, hsize;
+
+ nhandles = 0;
+ hsize = 0;
+ status = BS->LocateHandle(ByProtocol, filter, NULL,
+ &hsize, NULL);
+
+ if(status != EFI_BUFFER_TOO_SMALL) {
+ return (status);
+ }
+
+ handles = malloc(hsize);
+ nhandles = hsize / sizeof(EFI_HANDLE);
+
+ status = BS->LocateHandle(ByProtocol, filter, NULL,
+ &hsize, handles);
+
+ if(EFI_ERROR(status)) {
+ return (status);
+ }
+
+ for(i = 0; i < nhandles; i++) {
+ BS->ConnectController(handles[i], NULL, NULL, true);
+ }
+
+ free(handles);
+
+ return (status);
+}
+
+EFI_STATUS
+install_driver(EFI_DRIVER_BINDING *driver)
+{
+ EFI_STATUS status;
+
+ driver->ImageHandle = IH;
+ driver->DriverBindingHandle = NULL;
+ status = BS->InstallMultipleProtocolInterfaces(
+ &(driver->DriverBindingHandle),
+ &DriverBindingProtocolGUID, driver,
+ NULL);
+
+ if (EFI_ERROR(status)) {
+ printf("Failed to install driver (%ld)!\n",
+ EFI_ERROR_CODE(status));
+ }
+
+ return (status);
+}
diff --git a/stand/efi/libefi/efichar.c b/stand/efi/libefi/efichar.c
new file mode 100644
index 000000000000..dad4e963300c
--- /dev/null
+++ b/stand/efi/libefi/efichar.c
@@ -0,0 +1,201 @@
+/*-
+ * 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>
+__FBSDID("$FreeBSD$");
+
+#include <sys/types.h>
+#include <errno.h>
+#ifdef LIBEFI
+#include <stand.h>
+#else
+#include <stddef.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#endif
+#include <sys/efi.h>
+#include <machine/efi.h>
+
+#include "efichar.h"
+
+int
+ucs2len(const efi_char *str)
+{
+ int 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 efi_char *nm)
+{
+ size_t len;
+ efi_char 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 efi_char *nm, char **name)
+{
+ size_t len, sz;
+ efi_char c;
+ char *cp;
+ int freeit = *name == NULL;
+
+ sz = utf8_len_of_ucs2(nm) + 1;
+ len = 0;
+ if (*name != NULL)
+ cp = *name;
+ else
+ cp = *name = malloc(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)
+ free(*name);
+ return (EOVERFLOW);
+ }
+ *cp++ = '\0';
+
+ return (0);
+}
+
+int
+utf8_to_ucs2(const char *name, efi_char **nmp, size_t *len)
+{
+ 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;
+ return (0);
+}
diff --git a/stand/efi/libefi/efinet.c b/stand/efi/libefi/efinet.c
new file mode 100644
index 000000000000..cdb63c99f39b
--- /dev/null
+++ b/stand/efi/libefi/efinet.c
@@ -0,0 +1,390 @@
+/*-
+ * Copyright (c) 2001 Doug Rabson
+ * Copyright (c) 2002, 2006 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>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <net/ethernet.h>
+#include <netinet/in.h>
+#include <netinet/in_systm.h>
+
+#include <stand.h>
+#include <net.h>
+#include <netif.h>
+
+#include <efi.h>
+#include <efilib.h>
+
+static EFI_GUID sn_guid = EFI_SIMPLE_NETWORK_PROTOCOL;
+
+static void efinet_end(struct netif *);
+static ssize_t efinet_get(struct iodesc *, void **, time_t);
+static void efinet_init(struct iodesc *, void *);
+static int efinet_match(struct netif *, void *);
+static int efinet_probe(struct netif *, void *);
+static ssize_t efinet_put(struct iodesc *, void *, size_t);
+
+struct netif_driver efinetif = {
+ .netif_bname = "efinet",
+ .netif_match = efinet_match,
+ .netif_probe = efinet_probe,
+ .netif_init = efinet_init,
+ .netif_get = efinet_get,
+ .netif_put = efinet_put,
+ .netif_end = efinet_end,
+ .netif_ifs = NULL,
+ .netif_nifs = 0
+};
+
+#ifdef EFINET_DEBUG
+static void
+dump_mode(EFI_SIMPLE_NETWORK_MODE *mode)
+{
+ int i;
+
+ printf("State = %x\n", mode->State);
+ printf("HwAddressSize = %u\n", mode->HwAddressSize);
+ printf("MediaHeaderSize = %u\n", mode->MediaHeaderSize);
+ printf("MaxPacketSize = %u\n", mode->MaxPacketSize);
+ printf("NvRamSize = %u\n", mode->NvRamSize);
+ printf("NvRamAccessSize = %u\n", mode->NvRamAccessSize);
+ printf("ReceiveFilterMask = %x\n", mode->ReceiveFilterMask);
+ printf("ReceiveFilterSetting = %u\n", mode->ReceiveFilterSetting);
+ printf("MaxMCastFilterCount = %u\n", mode->MaxMCastFilterCount);
+ printf("MCastFilterCount = %u\n", mode->MCastFilterCount);
+ printf("MCastFilter = {");
+ for (i = 0; i < mode->MCastFilterCount; i++)
+ printf(" %s", ether_sprintf(mode->MCastFilter[i].Addr));
+ printf(" }\n");
+ printf("CurrentAddress = %s\n",
+ ether_sprintf(mode->CurrentAddress.Addr));
+ printf("BroadcastAddress = %s\n",
+ ether_sprintf(mode->BroadcastAddress.Addr));
+ printf("PermanentAddress = %s\n",
+ ether_sprintf(mode->PermanentAddress.Addr));
+ printf("IfType = %u\n", mode->IfType);
+ printf("MacAddressChangeable = %d\n", mode->MacAddressChangeable);
+ printf("MultipleTxSupported = %d\n", mode->MultipleTxSupported);
+ printf("MediaPresentSupported = %d\n", mode->MediaPresentSupported);
+ printf("MediaPresent = %d\n", mode->MediaPresent);
+}
+#endif
+
+static int
+efinet_match(struct netif *nif, void *machdep_hint)
+{
+ struct devdesc *dev = machdep_hint;
+
+ if (dev->d_unit == nif->nif_unit)
+ return (1);
+ return(0);
+}
+
+static int
+efinet_probe(struct netif *nif, void *machdep_hint)
+{
+
+ return (0);
+}
+
+static ssize_t
+efinet_put(struct iodesc *desc, void *pkt, size_t len)
+{
+ struct netif *nif = desc->io_netif;
+ EFI_SIMPLE_NETWORK *net;
+ EFI_STATUS status;
+ void *buf;
+
+ net = nif->nif_devdata;
+ if (net == NULL)
+ return (-1);
+
+ status = net->Transmit(net, 0, len, pkt, NULL, NULL, NULL);
+ if (status != EFI_SUCCESS)
+ return (-1);
+
+ /* Wait for the buffer to be transmitted */
+ do {
+ buf = NULL; /* XXX Is this needed? */
+ status = net->GetStatus(net, NULL, &buf);
+ /*
+ * XXX EFI1.1 and the E1000 card returns a different
+ * address than we gave. Sigh.
+ */
+ } while (status == EFI_SUCCESS && buf == NULL);
+
+ /* XXX How do we deal with status != EFI_SUCCESS now? */
+ return ((status == EFI_SUCCESS) ? len : -1);
+}
+
+static ssize_t
+efinet_get(struct iodesc *desc, void **pkt, time_t timeout)
+{
+ struct netif *nif = desc->io_netif;
+ EFI_SIMPLE_NETWORK *net;
+ EFI_STATUS status;
+ UINTN bufsz;
+ time_t t;
+ char *buf, *ptr;
+ ssize_t ret = -1;
+
+ net = nif->nif_devdata;
+ if (net == NULL)
+ return (ret);
+
+ bufsz = net->Mode->MaxPacketSize + ETHER_HDR_LEN + ETHER_CRC_LEN;
+ buf = malloc(bufsz + ETHER_ALIGN);
+ if (buf == NULL)
+ return (ret);
+ ptr = buf + ETHER_ALIGN;
+
+ t = getsecs();
+ while ((getsecs() - t) < timeout) {
+ status = net->Receive(net, NULL, &bufsz, ptr, NULL, NULL, NULL);
+ if (status == EFI_SUCCESS) {
+ *pkt = buf;
+ ret = (ssize_t)bufsz;
+ break;
+ }
+ if (status != EFI_NOT_READY)
+ break;
+ }
+
+ if (ret == -1)
+ free(buf);
+ return (ret);
+}
+
+static void
+efinet_init(struct iodesc *desc, void *machdep_hint)
+{
+ struct netif *nif = desc->io_netif;
+ EFI_SIMPLE_NETWORK *net;
+ EFI_HANDLE h;
+ EFI_STATUS status;
+ UINT32 mask;
+
+ if (nif->nif_driver->netif_ifs[nif->nif_unit].dif_unit < 0) {
+ printf("Invalid network interface %d\n", nif->nif_unit);
+ return;
+ }
+
+ h = nif->nif_driver->netif_ifs[nif->nif_unit].dif_private;
+ status = BS->HandleProtocol(h, &sn_guid, (VOID **)&nif->nif_devdata);
+ if (status != EFI_SUCCESS) {
+ printf("net%d: cannot fetch interface data (status=%lu)\n",
+ nif->nif_unit, EFI_ERROR_CODE(status));
+ return;
+ }
+
+ net = nif->nif_devdata;
+ if (net->Mode->State == EfiSimpleNetworkStopped) {
+ status = net->Start(net);
+ if (status != EFI_SUCCESS) {
+ printf("net%d: cannot start interface (status=%lu)\n",
+ nif->nif_unit, EFI_ERROR_CODE(status));
+ return;
+ }
+ }
+
+ if (net->Mode->State != EfiSimpleNetworkInitialized) {
+ status = net->Initialize(net, 0, 0);
+ if (status != EFI_SUCCESS) {
+ printf("net%d: cannot init. interface (status=%lu)\n",
+ nif->nif_unit, EFI_ERROR_CODE(status));
+ return;
+ }
+ }
+
+ mask = EFI_SIMPLE_NETWORK_RECEIVE_UNICAST |
+ EFI_SIMPLE_NETWORK_RECEIVE_BROADCAST;
+
+ status = net->ReceiveFilters(net, mask, 0, FALSE, 0, NULL);
+ if (status != EFI_SUCCESS) {
+ printf("net%d: cannot set rx. filters (status=%lu)\n",
+ nif->nif_unit, EFI_ERROR_CODE(status));
+ return;
+ }
+
+#ifdef EFINET_DEBUG
+ dump_mode(net->Mode);
+#endif
+
+ bcopy(net->Mode->CurrentAddress.Addr, desc->myea, 6);
+ desc->xid = 1;
+}
+
+static void
+efinet_end(struct netif *nif)
+{
+ EFI_SIMPLE_NETWORK *net = nif->nif_devdata;
+
+ if (net == NULL)
+ return;
+
+ net->Shutdown(net);
+}
+
+static int efinet_dev_init(void);
+static int efinet_dev_print(int);
+
+struct devsw efinet_dev = {
+ .dv_name = "net",
+ .dv_type = DEVT_NET,
+ .dv_init = efinet_dev_init,
+ .dv_strategy = NULL, /* Will be set in efinet_dev_init */
+ .dv_open = NULL, /* Will be set in efinet_dev_init */
+ .dv_close = NULL, /* Will be set in efinet_dev_init */
+ .dv_ioctl = noioctl,
+ .dv_print = efinet_dev_print,
+ .dv_cleanup = NULL
+};
+
+static int
+efinet_dev_init()
+{
+ struct netif_dif *dif;
+ struct netif_stats *stats;
+ EFI_DEVICE_PATH *devpath, *node;
+ EFI_SIMPLE_NETWORK *net;
+ EFI_HANDLE *handles, *handles2;
+ EFI_STATUS status;
+ UINTN sz;
+ int err, i, nifs;
+ extern struct devsw netdev;
+
+ sz = 0;
+ handles = NULL;
+ status = BS->LocateHandle(ByProtocol, &sn_guid, NULL, &sz, NULL);
+ if (status == EFI_BUFFER_TOO_SMALL) {
+ handles = (EFI_HANDLE *)malloc(sz);
+ status = BS->LocateHandle(ByProtocol, &sn_guid, NULL, &sz,
+ handles);
+ if (EFI_ERROR(status))
+ free(handles);
+ }
+ if (EFI_ERROR(status))
+ return (efi_status_to_errno(status));
+ handles2 = (EFI_HANDLE *)malloc(sz);
+ if (handles2 == NULL) {
+ free(handles);
+ return (ENOMEM);
+ }
+ nifs = 0;
+ for (i = 0; i < sz / sizeof(EFI_HANDLE); i++) {
+ devpath = efi_lookup_devpath(handles[i]);
+ if (devpath == NULL)
+ continue;
+ if ((node = efi_devpath_last_node(devpath)) == NULL)
+ continue;
+
+ if (DevicePathType(node) != MESSAGING_DEVICE_PATH ||
+ DevicePathSubType(node) != MSG_MAC_ADDR_DP)
+ continue;
+
+ /*
+ * Open the network device in exclusive mode. Without this
+ * we will be racing with the UEFI network stack. It will
+ * pull packets off the network leading to lost packets.
+ */
+ status = BS->OpenProtocol(handles[i], &sn_guid, (void **)&net,
+ IH, NULL, EFI_OPEN_PROTOCOL_EXCLUSIVE);
+ if (status != EFI_SUCCESS) {
+ printf("Unable to open network interface %d for "
+ "exclusive access: %lu\n", i,
+ EFI_ERROR_CODE(status));
+ }
+
+ handles2[nifs] = handles[i];
+ nifs++;
+ }
+ free(handles);
+ if (nifs == 0) {
+ err = ENOENT;
+ goto done;
+ }
+
+ err = efi_register_handles(&efinet_dev, handles2, NULL, nifs);
+ if (err != 0)
+ goto done;
+
+ efinetif.netif_ifs = calloc(nifs, sizeof(struct netif_dif));
+ stats = calloc(nifs, sizeof(struct netif_stats));
+ if (efinetif.netif_ifs == NULL || stats == NULL) {
+ free(efinetif.netif_ifs);
+ free(stats);
+ efinetif.netif_ifs = NULL;
+ err = ENOMEM;
+ goto done;
+ }
+ efinetif.netif_nifs = nifs;
+
+ for (i = 0; i < nifs; i++) {
+
+ dif = &efinetif.netif_ifs[i];
+ dif->dif_unit = i;
+ dif->dif_nsel = 1;
+ dif->dif_stats = &stats[i];
+ dif->dif_private = handles2[i];
+ }
+
+ efinet_dev.dv_open = netdev.dv_open;
+ efinet_dev.dv_close = netdev.dv_close;
+ efinet_dev.dv_strategy = netdev.dv_strategy;
+
+done:
+ free(handles2);
+ return (err);
+}
+
+static int
+efinet_dev_print(int verbose)
+{
+ CHAR16 *text;
+ EFI_HANDLE h;
+ int unit, ret = 0;
+
+ printf("%s devices:", efinet_dev.dv_name);
+ if ((ret = pager_output("\n")) != 0)
+ return (ret);
+
+ for (unit = 0, h = efi_find_handle(&efinet_dev, 0);
+ h != NULL; h = efi_find_handle(&efinet_dev, ++unit)) {
+ printf(" %s%d:", efinet_dev.dv_name, unit);
+ if (verbose) {
+ text = efi_devpath_name(efi_lookup_devpath(h));
+ if (text != NULL) {
+ printf(" %S", text);
+ efi_free_devpath_name(text);
+ }
+ }
+ if ((ret = pager_output("\n")) != 0)
+ break;
+ }
+ return (ret);
+}
diff --git a/stand/efi/libefi/efipart.c b/stand/efi/libefi/efipart.c
new file mode 100644
index 000000000000..724233c5ab08
--- /dev/null
+++ b/stand/efi/libefi/efipart.c
@@ -0,0 +1,984 @@
+/*-
+ * 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>
+__FBSDID("$FreeBSD$");
+
+#include <sys/disk.h>
+#include <sys/param.h>
+#include <sys/time.h>
+#include <sys/queue.h>
+#include <stddef.h>
+#include <stdarg.h>
+
+#include <bootstrap.h>
+
+#include <efi.h>
+#include <efilib.h>
+#include <efiprot.h>
+#include <disk.h>
+
+static EFI_GUID blkio_guid = BLOCK_IO_PROTOCOL;
+
+static int efipart_initfd(void);
+static int efipart_initcd(void);
+static int efipart_inithd(void);
+
+static int efipart_strategy(void *, int, daddr_t, size_t, char *, size_t *);
+static int efipart_realstrategy(void *, int, daddr_t, size_t, char *, size_t *);
+
+static int efipart_open(struct open_file *, ...);
+static int efipart_close(struct open_file *);
+static int efipart_ioctl(struct open_file *, u_long, void *);
+
+static int efipart_printfd(int);
+static int efipart_printcd(int);
+static int efipart_printhd(int);
+
+/* EISA PNP ID's for floppy controllers */
+#define PNP0604 0x604
+#define PNP0700 0x700
+#define PNP0701 0x701
+
+struct devsw efipart_fddev = {
+ .dv_name = "fd",
+ .dv_type = DEVT_FD,
+ .dv_init = efipart_initfd,
+ .dv_strategy = efipart_strategy,
+ .dv_open = efipart_open,
+ .dv_close = efipart_close,
+ .dv_ioctl = efipart_ioctl,
+ .dv_print = efipart_printfd,
+ .dv_cleanup = NULL
+};
+
+struct devsw efipart_cddev = {
+ .dv_name = "cd",
+ .dv_type = DEVT_CD,
+ .dv_init = efipart_initcd,
+ .dv_strategy = efipart_strategy,
+ .dv_open = efipart_open,
+ .dv_close = efipart_close,
+ .dv_ioctl = efipart_ioctl,
+ .dv_print = efipart_printcd,
+ .dv_cleanup = NULL
+};
+
+struct devsw efipart_hddev = {
+ .dv_name = "disk",
+ .dv_type = DEVT_DISK,
+ .dv_init = efipart_inithd,
+ .dv_strategy = efipart_strategy,
+ .dv_open = efipart_open,
+ .dv_close = efipart_close,
+ .dv_ioctl = efipart_ioctl,
+ .dv_print = efipart_printhd,
+ .dv_cleanup = NULL
+};
+
+static pdinfo_list_t fdinfo;
+static pdinfo_list_t cdinfo;
+static pdinfo_list_t hdinfo;
+
+static EFI_HANDLE *efipart_handles = NULL;
+static UINTN efipart_nhandles = 0;
+
+pdinfo_list_t *
+efiblk_get_pdinfo_list(struct devsw *dev)
+{
+ if (dev->dv_type == DEVT_DISK)
+ return (&hdinfo);
+ if (dev->dv_type == DEVT_CD)
+ return (&cdinfo);
+ if (dev->dv_type == DEVT_FD)
+ return (&fdinfo);
+ return (NULL);
+}
+
+pdinfo_t *
+efiblk_get_pdinfo(struct devdesc *dev)
+{
+ pdinfo_list_t *pdi;
+ pdinfo_t *pd = NULL;
+
+ pdi = efiblk_get_pdinfo_list(dev->d_dev);
+ if (pdi == NULL)
+ return (pd);
+
+ STAILQ_FOREACH(pd, pdi, pd_link) {
+ if (pd->pd_unit == dev->d_unit)
+ return (pd);
+ }
+ return (pd);
+}
+
+static int
+efiblk_pdinfo_count(pdinfo_list_t *pdi)
+{
+ pdinfo_t *pd;
+ int i = 0;
+
+ STAILQ_FOREACH(pd, pdi, pd_link) {
+ i++;
+ }
+ return (i);
+}
+
+static int
+efipart_inithandles(void)
+{
+ UINTN sz;
+ EFI_HANDLE *hin;
+ EFI_STATUS status;
+
+ if (efipart_nhandles != 0) {
+ free(efipart_handles);
+ efipart_handles = NULL;
+ efipart_nhandles = 0;
+ }
+
+ sz = 0;
+ hin = NULL;
+ status = BS->LocateHandle(ByProtocol, &blkio_guid, 0, &sz, hin);
+ if (status == EFI_BUFFER_TOO_SMALL) {
+ hin = malloc(sz);
+ status = BS->LocateHandle(ByProtocol, &blkio_guid, 0, &sz,
+ hin);
+ if (EFI_ERROR(status))
+ free(hin);
+ }
+ if (EFI_ERROR(status))
+ return (efi_status_to_errno(status));
+
+ efipart_handles = hin;
+ efipart_nhandles = sz;
+ return (0);
+}
+
+static ACPI_HID_DEVICE_PATH *
+efipart_floppy(EFI_DEVICE_PATH *node)
+{
+ ACPI_HID_DEVICE_PATH *acpi;
+
+ if (DevicePathType(node) == ACPI_DEVICE_PATH &&
+ DevicePathSubType(node) == ACPI_DP) {
+ acpi = (ACPI_HID_DEVICE_PATH *) node;
+ if (acpi->HID == EISA_PNP_ID(PNP0604) ||
+ acpi->HID == EISA_PNP_ID(PNP0700) ||
+ acpi->HID == EISA_PNP_ID(PNP0701)) {
+ return (acpi);
+ }
+ }
+ return (NULL);
+}
+
+/*
+ * Add or update entries with new handle data.
+ */
+static int
+efipart_fdinfo_add(EFI_HANDLE handle, uint32_t uid, EFI_DEVICE_PATH *devpath)
+{
+ pdinfo_t *fd;
+
+ fd = calloc(1, sizeof(pdinfo_t));
+ if (fd == NULL) {
+ printf("Failed to register floppy %d, out of memory\n", uid);
+ return (ENOMEM);
+ }
+ STAILQ_INIT(&fd->pd_part);
+
+ fd->pd_unit = uid;
+ fd->pd_handle = handle;
+ fd->pd_devpath = devpath;
+ STAILQ_INSERT_TAIL(&fdinfo, fd, pd_link);
+ return (0);
+}
+
+static void
+efipart_updatefd(void)
+{
+ EFI_DEVICE_PATH *devpath, *node;
+ ACPI_HID_DEVICE_PATH *acpi;
+ int i, nin;
+
+ nin = efipart_nhandles / sizeof (*efipart_handles);
+ for (i = 0; i < nin; i++) {
+ devpath = efi_lookup_devpath(efipart_handles[i]);
+ if (devpath == NULL)
+ continue;
+
+ if ((node = efi_devpath_last_node(devpath)) == NULL)
+ continue;
+ if ((acpi = efipart_floppy(node)) != NULL) {
+ efipart_fdinfo_add(efipart_handles[i], acpi->UID,
+ devpath);
+ }
+ }
+}
+
+static int
+efipart_initfd(void)
+{
+ int rv;
+
+ rv = efipart_inithandles();
+ if (rv != 0)
+ return (rv);
+ STAILQ_INIT(&fdinfo);
+
+ efipart_updatefd();
+
+ bcache_add_dev(efiblk_pdinfo_count(&fdinfo));
+ return (0);
+}
+
+/*
+ * Add or update entries with new handle data.
+ */
+static int
+efipart_cdinfo_add(EFI_HANDLE handle, EFI_HANDLE alias,
+ EFI_DEVICE_PATH *devpath)
+{
+ int unit;
+ pdinfo_t *cd;
+ pdinfo_t *pd;
+
+ unit = 0;
+ STAILQ_FOREACH(pd, &cdinfo, pd_link) {
+ if (efi_devpath_match(pd->pd_devpath, devpath) == true) {
+ pd->pd_handle = handle;
+ pd->pd_alias = alias;
+ return (0);
+ }
+ unit++;
+ }
+
+ cd = calloc(1, sizeof(pdinfo_t));
+ if (cd == NULL) {
+ printf("Failed to add cd %d, out of memory\n", unit);
+ return (ENOMEM);
+ }
+ STAILQ_INIT(&cd->pd_part);
+
+ cd->pd_handle = handle;
+ cd->pd_unit = unit;
+ cd->pd_alias = alias;
+ cd->pd_devpath = devpath;
+ STAILQ_INSERT_TAIL(&cdinfo, cd, pd_link);
+ return (0);
+}
+
+static void
+efipart_updatecd(void)
+{
+ int i, nin;
+ EFI_DEVICE_PATH *devpath, *devpathcpy, *tmpdevpath, *node;
+ EFI_HANDLE handle;
+ EFI_BLOCK_IO *blkio;
+ EFI_STATUS status;
+
+ nin = efipart_nhandles / sizeof (*efipart_handles);
+ for (i = 0; i < nin; i++) {
+ devpath = efi_lookup_devpath(efipart_handles[i]);
+ if (devpath == NULL)
+ continue;
+
+ if ((node = efi_devpath_last_node(devpath)) == NULL)
+ continue;
+ if (efipart_floppy(node) != NULL)
+ continue;
+
+ status = BS->HandleProtocol(efipart_handles[i],
+ &blkio_guid, (void **)&blkio);
+ if (EFI_ERROR(status))
+ continue;
+ /*
+ * If we come across a logical partition of subtype CDROM
+ * it doesn't refer to the CD filesystem itself, but rather
+ * to any usable El Torito boot image on it. In this case
+ * we try to find the parent device and add that instead as
+ * that will be the CD filesystem.
+ */
+ if (DevicePathType(node) == MEDIA_DEVICE_PATH &&
+ DevicePathSubType(node) == MEDIA_CDROM_DP) {
+ devpathcpy = efi_devpath_trim(devpath);
+ if (devpathcpy == NULL)
+ continue;
+ tmpdevpath = devpathcpy;
+ status = BS->LocateDevicePath(&blkio_guid, &tmpdevpath,
+ &handle);
+ free(devpathcpy);
+ if (EFI_ERROR(status))
+ continue;
+ devpath = efi_lookup_devpath(handle);
+ efipart_cdinfo_add(handle, efipart_handles[i],
+ devpath);
+ continue;
+ }
+
+ if (DevicePathType(node) == MESSAGING_DEVICE_PATH &&
+ DevicePathSubType(node) == MSG_ATAPI_DP) {
+ efipart_cdinfo_add(efipart_handles[i], NULL,
+ devpath);
+ continue;
+ }
+
+ /* USB or SATA cd without the media. */
+ if (blkio->Media->RemovableMedia &&
+ !blkio->Media->MediaPresent) {
+ efipart_cdinfo_add(efipart_handles[i], NULL,
+ devpath);
+ }
+ }
+}
+
+static int
+efipart_initcd(void)
+{
+ int rv;
+
+ rv = efipart_inithandles();
+ if (rv != 0)
+ return (rv);
+ STAILQ_INIT(&cdinfo);
+
+ efipart_updatecd();
+
+ bcache_add_dev(efiblk_pdinfo_count(&cdinfo));
+ return (0);
+}
+
+static int
+efipart_hdinfo_add(EFI_HANDLE disk_handle, EFI_HANDLE part_handle)
+{
+ EFI_DEVICE_PATH *disk_devpath, *part_devpath;
+ HARDDRIVE_DEVICE_PATH *node;
+ int unit;
+ pdinfo_t *hd, *pd, *last;
+
+ disk_devpath = efi_lookup_devpath(disk_handle);
+ part_devpath = efi_lookup_devpath(part_handle);
+ if (disk_devpath == NULL || part_devpath == NULL) {
+ return (ENOENT);
+ }
+ node = (HARDDRIVE_DEVICE_PATH *)efi_devpath_last_node(part_devpath);
+ if (node == NULL)
+ return (ENOENT); /* This should not happen. */
+
+ pd = calloc(1, sizeof(pdinfo_t));
+ if (pd == NULL) {
+ printf("Failed to add disk, out of memory\n");
+ return (ENOMEM);
+ }
+ STAILQ_INIT(&pd->pd_part);
+
+ STAILQ_FOREACH(hd, &hdinfo, pd_link) {
+ if (efi_devpath_match(hd->pd_devpath, disk_devpath) == true) {
+ /* Add the partition. */
+ pd->pd_handle = part_handle;
+ pd->pd_unit = node->PartitionNumber;
+ pd->pd_devpath = part_devpath;
+ STAILQ_INSERT_TAIL(&hd->pd_part, pd, pd_link);
+ return (0);
+ }
+ }
+
+ last = STAILQ_LAST(&hdinfo, pdinfo, pd_link);
+ if (last != NULL)
+ unit = last->pd_unit + 1;
+ else
+ unit = 0;
+
+ /* Add the disk. */
+ hd = pd;
+ hd->pd_handle = disk_handle;
+ hd->pd_unit = unit;
+ hd->pd_devpath = disk_devpath;
+ STAILQ_INSERT_TAIL(&hdinfo, hd, pd_link);
+
+ pd = calloc(1, sizeof(pdinfo_t));
+ if (pd == NULL) {
+ printf("Failed to add partition, out of memory\n");
+ return (ENOMEM);
+ }
+ STAILQ_INIT(&pd->pd_part);
+
+ /* Add the partition. */
+ pd->pd_handle = part_handle;
+ pd->pd_unit = node->PartitionNumber;
+ pd->pd_devpath = part_devpath;
+ STAILQ_INSERT_TAIL(&hd->pd_part, pd, pd_link);
+
+ return (0);
+}
+
+/*
+ * The MEDIA_FILEPATH_DP has device name.
+ * From U-Boot sources it looks like names are in the form
+ * of typeN:M, where type is interface type, N is disk id
+ * and M is partition id.
+ */
+static int
+efipart_hdinfo_add_filepath(EFI_HANDLE disk_handle)
+{
+ EFI_DEVICE_PATH *devpath;
+ FILEPATH_DEVICE_PATH *node;
+ char *pathname, *p;
+ int unit, len;
+ pdinfo_t *pd, *last;
+
+ /* First collect and verify all the data */
+ if ((devpath = efi_lookup_devpath(disk_handle)) == NULL)
+ return (ENOENT);
+ node = (FILEPATH_DEVICE_PATH *)efi_devpath_last_node(devpath);
+ if (node == NULL)
+ return (ENOENT); /* This should not happen. */
+
+ pd = calloc(1, sizeof(pdinfo_t));
+ if (pd == NULL) {
+ printf("Failed to add disk, out of memory\n");
+ return (ENOMEM);
+ }
+ STAILQ_INIT(&pd->pd_part);
+ last = STAILQ_LAST(&hdinfo, pdinfo, pd_link);
+ if (last != NULL)
+ unit = last->pd_unit + 1;
+ else
+ unit = 0;
+
+ /* FILEPATH_DEVICE_PATH has 0 terminated string */
+ for (len = 0; node->PathName[len] != 0; len++)
+ ;
+ if ((pathname = malloc(len + 1)) == NULL) {
+ printf("Failed to add disk, out of memory\n");
+ free(pd);
+ return (ENOMEM);
+ }
+ cpy16to8(node->PathName, pathname, len + 1);
+ p = strchr(pathname, ':');
+
+ /*
+ * Assume we are receiving handles in order, first disk handle,
+ * then partitions for this disk. If this assumption proves
+ * false, this code would need update.
+ */
+ if (p == NULL) { /* no colon, add the disk */
+ pd->pd_handle = disk_handle;
+ pd->pd_unit = unit;
+ pd->pd_devpath = devpath;
+ STAILQ_INSERT_TAIL(&hdinfo, pd, pd_link);
+ free(pathname);
+ return (0);
+ }
+ p++; /* skip the colon */
+ errno = 0;
+ unit = (int)strtol(p, NULL, 0);
+ if (errno != 0) {
+ printf("Bad unit number for partition \"%s\"\n", pathname);
+ free(pathname);
+ free(pd);
+ return (EUNIT);
+ }
+
+ /*
+ * We should have disk registered, if not, we are receiving
+ * handles out of order, and this code should be reworked
+ * to create "blank" disk for partition, and to find the
+ * disk based on PathName compares.
+ */
+ if (last == NULL) {
+ printf("BUG: No disk for partition \"%s\"\n", pathname);
+ free(pathname);
+ free(pd);
+ return (EINVAL);
+ }
+ /* Add the partition. */
+ pd->pd_handle = disk_handle;
+ pd->pd_unit = unit;
+ pd->pd_devpath = devpath;
+ STAILQ_INSERT_TAIL(&last->pd_part, pd, pd_link);
+ free(pathname);
+ return (0);
+}
+
+static void
+efipart_updatehd(void)
+{
+ int i, nin;
+ EFI_DEVICE_PATH *devpath, *devpathcpy, *tmpdevpath, *node;
+ EFI_HANDLE handle;
+ EFI_BLOCK_IO *blkio;
+ EFI_STATUS status;
+
+ nin = efipart_nhandles / sizeof (*efipart_handles);
+ for (i = 0; i < nin; i++) {
+ devpath = efi_lookup_devpath(efipart_handles[i]);
+ if (devpath == NULL)
+ continue;
+
+ if ((node = efi_devpath_last_node(devpath)) == NULL)
+ continue;
+ if (efipart_floppy(node) != NULL)
+ continue;
+
+ status = BS->HandleProtocol(efipart_handles[i],
+ &blkio_guid, (void **)&blkio);
+ if (EFI_ERROR(status))
+ continue;
+
+ if (DevicePathType(node) == MEDIA_DEVICE_PATH &&
+ DevicePathSubType(node) == MEDIA_HARDDRIVE_DP) {
+ devpathcpy = efi_devpath_trim(devpath);
+ if (devpathcpy == NULL)
+ continue;
+ tmpdevpath = devpathcpy;
+ status = BS->LocateDevicePath(&blkio_guid, &tmpdevpath,
+ &handle);
+ free(devpathcpy);
+ if (EFI_ERROR(status))
+ continue;
+ /*
+ * We do not support nested partitions.
+ */
+ devpathcpy = efi_lookup_devpath(handle);
+ if (devpathcpy == NULL)
+ continue;
+ if ((node = efi_devpath_last_node(devpathcpy)) == NULL)
+ continue;
+ if (DevicePathType(node) == MEDIA_DEVICE_PATH &&
+ DevicePathSubType(node) == MEDIA_HARDDRIVE_DP)
+ continue;
+ efipart_hdinfo_add(handle, efipart_handles[i]);
+ continue;
+ }
+
+ if (DevicePathType(node) == MEDIA_DEVICE_PATH &&
+ DevicePathSubType(node) == MEDIA_FILEPATH_DP) {
+ efipart_hdinfo_add_filepath(efipart_handles[i]);
+ continue;
+ }
+ }
+}
+
+static int
+efipart_inithd(void)
+{
+ int rv;
+
+ rv = efipart_inithandles();
+ if (rv != 0)
+ return (rv);
+ STAILQ_INIT(&hdinfo);
+
+ efipart_updatehd();
+
+ bcache_add_dev(efiblk_pdinfo_count(&hdinfo));
+ return (0);
+}
+
+static int
+efipart_print_common(struct devsw *dev, pdinfo_list_t *pdlist, int verbose)
+{
+ int ret = 0;
+ EFI_BLOCK_IO *blkio;
+ EFI_STATUS status;
+ EFI_HANDLE h;
+ pdinfo_t *pd;
+ CHAR16 *text;
+ struct disk_devdesc pd_dev;
+ char line[80];
+
+ if (STAILQ_EMPTY(pdlist))
+ return (0);
+
+ printf("%s devices:", dev->dv_name);
+ if ((ret = pager_output("\n")) != 0)
+ return (ret);
+
+ STAILQ_FOREACH(pd, pdlist, pd_link) {
+ h = pd->pd_handle;
+ if (verbose) { /* Output the device path. */
+ text = efi_devpath_name(efi_lookup_devpath(h));
+ if (text != NULL) {
+ printf(" %S", text);
+ efi_free_devpath_name(text);
+ if ((ret = pager_output("\n")) != 0)
+ break;
+ }
+ }
+ snprintf(line, sizeof(line),
+ " %s%d", dev->dv_name, pd->pd_unit);
+ printf("%s:", line);
+ status = BS->HandleProtocol(h, &blkio_guid, (void **)&blkio);
+ if (!EFI_ERROR(status)) {
+ printf(" %llu",
+ blkio->Media->LastBlock == 0? 0:
+ (unsigned long long) (blkio->Media->LastBlock + 1));
+ if (blkio->Media->LastBlock != 0) {
+ printf(" X %u", blkio->Media->BlockSize);
+ }
+ printf(" blocks");
+ if (blkio->Media->MediaPresent) {
+ if (blkio->Media->RemovableMedia)
+ printf(" (removable)");
+ } else {
+ printf(" (no media)");
+ }
+ if ((ret = pager_output("\n")) != 0)
+ break;
+ if (!blkio->Media->MediaPresent)
+ continue;
+
+ pd->pd_blkio = blkio;
+ pd_dev.d_dev = dev;
+ pd_dev.d_unit = pd->pd_unit;
+ pd_dev.d_slice = -1;
+ pd_dev.d_partition = -1;
+ pd_dev.d_opendata = blkio;
+ ret = disk_open(&pd_dev, blkio->Media->BlockSize *
+ (blkio->Media->LastBlock + 1),
+ blkio->Media->BlockSize);
+ if (ret == 0) {
+ ret = disk_print(&pd_dev, line, verbose);
+ disk_close(&pd_dev);
+ if (ret != 0)
+ return (ret);
+ } else {
+ /* Do not fail from disk_open() */
+ ret = 0;
+ }
+ } else {
+ if ((ret = pager_output("\n")) != 0)
+ break;
+ }
+ }
+ return (ret);
+}
+
+static int
+efipart_printfd(int verbose)
+{
+ return (efipart_print_common(&efipart_fddev, &fdinfo, verbose));
+}
+
+static int
+efipart_printcd(int verbose)
+{
+ return (efipart_print_common(&efipart_cddev, &cdinfo, verbose));
+}
+
+static int
+efipart_printhd(int verbose)
+{
+ return (efipart_print_common(&efipart_hddev, &hdinfo, verbose));
+}
+
+static int
+efipart_open(struct open_file *f, ...)
+{
+ va_list args;
+ struct disk_devdesc *dev;
+ pdinfo_t *pd;
+ EFI_BLOCK_IO *blkio;
+ EFI_STATUS status;
+
+ va_start(args, f);
+ dev = va_arg(args, struct disk_devdesc*);
+ va_end(args);
+ if (dev == NULL)
+ return (EINVAL);
+
+ pd = efiblk_get_pdinfo((struct devdesc *)dev);
+ if (pd == NULL)
+ return (EIO);
+
+ if (pd->pd_blkio == NULL) {
+ status = BS->HandleProtocol(pd->pd_handle, &blkio_guid,
+ (void **)&pd->pd_blkio);
+ if (EFI_ERROR(status))
+ return (efi_status_to_errno(status));
+ }
+
+ blkio = pd->pd_blkio;
+ if (!blkio->Media->MediaPresent)
+ return (EAGAIN);
+
+ pd->pd_open++;
+ if (pd->pd_bcache == NULL)
+ pd->pd_bcache = bcache_allocate();
+
+ if (dev->d_dev->dv_type == DEVT_DISK) {
+ int rc;
+
+ rc = disk_open(dev,
+ blkio->Media->BlockSize * (blkio->Media->LastBlock + 1),
+ blkio->Media->BlockSize);
+ if (rc != 0) {
+ pd->pd_open--;
+ if (pd->pd_open == 0) {
+ pd->pd_blkio = NULL;
+ bcache_free(pd->pd_bcache);
+ pd->pd_bcache = NULL;
+ }
+ }
+ return (rc);
+ }
+ return (0);
+}
+
+static int
+efipart_close(struct open_file *f)
+{
+ struct disk_devdesc *dev;
+ pdinfo_t *pd;
+
+ dev = (struct disk_devdesc *)(f->f_devdata);
+ if (dev == NULL)
+ return (EINVAL);
+
+ pd = efiblk_get_pdinfo((struct devdesc *)dev);
+ if (pd == NULL)
+ return (EINVAL);
+
+ pd->pd_open--;
+ if (pd->pd_open == 0) {
+ pd->pd_blkio = NULL;
+ bcache_free(pd->pd_bcache);
+ pd->pd_bcache = NULL;
+ }
+ if (dev->d_dev->dv_type == DEVT_DISK)
+ return (disk_close(dev));
+ return (0);
+}
+
+static int
+efipart_ioctl(struct open_file *f, u_long cmd, void *data)
+{
+ struct disk_devdesc *dev;
+ pdinfo_t *pd;
+ int rc;
+
+ dev = (struct disk_devdesc *)(f->f_devdata);
+ if (dev == NULL)
+ return (EINVAL);
+
+ pd = efiblk_get_pdinfo((struct devdesc *)dev);
+ if (pd == NULL)
+ return (EINVAL);
+
+ if (dev->d_dev->dv_type == DEVT_DISK) {
+ rc = disk_ioctl(dev, cmd, data);
+ if (rc != ENOTTY)
+ return (rc);
+ }
+
+ switch (cmd) {
+ case DIOCGSECTORSIZE:
+ *(u_int *)data = pd->pd_blkio->Media->BlockSize;
+ break;
+ case DIOCGMEDIASIZE:
+ *(uint64_t *)data = pd->pd_blkio->Media->BlockSize *
+ (pd->pd_blkio->Media->LastBlock + 1);
+ break;
+ default:
+ return (ENOTTY);
+ }
+
+ return (0);
+}
+
+/*
+ * efipart_readwrite()
+ * Internal equivalent of efipart_strategy(), which operates on the
+ * media-native block size. This function expects all I/O requests
+ * to be within the media size and returns an error if such is not
+ * the case.
+ */
+static int
+efipart_readwrite(EFI_BLOCK_IO *blkio, int rw, daddr_t blk, daddr_t nblks,
+ char *buf)
+{
+ EFI_STATUS status;
+
+ if (blkio == NULL)
+ return (ENXIO);
+ if (blk < 0 || blk > blkio->Media->LastBlock)
+ return (EIO);
+ if ((blk + nblks - 1) > blkio->Media->LastBlock)
+ return (EIO);
+
+ switch (rw & F_MASK) {
+ case F_READ:
+ status = blkio->ReadBlocks(blkio, blkio->Media->MediaId, blk,
+ nblks * blkio->Media->BlockSize, buf);
+ break;
+ case F_WRITE:
+ if (blkio->Media->ReadOnly)
+ return (EROFS);
+ status = blkio->WriteBlocks(blkio, blkio->Media->MediaId, blk,
+ nblks * blkio->Media->BlockSize, buf);
+ break;
+ default:
+ return (ENOSYS);
+ }
+
+ if (EFI_ERROR(status)) {
+ printf("%s: rw=%d, blk=%ju size=%ju status=%lu\n", __func__, rw,
+ blk, nblks, EFI_ERROR_CODE(status));
+ }
+ return (efi_status_to_errno(status));
+}
+
+static int
+efipart_strategy(void *devdata, int rw, daddr_t blk, size_t size,
+ char *buf, size_t *rsize)
+{
+ struct bcache_devdata bcd;
+ struct disk_devdesc *dev;
+ pdinfo_t *pd;
+
+ dev = (struct disk_devdesc *)devdata;
+ if (dev == NULL)
+ return (EINVAL);
+
+ pd = efiblk_get_pdinfo((struct devdesc *)dev);
+ if (pd == NULL)
+ return (EINVAL);
+
+ if (pd->pd_blkio->Media->RemovableMedia &&
+ !pd->pd_blkio->Media->MediaPresent)
+ return (ENXIO);
+
+ bcd.dv_strategy = efipart_realstrategy;
+ bcd.dv_devdata = devdata;
+ bcd.dv_cache = pd->pd_bcache;
+
+ if (dev->d_dev->dv_type == DEVT_DISK) {
+ daddr_t offset;
+
+ offset = dev->d_offset * pd->pd_blkio->Media->BlockSize;
+ offset /= 512;
+ return (bcache_strategy(&bcd, rw, blk + offset,
+ size, buf, rsize));
+ }
+ return (bcache_strategy(&bcd, rw, blk, size, buf, rsize));
+}
+
+static int
+efipart_realstrategy(void *devdata, int rw, daddr_t blk, size_t size,
+ char *buf, size_t *rsize)
+{
+ struct disk_devdesc *dev = (struct disk_devdesc *)devdata;
+ pdinfo_t *pd;
+ EFI_BLOCK_IO *blkio;
+ uint64_t off, disk_blocks, d_offset = 0;
+ char *blkbuf;
+ size_t blkoff, blksz;
+ int error;
+ size_t diskend, readstart;
+
+ if (dev == NULL || blk < 0)
+ return (EINVAL);
+
+ pd = efiblk_get_pdinfo((struct devdesc *)dev);
+ if (pd == NULL)
+ return (EINVAL);
+
+ blkio = pd->pd_blkio;
+ if (blkio == NULL)
+ return (ENXIO);
+
+ if (size == 0 || (size % 512) != 0)
+ return (EIO);
+
+ off = blk * 512;
+ /*
+ * Get disk blocks, this value is either for whole disk or for
+ * partition.
+ */
+ disk_blocks = 0;
+ if (dev->d_dev->dv_type == DEVT_DISK) {
+ if (disk_ioctl(dev, DIOCGMEDIASIZE, &disk_blocks) == 0) {
+ /* DIOCGMEDIASIZE does return bytes. */
+ disk_blocks /= blkio->Media->BlockSize;
+ }
+ d_offset = dev->d_offset;
+ }
+ if (disk_blocks == 0)
+ disk_blocks = blkio->Media->LastBlock + 1 - d_offset;
+
+ /* make sure we don't read past disk end */
+ if ((off + size) / blkio->Media->BlockSize > d_offset + disk_blocks) {
+ diskend = d_offset + disk_blocks;
+ readstart = off / blkio->Media->BlockSize;
+
+ if (diskend <= readstart) {
+ if (rsize != NULL)
+ *rsize = 0;
+
+ return (EIO);
+ }
+ size = diskend - readstart;
+ size = size * blkio->Media->BlockSize;
+ }
+
+ if (rsize != NULL)
+ *rsize = size;
+
+ if ((size % blkio->Media->BlockSize == 0) &&
+ (off % blkio->Media->BlockSize == 0))
+ return (efipart_readwrite(blkio, rw,
+ off / blkio->Media->BlockSize,
+ size / blkio->Media->BlockSize, buf));
+
+ /*
+ * The block size of the media is not a multiple of I/O.
+ */
+ blkbuf = malloc(blkio->Media->BlockSize);
+ if (blkbuf == NULL)
+ return (ENOMEM);
+
+ error = 0;
+ blk = off / blkio->Media->BlockSize;
+ blkoff = off % blkio->Media->BlockSize;
+ blksz = blkio->Media->BlockSize - blkoff;
+ while (size > 0) {
+ error = efipart_readwrite(blkio, rw, blk, 1, blkbuf);
+ if (error)
+ break;
+ if (size < blksz)
+ blksz = size;
+ bcopy(blkbuf + blkoff, buf, blksz);
+ buf += blksz;
+ size -= blksz;
+ blk++;
+ blkoff = 0;
+ blksz = blkio->Media->BlockSize;
+ }
+
+ free(blkbuf);
+ return (error);
+}
diff --git a/stand/efi/libefi/efizfs.c b/stand/efi/libefi/efizfs.c
new file mode 100644
index 000000000000..7c434765fb54
--- /dev/null
+++ b/stand/efi/libefi/efizfs.c
@@ -0,0 +1,122 @@
+/*-
+ * Copyright (c) 2008-2010 Rui Paulo
+ * Copyright (c) 2006 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 ``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 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>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <sys/disk.h>
+#include <stdint.h>
+
+#ifdef EFI_ZFS_BOOT
+#include <libzfs.h>
+#endif
+
+#include <efi.h>
+#include <efilib.h>
+
+#include "efizfs.h"
+
+#ifdef EFI_ZFS_BOOT
+static zfsinfo_list_t zfsinfo;
+
+uint64_t pool_guid;
+
+zfsinfo_list_t *
+efizfs_get_zfsinfo_list(void)
+{
+ return (&zfsinfo);
+}
+
+EFI_HANDLE
+efizfs_get_handle_by_guid(uint64_t guid)
+{
+ zfsinfo_t *zi;
+
+ STAILQ_FOREACH(zi, &zfsinfo, zi_link) {
+ if (zi->zi_pool_guid == guid) {
+ return (zi->zi_handle);
+ }
+ }
+ return (NULL);
+}
+
+static void
+insert_zfs(EFI_HANDLE handle, uint64_t guid)
+{
+ zfsinfo_t *zi;
+
+ zi = malloc(sizeof(zfsinfo_t));
+ zi->zi_handle = handle;
+ zi->zi_pool_guid = guid;
+ STAILQ_INSERT_TAIL(&zfsinfo, zi, zi_link);
+}
+
+void
+efi_zfs_probe(void)
+{
+ pdinfo_list_t *hdi;
+ pdinfo_t *hd, *pd = NULL;
+ char devname[SPECNAMELEN + 1];
+ uint64_t guid;
+
+ hdi = efiblk_get_pdinfo_list(&efipart_hddev);
+ STAILQ_INIT(&zfsinfo);
+
+ /*
+ * Find the handle for the boot device. The boot1 did find the
+ * device with loader binary, now we need to search for the
+ * same device and if it is part of the zfs pool, we record the
+ * pool GUID for currdev setup.
+ */
+ STAILQ_FOREACH(hd, hdi, pd_link) {
+ STAILQ_FOREACH(pd, &hd->pd_part, pd_link) {
+
+ snprintf(devname, sizeof(devname), "%s%dp%d:",
+ efipart_hddev.dv_name, hd->pd_unit, pd->pd_unit);
+
+ if (zfs_probe_dev(devname, &guid) == 0) {
+ insert_zfs(pd->pd_handle, guid);
+
+ if (efi_zfs_is_preferred(pd->pd_handle))
+ pool_guid = guid;
+ }
+
+ }
+ }
+}
+
+uint64_t
+ldi_get_size(void *priv)
+{
+ int fd = (uintptr_t) priv;
+ uint64_t size;
+
+ ioctl(fd, DIOCGMEDIASIZE, &size);
+ return (size);
+}
+#endif
diff --git a/stand/efi/libefi/env.c b/stand/efi/libefi/env.c
new file mode 100644
index 000000000000..ceec7b2a18f8
--- /dev/null
+++ b/stand/efi/libefi/env.c
@@ -0,0 +1,534 @@
+/*
+ * Copyright (c) 2015 Netflix, Inc. 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>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <stand.h>
+#include <string.h>
+#include <efi.h>
+#include <efilib.h>
+#include <uuid.h>
+#include <stdbool.h>
+#include "bootstrap.h"
+#ifdef BOOT_FORTH
+#include "ficl.h"
+#endif
+
+/*
+ * Simple wrappers to the underlying UEFI functions.
+ * See http://wiki.phoenix.com/wiki/index.php/EFI_RUNTIME_SERVICES
+ * for details.
+ */
+EFI_STATUS
+efi_get_next_variable_name(UINTN *variable_name_size, CHAR16 *variable_name,
+ EFI_GUID *vendor_guid)
+{
+ return (RS->GetNextVariableName(variable_name_size, variable_name,
+ vendor_guid));
+}
+
+EFI_STATUS
+efi_get_variable(CHAR16 *variable_name, EFI_GUID *vendor_guid,
+ UINT32 *attributes, UINTN *data_size, void *data)
+{
+ return (RS->GetVariable(variable_name, vendor_guid, attributes,
+ data_size, data));
+}
+
+EFI_STATUS
+efi_set_variable(CHAR16 *variable_name, EFI_GUID *vendor_guid,
+ UINT32 attributes, UINTN data_size, void *data)
+{
+ return (RS->SetVariable(variable_name, vendor_guid, attributes,
+ data_size, data));
+}
+
+void
+efi_init_environment(void)
+{
+ char var[128];
+
+ snprintf(var, sizeof(var), "%d.%02d", ST->Hdr.Revision >> 16,
+ ST->Hdr.Revision & 0xffff);
+ env_setenv("efi-version", EV_VOLATILE, var, env_noset, env_nounset);
+}
+
+COMMAND_SET(efishow, "efi-show", "print some or all EFI variables", command_efi_show);
+
+static int
+efi_print_var(CHAR16 *varnamearg, EFI_GUID *matchguid, int lflag)
+{
+ UINTN datasz, i;
+ EFI_STATUS status;
+ UINT32 attr;
+ CHAR16 *data;
+ char *str;
+ uint32_t uuid_status;
+ int is_ascii;
+
+ datasz = 0;
+ status = RS->GetVariable(varnamearg, matchguid, &attr,
+ &datasz, NULL);
+ if (status != EFI_BUFFER_TOO_SMALL) {
+ printf("Can't get the variable: error %#lx\n",
+ EFI_ERROR_CODE(status));
+ return (CMD_ERROR);
+ }
+ data = malloc(datasz);
+ status = RS->GetVariable(varnamearg, matchguid, &attr,
+ &datasz, data);
+ if (status != EFI_SUCCESS) {
+ printf("Can't get the variable: error %#lx\n",
+ EFI_ERROR_CODE(status));
+ return (CMD_ERROR);
+ }
+ uuid_to_string((uuid_t *)matchguid, &str, &uuid_status);
+ if (lflag) {
+ printf("%s 0x%x %S", str, attr, varnamearg);
+ } else {
+ printf("%s 0x%x %S=", str, attr, varnamearg);
+ is_ascii = 1;
+ free(str);
+ str = (char *)data;
+ for (i = 0; i < datasz - 1; i++) {
+ /* Quick hack to see if this ascii-ish string printable range plus tab, cr and lf */
+ if ((str[i] < 32 || str[i] > 126) && str[i] != 9 && str[i] != 10 && str[i] != 13) {
+ is_ascii = 0;
+ break;
+ }
+ }
+ if (str[datasz - 1] != '\0')
+ is_ascii = 0;
+ if (is_ascii)
+ printf("%s", str);
+ else {
+ for (i = 0; i < datasz / 2; i++) {
+ if (isalnum(data[i]) || isspace(data[i]))
+ printf("%c", data[i]);
+ else
+ printf("\\x%02x", data[i]);
+ }
+ }
+ }
+ free(data);
+ if (pager_output("\n"))
+ return (CMD_WARN);
+ return (CMD_OK);
+}
+
+static int
+command_efi_show(int argc, char *argv[])
+{
+ /*
+ * efi-show [-a]
+ * print all the env
+ * efi-show -u UUID
+ * print all the env vars tagged with UUID
+ * efi-show -v var
+ * search all the env vars and print the ones matching var
+ * eif-show -u UUID -v var
+ * eif-show UUID var
+ * print all the env vars that match UUID and var
+ */
+ /* NB: We assume EFI_GUID is the same as uuid_t */
+ int aflag = 0, gflag = 0, lflag = 0, vflag = 0;
+ int ch, rv;
+ unsigned i;
+ EFI_STATUS status;
+ EFI_GUID varguid = { 0,0,0,{0,0,0,0,0,0,0,0} };
+ EFI_GUID matchguid = { 0,0,0,{0,0,0,0,0,0,0,0} };
+ uint32_t uuid_status;
+ CHAR16 *varname;
+ CHAR16 *newnm;
+ CHAR16 varnamearg[128];
+ UINTN varalloc;
+ UINTN varsz;
+
+ while ((ch = getopt(argc, argv, "ag:lv:")) != -1) {
+ switch (ch) {
+ case 'a':
+ aflag = 1;
+ break;
+ case 'g':
+ gflag = 1;
+ uuid_from_string(optarg, (uuid_t *)&matchguid,
+ &uuid_status);
+ if (uuid_status != uuid_s_ok) {
+ printf("uid %s could not be parsed\n", optarg);
+ return (CMD_ERROR);
+ }
+ break;
+ case 'l':
+ lflag = 1;
+ break;
+ case 'v':
+ vflag = 1;
+ if (strlen(optarg) >= nitems(varnamearg)) {
+ printf("Variable %s is longer than %zd characters\n",
+ optarg, nitems(varnamearg));
+ return (CMD_ERROR);
+ }
+ for (i = 0; i < strlen(optarg); i++)
+ varnamearg[i] = optarg[i];
+ varnamearg[i] = 0;
+ break;
+ default:
+ printf("Invalid argument %c\n", ch);
+ return (CMD_ERROR);
+ }
+ }
+
+ if (aflag && (gflag || vflag)) {
+ printf("-a isn't compatible with -v or -u\n");
+ return (CMD_ERROR);
+ }
+
+ if (aflag && optind < argc) {
+ printf("-a doesn't take any args\n");
+ return (CMD_ERROR);
+ }
+
+ if (optind == argc)
+ aflag = 1;
+
+ argc -= optind;
+ argv += optind;
+
+ pager_open();
+ if (vflag && gflag) {
+ rv = efi_print_var(varnamearg, &matchguid, lflag);
+ pager_close();
+ return (rv);
+ }
+
+ if (argc == 2) {
+ optarg = argv[0];
+ if (strlen(optarg) >= nitems(varnamearg)) {
+ printf("Variable %s is longer than %zd characters\n",
+ optarg, nitems(varnamearg));
+ pager_close();
+ return (CMD_ERROR);
+ }
+ for (i = 0; i < strlen(optarg); i++)
+ varnamearg[i] = optarg[i];
+ varnamearg[i] = 0;
+ optarg = argv[1];
+ uuid_from_string(optarg, (uuid_t *)&matchguid,
+ &uuid_status);
+ if (uuid_status != uuid_s_ok) {
+ printf("uid %s could not be parsed\n", optarg);
+ pager_close();
+ return (CMD_ERROR);
+ }
+ rv = efi_print_var(varnamearg, &matchguid, lflag);
+ pager_close();
+ return (rv);
+ }
+
+ if (argc > 0) {
+ printf("Too many args %d\n", argc);
+ pager_close();
+ return (CMD_ERROR);
+ }
+
+ /*
+ * Initiate the search -- note the standard takes pain
+ * to specify the initial call must be a poiner to a NULL
+ * character.
+ */
+ varalloc = 1024;
+ varname = malloc(varalloc);
+ if (varname == NULL) {
+ printf("Can't allocate memory to get variables\n");
+ pager_close();
+ return (CMD_ERROR);
+ }
+ varname[0] = 0;
+ while (1) {
+ varsz = varalloc;
+ status = RS->GetNextVariableName(&varsz, varname, &varguid);
+ if (status == EFI_BUFFER_TOO_SMALL) {
+ varalloc = varsz;
+ newnm = realloc(varname, varalloc);
+ if (newnm == NULL) {
+ printf("Can't allocate memory to get variables\n");
+ free(varname);
+ pager_close();
+ return (CMD_ERROR);
+ }
+ varname = newnm;
+ continue; /* Try again with bigger buffer */
+ }
+ if (status != EFI_SUCCESS)
+ break;
+ if (aflag) {
+ if (efi_print_var(varname, &varguid, lflag) != CMD_OK)
+ break;
+ continue;
+ }
+ if (vflag) {
+ if (wcscmp(varnamearg, varname) == 0) {
+ if (efi_print_var(varname, &varguid, lflag) != CMD_OK)
+ break;
+ continue;
+ }
+ }
+ if (gflag) {
+ if (memcmp(&varguid, &matchguid, sizeof(varguid)) == 0) {
+ if (efi_print_var(varname, &varguid, lflag) != CMD_OK)
+ break;
+ continue;
+ }
+ }
+ }
+ free(varname);
+ pager_close();
+
+ return (CMD_OK);
+}
+
+COMMAND_SET(efiset, "efi-set", "set EFI variables", command_efi_set);
+
+static int
+command_efi_set(int argc, char *argv[])
+{
+ char *uuid, *var, *val;
+ CHAR16 wvar[128];
+ EFI_GUID guid;
+ uint32_t status;
+ EFI_STATUS err;
+
+ if (argc != 4) {
+ printf("efi-set uuid var new-value\n");
+ return (CMD_ERROR);
+ }
+ uuid = argv[1];
+ var = argv[2];
+ val = argv[3];
+ uuid_from_string(uuid, (uuid_t *)&guid, &status);
+ if (status != uuid_s_ok) {
+ printf("Invalid uuid %s %d\n", uuid, status);
+ return (CMD_ERROR);
+ }
+ cpy8to16(var, wvar, sizeof(wvar));
+ err = RS->SetVariable(wvar, &guid,
+ EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS,
+ strlen(val) + 1, val);
+ if (EFI_ERROR(err)) {
+ printf("Failed to set variable: error %lu\n", EFI_ERROR_CODE(err));
+ return (CMD_ERROR);
+ }
+ return (CMD_OK);
+}
+
+COMMAND_SET(efiunset, "efi-unset", "delete / unset EFI variables", command_efi_unset);
+
+static int
+command_efi_unset(int argc, char *argv[])
+{
+ char *uuid, *var;
+ CHAR16 wvar[128];
+ EFI_GUID guid;
+ uint32_t status;
+ EFI_STATUS err;
+
+ if (argc != 3) {
+ printf("efi-unset uuid var\n");
+ return (CMD_ERROR);
+ }
+ uuid = argv[1];
+ var = argv[2];
+ uuid_from_string(uuid, (uuid_t *)&guid, &status);
+ if (status != uuid_s_ok) {
+ printf("Invalid uuid %s\n", uuid);
+ return (CMD_ERROR);
+ }
+ cpy8to16(var, wvar, 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));
+ return (CMD_ERROR);
+ }
+ return (CMD_OK);
+}
+
+#ifdef BOOT_FORTH
+/*
+ * FreeBSD's loader interaction words and extras
+ *
+ * efi-setenv ( value n name n guid n attr -- 0 | -1)
+ * efi-getenv ( guid n addr n -- addr' n' | -1 )
+ * efi-unsetenv ( name n guid n'' -- )
+ */
+
+/*
+ * efi-setenv
+ * efi-setenv ( value n name n guid n attr -- 0 | -1)
+ *
+ * Set environment variables using the SetVariable EFI runtime service.
+ *
+ * Value and guid are passed through in binary form (so guid needs to be
+ * converted to binary form from its string form). Name is converted from
+ * ASCII to CHAR16. Since ficl doesn't have support for internationalization,
+ * there's no native CHAR16 interface provided.
+ *
+ * attr is an int in the bitmask of the following attributes for this variable.
+ *
+ * 1 Non volatile
+ * 2 Boot service access
+ * 4 Run time access
+ * (corresponding to the same bits in the UEFI spec).
+ */
+static void
+ficlEfiSetenv(FICL_VM *pVM)
+{
+ char *value = NULL, *guid = NULL;
+ CHAR16 *name = NULL;
+ int i;
+ char *namep, *valuep, *guidp;
+ int names, values, guids, attr;
+ EFI_STATUS status;
+ uuid_t u;
+ uint32_t ustatus;
+ bool error = true;
+
+#if FICL_ROBUST > 1
+ vmCheckStack(pVM, 6, 0);
+#endif
+ attr = stackPopINT(pVM->pStack);
+ guids = stackPopINT(pVM->pStack);
+ guidp = (char*)stackPopPtr(pVM->pStack);
+ names = stackPopINT(pVM->pStack);
+ namep = (char*)stackPopPtr(pVM->pStack);
+ values = stackPopINT(pVM->pStack);
+ valuep = (char*)stackPopPtr(pVM->pStack);
+
+ guid = (char*)ficlMalloc(guids);
+ if (guid == NULL)
+ goto out;
+ memcpy(guid, guidp, guids);
+ uuid_from_string(guid, &u, &ustatus);
+ if (ustatus != uuid_s_ok) {
+ stackPushINT(pVM->pStack, -1);
+ goto out;
+ }
+
+ name = ficlMalloc((names + 1) * sizeof(CHAR16));
+ if (name == NULL)
+ goto out;
+ for (i = 0; i < names; i++)
+ name[i] = namep[i];
+ name[names] = 0;
+
+ value = ficlMalloc(values + 1);
+ if (value == NULL)
+ goto out;
+ memcpy(value, valuep, values);
+
+ status = efi_set_variable(name, (EFI_GUID *)&u, attr, values, value);
+ if (status == EFI_SUCCESS)
+ stackPushINT(pVM->pStack, 0);
+ else
+ stackPushINT(pVM->pStack, -1);
+ error = false;
+out:
+ ficlFree(name);
+ ficlFree(value);
+ ficlFree(guid);
+
+ if (error == true)
+ vmThrowErr(pVM, "Error: out of memory");
+}
+
+static void
+ficlEfiGetenv(FICL_VM *pVM)
+{
+ char *name, *value;
+ char *namep;
+ int names;
+
+#if FICL_ROBUST > 1
+ vmCheckStack(pVM, 2, 2);
+#endif
+ names = stackPopINT(pVM->pStack);
+ namep = (char*) stackPopPtr(pVM->pStack);
+
+ name = (char*) ficlMalloc(names+1);
+ if (name == NULL)
+ vmThrowErr(pVM, "Error: out of memory");
+ strncpy(name, namep, names);
+ name[names] = '\0';
+
+ value = getenv(name);
+ ficlFree(name);
+
+ if(value != NULL) {
+ stackPushPtr(pVM->pStack, value);
+ stackPushINT(pVM->pStack, strlen(value));
+ } else
+ stackPushINT(pVM->pStack, -1);
+}
+
+static void
+ficlEfiUnsetenv(FICL_VM *pVM)
+{
+ char *name;
+ char *namep;
+ int names;
+
+#if FICL_ROBUST > 1
+ vmCheckStack(pVM, 2, 0);
+#endif
+ names = stackPopINT(pVM->pStack);
+ namep = (char*) stackPopPtr(pVM->pStack);
+
+ name = (char*) ficlMalloc(names+1);
+ if (name == NULL)
+ vmThrowErr(pVM, "Error: out of memory");
+ strncpy(name, namep, names);
+ name[names] = '\0';
+
+ unsetenv(name);
+ ficlFree(name);
+}
+
+/**************************************************************************
+** Add FreeBSD UEFI platform extensions into the system dictionary
+**************************************************************************/
+void ficlEfiCompilePlatform(FICL_SYSTEM *pSys)
+{
+ FICL_DICT *dp = pSys->dp;
+ assert (dp);
+
+ dictAppendWord(dp, "efi-setenv", ficlEfiSetenv, FW_DEFAULT);
+ dictAppendWord(dp, "efi-getenv", ficlEfiGetenv, FW_DEFAULT);
+ dictAppendWord(dp, "efi-unsetenv", ficlEfiUnsetenv, FW_DEFAULT);
+}
+
+FICL_COMPILE_SET(ficlEfiCompilePlatform);
+
+#endif /* BOOT_FORTH */
diff --git a/stand/efi/libefi/errno.c b/stand/efi/libefi/errno.c
new file mode 100644
index 000000000000..0f354c3f3c8f
--- /dev/null
+++ b/stand/efi/libefi/errno.c
@@ -0,0 +1,157 @@
+/*-
+ * Copyright (c) 2006 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 ``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 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>
+__FBSDID("$FreeBSD$");
+
+#include <efi.h>
+#include <efilib.h>
+
+EFI_STATUS
+errno_to_efi_status(int errno)
+{
+ EFI_STATUS status;
+
+ switch (errno) {
+ case EPERM:
+ status = EFI_ACCESS_DENIED;
+ break;
+
+ case EOVERFLOW:
+ status = EFI_BUFFER_TOO_SMALL;
+ break;
+
+ case EIO:
+ status = EFI_DEVICE_ERROR;
+ break;
+
+ case EINVAL:
+ status = EFI_INVALID_PARAMETER;
+ break;
+
+ case ESTALE:
+ status = EFI_MEDIA_CHANGED;
+ break;
+
+ case ENXIO:
+ status = EFI_NO_MEDIA;
+ break;
+
+ case ENOENT:
+ status = EFI_NOT_FOUND;
+ break;
+
+ case ENOMEM:
+ status = EFI_OUT_OF_RESOURCES;
+ break;
+
+ case ENOTSUP:
+ case ENODEV:
+ status = EFI_UNSUPPORTED;
+ break;
+
+ case ENOSPC:
+ status = EFI_VOLUME_FULL;
+ break;
+
+ case EACCES:
+ status = EFI_WRITE_PROTECTED;
+ break;
+
+ case 0:
+ status = EFI_SUCCESS;
+ break;
+
+ default:
+ status = EFI_DEVICE_ERROR;
+ break;
+ }
+
+ return (status);
+}
+
+int
+efi_status_to_errno(EFI_STATUS status)
+{
+ int errno;
+
+ switch (status) {
+ case EFI_ACCESS_DENIED:
+ errno = EPERM;
+ break;
+
+ case EFI_BUFFER_TOO_SMALL:
+ errno = EOVERFLOW;
+ break;
+
+ case EFI_DEVICE_ERROR:
+ case EFI_VOLUME_CORRUPTED:
+ errno = EIO;
+ break;
+
+ case EFI_INVALID_PARAMETER:
+ errno = EINVAL;
+ break;
+
+ case EFI_MEDIA_CHANGED:
+ errno = ESTALE;
+ break;
+
+ case EFI_NO_MEDIA:
+ errno = ENXIO;
+ break;
+
+ case EFI_NOT_FOUND:
+ errno = ENOENT;
+ break;
+
+ case EFI_OUT_OF_RESOURCES:
+ errno = ENOMEM;
+ break;
+
+ case EFI_UNSUPPORTED:
+ errno = ENODEV;
+ break;
+
+ case EFI_VOLUME_FULL:
+ errno = ENOSPC;
+ break;
+
+ case EFI_WRITE_PROTECTED:
+ errno = EACCES;
+ break;
+
+ case 0:
+ errno = 0;
+ break;
+
+ default:
+ errno = EDOOFUS;
+ break;
+ }
+
+ return (errno);
+}
diff --git a/stand/efi/libefi/handles.c b/stand/efi/libefi/handles.c
new file mode 100644
index 000000000000..1e4ef6ffbd50
--- /dev/null
+++ b/stand/efi/libefi/handles.c
@@ -0,0 +1,118 @@
+/*-
+ * Copyright (c) 2006 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 ``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 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>
+__FBSDID("$FreeBSD$");
+
+#include <efi.h>
+#include <efilib.h>
+
+struct entry {
+ EFI_HANDLE handle;
+ EFI_HANDLE alias;
+ struct devsw *dev;
+ int unit;
+ uint64_t extra;
+};
+
+struct entry *entry;
+int nentries;
+
+int
+efi_register_handles(struct devsw *sw, EFI_HANDLE *handles,
+ EFI_HANDLE *aliases, int count)
+{
+ size_t sz;
+ int idx, unit;
+
+ idx = nentries;
+ nentries += count;
+ sz = nentries * sizeof(struct entry);
+ entry = (entry == NULL) ? malloc(sz) : realloc(entry, sz);
+ for (unit = 0; idx < nentries; idx++, unit++) {
+ entry[idx].handle = handles[unit];
+ if (aliases != NULL)
+ entry[idx].alias = aliases[unit];
+ else
+ entry[idx].alias = NULL;
+ entry[idx].dev = sw;
+ entry[idx].unit = unit;
+ }
+ return (0);
+}
+
+EFI_HANDLE
+efi_find_handle(struct devsw *dev, int unit)
+{
+ int idx;
+
+ for (idx = 0; idx < nentries; idx++) {
+ if (entry[idx].dev != dev)
+ continue;
+ if (entry[idx].unit != unit)
+ continue;
+ return (entry[idx].handle);
+ }
+ return (NULL);
+}
+
+int
+efi_handle_lookup(EFI_HANDLE h, struct devsw **dev, int *unit, uint64_t *extra)
+{
+ int idx;
+
+ for (idx = 0; idx < nentries; idx++) {
+ if (entry[idx].handle != h && entry[idx].alias != h)
+ continue;
+ if (dev != NULL)
+ *dev = entry[idx].dev;
+ if (unit != NULL)
+ *unit = entry[idx].unit;
+ if (extra != NULL)
+ *extra = entry[idx].extra;
+ return (0);
+ }
+ return (ENOENT);
+}
+
+int
+efi_handle_update_dev(EFI_HANDLE h, struct devsw *dev, int unit,
+ uint64_t guid)
+{
+ int idx;
+
+ for (idx = 0; idx < nentries; idx++) {
+ if (entry[idx].handle != h)
+ continue;
+ entry[idx].dev = dev;
+ entry[idx].unit = unit;
+ entry[idx].alias = NULL;
+ entry[idx].extra = guid;
+ return (0);
+ }
+
+ return (ENOENT);
+}
diff --git a/stand/efi/libefi/libefi.c b/stand/efi/libefi/libefi.c
new file mode 100644
index 000000000000..e0a721f58b32
--- /dev/null
+++ b/stand/efi/libefi/libefi.c
@@ -0,0 +1,52 @@
+/*-
+ * Copyright (c) 2000 Doug Rabson
+ * 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>
+__FBSDID("$FreeBSD$");
+
+#include <efi.h>
+#include <eficonsctl.h>
+#include <efilib.h>
+#include <stand.h>
+
+EFI_HANDLE IH;
+EFI_SYSTEM_TABLE *ST;
+EFI_BOOT_SERVICES *BS;
+EFI_RUNTIME_SERVICES *RS;
+
+void *
+efi_get_table(EFI_GUID *tbl)
+{
+ EFI_GUID *id;
+ int i;
+
+ for (i = 0; i < ST->NumberOfTableEntries; i++) {
+ id = &ST->ConfigurationTable[i].VendorGuid;
+ if (!memcmp(id, tbl, sizeof(EFI_GUID)))
+ return (ST->ConfigurationTable[i].VendorTable);
+ }
+ return (NULL);
+}
diff --git a/stand/efi/libefi/time.c b/stand/efi/libefi/time.c
new file mode 100644
index 000000000000..fe0d2ef2702b
--- /dev/null
+++ b/stand/efi/libefi/time.c
@@ -0,0 +1,283 @@
+/*-
+ * Copyright (c) 1999, 2000
+ * Intel Corporation.
+ * 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.
+ *
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ *
+ * This product includes software developed by Intel Corporation and
+ * its contributors.
+ *
+ * 4. Neither the name of Intel Corporation or its contributors may be
+ * used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY INTEL CORPORATION 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 INTEL CORPORATION 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>
+__FBSDID("$FreeBSD$");
+
+#include <efi.h>
+#include <efilib.h>
+
+#include <time.h>
+#include <sys/time.h>
+
+/*
+ * Accurate only for the past couple of centuries;
+ * that will probably do.
+ *
+ * (#defines From FreeBSD 3.2 lib/libc/stdtime/tzfile.h)
+ */
+
+#define isleap(y) (((y) % 4) == 0 && \
+ (((y) % 100) != 0 || ((y) % 400) == 0))
+#define SECSPERHOUR (60*60)
+#define SECSPERDAY (24 * SECSPERHOUR)
+
+/*
+ * These arrays give the cumulative number of days up to the first of the
+ * month number used as the index (1 -> 12) for regular and leap years.
+ * The value at index 13 is for the whole year.
+ */
+static const time_t CumulativeDays[2][14] = {
+ {0,
+ 0,
+ 31,
+ 31 + 28,
+ 31 + 28 + 31,
+ 31 + 28 + 31 + 30,
+ 31 + 28 + 31 + 30 + 31,
+ 31 + 28 + 31 + 30 + 31 + 30,
+ 31 + 28 + 31 + 30 + 31 + 30 + 31,
+ 31 + 28 + 31 + 30 + 31 + 30 + 31 + 31,
+ 31 + 28 + 31 + 30 + 31 + 30 + 31 + 31 + 30,
+ 31 + 28 + 31 + 30 + 31 + 30 + 31 + 31 + 30 + 31,
+ 31 + 28 + 31 + 30 + 31 + 30 + 31 + 31 + 30 + 31 + 30,
+ 31 + 28 + 31 + 30 + 31 + 30 + 31 + 31 + 30 + 31 + 30 + 31 },
+ {0,
+ 0,
+ 31,
+ 31 + 29,
+ 31 + 29 + 31,
+ 31 + 29 + 31 + 30,
+ 31 + 29 + 31 + 30 + 31,
+ 31 + 29 + 31 + 30 + 31 + 30,
+ 31 + 29 + 31 + 30 + 31 + 30 + 31,
+ 31 + 29 + 31 + 30 + 31 + 30 + 31 + 31,
+ 31 + 29 + 31 + 30 + 31 + 30 + 31 + 31 + 30,
+ 31 + 29 + 31 + 30 + 31 + 30 + 31 + 31 + 30 + 31,
+ 31 + 29 + 31 + 30 + 31 + 30 + 31 + 31 + 30 + 31 + 30,
+ 31 + 29 + 31 + 30 + 31 + 30 + 31 + 31 + 30 + 31 + 30 + 31 }};
+
+void
+efi_time_init(void)
+{
+}
+
+void
+efi_time_fini(void)
+{
+}
+
+void
+to_efi_time(EFI_TIME *efi_time, time_t time)
+{
+ int lyear, month;
+ time_t seconds;
+
+ if (time >= 0) {
+ efi_time->Year = 1970;
+ lyear = isleap(efi_time->Year);
+ month = 13;
+ seconds = CumulativeDays[lyear][month] * SECSPERDAY;
+ while (time > seconds) {
+ time -= seconds;
+ efi_time->Year++;
+ lyear = isleap(efi_time->Year);
+ seconds = CumulativeDays[lyear][month] * SECSPERDAY;
+ }
+
+ efi_time->Month = 0;
+ while (time >
+ CumulativeDays[lyear][month] * SECSPERDAY) {
+ efi_time->Month++;
+ }
+
+ month = efi_time->Month - 1;
+ time -= CumulativeDays[lyear][month] * SECSPERDAY;
+
+ for (efi_time->Day = 0; time > SECSPERDAY; efi_time->Day++)
+ time -= SECSPERDAY;
+
+ for (efi_time->Hour = 0; time > SECSPERHOUR; efi_time->Hour++)
+ time -= SECSPERHOUR;
+
+ for (efi_time->Minute = 0; time > 60; efi_time->Minute++)
+ time -= 60;
+
+ efi_time->Second = time;
+ efi_time->Nanosecond = 0;
+ efi_time->TimeZone = 0;
+ efi_time->Daylight = 0;
+ } else {
+ memset(efi_time, 0, sizeof(EFI_TIME));
+ }
+}
+
+time_t
+from_efi_time(EFI_TIME *ETime)
+{
+ time_t UTime;
+ int Year;
+
+ /*
+ * Do a santity check
+ */
+ if (ETime->Year < 1998 || ETime->Year > 2099 ||
+ ETime->Month == 0 || ETime->Month > 12 ||
+ ETime->Day == 0 || ETime->Month > 31 ||
+ ETime->Hour > 23 || ETime->Minute > 59 ||
+ ETime->Second > 59 || ETime->TimeZone < -1440 ||
+ (ETime->TimeZone > 1440 && ETime->TimeZone != 2047)) {
+ return (0);
+ }
+
+ /*
+ * Years
+ */
+ UTime = 0;
+ for (Year = 1970; Year != ETime->Year; ++Year) {
+ UTime += (CumulativeDays[isleap(Year)][13] * SECSPERDAY);
+ }
+
+ /*
+ * UTime should now be set to 00:00:00 on Jan 1 of the file's year.
+ *
+ * Months
+ */
+ UTime += (CumulativeDays[isleap(ETime->Year)][ETime->Month] *
+ SECSPERDAY);
+
+ /*
+ * UTime should now be set to 00:00:00 on the first of the file's
+ * month and year.
+ *
+ * Days -- Don't count the file's day
+ */
+ UTime += (((ETime->Day > 0) ? ETime->Day-1:0) * SECSPERDAY);
+
+ /*
+ * Hours
+ */
+ UTime += (ETime->Hour * SECSPERHOUR);
+
+ /*
+ * Minutes
+ */
+ UTime += (ETime->Minute * 60);
+
+ /*
+ * Seconds
+ */
+ UTime += ETime->Second;
+
+ /*
+ * EFI time is repored in local time. Adjust for any time zone
+ * offset to get true UT
+ */
+ if (ETime->TimeZone != EFI_UNSPECIFIED_TIMEZONE) {
+ /*
+ * TimeZone is kept in minues...
+ */
+ UTime += (ETime->TimeZone * 60);
+ }
+
+ return (UTime);
+}
+
+static int
+EFI_GetTimeOfDay(OUT struct timeval *tp, OUT struct timezone *tzp)
+{
+ EFI_TIME EfiTime;
+ EFI_TIME_CAPABILITIES Capabilities;
+ EFI_STATUS Status;
+
+ /*
+ * Get time from EFI
+ */
+
+ Status = RS->GetTime(&EfiTime, &Capabilities);
+ if (EFI_ERROR(Status))
+ return (-1);
+
+ /*
+ * Convert to UNIX time (ie seconds since the epoch
+ */
+
+ tp->tv_sec = from_efi_time(&EfiTime);
+ tp->tv_usec = 0; /* EfiTime.Nanosecond * 1000; */
+
+ /*
+ * Do something with the timezone if needed
+ */
+
+ if (tzp != NULL) {
+ if (EfiTime.TimeZone == EFI_UNSPECIFIED_TIMEZONE)
+ tzp->tz_minuteswest = 0;
+ else
+ tzp->tz_minuteswest = EfiTime.TimeZone;
+ /*
+ * This isn't quit right since it doesn't deal with
+ * EFI_TIME_IN_DAYLIGHT
+ */
+ tzp->tz_dsttime =
+ EfiTime.Daylight & EFI_TIME_ADJUST_DAYLIGHT ? 1 : 0;
+ }
+
+ return (0);
+}
+
+time_t
+time(time_t *tloc)
+{
+ struct timeval tv;
+
+ memset(&tv, 0, sizeof(tv));
+ EFI_GetTimeOfDay(&tv, NULL);
+
+ if (tloc)
+ *tloc = tv.tv_sec;
+ return (tv.tv_sec);
+}
+
+time_t
+getsecs(void)
+{
+
+ return (time(NULL));
+}
diff --git a/stand/efi/libefi/time_event.c b/stand/efi/libefi/time_event.c
new file mode 100644
index 000000000000..f96f1d845f6a
--- /dev/null
+++ b/stand/efi/libefi/time_event.c
@@ -0,0 +1,82 @@
+/*-
+ * Copyright (c) 2016 Andrew Turner
+ * 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>
+__FBSDID("$FreeBSD$");
+
+#include <efi.h>
+#include <efilib.h>
+
+#include <time.h>
+#include <sys/time.h>
+
+static EFI_EVENT time_event;
+static uint64_t curtime;
+
+static void
+time_update(EFI_EVENT event, void *context)
+{
+
+ curtime += 10;
+}
+
+void
+efi_time_init(void)
+{
+
+ /* Create a timer event */
+ BS->CreateEvent(EVT_TIMER | EVT_NOTIFY_SIGNAL, TPL_CALLBACK,
+ time_update, 0, &time_event);
+ /* Use a 10ms timer */
+ BS->SetTimer(time_event, TimerPeriodic, 100000);
+}
+
+void
+efi_time_fini(void)
+{
+
+ /* Cancel the timer */
+ BS->SetTimer(time_event, TimerCancel, 0);
+ BS->CloseEvent(time_event);
+}
+
+time_t
+time(time_t *tloc)
+{
+ time_t t;
+
+ t = curtime / 1000;
+ if (tloc != NULL)
+ *tloc = t;
+
+ return (t);
+}
+
+time_t
+getsecs(void)
+{
+ return time(0);
+}
diff --git a/stand/efi/libefi/wchar.c b/stand/efi/libefi/wchar.c
new file mode 100644
index 000000000000..d8d81aca4bcc
--- /dev/null
+++ b/stand/efi/libefi/wchar.c
@@ -0,0 +1,73 @@
+/*-
+ * Copyright 2016 Netflix, Inc. 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>
+__FBSDID("$FreeBSD$");
+
+#include <efi.h>
+#include <efilib.h>
+
+/*
+ * CHAR16 related functions moved from loader.
+ * Perhaps we should move those to libstand afterall, but they are
+ * needed only by UEFI.
+ */
+
+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';
+}