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
21 * $FreeBSD: head/sys/boot/efi/boot1/boot1.c 296713 2016-03-12 06:50:16Z andrew $
24 #include <sys/param.h>
25 #include <machine/elf.h>
26 #include <machine/stdarg.h>
31 #include <eficonsctl.h>
33 #include "boot_module.h"
36 #define PATH_CONFIG "/boot/config"
37 #define PATH_DOTCONFIG "/boot.config"
38 #define PATH_LOADER "/loader.efi" /* /boot is dedicated */
39 #define PATH_LOADER_ALT "/boot/loader.efi" /* /boot in root */
41 static const boot_module_t *boot_modules[] =
48 #define NUM_BOOT_MODULES NELEM(boot_modules)
49 /* The initial number of handles used to query EFI for partitions. */
50 #define NUM_HANDLES_INIT 24
52 EFI_STATUS efi_main(EFI_HANDLE Ximage, EFI_SYSTEM_TABLE* Xsystab);
54 EFI_SYSTEM_TABLE *systab;
55 EFI_BOOT_SERVICES *bs;
56 static EFI_HANDLE *image;
58 static EFI_GUID BlockIoProtocolGUID = BLOCK_IO_PROTOCOL;
59 static EFI_GUID DevicePathGUID = DEVICE_PATH_PROTOCOL;
60 static EFI_GUID LoadedImageGUID = LOADED_IMAGE_PROTOCOL;
61 static EFI_GUID ConsoleControlGUID = EFI_CONSOLE_CONTROL_PROTOCOL_GUID;
64 * XXX DragonFly's libstand doesn't provide a way to override the malloc
70 * Provide Malloc / Free backed by EFIs AllocatePool / FreePool which ensures
71 * memory is correctly aligned avoiding EFI_INVALID_PARAMETER returns from
75 Malloc(size_t len, const char *file __unused, int line __unused)
79 if (bs->AllocatePool(EfiLoaderData, len, &out) == EFI_SUCCESS)
86 Free(void *buf, const char *file __unused, int line __unused)
88 (void)bs->FreePool(buf);
94 * nodes_match returns TRUE if the imgpath isn't NULL and the nodes match,
98 nodes_match(EFI_DEVICE_PATH *imgpath, EFI_DEVICE_PATH *devpath)
102 if (imgpath == NULL || imgpath->Type != devpath->Type ||
103 imgpath->SubType != devpath->SubType)
106 len = DevicePathNodeLength(imgpath);
107 if (len != DevicePathNodeLength(devpath))
110 return (memcmp(imgpath, devpath, (size_t)len) == 0);
114 * device_paths_match returns TRUE if the imgpath isn't NULL and all nodes
115 * in imgpath and devpath match up to their respect occurances of a media
116 * node, FALSE otherwise.
119 device_paths_match(EFI_DEVICE_PATH *imgpath, EFI_DEVICE_PATH *devpath)
125 while (!IsDevicePathEnd(imgpath) && !IsDevicePathEnd(devpath)) {
126 if (IsDevicePathType(imgpath, MEDIA_DEVICE_PATH) &&
127 IsDevicePathType(devpath, MEDIA_DEVICE_PATH))
130 if (!nodes_match(imgpath, devpath))
133 imgpath = NextDevicePathNode(imgpath);
134 devpath = NextDevicePathNode(devpath);
141 * devpath_last returns the last non-path end node in devpath.
143 static EFI_DEVICE_PATH *
144 devpath_last(EFI_DEVICE_PATH *devpath)
147 while (!IsDevicePathEnd(NextDevicePathNode(devpath)))
148 devpath = NextDevicePathNode(devpath);
154 * devpath_node_str is a basic output method for a devpath node which
155 * only understands a subset of the available sub types.
157 * If we switch to UEFI 2.x then we should update it to use:
158 * EFI_DEVICE_PATH_TO_TEXT_PROTOCOL.
161 devpath_node_str(char *buf, size_t size, EFI_DEVICE_PATH *devpath)
164 switch (devpath->Type) {
165 case MESSAGING_DEVICE_PATH:
166 switch (devpath->SubType) {
168 ATAPI_DEVICE_PATH *atapi;
170 atapi = (ATAPI_DEVICE_PATH *)(void *)devpath;
171 return snprintf(buf, size, "ata(%s,%s,0x%x)",
172 (atapi->PrimarySecondary == 1) ? "Sec" : "Pri",
173 (atapi->SlaveMaster == 1) ? "Slave" : "Master",
177 USB_DEVICE_PATH *usb;
179 usb = (USB_DEVICE_PATH *)devpath;
180 return snprintf(buf, size, "usb(0x%02x,0x%02x)",
181 usb->ParentPortNumber, usb->InterfaceNumber);
184 SCSI_DEVICE_PATH *scsi;
186 scsi = (SCSI_DEVICE_PATH *)(void *)devpath;
187 return snprintf(buf, size, "scsi(0x%02x,0x%02x)",
188 scsi->Pun, scsi->Lun);
191 SATA_DEVICE_PATH *sata;
193 sata = (SATA_DEVICE_PATH *)(void *)devpath;
194 return snprintf(buf, size, "sata(0x%x,0x%x,0x%x)",
195 sata->HBAPortNumber, sata->PortMultiplierPortNumber,
199 return snprintf(buf, size, "msg(0x%02x)",
203 case HARDWARE_DEVICE_PATH:
204 switch (devpath->SubType) {
206 PCI_DEVICE_PATH *pci;
208 pci = (PCI_DEVICE_PATH *)devpath;
209 return snprintf(buf, size, "pci(0x%02x,0x%02x)",
210 pci->Device, pci->Function);
213 return snprintf(buf, size, "hw(0x%02x)",
217 case ACPI_DEVICE_PATH: {
218 ACPI_HID_DEVICE_PATH *acpi;
220 acpi = (ACPI_HID_DEVICE_PATH *)(void *)devpath;
221 if ((acpi->HID & PNP_EISA_ID_MASK) == PNP_EISA_ID_CONST) {
222 switch (EISA_ID_TO_NUM(acpi->HID)) {
224 return snprintf(buf, size, "pciroot(0x%x)",
227 return snprintf(buf, size, "pcieroot(0x%x)",
230 return snprintf(buf, size, "floppy(0x%x)",
233 return snprintf(buf, size, "keyboard(0x%x)",
236 return snprintf(buf, size, "serial(0x%x)",
239 return snprintf(buf, size, "parallelport(0x%x)",
242 return snprintf(buf, size, "acpi(pnp%04x,0x%x)",
243 EISA_ID_TO_NUM(acpi->HID), acpi->UID);
247 return snprintf(buf, size, "acpi(0x%08x,0x%x)", acpi->HID,
250 case MEDIA_DEVICE_PATH:
251 switch (devpath->SubType) {
252 case MEDIA_CDROM_DP: {
253 CDROM_DEVICE_PATH *cdrom;
255 cdrom = (CDROM_DEVICE_PATH *)(void *)devpath;
256 return snprintf(buf, size, "cdrom(%x)",
259 case MEDIA_HARDDRIVE_DP: {
260 HARDDRIVE_DEVICE_PATH *hd;
262 hd = (HARDDRIVE_DEVICE_PATH *)(void *)devpath;
263 return snprintf(buf, size, "hd(%x)",
264 hd->PartitionNumber);
267 return snprintf(buf, size, "media(0x%02x)",
270 case BBS_DEVICE_PATH:
271 return snprintf(buf, size, "bbs(0x%02x)", devpath->SubType);
272 case END_DEVICE_PATH_TYPE:
276 return snprintf(buf, size, "type(0x%02x, 0x%02x)", devpath->Type,
281 * devpath_strlcat appends a text description of devpath to buf but not more
282 * than size - 1 characters followed by NUL-terminator.
285 devpath_strlcat(char *buf, size_t size, EFI_DEVICE_PATH *devpath)
292 while (!IsDevicePathEnd(devpath)) {
293 len = snprintf(buf, size - used, "%s", sep);
299 len = devpath_node_str(buf, size - used, devpath);
304 devpath = NextDevicePathNode(devpath);
312 * devpath_str is convenience method which returns the text description of
313 * devpath using a static buffer, so it isn't thread safe!
316 devpath_str(EFI_DEVICE_PATH *devpath)
318 static char buf[256];
320 devpath_strlcat(buf, sizeof(buf), devpath);
326 * load_loader attempts to load the loader image data.
328 * It tries each module and its respective devices, identified by mod->probe,
329 * in order until a successful load occurs at which point it returns EFI_SUCCESS
330 * and EFI_NOT_FOUND otherwise.
332 * Only devices which have preferred matching the preferred parameter are tried.
335 load_loader(const boot_module_t **modp, dev_info_t **devinfop, void **bufp,
336 size_t *bufsize, BOOLEAN preferred)
340 const boot_module_t *mod;
343 for (i = 0; i < NUM_BOOT_MODULES; i++) {
344 if (boot_modules[i] == NULL)
346 mod = boot_modules[i];
347 for (dev = mod->devices(); dev != NULL; dev = dev->next) {
348 if (dev->preferred != preferred)
351 status = mod->load(PATH_LOADER, dev, bufp, bufsize);
352 if (status == EFI_NOT_FOUND) {
353 status = mod->load(PATH_LOADER_ALT, dev, bufp,
356 if (status == EFI_SUCCESS) {
359 return (EFI_SUCCESS);
364 return (EFI_NOT_FOUND);
368 * try_boot only returns if it fails to load the loader. If it succeeds
369 * it simply boots, otherwise it returns the status of last EFI call.
374 size_t bufsize, loadersize, cmdsize;
375 void *buf, *loaderbuf;
378 const boot_module_t *mod;
379 EFI_HANDLE loaderhandle;
380 EFI_LOADED_IMAGE *loaded_image;
383 status = load_loader(&mod, &dev, &loaderbuf, &loadersize, TRUE);
384 if (status != EFI_SUCCESS) {
385 status = load_loader(&mod, &dev, &loaderbuf, &loadersize,
387 if (status != EFI_SUCCESS) {
388 printf("Failed to load '%s' or '%s'\n",
389 PATH_LOADER, PATH_LOADER_ALT);
395 * Read in and parse the command line from /boot.config or /boot/config,
396 * if present. We'll pass it the next stage via a simple ASCII
397 * string. loader.efi has a hack for ASCII strings, so we'll use that to
398 * keep the size down here. We only try to read the alternate file if
399 * we get EFI_NOT_FOUND because all other errors mean that the boot_module
400 * had troubles with the filesystem. We could return early, but we'll let
401 * loading the actual kernel sort all that out. Since these files are
402 * optional, we don't report errors in trying to read them.
406 status = mod->load(PATH_DOTCONFIG, dev, &buf, &bufsize);
407 if (status == EFI_NOT_FOUND)
408 status = mod->load(PATH_CONFIG, dev, &buf, &bufsize);
409 if (status == EFI_SUCCESS) {
410 cmdsize = bufsize + 1;
411 cmd = malloc(cmdsize);
414 memcpy(cmd, buf, bufsize);
420 if ((status = bs->LoadImage(TRUE, image, devpath_last(dev->devpath),
421 loaderbuf, loadersize, &loaderhandle)) != EFI_SUCCESS) {
422 printf("Failed to load image provided by %s, size: %zu, (%llu)\n",
423 mod->name, loadersize, status);
427 if ((status = bs->HandleProtocol(loaderhandle, &LoadedImageGUID,
428 (VOID**)&loaded_image)) != EFI_SUCCESS) {
429 printf("Failed to query LoadedImage provided by %s (%llu)\n",
435 printf(" command args: %s\n", cmd);
437 loaded_image->DeviceHandle = dev->devhandle;
438 loaded_image->LoadOptionsSize = cmdsize;
439 loaded_image->LoadOptions = cmd;
441 DPRINTF("Starting '%s' in 5 seconds...", PATH_LOADER_EFI);
453 if ((status = bs->StartImage(loaderhandle, NULL, NULL)) !=
455 printf("Failed to start image provided by %s (%llu)\n",
457 loaded_image->LoadOptionsSize = 0;
458 loaded_image->LoadOptions = NULL;
466 if (loaderbuf != NULL)
473 * probe_handle determines if the passed handle represents a logical partition
474 * if it does it uses each module in order to probe it and if successful it
475 * returns EFI_SUCCESS.
478 probe_handle(EFI_HANDLE h, EFI_DEVICE_PATH *imgpath, BOOLEAN *preferred)
482 EFI_DEVICE_PATH *devpath;
486 /* Figure out if we're dealing with an actual partition. */
487 status = bs->HandleProtocol(h, &DevicePathGUID, (void **)&devpath);
488 if (status == EFI_UNSUPPORTED)
491 if (status != EFI_SUCCESS) {
492 DPRINTF("\nFailed to query DevicePath (%llu)\n",
497 DPRINTF("probing: %s\n", devpath_str(devpath));
499 status = bs->HandleProtocol(h, &BlockIoProtocolGUID, (void **)&blkio);
500 if (status == EFI_UNSUPPORTED)
503 if (status != EFI_SUCCESS) {
504 DPRINTF("\nFailed to query BlockIoProtocol (%llu)\n",
509 if (!blkio->Media->LogicalPartition)
510 return (EFI_UNSUPPORTED);
512 *preferred = device_paths_match(imgpath, devpath);
514 /* Run through each module, see if it can load this partition */
515 for (i = 0; i < NUM_BOOT_MODULES; i++) {
516 if (boot_modules[i] == NULL)
519 if ((status = bs->AllocatePool(EfiLoaderData,
520 sizeof(*devinfo), (void **)&devinfo)) !=
522 DPRINTF("\nFailed to allocate devinfo (%llu)\n",
526 devinfo->dev = blkio;
527 devinfo->devpath = devpath;
528 devinfo->devhandle = h;
529 devinfo->devdata = NULL;
530 devinfo->preferred = *preferred;
531 devinfo->next = NULL;
533 status = boot_modules[i]->probe(devinfo);
534 if (status == EFI_SUCCESS)
535 return (EFI_SUCCESS);
536 (void)bs->FreePool(devinfo);
539 return (EFI_UNSUPPORTED);
543 * probe_handle_status calls probe_handle and outputs the returned status
547 probe_handle_status(EFI_HANDLE h, EFI_DEVICE_PATH *imgpath)
553 status = probe_handle(h, imgpath, &preferred);
557 case EFI_UNSUPPORTED:
559 DPRINTF(" not supported\n");
564 DPRINTF(" supported (preferred)\n");
567 DPRINTF(" supported\n");
572 DPRINTF(" error (%llu)\n", status);
579 efi_main(EFI_HANDLE Ximage, EFI_SYSTEM_TABLE *Xsystab)
582 EFI_LOADED_IMAGE *img;
583 EFI_DEVICE_PATH *imgpath;
585 EFI_CONSOLE_CONTROL_PROTOCOL *ConsoleControl = NULL;
586 SIMPLE_TEXT_OUTPUT_INTERFACE *conout = NULL;
587 UINTN i, max_dim, best_mode, cols, rows, hsize, nhandles;
589 /* Basic initialization*/
592 bs = Xsystab->BootServices;
594 /* Set up the console, so printf works. */
595 status = bs->LocateProtocol(&ConsoleControlGUID, NULL,
596 (VOID **)&ConsoleControl);
597 if (status == EFI_SUCCESS)
598 (void)ConsoleControl->SetMode(ConsoleControl,
599 EfiConsoleControlScreenText);
601 * Reset the console and find the best text mode.
603 conout = systab->ConOut;
604 conout->Reset(conout, TRUE);
605 max_dim = best_mode = 0;
607 status = conout->QueryMode(conout, i, &cols, &rows);
608 if (EFI_ERROR(status)) {
609 /* Mode 1 (80x50) can be unsupported on some hw. */
615 if (cols * rows > max_dim) {
616 max_dim = cols * rows;
621 conout->SetMode(conout, best_mode);
622 conout->EnableCursor(conout, TRUE);
623 conout->ClearScreen(conout);
625 printf("\n>> DragonFly EFI boot block\n");
626 printf(" Loader path: %s:%s\n\n", PATH_LOADER, PATH_LOADER_ALT);
627 printf(" Initializing modules:");
628 for (i = 0; i < NUM_BOOT_MODULES; i++) {
629 if (boot_modules[i] == NULL)
632 printf(" %s", boot_modules[i]->name);
633 if (boot_modules[i]->init != NULL)
634 boot_modules[i]->init();
638 /* Get all the device handles */
639 hsize = (UINTN)NUM_HANDLES_INIT * sizeof(EFI_HANDLE);
640 if ((status = bs->AllocatePool(EfiLoaderData, hsize, (void **)&handles))
642 panic("Failed to allocate %d handles (%llu)", NUM_HANDLES_INIT,
645 status = bs->LocateHandle(ByProtocol, &BlockIoProtocolGUID, NULL,
650 case EFI_BUFFER_TOO_SMALL:
651 (void)bs->FreePool(handles);
652 if ((status = bs->AllocatePool(EfiLoaderData, hsize,
653 (void **)&handles)) != EFI_SUCCESS) {
654 panic("Failed to allocate %llu handles (%llu)", hsize /
655 sizeof(*handles), status);
657 status = bs->LocateHandle(ByProtocol, &BlockIoProtocolGUID,
658 NULL, &hsize, handles);
659 if (status != EFI_SUCCESS)
660 panic("Failed to get device handles (%llu)\n",
664 panic("Failed to get device handles (%llu)",
668 /* Scan all partitions, probing with all modules. */
669 nhandles = hsize / sizeof(*handles);
670 printf(" Probing %llu block devices...", nhandles);
673 /* Determine the devpath of our image so we can prefer it. */
674 status = bs->HandleProtocol(image, &LoadedImageGUID, (VOID**)&img);
676 if (status == EFI_SUCCESS) {
677 status = bs->HandleProtocol(img->DeviceHandle, &DevicePathGUID,
679 if (status != EFI_SUCCESS)
680 DPRINTF("Failed to get image DevicePath (%llu)\n",
682 DPRINTF("boot1 imagepath: %s\n", devpath_str(imgpath));
685 for (i = 0; i < nhandles; i++)
686 probe_handle_status(handles[i], imgpath);
689 /* Status summary. */
690 for (i = 0; i < NUM_BOOT_MODULES; i++) {
691 if (boot_modules[i] != NULL) {
693 boot_modules[i]->status();
699 /* If we get here, we're out of luck... */
700 panic("No bootable partitions found!");
704 * add_device adds a device to the passed devinfo list.
707 add_device(dev_info_t **devinfop, dev_info_t *devinfo)
711 if (*devinfop == NULL) {
716 for (dev = *devinfop; dev->next != NULL; dev = dev->next)
723 panic(const char *fmt, ...)
744 systab->ConOut->OutputString(systab->ConOut, buf);
748 systab->ConOut->OutputString(systab->ConOut, buf);