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);
_______________________________________________
svn-src-all@freebsd.org mailing list
https://lists.freebsd.org/mailman/listinfo/svn-src-all
To unsubscribe, send any mail to "svn-src-all-unsubscr...@freebsd.org"

Reply via email to