svn commit: r348811 - head/stand/efi/boot1

Warner Losh imp at FreeBSD.org
Sat Jun 8 18:59:52 UTC 2019


Author: imp
Date: Sat Jun  8 18:59:50 2019
New Revision: 348811
URL: https://svnweb.freebsd.org/changeset/base/348811

Log:
  Break out the disk selection protocol from the rest of boot1.
  
  Segregate the disk probing and selection protocol from the rest of the
  boot loader.
  
  Reviewed by: tsoome, bcran
  Differential Revision: https://reviews.freebsd.org/D20547

Added:
  head/stand/efi/boot1/proto.c   (contents, props changed)
  head/stand/efi/boot1/proto.h   (contents, props changed)
Modified:
  head/stand/efi/boot1/Makefile
  head/stand/efi/boot1/boot1.c
  head/stand/efi/boot1/boot_module.h

Modified: head/stand/efi/boot1/Makefile
==============================================================================
--- head/stand/efi/boot1/Makefile	Sat Jun  8 18:26:48 2019	(r348810)
+++ head/stand/efi/boot1/Makefile	Sat Jun  8 18:59:50 2019	(r348811)
@@ -5,7 +5,7 @@
 BOOT1?=		boot1
 PROG=		${BOOT1}.sym
 INTERNALPROG=
-WARNS?=		6
+WARNS=		6
 
 CFLAGS+=	-DEFI_BOOT1
 # We implement a slightly non-standard %S in that it always takes a
@@ -28,7 +28,7 @@ CWARNFLAGS.zfs_module.c += -Wno-unused-parameter
 CWARNFLAGS.zfs_module.c += -Wno-unused-function
 
 # architecture-specific loader code
-SRCS+=	boot1.c self_reloc.c start.S ufs_module.c devpath.c
+SRCS+=	boot1.c proto.c self_reloc.c start.S ufs_module.c devpath.c
 .if ${MK_LOADER_ZFS} != "no"
 SRCS+=		zfs_module.c
 CFLAGS.zfs_module.c+=	-I${ZFSSRC}

Modified: head/stand/efi/boot1/boot1.c
==============================================================================
--- head/stand/efi/boot1/boot1.c	Sat Jun  8 18:26:48 2019	(r348810)
+++ head/stand/efi/boot1/boot1.c	Sat Jun  8 18:59:50 2019	(r348811)
@@ -33,10 +33,11 @@ __FBSDID("$FreeBSD$");
 
 #include "boot_module.h"
 #include "paths.h"
+#include "proto.h"
 
 static void efi_panic(EFI_STATUS s, const char *fmt, ...) __dead2 __printflike(2, 3);
 
-static const boot_module_t *boot_modules[] =
+const boot_module_t *boot_modules[] =
 {
 #ifdef EFI_ZFS_BOOT
 	&zfs_module,
@@ -45,9 +46,8 @@ static const boot_module_t *boot_modules[] =
 	&ufs_module
 #endif
 };
+const UINTN num_boot_modules = nitems(boot_modules);
 
-#define	NUM_BOOT_MODULES	nitems(boot_modules)
-
 static EFI_GUID BlockIoProtocolGUID = BLOCK_IO_PROTOCOL;
 static EFI_GUID DevicePathGUID = DEVICE_PATH_PROTOCOL;
 static EFI_GUID LoadedImageGUID = LOADED_IMAGE_PROTOCOL;
@@ -91,65 +91,19 @@ Calloc(size_t n1, size_t n2, const char *file, int lin
 }
 
 /*
- * load_loader attempts to load the loader image data.
- *
- * It tries each module and its respective devices, identified by mod->probe,
- * in order until a successful load occurs at which point it returns EFI_SUCCESS
- * and EFI_NOT_FOUND otherwise.
- *
- * Only devices which have preferred matching the preferred parameter are tried.
- */
-static EFI_STATUS
-load_loader(const boot_module_t **modp, dev_info_t **devinfop, void **bufp,
-    size_t *bufsize, int preferred)
-{
-	UINTN i;
-	dev_info_t *dev;
-	const boot_module_t *mod;
-
-	for (i = 0; i < NUM_BOOT_MODULES; i++) {
-		mod = boot_modules[i];
-		for (dev = mod->devices(); dev != NULL; dev = dev->next) {
-			if (dev->preferred != preferred)
-				continue;
-
-			if (mod->load(PATH_LOADER_EFI, dev, bufp, bufsize) ==
-			    EFI_SUCCESS) {
-				*devinfop = dev;
-				*modp = mod;
-				return (EFI_SUCCESS);
-			}
-		}
-	}
-
-	return (EFI_NOT_FOUND);
-}
-
-/*
  * try_boot only returns if it fails to load the loader. If it succeeds
  * it simply boots, otherwise it returns the status of last EFI call.
  */
