2 * Copyright (c) 1998 Robert Nordier
4 * Copyright (c) 2001 Robert Drehmel
6 * Copyright (c) 2014 Nathan Whitehorn
8 * Copyright (c) 2015 Eric McCorkle
11 * Redistribution and use in source and binary forms are freely
12 * permitted provided that the above copyright notice and this
13 * paragraph and the following disclaimer are duplicated in all
16 * This software is provided "AS IS" and without any express or
17 * implied warranties, including, without limitation, the implied
18 * warranties of merchantability and fitness for a particular
22 #include <sys/param.h>
23 #include <machine/elf.h>
24 #include <machine/stdarg.h>
28 #include <eficonsctl.h>
31 #include "boot_module.h"
35 static EFI_GUID BlockIoProtocolGUID = BLOCK_IO_PROTOCOL;
36 static EFI_GUID DevicePathGUID = DEVICE_PATH_PROTOCOL;
39 static const char *prio_str[] = {
48 * probe_handle determines if the passed handle represents a logical partition
49 * if it does it uses each module in order to probe it and if successful it
50 * returns EFI_SUCCESS.
53 probe_handle(EFI_HANDLE h, EFI_DEVICE_PATH *imgpath)
57 EFI_DEVICE_PATH *devpath;
62 /* Figure out if we're dealing with an actual partition. */
63 status = OpenProtocolByHandle(h, &DevicePathGUID, (void **)&devpath);
64 if (status == EFI_UNSUPPORTED)
67 if (status != EFI_SUCCESS) {
68 DPRINTF("\nFailed to query DevicePath (%lu)\n",
69 EFI_ERROR_CODE(status));
74 CHAR16 *text = efi_devpath_name(devpath);
75 DPRINTF("probing: %S ", text);
76 efi_free_devpath_name(text);
79 status = OpenProtocolByHandle(h, &BlockIoProtocolGUID, (void **)&blkio);
80 if (status == EFI_UNSUPPORTED)
83 if (status != EFI_SUCCESS) {
84 DPRINTF("\nFailed to query BlockIoProtocol (%lu)\n",
85 EFI_ERROR_CODE(status));
89 if (!blkio->Media->LogicalPartition)
92 preferred = efi_devpath_same_disk(imgpath, devpath);
94 /* Run through each module, see if it can load this partition */
95 devinfo = malloc(sizeof(*devinfo));
96 if (devinfo == NULL) {
97 DPRINTF("\nFailed to allocate devinfo\n");
100 devinfo->dev = blkio;
101 devinfo->devpath = devpath;
102 devinfo->devhandle = h;
103 devinfo->preferred = preferred;
104 devinfo->next = NULL;
106 for (i = 0; i < num_boot_modules; i++) {
107 devinfo->devdata = NULL;
109 status = boot_modules[i]->probe(devinfo);
110 if (status == EFI_SUCCESS)
111 return (preferred + 1);
119 * load_loader attempts to load the loader image data.
121 * It tries each module and its respective devices, identified by mod->probe,
122 * in order until a successful load occurs at which point it returns EFI_SUCCESS
123 * and EFI_NOT_FOUND otherwise.
125 * Only devices which have preferred matching the preferred parameter are tried.
128 load_loader(const boot_module_t **modp, dev_info_t **devinfop, void **bufp,
129 size_t *bufsize, int preferred)
133 const boot_module_t *mod;
135 for (i = 0; i < num_boot_modules; i++) {
136 mod = boot_modules[i];
137 for (dev = mod->devices(); dev != NULL; dev = dev->next) {
138 if (dev->preferred != preferred)
141 if (mod->load(PATH_LOADER_EFI, dev, bufp, bufsize) ==
145 return (EFI_SUCCESS);
150 return (EFI_NOT_FOUND);
154 choice_protocol(EFI_HANDLE *handles, UINTN nhandles, EFI_DEVICE_PATH *imgpath)
158 UINT16 boot_order[100];
162 const boot_module_t *mod;
167 /* Report UEFI Boot Manager Protocol details */
169 sz = sizeof(boot_current);
170 if (efi_global_getenv("BootCurrent", &boot_current, &sz) == EFI_SUCCESS) {
171 printf(" BootCurrent: %04x\n", boot_current);
173 sz = sizeof(boot_order);
174 if (efi_global_getenv("BootOrder", &boot_order, &sz) == EFI_SUCCESS) {
175 printf(" BootOrder:");
176 for (i = 0; i < sz / sizeof(boot_order[0]); i++)
177 printf(" %04x%s", boot_order[i],
178 boot_order[i] == boot_current ? "[*]" : "");
185 * For testing failover scenarios, it's nice to be able to fail fast.
186 * Define TEST_FAILURE to create a boot1.efi that always fails after
187 * reporting the boot manager protocol details.
189 BS->Exit(IH, EFI_OUT_OF_RESOURCES, 0, NULL);
192 /* Scan all partitions, probing with all modules. */
193 printf(" Probing %zu block devices...", nhandles);
195 for (i = 0; i < nhandles; i++) {
196 rv = probe_handle(handles[i], imgpath);
198 printf("%c", "x.+*"[rv + 1]);
200 printf("%s\n", prio_str[rv + 1]);
206 /* Status summary. */
207 for (i = 0; i < num_boot_modules; i++) {
209 boot_modules[i]->status();
212 status = load_loader(&mod, &dev, &loaderbuf, &loadersize, 1);
213 if (status != EFI_SUCCESS) {
214 status = load_loader(&mod, &dev, &loaderbuf, &loadersize, 0);
215 if (status != EFI_SUCCESS) {
216 printf("Failed to load '%s'\n", PATH_LOADER_EFI);
221 try_boot(mod, dev, loaderbuf, loadersize);