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