svn commit: r294060 - in head/sys/boot/efi: boot1 include loader

Steven Hartland smh at FreeBSD.org
Fri Jan 15 01:22:38 UTC 2016


Author: smh
Date: Fri Jan 15 01:22:36 2016
New Revision: 294060
URL: https://svnweb.freebsd.org/changeset/base/294060

Log:
  Modularise EFI boot loader
  
  Make EFI boot loader modular in preparation for adding ZFS support.
  
  This is a partial commit of the D4515.
  
  Submitted by:	Eric McCorkle
  Reviewed by:	emaste (in part)
  MFC after:	2 weeks
  X-MFC-With:	r293268
  Sponsored by:	Multiplay
  Differential Revision:	https://reviews.freebsd.org/D4515

Added:
  head/sys/boot/efi/boot1/boot_module.h   (contents, props changed)
  head/sys/boot/efi/boot1/ufs_module.c   (contents, props changed)
Modified:
  head/sys/boot/efi/boot1/Makefile
  head/sys/boot/efi/boot1/boot1.c
  head/sys/boot/efi/include/efilib.h
  head/sys/boot/efi/loader/devicename.c
  head/sys/boot/efi/loader/main.c

Modified: head/sys/boot/efi/boot1/Makefile
==============================================================================
--- head/sys/boot/efi/boot1/Makefile	Fri Jan 15 01:06:37 2016	(r294059)
+++ head/sys/boot/efi/boot1/Makefile	Fri Jan 15 01:22:36 2016	(r294060)
@@ -2,7 +2,7 @@
 
 MAN=
 
-.include <bsd.own.mk>
+.include <src.opts.mk>
 
 MK_SSP=		no
 
@@ -11,13 +11,14 @@ INTERNALPROG=
 WARNS?=		6
 
 # architecture-specific loader code
-SRCS=	boot1.c self_reloc.c start.S
+SRCS=	boot1.c self_reloc.c start.S ufs_module.c
 
 CFLAGS+=	-I.
 CFLAGS+=	-I${.CURDIR}/../include
 CFLAGS+=	-I${.CURDIR}/../include/${MACHINE}
 CFLAGS+=	-I${.CURDIR}/../../../contrib/dev/acpica/include
 CFLAGS+=	-I${.CURDIR}/../../..
+CFLAGS+=	-DEFI_UFS_BOOT
 
 # Always add MI sources and REGULAR efi loader bits
 .PATH:		${.CURDIR}/../loader/arch/${MACHINE}

Modified: head/sys/boot/efi/boot1/boot1.c
==============================================================================
--- head/sys/boot/efi/boot1/boot1.c	Fri Jan 15 01:06:37 2016	(r294059)
+++ head/sys/boot/efi/boot1/boot1.c	Fri Jan 15 01:22:36 2016	(r294060)
@@ -5,6 +5,8 @@
  * All rights reserved.
  * Copyright (c) 2014 Nathan Whitehorn
  * All rights reserved.
+ * Copyright (c) 2015 Eric McCorkle
+ * All rights reserved.
  *
  * Redistribution and use in source and binary forms are freely
  * permitted provided that the above copyright notice and this
@@ -21,7 +23,6 @@
 __FBSDID("$FreeBSD$");
 
 #include <sys/param.h>
-#include <sys/dirent.h>
 #include <machine/elf.h>
 #include <machine/stdarg.h>
 #include <stand.h>
@@ -29,19 +30,29 @@ __FBSDID("$FreeBSD$");
 #include <efi.h>
 #include <eficonsctl.h>
 
+#include "boot_module.h"
+
 #define _PATH_LOADER	"/boot/loader.efi"
-#define _PATH_KERNEL	"/boot/kernel/kernel"
 
-#define BSIZEMAX	16384
+static const boot_module_t *boot_modules[] =
+{
+#ifdef EFI_UFS_BOOT
+	&ufs_module
+#endif
+};
+
+#define NUM_BOOT_MODULES (sizeof(boot_modules) / sizeof(boot_module_t*))
+/* The initial number of handles used to query EFI for partitions. */
+#define NUM_HANDLES_INIT	24
 
-void panic(const char *fmt, ...) __dead2;
 void putchar(int c);
 EFI_STATUS efi_main(EFI_HANDLE Ximage, EFI_SYSTEM_TABLE* Xsystab);
 
-static int domount(EFI_DEVICE_PATH *device, EFI_BLOCK_IO *blkio, int quiet);
-static void load(const char *fname);
+static void try_load(const boot_module_t* mod);
+static EFI_STATUS probe_handle(EFI_HANDLE h);
 