-static EFI_STATUS
-try_boot(void)
+EFI_STATUS
+try_boot(const boot_module_t *mod, dev_info_t *dev, void *loaderbuf, size_t loadersize)
 {
-	size_t bufsize, loadersize, cmdsize;
-	void *buf, *loaderbuf;
+	size_t bufsize, cmdsize;
+	void *buf;
 	char *cmd;
-	dev_info_t *dev;
-	const boot_module_t *mod;
 	EFI_HANDLE loaderhandle;
 	EFI_LOADED_IMAGE *loaded_image;
 	EFI_STATUS status;
 
-	status = load_loader(&mod, &dev, &loaderbuf, &loadersize, 1);
-	if (status != EFI_SUCCESS) {
-		status = load_loader(&mod, &dev, &loaderbuf, &loadersize, 0);
-		if (status != EFI_SUCCESS) {
-			printf("Failed to load '%s'\n", PATH_LOADER_EFI);
-			return (status);
-		}
-	}
-
 	/*
 	 * Read in and parse the command line from /boot.config or /boot/config,
 	 * if present. We'll pass it the next stage via a simple ASCII
@@ -228,84 +182,6 @@ errout:
 	return (status);
 }
 
-/*
- * probe_handle determines if the passed handle represents a logical partition
- * if it does it uses each module in order to probe it and if successful it
- * returns 0.
- */
-static int
-probe_handle(EFI_HANDLE h, EFI_DEVICE_PATH *imgpath)
-{
-	dev_info_t *devinfo;
-	EFI_BLOCK_IO *blkio;
-	EFI_DEVICE_PATH *devpath;
-	EFI_STATUS status;
-	UINTN i;
-	int preferred;
-
-	/* Figure out if we're dealing with an actual partition. */
-	status = BS->HandleProtocol(h, &DevicePathGUID, (void **)&devpath);
-	if (status == EFI_UNSUPPORTED)
-		return (0);
-
-	if (status != EFI_SUCCESS) {
-		DPRINTF("\nFailed to query DevicePath (%lu)\n",
-		    EFI_ERROR_CODE(status));
-		return (-1);
-	}
-#ifdef EFI_DEBUG
-	{
-		CHAR16 *text = efi_devpath_name(devpath);
-		DPRINTF("probing: %S ", text);
-		efi_free_devpath_name(text);
-	}
-#endif
-	status = BS->HandleProtocol(h, &BlockIoProtocolGUID, (void **)&blkio);
-	if (status == EFI_UNSUPPORTED)
-		return (0);
-
-	if (status != EFI_SUCCESS) {
-		DPRINTF("\nFailed to query BlockIoProtocol (%lu)\n",
-		    EFI_ERROR_CODE(status));
-		return (-1);
-	}
-
-	if (!blkio->Media->LogicalPartition)
-		return (0);
-
-	preferred = efi_devpath_same_disk(imgpath, devpath);
-
-	/* Run through each module, see if it can load this partition */
-	devinfo = malloc(sizeof(*devinfo));
-	if (devinfo == NULL) {
-		DPRINTF("\nFailed to allocate devinfo\n");
-		return (-1);
-	}
-	devinfo->dev = blkio;
-	devinfo->devpath = devpath;
-	devinfo->devhandle = h;
-	devinfo->preferred = preferred;
-	devinfo->next = NULL;
-
-	for (i = 0; i < NUM_BOOT_MODULES; i++) {
-		devinfo->devdata = NULL;
-
-		status = boot_modules[i]->probe(devinfo);
-		if (status == EFI_SUCCESS)
-			return (preferred + 1);
-	}
-	free(devinfo);
-
-	return (0);
-}
-
-const char *prio_str[] = {
-	"error",
-	"not supported",
-	"good",
-	"better"
-};
-
 EFI_STATUS
 efi_main(EFI_HANDLE Ximage, EFI_SYSTEM_TABLE *Xsystab)
 {
@@ -317,10 +193,6 @@ efi_main(EFI_HANDLE Ximage, EFI_SYSTEM_TABLE *Xsystab)
 	SIMPLE_TEXT_OUTPUT_INTERFACE *conout = NULL;
 	UINTN i, hsize, nhandles;
 	CHAR16 *text;
-	UINT16 boot_current;
-	size_t sz;
-	UINT16 boot_order[100];
-	int rv;
 
 	/* Basic initialization*/
 	ST = Xsystab;
@@ -348,13 +220,27 @@ efi_main(EFI_HANDLE Ximage, EFI_SYSTEM_TABLE *Xsystab)
 	printf("\n>> FreeBSD EFI boot block\n");
 	printf("   Loader path: %s\n\n", PATH_LOADER_EFI);
 	printf("   Initializing modules:");
-	for (i = 0; i < NUM_BOOT_MODULES; i++) {
+	for (i = 0; i < num_boot_modules; i++) {
 		printf(" %s", boot_modules[i]->name);
 		if (boot_modules[i]->init != NULL)
 			boot_modules[i]->init();
 	}
 	putchar('\n');
 
+	/* Fetch all the block I/O handles, we have to search through them later */
+	hsize = 0;
+	BS->LocateHandle(ByProtocol, &BlockIoProtocolGUID, NULL,
+	    &hsize, NULL);
+	handles = malloc(hsize);
+	if (handles == NULL)
+		efi_panic(EFI_OUT_OF_RESOURCES, "Failed to allocate %d handles\n",
+		    hsize);
+	status = BS->LocateHandle(ByProtocol, &BlockIoProtocolGUID,
+	    NULL, &hsize, handles);
+	if (status != EFI_SUCCESS)
+		efi_panic(status, "Failed to get device handles\n");
+	nhandles = hsize / sizeof(*handles);
+
 	/* Determine the devpath of our image so we can prefer it. */
 	status = BS->HandleProtocol(IH, &LoadedImageGUID, (VOID**)&img);
 	imgpath = NULL;
@@ -381,64 +267,7 @@ efi_main(EFI_HANDLE Ximage, EFI_SYSTEM_TABLE *Xsystab)
 		}
 	}
 
-	boot_current = 0;
-	sz = sizeof(boot_current);
-	if (efi_global_getenv("BootCurrent", &boot_current, &sz) == EFI_SUCCESS) {
-		printf("   BootCurrent: %04x\n", boot_current);
-
-		sz = sizeof(boot_order);
-		if (efi_global_getenv("BootOrder", &boot_order, &sz) == EFI_SUCCESS) {
-			printf("   BootOrder:");
-			for (i = 0; i < sz / sizeof(boot_order[0]); i++)
-				printf(" %04x%s", boot_order[i],
-				    boot_order[i] == boot_current ? "[*]" : "");
-			printf("\n");
-		}
-	}
-
-#ifdef TEST_FAILURE
-	/*
-	 * For testing failover scenarios, it's nice to be able to fail fast.
-	 * Define TEST_FAILURE to create a boot1.efi that always fails after
-	 * reporting the boot manager protocol details.
-	 */
-	BS->Exit(IH, EFI_OUT_OF_RESOURCES, 0, NULL);
-#endif
-
-	hsize = 0;
-	BS->LocateHandle(ByProtocol, &BlockIoProtocolGUID, NULL,
-	    &hsize, NULL);
-	handles = malloc(hsize);
-	if (handles == NULL)
-		efi_panic(EFI_OUT_OF_RESOURCES, "Failed to allocate %d handles\n",
-		    hsize);
-	status = BS->LocateHandle(ByProtocol, &BlockIoProtocolGUID,
-	    NULL, &hsize, handles);
-	if (status != EFI_SUCCESS)
-		efi_panic(status, "Failed to get device handles\n");
-
-	/* Scan all partitions, probing with all modules. */
-	nhandles = hsize / sizeof(*handles);
-	printf("   Probing %zu block devices...", nhandles);
-	DPRINTF("\n");
-
-	for (i = 0; i < nhandles; i++) {
-		rv = probe_handle(handles[i], imgpath);
-#ifdef EFI_DEBUG
-		printf("%c", "x.+*"[rv + 1]);
-#else
-		printf("%s\n", prio_str[rv + 1]);
-#endif
-	}
-	printf(" done\n");
-
-	/* Status summary. */
-	for (i = 0; i < NUM_BOOT_MODULES; i++) {
-		printf("    ");
-		boot_modules[i]->status();
-	}
-
-	try_boot();
+	choice_protocol(handles, nhandles, imgpath);
 
 	/* If we get here, we're out of luck... */
 	efi_panic(EFI_LOAD_ERROR, "No bootable partitions found!");

Modified: head/stand/efi/boot1/boot_module.h
==============================================================================
--- head/stand/efi/boot1/boot_module.h	Sat Jun  8 18:26:48 2019	(r348810)
+++ head/stand/efi/boot1/boot_module.h	Sat Jun  8 18:59:50 2019	(r348811)
@@ -96,6 +96,9 @@ typedef struct boot_module_t
 	dev_info_t *(*devices)(void);
 } boot_module_t;
 
