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/cdefs.h>
23 __FBSDID("$FreeBSD$");
25 #include <sys/param.h>
26 #include <machine/elf.h>
27 #include <machine/stdarg.h>
31 #include <eficonsctl.h>
34 #include "boot_module.h"
37 static void efi_panic(EFI_STATUS s, const char *fmt, ...) __dead2 __printflike(2, 3);
39 static const boot_module_t *boot_modules[] =
49 #define NUM_BOOT_MODULES nitems(boot_modules)
51 static EFI_GUID BlockIoProtocolGUID = BLOCK_IO_PROTOCOL;
52 static EFI_GUID DevicePathGUID = DEVICE_PATH_PROTOCOL;
53 static EFI_GUID LoadedImageGUID = LOADED_IMAGE_PROTOCOL;
54 static EFI_GUID ConsoleControlGUID = EFI_CONSOLE_CONTROL_PROTOCOL_GUID;
57 * Provide Malloc / Free / Calloc backed by EFIs AllocatePool / FreePool which ensures
58 * memory is correctly aligned avoiding EFI_INVALID_PARAMETER returns from
63 Malloc(size_t len, const char *file __unused, int line __unused)
67 if (BS->AllocatePool(EfiLoaderData, len, &out) == EFI_SUCCESS)
74 Free(void *buf, const char *file __unused, int line __unused)
77 (void)BS->FreePool(buf);
81 Calloc(size_t n1, size_t n2, const char *file, int line)
87 if ((res = Malloc(bytes, file, line)) != NULL)
94 * load_loader attempts to load the loader image data.
96 * It tries each module and its respective devices, identified by mod->probe,
97 * in order until a successful load occurs at which point it returns EFI_SUCCESS
98 * and EFI_NOT_FOUND otherwise.
100 * Only devices which have preferred matching the preferred parameter are tried.
103 load_loader(const boot_module_t **modp, dev_info_t **devinfop, void **bufp,
104 size_t *bufsize, BOOLEAN preferred)
108 const boot_module_t *mod;
110 for (i = 0; i < NUM_BOOT_MODULES; i++) {
111 mod = boot_modules[i];
112 for (dev = mod->devices(); dev != NULL; dev = dev->next) {
113 if (dev->preferred != preferred)
116 if (mod->load(PATH_LOADER_EFI, dev, bufp, bufsize) ==
120 return (EFI_SUCCESS);
125 return (EFI_NOT_FOUND);
129 * try_boot only returns if it fails to load the loader. If it succeeds
130 * it simply boots, otherwise it returns the status of last EFI call.
135 size_t bufsize, loadersize, cmdsize;
136 void *buf, *loaderbuf;
139 const boot_module_t *mod;
140 EFI_HANDLE loaderhandle;
141 EFI_LOADED_IMAGE *loaded_image;
144 status = load_loader(&mod, &dev, &loaderbuf, &loadersize, TRUE);
145 if (status != EFI_SUCCESS) {
146 status = load_loader(&mod, &dev, &loaderbuf, &loadersize,
148 if (status != EFI_SUCCESS) {
149 printf("Failed to load '%s'\n", PATH_LOADER_EFI);
155 * Read in and parse the command line from /boot.config or /boot/config,
156 * if present. We'll pass it the next stage via a simple ASCII
157 * string. loader.efi has a hack for ASCII strings, so we'll use that to
158 * keep the size down here. We only try to read the alternate file if
159 * we get EFI_NOT_FOUND because all other errors mean that the boot_module
160 * had troubles with the filesystem. We could return early, but we'll let
161 * loading the actual kernel sort all that out. Since these files are
162 * optional, we don't report errors in trying to read them.
166 status = mod->load(PATH_DOTCONFIG, dev, &buf, &bufsize);
167 if (status == EFI_NOT_FOUND)
168 status = mod->load(PATH_CONFIG, dev, &buf, &bufsize);
169 if (status == EFI_SUCCESS) {
170 cmdsize = bufsize + 1;
171 cmd = malloc(cmdsize);
174 memcpy(cmd, buf, bufsize);
180 if ((status = BS->LoadImage(TRUE, IH, efi_devpath_last_node(dev->devpath),
181 loaderbuf, loadersize, &loaderhandle)) != EFI_SUCCESS) {
182 printf("Failed to load image provided by %s, size: %zu, (%lu)\n",
183 mod->name, loadersize, EFI_ERROR_CODE(status));
187 if ((status = BS->HandleProtocol(loaderhandle, &LoadedImageGUID,
188 (VOID**)&loaded_image)) != EFI_SUCCESS) {
189 printf("Failed to query LoadedImage provided by %s (%lu)\n",
190 mod->name, EFI_ERROR_CODE(status));
195 printf(" command args: %s\n", cmd);
197 loaded_image->DeviceHandle = dev->devhandle;
198 loaded_image->LoadOptionsSize = cmdsize;
199 loaded_image->LoadOptions = cmd;
201 DPRINTF("Starting '%s' in 5 seconds...", PATH_LOADER_EFI);
213 if ((status = BS->StartImage(loaderhandle, NULL, NULL)) !=
215 printf("Failed to start image provided by %s (%lu)\n",
216 mod->name, EFI_ERROR_CODE(status));
217 loaded_image->LoadOptionsSize = 0;
218 loaded_image->LoadOptions = NULL;
226 if (loaderbuf != NULL)
233 * probe_handle determines if the passed handle represents a logical partition
234 * if it does it uses each module in order to probe it and if successful it
235 * returns EFI_SUCCESS.
238 probe_handle(EFI_HANDLE h, EFI_DEVICE_PATH *imgpath, BOOLEAN *preferred)
242 EFI_DEVICE_PATH *devpath;
246 /* Figure out if we're dealing with an actual partition. */
247 status = BS->HandleProtocol(h, &DevicePathGUID, (void **)&devpath);
248 if (status == EFI_UNSUPPORTED)
251 if (status != EFI_SUCCESS) {
252 DPRINTF("\nFailed to query DevicePath (%lu)\n",
253 EFI_ERROR_CODE(status));
258 CHAR16 *text = efi_devpath_name(devpath);
259 DPRINTF("probing: %S\n", text);
260 efi_free_devpath_name(text);
263 status = BS->HandleProtocol(h, &BlockIoProtocolGUID, (void **)&blkio);
264 if (status == EFI_UNSUPPORTED)
267 if (status != EFI_SUCCESS) {
268 DPRINTF("\nFailed to query BlockIoProtocol (%lu)\n",
269 EFI_ERROR_CODE(status));
273 if (!blkio->Media->LogicalPartition)
274 return (EFI_UNSUPPORTED);
276 *preferred = efi_devpath_same_disk(imgpath, devpath);
278 /* Run through each module, see if it can load this partition */
279 devinfo = malloc(sizeof(*devinfo));
280 if (devinfo == NULL) {
281 DPRINTF("\nFailed to allocate devinfo\n");
282 return (EFI_UNSUPPORTED);
284 devinfo->dev = blkio;
285 devinfo->devpath = devpath;
286 devinfo->devhandle = h;
287 devinfo->preferred = *preferred;
288 devinfo->next = NULL;
290 for (i = 0; i < NUM_BOOT_MODULES; i++) {
291 devinfo->devdata = NULL;
292 status = boot_modules[i]->probe(devinfo);
293 if (status == EFI_SUCCESS)
294 return (EFI_SUCCESS);
298 return (EFI_UNSUPPORTED);
302 * probe_handle_status calls probe_handle and outputs the returned status
306 probe_handle_status(EFI_HANDLE h, EFI_DEVICE_PATH *imgpath)
312 status = probe_handle(h, imgpath, &preferred);
316 case EFI_UNSUPPORTED:
318 DPRINTF(" not supported\n");
323 DPRINTF(" supported (preferred)\n");
326 DPRINTF(" supported\n");
331 DPRINTF(" error (%lu)\n", EFI_ERROR_CODE(status));
338 efi_main(EFI_HANDLE Ximage, EFI_SYSTEM_TABLE *Xsystab)
341 EFI_LOADED_IMAGE *img;
342 EFI_DEVICE_PATH *imgpath;
344 EFI_CONSOLE_CONTROL_PROTOCOL *ConsoleControl = NULL;
345 SIMPLE_TEXT_OUTPUT_INTERFACE *conout = NULL;
346 UINTN i, hsize, nhandles;
350 UINT16 boot_order[100];
352 /* Basic initialization*/
355 BS = ST->BootServices;
356 RS = ST->RuntimeServices;
358 /* Set up the console, so printf works. */
359 status = BS->LocateProtocol(&ConsoleControlGUID, NULL,
360 (VOID **)&ConsoleControl);
361 if (status == EFI_SUCCESS)
362 (void)ConsoleControl->SetMode(ConsoleControl,
363 EfiConsoleControlScreenText);
365 * Reset the console enable the cursor. Later we'll choose a better
366 * console size through GOP/UGA.
369 conout->Reset(conout, TRUE);
370 /* Explicitly set conout to mode 0, 80x25 */
371 conout->SetMode(conout, 0);
372 conout->EnableCursor(conout, TRUE);
373 conout->ClearScreen(conout);
375 printf("\n>> FreeBSD EFI boot block\n");
376 printf(" Loader path: %s\n\n", PATH_LOADER_EFI);
377 printf(" Initializing modules:");
378 for (i = 0; i < NUM_BOOT_MODULES; i++) {
379 printf(" %s", boot_modules[i]->name);
380 if (boot_modules[i]->init != NULL)
381 boot_modules[i]->init();
385 /* Determine the devpath of our image so we can prefer it. */
386 status = BS->HandleProtocol(IH, &LoadedImageGUID, (VOID**)&img);
388 if (status == EFI_SUCCESS) {
389 text = efi_devpath_name(img->FilePath);
391 printf(" Load Path: %S\n", text);
392 efi_setenv_freebsd_wcs("Boot1Path", text);
393 efi_free_devpath_name(text);
396 status = BS->HandleProtocol(img->DeviceHandle, &DevicePathGUID,
398 if (status != EFI_SUCCESS) {
399 DPRINTF("Failed to get image DevicePath (%lu)\n",
400 EFI_ERROR_CODE(status));
402 text = efi_devpath_name(imgpath);
404 printf(" Load Device: %S\n", text);
405 efi_setenv_freebsd_wcs("Boot1Dev", text);
406 efi_free_devpath_name(text);
412 sz = sizeof(boot_current);
413 if (efi_global_getenv("BootCurrent", &boot_current, &sz) == EFI_SUCCESS) {
414 printf(" BootCurrent: %04x\n", boot_current);
416 sz = sizeof(boot_order);
417 if (efi_global_getenv("BootOrder", &boot_order, &sz) == EFI_SUCCESS) {
418 printf(" BootOrder:");
419 for (i = 0; i < sz / sizeof(boot_order[0]); i++)
420 printf(" %04x%s", boot_order[i],
421 boot_order[i] == boot_current ? "[*]" : "");
428 * For testing failover scenarios, it's nice to be able to fail fast.
429 * Define TEST_FAILURE to create a boot1.efi that always fails after
430 * reporting the boot manager protocol details.
432 BS->Exit(IH, EFI_OUT_OF_RESOURCES, 0, NULL);
436 BS->LocateHandle(ByProtocol, &BlockIoProtocolGUID, NULL,
438 handles = malloc(hsize);
440 efi_panic(EFI_OUT_OF_RESOURCES, "Failed to allocate %d handles\n",
442 status = BS->LocateHandle(ByProtocol, &BlockIoProtocolGUID,
443 NULL, &hsize, handles);
444 if (status != EFI_SUCCESS)
445 efi_panic(status, "Failed to get device handles\n");
447 /* Scan all partitions, probing with all modules. */
448 nhandles = hsize / sizeof(*handles);
449 printf(" Probing %zu block devices...", nhandles);
452 for (i = 0; i < nhandles; i++)
453 probe_handle_status(handles[i], imgpath);
456 /* Status summary. */
457 for (i = 0; i < NUM_BOOT_MODULES; i++) {
459 boot_modules[i]->status();
464 /* If we get here, we're out of luck... */
465 efi_panic(EFI_LOAD_ERROR, "No bootable partitions found!");
469 * add_device adds a device to the passed devinfo list.
472 add_device(dev_info_t **devinfop, dev_info_t *devinfo)
476 if (*devinfop == NULL) {
481 for (dev = *devinfop; dev->next != NULL; dev = dev->next)
488 * OK. We totally give up. Exit back to EFI with a sensible status so
489 * it can try the next option on the list.
492 efi_panic(EFI_STATUS s, const char *fmt, ...)
502 BS->Exit(IH, s, 0, NULL);
513 ST->ConOut->OutputString(ST->ConOut, buf);
517 ST->ConOut->OutputString(ST->ConOut, buf);