-static EFI_SYSTEM_TABLE *systab;
+EFI_SYSTEM_TABLE *systab;
+EFI_BOOT_SERVICES *bs;
 static EFI_HANDLE *image;
 
 static EFI_GUID BlockIoProtocolGUID = BLOCK_IO_PROTOCOL;
@@ -49,27 +60,92 @@ static EFI_GUID DevicePathGUID = DEVICE_
 static EFI_GUID LoadedImageGUID = LOADED_IMAGE_PROTOCOL;
 static EFI_GUID ConsoleControlGUID = EFI_CONSOLE_CONTROL_PROTOCOL_GUID;
 
-static EFI_BLOCK_IO *bootdev;
-static EFI_DEVICE_PATH *bootdevpath;
-static EFI_HANDLE *bootdevhandle;
+/*
+ * Provide Malloc / Free backed by EFIs AllocatePool / FreePool which ensures
+ * memory is correctly aligned avoiding EFI_INVALID_PARAMETER returns from
+ * EFI methods.
+ */
+void *
+Malloc(size_t len, const char *file __unused, int line __unused)
+{
+	void *out;
+
+	if (bs->AllocatePool(EfiLoaderData, len, &out) == EFI_SUCCESS)
+		return (out);
+
+	return (NULL);
+}
+
+void
+Free(void *buf, const char *file __unused, int line __unused)
+{
+	(void)bs->FreePool(buf);
+}
 