+extern const boot_module_t *boot_modules[];
+extern const UINTN num_boot_modules;
+
 /* Standard boot modules. */
 #ifdef EFI_UFS_BOOT
 extern const boot_module_t ufs_module;

Added: head/stand/efi/boot1/proto.c
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ head/stand/efi/boot1/proto.c	Sat Jun  8 18:59:50 2019	(r348811)
@@ -0,0 +1,223 @@
+/*-
+ * 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 reserved.
+ *
+ * Redistribution and use in source and binary forms are freely
+ * permitted provided that the above copyright notice and this
+ * paragraph and the following disclaimer are duplicated in all
+ * such forms.
+ *
+ * This software is provided "AS IS" and without any express or
+ * implied warranties, including, without limitation, the implied
+ * warranties of merchantability and fitness for a particular
+ * purpose.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <machine/elf.h>
+#include <machine/stdarg.h>
+#include <stand.h>
+
+#include <efi.h>
+#include <eficonsctl.h>
+#include <efichar.h>
+
+#include "boot_module.h"
+#include "paths.h"
+#include "proto.h"
+
+static EFI_GUID BlockIoProtocolGUID = BLOCK_IO_PROTOCOL;
+static EFI_GUID DevicePathGUID = DEVICE_PATH_PROTOCOL;
+
+static const char *prio_str[] = {
+	"error",
+	"not supported",
+	"good",
+	"better"
+};
+
+/*
+ * probe_handle determines if the passed handle represents a logical partition
+ * if it does it uses each module in order to probe it and if successful it
+ * returns EFI_SUCCESS.
+ */
+static int
+probe_handle(EFI_HANDLE h, EFI_DEVICE_PATH *imgpath)
+{
+	dev_info_t *devinfo;
+	EFI_BLOCK_IO *blkio;
+	EFI_DEVICE_PATH *devpath;
+	EFI_STATUS status;
+	UINTN i;
+	int preferred;
+
+	/* Figure out if we're dealing with an actual partition. */
+	status = BS->HandleProtocol(h, &DevicePathGUID, (void **)&devpath);
+	if (status == EFI_UNSUPPORTED)
+		return (0);
+
+	if (status != EFI_SUCCESS) {
+		DPRINTF("\nFailed to query DevicePath (%lu)\n",
+		    EFI_ERROR_CODE(status));
+		return (-1);
+	}
+#ifdef EFI_DEBUG
+	{
+		CHAR16 *text = efi_devpath_name(devpath);
+		DPRINTF("probing: %S ", text);
+		efi_free_devpath_name(text);
+	}
+#endif
+	status = BS->HandleProtocol(h, &BlockIoProtocolGUID, (void **)&blkio);
+	if (status == EFI_UNSUPPORTED)
+		return (0);
+
+	if (status != EFI_SUCCESS) {
+		DPRINTF("\nFailed to query BlockIoProtocol (%lu)\n",
+		    EFI_ERROR_CODE(status));
+		return (-1);
+	}
+
+	if (!blkio->Media->LogicalPartition)
+		return (0);
+
+	preferred = efi_devpath_same_disk(imgpath, devpath);
+
+	/* Run through each module, see if it can load this partition */
+	devinfo = malloc(sizeof(*devinfo));
+	if (devinfo == NULL) {
+		DPRINTF("\nFailed to allocate devinfo\n");
+		return (-1);
+	}
+	devinfo->dev = blkio;
+	devinfo->devpath = devpath;
+	devinfo->devhandle = h;
+	devinfo->preferred = preferred;
+	devinfo->next = NULL;
+
+	for (i = 0; i < num_boot_modules; i++) {
+		devinfo->devdata = NULL;
+
+		status = boot_modules[i]->probe(devinfo);
+		if (status == EFI_SUCCESS)
+			return (preferred + 1);
+	}
+	free(devinfo);
+
+	return (0);
+}
+
+/*
+ * load_loader attempts to load the loader image data.
+ *
+ * It tries each module and its respective devices, identified by mod->probe,
+ * in order until a successful load occurs at which point it returns EFI_SUCCESS
+ * and EFI_NOT_FOUND otherwise.
+ *
+ * Only devices which have preferred matching the preferred parameter are tried.
+ */
+static EFI_STATUS
+load_loader(const boot_module_t **modp, dev_info_t **devinfop, void **bufp,
+    size_t *bufsize, int preferred)
+{
+	UINTN i;
+	dev_info_t *dev;
+	const boot_module_t *mod;
+
+	for (i = 0; i < num_boot_modules; i++) {
+		mod = boot_modules[i];
+		for (dev = mod->devices(); dev != NULL; dev = dev->next) {
+			if (dev->preferred != preferred)
+				continue;
+
+			if (mod->load(PATH_LOADER_EFI, dev, bufp, bufsize) ==
+			    EFI_SUCCESS) {
+				*devinfop = dev;
+				*modp = mod;
+				return (EFI_SUCCESS);
+			}
+		}
+	}
+
+	return (EFI_NOT_FOUND);
+}
+
+void
+choice_protocol(EFI_HANDLE *handles, UINTN nhandles, EFI_DEVICE_PATH *imgpath)
+{
+	UINT16 boot_current;
+	size_t sz;
+	UINT16 boot_order[100];
+	unsigned i;
+	int rv;
+	EFI_STATUS status;
+	const boot_module_t *mod;
+	dev_info_t *dev;
+	void *loaderbuf;
+	size_t loadersize;
+
+	/* Report UEFI Boot Manager Protocol details */
+	boot_current = 0;
+	sz = sizeof(boot_current);
+	if (efi_global_getenv("BootCurrent", &boot_current, &sz) == EFI_SUCCESS) {
+		printf("   BootCurrent: %04x\n", boot_current);
+
+		sz = sizeof(boot_order);
+		if (efi_global_getenv("BootOrder", &boot_order, &sz) == EFI_SUCCESS) {
+			printf("   BootOrder:");
+			for (i = 0; i < sz / sizeof(boot_order[0]); i++)
+				printf(" %04x%s", boot_order[i],
+				    boot_order[i] == boot_current ? "[*]" : "");
+			printf("\n");
+		}
+	}
+
+#ifdef TEST_FAILURE
+	/*
+	 * For testing failover scenarios, it's nice to be able to fail fast.
+	 * Define TEST_FAILURE to create a boot1.efi that always fails after
+	 * reporting the boot manager protocol details.
+	 */
+	BS->Exit(IH, EFI_OUT_OF_RESOURCES, 0, NULL);
+#endif
+
+	/* Scan all partitions, probing with all modules. */
+	printf("   Probing %zu block devices...", nhandles);
+	DPRINTF("\n");
+	for (i = 0; i < nhandles; i++) {
+		rv = probe_handle(handles[i], imgpath);
+#ifdef EFI_DEBUG
+		printf("%c", "x.+*"[rv + 1]);
+#else
+		printf("%s\n", prio_str[rv + 1]);
+#endif
+	}
+	printf(" done\n");
+
+
+	/* Status summary. */
+	for (i = 0; i < num_boot_modules; i++) {
+		printf("    ");
+		boot_modules[i]->status();
+	}
+
+	status = load_loader(&mod, &dev, &loaderbuf, &loadersize, 1);
+	if (status != EFI_SUCCESS) {
+		status = load_loader(&mod, &dev, &loaderbuf, &loadersize, 0);
+		if (status != EFI_SUCCESS) {
+			printf("Failed to load '%s'\n", PATH_LOADER_EFI);
+			return;
+		}
+	}
+
+	try_boot(mod, dev, loaderbuf, loadersize);
+}

Added: head/stand/efi/boot1/proto.h
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ head/stand/efi/boot1/proto.h	Sat Jun  8 18:59:50 2019	(r348811)
@@ -0,0 +1,29 @@
+/*-
+ * Copyright (c) 2019 Netflix, Inc
+ *
+ * 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$
+ */
+
+void choice_protocol(EFI_HANDLE *handles, UINTN nhandles, EFI_DEVICE_PATH *imgpath);
+EFI_STATUS try_boot(const boot_module_t *mod, dev_info_t *dev, void *loaderbuf, size_t loadersize);


More information about the svn-src-all mailing list