libefi: Move EFI ZFS functions to libefi
[unleashed.git] / usr / src / boot / sys / boot / efi / boot1 / boot1.c
blob98fd3b00ffc626c43d5f4d768b25879eb10c5ed1
1 /*-
2 * Copyright (c) 1998 Robert Nordier
3 * All rights reserved.
4 * Copyright (c) 2001 Robert Drehmel
5 * All rights reserved.
6 * Copyright (c) 2014 Nathan Whitehorn
7 * All rights reserved.
8 * Copyright (c) 2015 Eric McCorkle
9 * All rights reserved.
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
14 * such forms.
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
19 * purpose.
22 #include <sys/cdefs.h>
24 #include <sys/param.h>
25 #include <machine/elf.h>
26 #include <machine/stdarg.h>
27 #include <stand.h>
29 #include <efi.h>
30 #include <eficonsctl.h>
32 #include <bootstrap.h>
33 #include "boot_module.h"
34 #include "paths.h"
36 struct arch_switch archsw;
37 struct fs_ops *file_system[] = {
38 NULL
41 static const boot_module_t *boot_modules[] =
43 &zfs_module,
44 &ufs_module
47 #define NUM_BOOT_MODULES nitems(boot_modules)
48 /* The initial number of handles used to query EFI for partitions. */
49 #define NUM_HANDLES_INIT 24
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 backed by EFIs AllocatePool / FreePool which ensures
58 * memory is correctly aligned avoiding EFI_INVALID_PARAMETER returns from
59 * EFI methods.
61 void *
62 Malloc(size_t len, const char *file __unused, int line __unused)
64 void *out;
66 if (BS->AllocatePool(EfiLoaderData, len, &out) == EFI_SUCCESS)
67 return (out);
69 return (NULL);
72 void
73 Free(void *buf, const char *file __unused, int line __unused)
75 if (buf != NULL)
76 (void)BS->FreePool(buf);
80 * nodes_match returns TRUE if the imgpath isn't NULL and the nodes match,
81 * FALSE otherwise.
83 static BOOLEAN
84 nodes_match(EFI_DEVICE_PATH *imgpath, EFI_DEVICE_PATH *devpath)
86 size_t len;
88 if (imgpath == NULL || imgpath->Type != devpath->Type ||
89 imgpath->SubType != devpath->SubType)
90 return (FALSE);
92 len = DevicePathNodeLength(imgpath);
93 if (len != DevicePathNodeLength(devpath))
94 return (FALSE);
96 return (memcmp(imgpath, devpath, (size_t)len) == 0);
100 * device_paths_match returns TRUE if the imgpath isn't NULL and all nodes
101 * in imgpath and devpath match up to their respective occurences of a
102 * media node, FALSE otherwise.
104 static BOOLEAN
105 device_paths_match(EFI_DEVICE_PATH *imgpath, EFI_DEVICE_PATH *devpath)
108 if (imgpath == NULL)
109 return (FALSE);
111 while (!IsDevicePathEnd(imgpath) && !IsDevicePathEnd(devpath)) {
112 if (IsDevicePathType(imgpath, MEDIA_DEVICE_PATH) &&
113 IsDevicePathType(devpath, MEDIA_DEVICE_PATH))
114 return (TRUE);
116 if (!nodes_match(imgpath, devpath))
117 return (FALSE);
119 imgpath = NextDevicePathNode(imgpath);
120 devpath = NextDevicePathNode(devpath);
123 return (FALSE);
127 * devpath_last returns the last non-path end node in devpath.
129 static EFI_DEVICE_PATH *
130 devpath_last(EFI_DEVICE_PATH *devpath)
133 while (!IsDevicePathEnd(NextDevicePathNode(devpath)))
134 devpath = NextDevicePathNode(devpath);
136 return (devpath);
140 * devpath_node_str is a basic output method for a devpath node which
141 * only understands a subset of the available sub types.
143 * If we switch to UEFI 2.x then we should update it to use:
144 * EFI_DEVICE_PATH_TO_TEXT_PROTOCOL.
146 static int
147 devpath_node_str(char *buf, size_t size, EFI_DEVICE_PATH *devpath)
150 switch (devpath->Type) {
151 case MESSAGING_DEVICE_PATH:
152 switch (devpath->SubType) {
153 case MSG_ATAPI_DP: {
154 ATAPI_DEVICE_PATH *atapi;
156 atapi = (ATAPI_DEVICE_PATH *)(void *)devpath;
157 return snprintf(buf, size, "ata(%s,%s,0x%x)",
158 (atapi->PrimarySecondary == 1) ? "Sec" : "Pri",
159 (atapi->SlaveMaster == 1) ? "Slave" : "Master",
160 atapi->Lun);
162 case MSG_USB_DP: {
163 USB_DEVICE_PATH *usb;
165 usb = (USB_DEVICE_PATH *)devpath;
166 return snprintf(buf, size, "usb(0x%02x,0x%02x)",
167 usb->ParentPortNumber, usb->InterfaceNumber);
169 case MSG_SCSI_DP: {
170 SCSI_DEVICE_PATH *scsi;
172 scsi = (SCSI_DEVICE_PATH *)(void *)devpath;
173 return snprintf(buf, size, "scsi(0x%02x,0x%02x)",
174 scsi->Pun, scsi->Lun);
176 case MSG_SATA_DP: {
177 SATA_DEVICE_PATH *sata;
179 sata = (SATA_DEVICE_PATH *)(void *)devpath;
180 return snprintf(buf, size, "sata(0x%x,0x%x,0x%x)",
181 sata->HBAPortNumber, sata->PortMultiplierPortNumber,
182 sata->Lun);
184 default:
185 return snprintf(buf, size, "msg(0x%02x)",
186 devpath->SubType);
188 break;
189 case HARDWARE_DEVICE_PATH:
190 switch (devpath->SubType) {
191 case HW_PCI_DP: {
192 PCI_DEVICE_PATH *pci;
194 pci = (PCI_DEVICE_PATH *)devpath;
195 return snprintf(buf, size, "pci(0x%02x,0x%02x)",
196 pci->Device, pci->Function);
198 default:
199 return snprintf(buf, size, "hw(0x%02x)",
200 devpath->SubType);
202 break;
203 case ACPI_DEVICE_PATH: {
204 ACPI_HID_DEVICE_PATH *acpi;
206 acpi = (ACPI_HID_DEVICE_PATH *)(void *)devpath;
207 if ((acpi->HID & PNP_EISA_ID_MASK) == PNP_EISA_ID_CONST) {
208 switch (EISA_ID_TO_NUM(acpi->HID)) {
209 case 0x0a03:
210 return snprintf(buf, size, "pciroot(0x%x)",
211 acpi->UID);
212 case 0x0a08:
213 return snprintf(buf, size, "pcieroot(0x%x)",
214 acpi->UID);
215 case 0x0604:
216 return snprintf(buf, size, "floppy(0x%x)",
217 acpi->UID);
218 case 0x0301:
219 return snprintf(buf, size, "keyboard(0x%x)",
220 acpi->UID);
221 case 0x0501:
222 return snprintf(buf, size, "serial(0x%x)",
223 acpi->UID);
224 case 0x0401:
225 return snprintf(buf, size, "parallelport(0x%x)",
226 acpi->UID);
227 default:
228 return snprintf(buf, size, "acpi(pnp%04x,0x%x)",
229 EISA_ID_TO_NUM(acpi->HID), acpi->UID);
233 return snprintf(buf, size, "acpi(0x%08x,0x%x)", acpi->HID,
234 acpi->UID);
236 case MEDIA_DEVICE_PATH:
237 switch (devpath->SubType) {
238 case MEDIA_CDROM_DP: {
239 CDROM_DEVICE_PATH *cdrom;
241 cdrom = (CDROM_DEVICE_PATH *)(void *)devpath;
242 return snprintf(buf, size, "cdrom(%x)",
243 cdrom->BootEntry);
245 case MEDIA_HARDDRIVE_DP: {
246 HARDDRIVE_DEVICE_PATH *hd;
248 hd = (HARDDRIVE_DEVICE_PATH *)(void *)devpath;
249 return snprintf(buf, size, "hd(%x)",
250 hd->PartitionNumber);
252 default:
253 return snprintf(buf, size, "media(0x%02x)",
254 devpath->SubType);
256 case BBS_DEVICE_PATH:
257 return snprintf(buf, size, "bbs(0x%02x)", devpath->SubType);
258 case END_DEVICE_PATH_TYPE:
259 return (0);
262 return snprintf(buf, size, "type(0x%02x, 0x%02x)", devpath->Type,
263 devpath->SubType);
267 * devpath_strlcat appends a text description of devpath to buf but not more
268 * than size - 1 characters followed by NUL-terminator.
271 devpath_strlcat(char *buf, size_t size, EFI_DEVICE_PATH *devpath)
273 size_t len, used;
274 const char *sep;
276 sep = "";
277 used = 0;
278 while (!IsDevicePathEnd(devpath)) {
279 len = snprintf(buf, size - used, "%s", sep);
280 used += len;
281 if (used > size)
282 return (used);
283 buf += len;
285 len = devpath_node_str(buf, size - used, devpath);
286 used += len;
287 if (used > size)
288 return (used);
289 buf += len;
290 devpath = NextDevicePathNode(devpath);
291 sep = ":";
294 return (used);
298 * devpath_str is convenience method which returns the text description of
299 * devpath using a static buffer, so it isn't thread safe!
301 char *
302 devpath_str(EFI_DEVICE_PATH *devpath)
304 static char buf[256];
306 devpath_strlcat(buf, sizeof(buf), devpath);
308 return buf;
312 * load_loader attempts to load the loader image data.
314 * It tries each module and its respective devices, identified by mod->probe,
315 * in order until a successful load occurs at which point it returns EFI_SUCCESS
316 * and EFI_NOT_FOUND otherwise.
318 * Only devices which have preferred matching the preferred parameter are tried.
320 static EFI_STATUS
321 load_loader(const boot_module_t **modp, dev_info_t **devinfop, void **bufp,
322 size_t *bufsize, BOOLEAN preferred)
324 UINTN i;
325 dev_info_t *dev;
326 const boot_module_t *mod;
328 for (i = 0; i < NUM_BOOT_MODULES; i++) {
329 mod = boot_modules[i];
330 for (dev = mod->devices(); dev != NULL; dev = dev->next) {
331 if (dev->preferred != preferred)
332 continue;
334 if (mod->load(PATH_LOADER_EFI, dev, bufp, bufsize) ==
335 EFI_SUCCESS) {
336 *devinfop = dev;
337 *modp = mod;
338 return (EFI_SUCCESS);
343 return (EFI_NOT_FOUND);
347 * try_boot only returns if it fails to load the loader. If it succeeds
348 * it simply boots, otherwise it returns the status of last EFI call.
350 static EFI_STATUS
351 try_boot(void)
353 size_t bufsize, loadersize, cmdsize;
354 void *buf, *loaderbuf;
355 char *cmd;
356 dev_info_t *dev;
357 const boot_module_t *mod;
358 EFI_HANDLE loaderhandle;
359 EFI_LOADED_IMAGE *loaded_image;
360 EFI_STATUS status;
362 status = load_loader(&mod, &dev, &loaderbuf, &loadersize, TRUE);
363 if (status != EFI_SUCCESS) {
364 status = load_loader(&mod, &dev, &loaderbuf, &loadersize,
365 FALSE);
366 if (status != EFI_SUCCESS) {
367 printf("Failed to load '%s'\n", PATH_LOADER_EFI);
368 return (status);
373 * Read in and parse the command line from /boot.config or /boot/config,
374 * if present. We'll pass it the next stage via a simple ASCII
375 * string. loader.efi has a hack for ASCII strings, so we'll use that to
376 * keep the size down here. We only try to read the alternate file if
377 * we get EFI_NOT_FOUND because all other errors mean that the boot_module
378 * had troubles with the filesystem. We could return early, but we'll let
379 * loading the actual kernel sort all that out. Since these files are
380 * optional, we don't report errors in trying to read them.
382 cmd = NULL;
383 cmdsize = 0;
384 status = mod->load(PATH_DOTCONFIG, dev, &buf, &bufsize);
385 if (status == EFI_NOT_FOUND)
386 status = mod->load(PATH_CONFIG, dev, &buf, &bufsize);
387 if (status == EFI_SUCCESS) {
388 cmdsize = bufsize + 1;
389 cmd = malloc(cmdsize);
390 if (cmd == NULL)
391 goto errout;
392 memcpy(cmd, buf, bufsize);
393 cmd[bufsize] = '\0';
394 free(buf);
395 buf = NULL;
398 if ((status = BS->LoadImage(TRUE, IH, devpath_last(dev->devpath),
399 loaderbuf, loadersize, &loaderhandle)) != EFI_SUCCESS) {
400 printf("Failed to load image provided by %s, size: %zu, (%lu)\n",
401 mod->name, loadersize, EFI_ERROR_CODE(status));
402 goto errout;
405 if ((status = BS->HandleProtocol(loaderhandle, &LoadedImageGUID,
406 (VOID**)&loaded_image)) != EFI_SUCCESS) {
407 printf("Failed to query LoadedImage provided by %s (%lu)\n",
408 mod->name, EFI_ERROR_CODE(status));
409 goto errout;
412 if (cmd != NULL)
413 printf(" command args: %s\n", cmd);
415 loaded_image->DeviceHandle = dev->devhandle;
416 loaded_image->LoadOptionsSize = cmdsize;
417 loaded_image->LoadOptions = cmd;
419 DPRINTF("Starting '%s' in 5 seconds...", PATH_LOADER_EFI);
420 DSTALL(1000000);
421 DPRINTF(".");
422 DSTALL(1000000);
423 DPRINTF(".");
424 DSTALL(1000000);
425 DPRINTF(".");
426 DSTALL(1000000);
427 DPRINTF(".");
428 DSTALL(1000000);
429 DPRINTF(".\n");
431 if ((status = BS->StartImage(loaderhandle, NULL, NULL)) !=
432 EFI_SUCCESS) {
433 printf("Failed to start image provided by %s (%lu)\n",
434 mod->name, EFI_ERROR_CODE(status));
435 loaded_image->LoadOptionsSize = 0;
436 loaded_image->LoadOptions = NULL;
439 errout:
440 if (cmd != NULL)
441 free(cmd);
442 if (buf != NULL)
443 free(buf);
444 if (loaderbuf != NULL)
445 free(loaderbuf);
447 return (status);
451 * probe_handle determines if the passed handle represents a logical partition
452 * if it does it uses each module in order to probe it and if successful it
453 * returns EFI_SUCCESS.
455 static EFI_STATUS
456 probe_handle(EFI_HANDLE h, EFI_DEVICE_PATH *imgpath, BOOLEAN *preferred)
458 dev_info_t *devinfo;
459 EFI_BLOCK_IO *blkio;
460 EFI_DEVICE_PATH *devpath;
461 EFI_STATUS status;
462 UINTN i;
464 /* Figure out if we're dealing with an actual partition. */
465 status = BS->HandleProtocol(h, &DevicePathGUID, (void **)&devpath);
466 if (status == EFI_UNSUPPORTED)
467 return (status);
469 if (status != EFI_SUCCESS) {
470 DPRINTF("\nFailed to query DevicePath (%lu)\n",
471 EFI_ERROR_CODE(status));
472 return (status);
475 DPRINTF("probing: %s\n", devpath_str(devpath));
477 status = BS->HandleProtocol(h, &BlockIoProtocolGUID, (void **)&blkio);
478 if (status == EFI_UNSUPPORTED)
479 return (status);
481 if (status != EFI_SUCCESS) {
482 DPRINTF("\nFailed to query BlockIoProtocol (%lu)\n",
483 EFI_ERROR_CODE(status));
484 return (status);
487 if (!blkio->Media->LogicalPartition)
488 return (EFI_UNSUPPORTED);
490 *preferred = device_paths_match(imgpath, devpath);
492 /* Run through each module, see if it can load this partition */
493 for (i = 0; i < NUM_BOOT_MODULES; i++) {
494 if ((status = BS->AllocatePool(EfiLoaderData,
495 sizeof(*devinfo), (void **)&devinfo)) !=
496 EFI_SUCCESS) {
497 DPRINTF("\nFailed to allocate devinfo (%lu)\n",
498 EFI_ERROR_CODE(status));
499 continue;
501 devinfo->dev = blkio;
502 devinfo->devpath = devpath;
503 devinfo->devhandle = h;
504 devinfo->devdata = NULL;
505 devinfo->preferred = *preferred;
506 devinfo->next = NULL;
508 status = boot_modules[i]->probe(devinfo);
509 if (status == EFI_SUCCESS)
510 return (EFI_SUCCESS);
511 (void)BS->FreePool(devinfo);
514 return (EFI_UNSUPPORTED);
518 * probe_handle_status calls probe_handle and outputs the returned status
519 * of the call.
521 static void
522 probe_handle_status(EFI_HANDLE h, EFI_DEVICE_PATH *imgpath)
524 EFI_STATUS status;
525 BOOLEAN preferred = false;
527 status = probe_handle(h, imgpath, &preferred);
529 DPRINTF("probe: ");
530 switch (status) {
531 case EFI_UNSUPPORTED:
532 printf(".");
533 DPRINTF(" not supported\n");
534 break;
535 case EFI_SUCCESS:
536 if (preferred) {
537 printf("%c", '*');
538 DPRINTF(" supported (preferred)\n");
539 } else {
540 printf("%c", '+');
541 DPRINTF(" supported\n");
543 break;
544 default:
545 printf("x");
546 DPRINTF(" error (%lu)\n", EFI_ERROR_CODE(status));
547 break;
549 DSTALL(500000);
552 EFI_STATUS
553 efi_main(EFI_HANDLE Ximage, EFI_SYSTEM_TABLE *Xsystab)
555 EFI_HANDLE *handles;
556 EFI_LOADED_IMAGE *img;
557 EFI_DEVICE_PATH *imgpath;
558 EFI_STATUS status;
559 EFI_CONSOLE_CONTROL_PROTOCOL *ConsoleControl = NULL;
560 SIMPLE_TEXT_OUTPUT_INTERFACE *conout = NULL;
561 UINTN i, max_dim, best_mode, cols, rows, hsize, nhandles;
563 /* Basic initialization*/
564 ST = Xsystab;
565 IH = Ximage;
566 BS = Xsystab->BootServices;
567 RS = Xsystab->RuntimeServices;
569 /* Set up the console, so printf works. */
570 status = BS->LocateProtocol(&ConsoleControlGUID, NULL,
571 (VOID **)&ConsoleControl);
572 if (status == EFI_SUCCESS)
573 (void)ConsoleControl->SetMode(ConsoleControl,
574 EfiConsoleControlScreenText);
576 * Reset the console and find the best text mode.
578 conout = ST->ConOut;
579 conout->Reset(conout, TRUE);
580 max_dim = best_mode = 0;
581 for (i = 0; ; i++) {
582 status = conout->QueryMode(conout, i, &cols, &rows);
583 if (EFI_ERROR(status))
584 break;
585 if (cols * rows > max_dim) {
586 max_dim = cols * rows;
587 best_mode = i;
590 if (max_dim > 0)
591 conout->SetMode(conout, best_mode);
592 conout->EnableCursor(conout, TRUE);
593 conout->ClearScreen(conout);
595 printf("\n>> illumos EFI boot block\n");
596 printf(" Loader path: %s\n\n", PATH_LOADER_EFI);
597 printf(" Initializing modules:");
598 for (i = 0; i < NUM_BOOT_MODULES; i++) {
599 printf(" %s", boot_modules[i]->name);
600 if (boot_modules[i]->init != NULL)
601 boot_modules[i]->init();
603 putchar('\n');
605 /* Get all the device handles */
606 hsize = (UINTN)NUM_HANDLES_INIT * sizeof(EFI_HANDLE);
607 if ((status = BS->AllocatePool(EfiLoaderData, hsize, (void **)&handles))
608 != EFI_SUCCESS)
609 panic("Failed to allocate %d handles (%lu)", NUM_HANDLES_INIT,
610 EFI_ERROR_CODE(status));
612 status = BS->LocateHandle(ByProtocol, &BlockIoProtocolGUID, NULL,
613 &hsize, handles);
614 switch (status) {
615 case EFI_SUCCESS:
616 break;
617 case EFI_BUFFER_TOO_SMALL:
618 (void)BS->FreePool(handles);
619 if ((status = BS->AllocatePool(EfiLoaderData, hsize,
620 (void **)&handles)) != EFI_SUCCESS) {
621 panic("Failed to allocate %zu handles (%lu)", hsize /
622 sizeof(*handles), EFI_ERROR_CODE(status));
624 status = BS->LocateHandle(ByProtocol, &BlockIoProtocolGUID,
625 NULL, &hsize, handles);
626 if (status != EFI_SUCCESS)
627 panic("Failed to get device handles (%lu)\n",
628 EFI_ERROR_CODE(status));
629 break;
630 default:
631 panic("Failed to get device handles (%lu)",
632 EFI_ERROR_CODE(status));
635 /* Scan all partitions, probing with all modules. */
636 nhandles = hsize / sizeof(*handles);
637 printf(" Probing %zu block devices...", nhandles);
638 DPRINTF("\n");
640 /* Determine the devpath of our image so we can prefer it. */
641 status = BS->HandleProtocol(IH, &LoadedImageGUID, (VOID**)&img);
642 imgpath = NULL;
643 if (status == EFI_SUCCESS) {
644 status = BS->HandleProtocol(img->DeviceHandle, &DevicePathGUID,
645 (void **)&imgpath);
646 if (status != EFI_SUCCESS)
647 DPRINTF("Failed to get image DevicePath (%lu)\n",
648 EFI_ERROR_CODE(status));
649 DPRINTF("boot1 imagepath: %s\n", devpath_str(imgpath));
652 for (i = 0; i < nhandles; i++)
653 probe_handle_status(handles[i], imgpath);
654 printf(" done\n");
656 /* Status summary. */
657 for (i = 0; i < NUM_BOOT_MODULES; i++) {
658 printf(" ");
659 boot_modules[i]->status();
662 try_boot();
664 /* If we get here, we're out of luck... */
665 panic("No bootable partitions found!");
669 * add_device adds a device to the passed devinfo list.
671 void
672 add_device(dev_info_t **devinfop, dev_info_t *devinfo)
674 dev_info_t *dev;
676 if (*devinfop == NULL) {
677 *devinfop = devinfo;
678 return;
681 for (dev = *devinfop; dev->next != NULL; dev = dev->next)
684 dev->next = devinfo;
687 void
688 panic(const char *fmt, ...)
690 va_list ap;
692 printf("panic: ");
693 va_start(ap, fmt);
694 vprintf(fmt, ap);
695 va_end(ap);
696 printf("\n");
698 while (1) {}
701 void
702 putchar(int c)
704 CHAR16 buf[2];
706 if (c == '\n') {
707 buf[0] = '\r';
708 buf[1] = 0;
709 ST->ConOut->OutputString(ST->ConOut, buf);
711 buf[0] = c;
712 buf[1] = 0;
713 ST->ConOut->OutputString(ST->ConOut, buf);
717 getchar(void)
719 EFI_INPUT_KEY key;
720 EFI_STATUS status;
721 UINTN junk;
723 status = ST->ConIn->ReadKeyStroke(ST->ConIn, &key);
724 if (status == EFI_NOT_READY) {
725 BS->WaitForEvent(1, &ST->ConIn->WaitForKey, &junk);
726 status = ST->ConIn->ReadKeyStroke(ST->ConIn, &key);
728 return (key.UnicodeChar);