-EFI_STATUS efi_main(EFI_HANDLE Ximage, EFI_SYSTEM_TABLE* Xsystab)
+/*
+ * This function only returns if it fails to load the kernel. If it
+ * succeeds, it simply boots the kernel.
+ */
+void
+try_load(const boot_module_t *mod)
 {
-	EFI_HANDLE handles[128];
-	EFI_BLOCK_IO *blkio;
-	UINTN i, nparts = sizeof(handles), cols, rows, max_dim, best_mode;
+	size_t bufsize;
+	void *buf;
+	dev_info_t *dev;
+	EFI_HANDLE loaderhandle;
+	EFI_LOADED_IMAGE *loaded_image;
+	EFI_STATUS status;
+
+	status = mod->load(_PATH_LOADER, &dev, &buf, &bufsize);
+	if (status == EFI_NOT_FOUND)
+		return;
+
+	if (status != EFI_SUCCESS) {
+		printf("%s failed to load %s (%lu)\n", mod->name, _PATH_LOADER,
+		    EFI_ERROR_CODE(status));
+		return;
+	}
+
+	if ((status = bs->LoadImage(TRUE, image, dev->devpath, buf, bufsize,
+	    &loaderhandle)) != EFI_SUCCESS) {
+		printf("Failed to load image provided by %s, size: %zu, (%lu)\n",
+		     mod->name, bufsize, EFI_ERROR_CODE(status));
+		return;
+	}
+
+	if ((status = bs->HandleProtocol(loaderhandle, &LoadedImageGUID,
+	    (VOID**)&loaded_image)) != EFI_SUCCESS) {
+		printf("Failed to query LoadedImage provided by %s (%lu)\n",
+		    mod->name, EFI_ERROR_CODE(status));
+		return;
+	}
+
+	loaded_image->DeviceHandle = dev->devhandle;
+
+	if ((status = bs->StartImage(loaderhandle, NULL, NULL)) !=
+	    EFI_SUCCESS) {
+		printf("Failed start image provided by %s (%lu)\n", mod->name,
+		    EFI_ERROR_CODE(status));
+		return;
+	}
+}
+
+EFI_STATUS
+efi_main(EFI_HANDLE Ximage, EFI_SYSTEM_TABLE *Xsystab)
+{
+	EFI_HANDLE *handles;
 	EFI_STATUS status;
-	EFI_DEVICE_PATH *devpath;
-	EFI_BOOT_SERVICES *BS;
 	EFI_CONSOLE_CONTROL_PROTOCOL *ConsoleControl = NULL;
 	SIMPLE_TEXT_OUTPUT_INTERFACE *conout = NULL;
-	const char *path = _PATH_LOADER;
+	UINTN i, max_dim, best_mode, cols, rows, hsize, nhandles;
 
+	/* Basic initialization*/
 	systab = Xsystab;
 	image = Ximage;
+	bs = Xsystab->BootServices;
 
-	BS = systab->BootServices;
-	status = BS->LocateProtocol(&ConsoleControlGUID, NULL,
+	/* Set up the console, so printf works. */
+	status = bs->LocateProtocol(&ConsoleControlGUID, NULL,
 	    (VOID **)&ConsoleControl);
 	if (status == EFI_SUCCESS)
 		(void)ConsoleControl->SetMode(ConsoleControl,
@@ -94,200 +170,162 @@ EFI_STATUS efi_main(EFI_HANDLE Ximage, E
 	conout->EnableCursor(conout, TRUE);
 	conout->ClearScreen(conout);
 
-	printf("\n"
-	       ">> FreeBSD EFI boot block\n");
-	printf("   Loader path: %s\n", path);
-
-	status = systab->BootServices->LocateHandle(ByProtocol,
-	    &BlockIoProtocolGUID, NULL, &nparts, handles);
-	nparts /= sizeof(handles[0]);
-
-	for (i = 0; i < nparts; i++) {
-		status = systab->BootServices->HandleProtocol(handles[i],
-		    &DevicePathGUID, (void **)&devpath);
-		if (EFI_ERROR(status))
+	printf("\n>> FreeBSD EFI boot block\n");
+	printf("   Loader path: %s\n\n", _PATH_LOADER);
+	printf("   Initializing modules:");
+	for (i = 0; i < NUM_BOOT_MODULES; i++) {
+		if (boot_modules[i] == NULL)
 			continue;
 
-		while (!IsDevicePathEnd(NextDevicePathNode(devpath)))
-			devpath = NextDevicePathNode(devpath);
+		printf(" %s", boot_modules[i]->name);
+		if (boot_modules[i]->init != NULL)
+			boot_modules[i]->init();
+	}
+	putchar('\n');
 
-		status = systab->BootServices->HandleProtocol(handles[i],
-		    &BlockIoProtocolGUID, (void **)&blkio);
-		if (EFI_ERROR(status))
-			continue;
+	/* Get all the device handles */
+	hsize = (UINTN)NUM_HANDLES_INIT * sizeof(EFI_HANDLE);
+	if ((status = bs->AllocatePool(EfiLoaderData, hsize, (void **)&handles))
+	    != EFI_SUCCESS)
+		panic("Failed to allocate %d handles (%lu)", NUM_HANDLES_INIT,
+		    EFI_ERROR_CODE(status));
 
-		if (!blkio->Media->LogicalPartition)
-			continue;
+	status = bs->LocateHandle(ByProtocol, &BlockIoProtocolGUID, NULL,
+	    &hsize, handles);
+	switch (status) {
+	case EFI_SUCCESS:
+		break;
+	case EFI_BUFFER_TOO_SMALL:
+		(void)bs->FreePool(handles);
+		if ((status = bs->AllocatePool(EfiLoaderData, hsize,
+		    (void **)&handles) != EFI_SUCCESS)) {
+			panic("Failed to allocate %zu handles (%lu)", hsize /
+			    sizeof(*handles), EFI_ERROR_CODE(status));
+		}
+		status = bs->LocateHandle(ByProtocol, &BlockIoProtocolGUID,
+		    NULL, &hsize, handles);
+		if (status != EFI_SUCCESS)
+			panic("Failed to get device handles (%lu)\n",
+			    EFI_ERROR_CODE(status));
+		break;
+	default:
+		panic("Failed to get device handles (%lu)",
+		    EFI_ERROR_CODE(status));
+	}
 
-		if (domount(devpath, blkio, 1) >= 0)
+	/* Scan all partitions, probing with all modules. */
+	nhandles = hsize / sizeof(*handles);
+	printf("   Probing %zu block devices...", nhandles);
+	for (i = 0; i < nhandles; i++) {
+		status = probe_handle(handles[i]);
+		switch (status) {
+		case EFI_UNSUPPORTED:
+			printf(".");
+			break;
+		case EFI_SUCCESS:
+			printf("+");
+			break;
+		default:
+			printf("x");
 			break;
+		}
 	}
+	printf(" done\n");
 
-	if (i == nparts)
-		panic("No bootable partition found");
-
-	bootdevhandle = handles[i];
-	load(path);
+	/* Status summary. */
+	for (i = 0; i < NUM_BOOT_MODULES; i++) {
+		if (boot_modules[i] != NULL) {
+			printf("    ");
+			boot_modules[i]->status();
+		}
+	}
 
-	panic("Load failed");
+	/* Select a partition to boot by trying each module in order. */
+	for (i = 0; i < NUM_BOOT_MODULES; i++)
+		if (boot_modules[i] != NULL)
+			try_load(boot_modules[i]);
 
-	return EFI_SUCCESS;
+	/* If we get here, we're out of luck... */
+	panic("No bootable partitions found!");
 }
 
-static int
-dskread(void *buf, u_int64_t lba, int nblk)
+static EFI_STATUS
+probe_handle(EFI_HANDLE h)
 {
+	dev_info_t *devinfo;
+	EFI_BLOCK_IO *blkio;
+	EFI_DEVICE_PATH *devpath;
 	EFI_STATUS status;
-	int size;
+	UINTN i;
 
-	lba = lba / (bootdev->Media->BlockSize / DEV_BSIZE);
-	size = nblk * DEV_BSIZE;
-	status = bootdev->ReadBlocks(bootdev, bootdev->Media->MediaId, lba,
-	    size, buf);
+	/* Figure out if we're dealing with an actual partition. */
+	status = bs->HandleProtocol(h, &DevicePathGUID, (void **)&devpath);
+	if (status == EFI_UNSUPPORTED)
+		return (status);
 
-	if (EFI_ERROR(status))
-		return (-1);
+	if (status != EFI_SUCCESS) {
+		DPRINTF("\nFailed to query DevicePath (%lu)\n",
+		    EFI_ERROR_CODE(status));
+		return (status);
+	}
 
-	return (0);
-}
+	while (!IsDevicePathEnd(NextDevicePathNode(devpath)))
+		devpath = NextDevicePathNode(devpath);
 
-#include "ufsread.c"
+	status = bs->HandleProtocol(h, &BlockIoProtocolGUID, (void **)&blkio);
+	if (status == EFI_UNSUPPORTED)
+		return (status);
 
-static ssize_t
-fsstat(ufs_ino_t inode)
-{
-#ifndef UFS2_ONLY
-	static struct ufs1_dinode dp1;
-#endif
-#ifndef UFS1_ONLY
-	static struct ufs2_dinode dp2;
-#endif
-	static struct fs fs;
-	static ufs_ino_t inomap;
-	char *blkbuf;
-	void *indbuf;
-	size_t n, size;
-	static ufs2_daddr_t blkmap, indmap;
-
-	blkbuf = dmadat->blkbuf;
-	indbuf = dmadat->indbuf;
-	if (!dsk_meta) {
-		inomap = 0;
-		for (n = 0; sblock_try[n] != -1; n++) {
-			if (dskread(dmadat->sbbuf, sblock_try[n] / DEV_BSIZE,
-			    SBLOCKSIZE / DEV_BSIZE))
-				return -1;
-			memcpy(&fs, dmadat->sbbuf, sizeof(struct fs));
-			if ((
-#if defined(UFS1_ONLY)
-			    fs.fs_magic == FS_UFS1_MAGIC
-#elif defined(UFS2_ONLY)
-			    (fs.fs_magic == FS_UFS2_MAGIC &&
-			    fs.fs_sblockloc == sblock_try[n])
-#else
-			    fs.fs_magic == FS_UFS1_MAGIC ||
-			    (fs.fs_magic == FS_UFS2_MAGIC &&
-			    fs.fs_sblockloc == sblock_try[n])
-#endif
-			    ) &&
-			    fs.fs_bsize <= MAXBSIZE &&
-			    fs.fs_bsize >= (int32_t)sizeof(struct fs))
-				break;
-		}
-		if (sblock_try[n] == -1) {
-			return -1;
-		}
-		dsk_meta++;
-	} else
-		memcpy(&fs, dmadat->sbbuf, sizeof(struct fs));
-	if (!inode)
-		return 0;
-	if (inomap != inode) {
-		n = IPERVBLK(&fs);
-		if (dskread(blkbuf, INO_TO_VBA(&fs, n, inode), DBPERVBLK))
-			return -1;
-		n = INO_TO_VBO(n, inode);
-#if defined(UFS1_ONLY)
-		memcpy(&dp1, (struct ufs1_dinode *)blkbuf + n,
-		    sizeof(struct ufs1_dinode));
-#elif defined(UFS2_ONLY)
-		memcpy(&dp2, (struct ufs2_dinode *)blkbuf + n,
-		    sizeof(struct ufs2_dinode));
-#else
-		if (fs.fs_magic == FS_UFS1_MAGIC)
-			memcpy(&dp1, (struct ufs1_dinode *)(void *)blkbuf + n,
-			    sizeof(struct ufs1_dinode));
-		else
-			memcpy(&dp2, (struct ufs2_dinode *)(void *)blkbuf + n,
-			    sizeof(struct ufs2_dinode));
-#endif
-		inomap = inode;
-		fs_off = 0;
-		blkmap = indmap = 0;
-	}
-	size = DIP(di_size);
-	n = size - fs_off;
-	return (n);
-}
+	if (status != EFI_SUCCESS) {
+		DPRINTF("\nFailed to query BlockIoProtocol (%lu)\n",
+		    EFI_ERROR_CODE(status));
+		return (status);
+	}
 
-static struct dmadat __dmadat;
+	if (!blkio->Media->LogicalPartition)
+		return (EFI_UNSUPPORTED);
 
-static int
-domount(EFI_DEVICE_PATH *device, EFI_BLOCK_IO *blkio, int quiet)
-{
+	/* Run through each module, see if it can load this partition */
+	for (i = 0; i < NUM_BOOT_MODULES; i++) {
+		if (boot_modules[i] == NULL)
+			continue;
+
+		if ((status = bs->AllocatePool(EfiLoaderData,
+		    sizeof(*devinfo), (void **)&devinfo)) !=
+		    EFI_SUCCESS) {
+			DPRINTF("\nFailed to allocate devinfo (%lu)\n",
+			    EFI_ERROR_CODE(status));
+			continue;
+		}
+		devinfo->dev = blkio;
+		devinfo->devpath = devpath;
+		devinfo->devhandle = h;
+		devinfo->devdata = NULL;
+		devinfo->next = NULL;
+
+		status = boot_modules[i]->probe(devinfo);
+		if (status == EFI_SUCCESS)
+			return (EFI_SUCCESS);
+		(void)bs->FreePool(devinfo);
+	}
 
-	dmadat = &__dmadat;
-	bootdev = blkio;
-	bootdevpath = device;
-	if (fsread(0, NULL, 0)) {
-		if (!quiet)
-			printf("domount: can't read superblock\n");
-		return (-1);
-	}
-	if (!quiet)
-		printf("Succesfully mounted UFS filesystem\n");
-	return (0);
+	return (EFI_UNSUPPORTED);
 }
 
-static void
-load(const char *fname)
+void
+add_device(dev_info_t **devinfop, dev_info_t *devinfo)
 {
-	ufs_ino_t ino;
-	EFI_STATUS status;
-	EFI_HANDLE loaderhandle;
-	EFI_LOADED_IMAGE *loaded_image;
-	void *buffer;
-	size_t bufsize;
+	dev_info_t *dev;
 
-	if ((ino = lookup(fname)) == 0) {
-		printf("File %s not found\n", fname);
+	if (*devinfop == NULL) {
+		*devinfop = devinfo;
 		return;
 	}
 
-	bufsize = fsstat(ino);
-	status = systab->BootServices->AllocatePool(EfiLoaderData,
-	    bufsize, &buffer);
-	fsread(ino, buffer, bufsize);
-
-	/* XXX: For secure boot, we need our own loader here */
-	status = systab->BootServices->LoadImage(TRUE, image, bootdevpath,
-	    buffer, bufsize, &loaderhandle);
-	if (EFI_ERROR(status))
-		printf("LoadImage failed with error %lu\n",
-		    EFI_ERROR_CODE(status));
-
-	status = systab->BootServices->HandleProtocol(loaderhandle,
-	    &LoadedImageGUID, (VOID**)&loaded_image);
-	if (EFI_ERROR(status))
-		printf("HandleProtocol failed with error %lu\n",
-		    EFI_ERROR_CODE(status));
+	for (dev = *devinfop; dev->next != NULL; dev = dev->next)
+		;
 
-	loaded_image->DeviceHandle = bootdevhandle;
-
-	status = systab->BootServices->StartImage(loaderhandle, NULL, NULL);
-	if (EFI_ERROR(status))
-		printf("StartImage failed with error %lu\n",
-		    EFI_ERROR_CODE(status));
+	dev->next = devinfo;
 }
 
 void

Added: head/sys/boot/efi/boot1/boot_module.h
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ head/sys/boot/efi/boot1/boot_module.h	Fri Jan 15 01:22:36 2016	(r294060)
@@ -0,0 +1,110 @@
+/*-
+ * Copyright (c) 2015 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$
+ */
+
+#ifndef _BOOT_MODULE_H_
+#define _BOOT_MODULE_H_
+
+#include <stdbool.h>
+
+#include <efi.h>
+#include <efilib.h>
+#include <eficonsctl.h>
+
+#ifdef EFI_DEBUG
+#define DPRINTF(fmt, args...) \
+        do { \
+                printf(fmt, ##args) \
+        } while (0)
+#else
+#define DPRINTF(fmt, args...) {}
+#endif
+
+/* EFI device info */
+typedef struct dev_info
+{
+	EFI_BLOCK_IO *dev;
+	EFI_DEVICE_PATH *devpath;
+	EFI_HANDLE *devhandle;
+	void *devdata;
+	struct dev_info *next;
+} dev_info_t;
+
+/*
+ * A boot loader module.
+ *
+ * This is a standard interface for filesystem modules in the EFI system.
+ */
+typedef struct boot_module_t
+{
+	const char *name;
+
+	/* init is the optional initialiser for the module. */
+	void (*init)();
+
+	/*
+	 * probe checks to see if the module can handle dev.
+	 *
+	 * Return codes:
+	 * EFI_SUCCESS = The module can handle the device.
+	 * EFI_NOT_FOUND = The module can not handle the device.
+	 * Other = The module encountered an error.
+	 */
+	EFI_STATUS (*probe)(dev_info_t* dev);
+
+	/*
+	 * load should select the best out of a set of devices that probe
+	 * indicated were loadable and load it.
+	 *
+	 * Return codes:
+	 * EFI_SUCCESS = The module can handle the device.
+	 * EFI_NOT_FOUND = The module can not handle the device.
+	 * Other = The module encountered an error.
+	 */
+	EFI_STATUS (*load)(const char *loader_path, dev_info_t **devinfo,
+	    void **buf, size_t *bufsize);
+
+	/* status outputs information about the probed devices. */
+	void (*status)();
+
+} boot_module_t;
+
+/* Standard boot modules. */
+#ifdef EFI_UFS_BOOT
+extern const boot_module_t ufs_module;
+#endif
+
+/* Functions available to modules. */
+extern void add_device(dev_info_t **devinfop, dev_info_t *devinfo);
+extern void panic(const char *fmt, ...) __dead2;
+extern int printf(const char *fmt, ...);
+extern int vsnprintf(char *str, size_t sz, const char *fmt, va_list ap);
+
+extern EFI_SYSTEM_TABLE *systab;
+extern EFI_BOOT_SERVICES *bs;
+
+#endif

Added: head/sys/boot/efi/boot1/ufs_module.c
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ head/sys/boot/efi/boot1/ufs_module.c	Fri Jan 15 01:22:36 2016	(r294060)
@@ -0,0 +1,253 @@
+/*-
+ * Copyright (c) 1998 Robert Nordier
+ * All rights reserved.
+ * Copyright (c) 2001 Robert Drehmel
+ * All rights reserved.
+ * Copyright (c) 2014 Nathan Whitehorn
+ * All rights reserved.
+ * Copyright (c) 2015 Eric McCorkle
+ * All rights reverved.
+ *
+ * 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 <stdarg.h>
+#include <stdbool.h>
+#include <sys/cdefs.h>
+#include <sys/param.h>
+#include <efi.h>
+
+#include "boot_module.h"
+
+static dev_info_t *devinfo;
+static dev_info_t *devices;
+
+static int
+dskread(void *buf, u_int64_t lba, int nblk)
+{
+	int size;
+	EFI_STATUS status;
+
+	lba = lba / (devinfo->dev->Media->BlockSize / DEV_BSIZE);
+	size = nblk * DEV_BSIZE;
+
+	status = devinfo->dev->ReadBlocks(devinfo->dev,
+	    devinfo->dev->Media->MediaId, lba, size, buf);
+
+	if (status != EFI_SUCCESS) {
+		DPRINTF("dskread: failed dev: %p, id: %u, lba: %lu, size: %d, "
+		    "status: %lu\n", devinfo->dev,
+		    devinfo->dev->Media->MediaId, lba, size,
+		    EFI_ERROR_CODE(status));
+		return (-1);
+	}
+
+	return (0);
+}
+
+#include "ufsread.c"
+
+static ssize_t
+fsstat(ufs_ino_t inode)
+{
+#ifndef UFS2_ONLY
+	static struct ufs1_dinode dp1;
+#endif
+#ifndef UFS1_ONLY
+	static struct ufs2_dinode dp2;
+#endif
+	static struct fs fs;
+	static ufs_ino_t inomap;
+	char *blkbuf;
+	void *indbuf;
+	size_t n, size;
+	static ufs2_daddr_t blkmap, indmap;
+
+	blkbuf = dmadat->blkbuf;
+	indbuf = dmadat->indbuf;
+	if (!dsk_meta) {
+		inomap = 0;
+		for (n = 0; sblock_try[n] != -1; n++) {
+			if (dskread(dmadat->sbbuf, sblock_try[n] / DEV_BSIZE,
+			    SBLOCKSIZE / DEV_BSIZE))
+				return (-1);
+			memcpy(&fs, dmadat->sbbuf, sizeof(struct fs));
+			if ((
+#if defined(UFS1_ONLY)
+			    fs.fs_magic == FS_UFS1_MAGIC
+#elif defined(UFS2_ONLY)
+			    (fs.fs_magic == FS_UFS2_MAGIC &&
+			    fs.fs_sblockloc == sblock_try[n])
+#else
+			    fs.fs_magic == FS_UFS1_MAGIC ||
+			    (fs.fs_magic == FS_UFS2_MAGIC &&
+			    fs.fs_sblockloc == sblock_try[n])
+#endif
+			    ) &&
+			    fs.fs_bsize <= MAXBSIZE &&
+			    fs.fs_bsize >= (int32_t)sizeof(struct fs))
+				break;
+		}
+		if (sblock_try[n] == -1) {
+			return (-1);
+		}
+		dsk_meta++;
+	} else
+		memcpy(&fs, dmadat->sbbuf, sizeof(struct fs));
+	if (!inode)
+		return (0);
+	if (inomap != inode) {
+		n = IPERVBLK(&fs);
+		if (dskread(blkbuf, INO_TO_VBA(&fs, n, inode), DBPERVBLK))
+			return (-1);
+		n = INO_TO_VBO(n, inode);
+#if defined(UFS1_ONLY)
+		memcpy(&dp1, (struct ufs1_dinode *)blkbuf + n,
+		    sizeof(struct ufs1_dinode));
+#elif defined(UFS2_ONLY)
+		memcpy(&dp2, (struct ufs2_dinode *)blkbuf + n,
+		    sizeof(struct ufs2_dinode));
+#else
+		if (fs.fs_magic == FS_UFS1_MAGIC)
+			memcpy(&dp1, (struct ufs1_dinode *)(void *)blkbuf + n,
+			    sizeof(struct ufs1_dinode));
+		else
+			memcpy(&dp2, (struct ufs2_dinode *)(void *)blkbuf + n,
+			    sizeof(struct ufs2_dinode));
+#endif
+		inomap = inode;
+		fs_off = 0;
+		blkmap = indmap = 0;
+	}
+	size = DIP(di_size);
+	n = size - fs_off;
+
+	return (n);
+}
+
+static struct dmadat __dmadat;
+
+static EFI_STATUS
+probe(dev_info_t* dev)
+{
+
+	devinfo = dev;
+	dmadat = &__dmadat;
+	if (fsread(0, NULL, 0) < 0)
+		return (EFI_UNSUPPORTED);
+
+	add_device(&devices, dev);
+
+	return (EFI_SUCCESS);
+}
+
+static EFI_STATUS
+try_load(dev_info_t *dev, const char *loader_path, void **bufp, size_t *bufsize)
+{
+	ufs_ino_t ino;
+	EFI_STATUS status;
+	size_t size;
+	ssize_t read;
+	void *buf;
+
+	devinfo = dev;
+	if ((ino = lookup(loader_path)) == 0)
+		return (EFI_NOT_FOUND);
+
+	size = fsstat(ino);
+	if (size <= 0) {
+		printf("Failed to fsstat %s ino: %d\n", loader_path, ino);
+		return (EFI_INVALID_PARAMETER);
+	}
+
+	if ((status = bs->AllocatePool(EfiLoaderData, size, &buf)) !=
+	    EFI_SUCCESS) {
+		printf("Failed to allocate read buffer (%lu)\n",
+		    EFI_ERROR_CODE(status));
+		return (status);
+	}
+
+	read = fsread(ino, buf, size);
+	if ((size_t)read != size) {
+		printf("Failed to read %s (%zd != %zu)\n", loader_path, read,
+		    size);
+		(void)bs->FreePool(buf);
+		return (EFI_INVALID_PARAMETER);
+	}
+
+	*bufp = buf;
+	*bufsize = size;
+
+	return (EFI_SUCCESS);
+}
+
+static EFI_STATUS
+load(const char *loader_path, dev_info_t **devinfop, void **buf,
+    size_t *bufsize)
+{
+	dev_info_t *dev;
+	EFI_STATUS status;
+
+	for (dev = devices; dev != NULL; dev = dev->next) {
+		status = try_load(dev, loader_path, buf, bufsize);
+		if (status == EFI_SUCCESS) {
+			*devinfop = dev;
+			return (EFI_SUCCESS);
+		} else if (status != EFI_NOT_FOUND) {
+			return (status);
+		}
+	}
+
+	return (EFI_NOT_FOUND);
+}
+
+static void
+status()
+{
+	int i;
+	dev_info_t *dev;
+
+	for (dev = devices, i = 0; dev != NULL; dev = dev->next, i++)
+		;
+
+	printf("%s found ", ufs_module.name);
+	switch (i) {
+	case 0:
+		printf("no partitions\n");
+		break;
+	case 1:
+		printf("%d partition\n", i);
+		break;
+	default:
+		printf("%d partitions\n", i);
+	}
+}
+
+const boot_module_t ufs_module =
+{
+	.name = "UFS",
+	.probe = probe,
+	.load = load,
+	.status = status
+};

Modified: head/sys/boot/efi/include/efilib.h
==============================================================================
--- head/sys/boot/efi/include/efilib.h	Fri Jan 15 01:06:37 2016	(r294059)
+++ head/sys/boot/efi/include/efilib.h	Fri Jan 15 01:22:36 2016	(r294060)
@@ -39,7 +39,6 @@ extern struct devsw efinet_dev;
 extern struct netif_driver efinetif;
 
 void *efi_get_table(EFI_GUID *tbl);
-void efi_main(EFI_HANDLE image_handle, EFI_SYSTEM_TABLE *system_table);
 
 int efi_register_handles(struct devsw *, EFI_HANDLE *, EFI_HANDLE *, int);
 EFI_HANDLE efi_find_handle(struct devsw *, int);

Modified: head/sys/boot/efi/loader/devicename.c
==============================================================================
--- head/sys/boot/efi/loader/devicename.c	Fri Jan 15 01:06:37 2016	(r294059)
+++ head/sys/boot/efi/loader/devicename.c	Fri Jan 15 01:22:36 2016	(r294060)
@@ -31,6 +31,7 @@ __FBSDID("$FreeBSD$");
 #include <stand.h>
 #include <string.h>
 #include <sys/disklabel.h>
+#include <sys/param.h>
 #include <bootstrap.h>
 
 #include <efi.h>
@@ -86,7 +87,7 @@ efi_parsedev(struct devdesc **dev, const
 	struct devsw *dv;
 	char *cp;
 	const char *np;
-	int i, err;
+	int i;
 
 	/* minimum length check */
 	if (strlen(devspec) < 2)
@@ -101,24 +102,26 @@ efi_parsedev(struct devdesc **dev, const
 	if (devsw[i] == NULL)
 		return (ENOENT);
 
-	idev = malloc(sizeof(struct devdesc));
-	if (idev == NULL)
-		return (ENOMEM);
-
-	idev->d_dev = dv;
-	idev->d_type = dv->dv_type;
-	idev->d_unit = -1;
-
-	err = 0;
 	np = devspec + strlen(dv->dv_name);
-	if (*np != '\0' && *np != ':') {
-		idev->d_unit = strtol(np, &cp, 0);
-		if (cp == np) {
-			idev->d_unit = -1;
-			free(idev);
-			return (EUNIT);
+
+	{
+		idev = malloc(sizeof(struct devdesc));
+		if (idev == NULL)
+			return (ENOMEM);
+
+		idev->d_dev = dv;
+		idev->d_type = dv->dv_type;
+		idev->d_unit = -1;
+		if (*np != '\0' && *np != ':') {
+			idev->d_unit = strtol(np, &cp, 0);
+			if (cp == np) {
+				idev->d_unit = -1;
+				free(idev);
+				return (EUNIT);
+			}
 		}
 	}
+
 	if (*cp != '\0' && *cp != ':') {
 		free(idev);
 		return (EINVAL);
@@ -137,7 +140,7 @@ char *
 efi_fmtdev(void *vdev)
 {
 	struct devdesc *dev = (struct devdesc *)vdev;
-	static char buf[32];	/* XXX device length constant? */
+	static char buf[SPECNAMELEN + 1];
 
 	switch(dev->d_type) {
 	case DEVT_NONE:

Modified: head/sys/boot/efi/loader/main.c
==============================================================================
--- head/sys/boot/efi/loader/main.c	Fri Jan 15 01:06:37 2016	(r294059)
+++ head/sys/boot/efi/loader/main.c	Fri Jan 15 01:22:36 2016	(r294060)
@@ -28,6 +28,7 @@
 #include <sys/cdefs.h>
 __FBSDID("$FreeBSD$");
 
+#include <sys/param.h>
 #include <stand.h>
 #include <string.h>
 #include <setjmp.h>
@@ -45,7 +46,6 @@ extern char bootprog_rev[];
 extern char bootprog_date[];
 extern char bootprog_maker[];
 
-struct devdesc currdev;		/* our current device */
 struct arch_switch archsw;	/* MI/MD interface boundary */
 
 EFI_GUID acpi = ACPI_TABLE_GUID;
@@ -61,15 +61,36 @@ EFI_GUID memtype = MEMORY_TYPE_INFORMATI
 EFI_GUID debugimg = DEBUG_IMAGE_INFO_TABLE_GUID;
 EFI_GUID fdtdtb = FDT_TABLE_GUID;
 
+/*
+ * Need this because EFI uses UTF-16 unicode string constants, but we
+ * use UTF-8. We can't use printf due to the possiblity of \0 and we
+ * don't support support wide characters either.
+ */
+static void
+print_str16(const CHAR16 *str)
+{
+	int i;
+
+	for (i = 0; str[i]; i++)
+		printf("%c", (char)str[i]);
+}
+
 EFI_STATUS

*** DIFF OUTPUT TRUNCATED AT 1000 LINES ***


More information about the svn-src-all mailing list