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>
24 #include <sys/param.h>
25 #include <machine/elf.h>
26 #include <machine/stdarg.h>
30 #include <eficonsctl.h>
32 #include <bootstrap.h>
33 #include "boot_module.h"
36 struct arch_switch archsw
;
37 struct fs_ops
*file_system
[] = {
41 static const boot_module_t
*boot_modules
[] =
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
62 Malloc(size_t len
, const char *file __unused
, int line __unused
)
66 if (BS
->AllocatePool(EfiLoaderData
, len
, &out
) == EFI_SUCCESS
)
73 Free(void *buf
, const char *file __unused
, int line __unused
)
76 (void)BS
->FreePool(buf
);
80 * nodes_match returns TRUE if the imgpath isn't NULL and the nodes match,
84 nodes_match(EFI_DEVICE_PATH
*imgpath
, EFI_DEVICE_PATH
*devpath
)
88 if (imgpath
== NULL
|| imgpath
->Type
!= devpath
->Type
||
89 imgpath
->SubType
!= devpath
->SubType
)
92 len
= DevicePathNodeLength(imgpath
);
93 if (len
!= DevicePathNodeLength(devpath
))
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.
105 device_paths_match(EFI_DEVICE_PATH
*imgpath
, EFI_DEVICE_PATH
*devpath
)
111 while (!IsDevicePathEnd(imgpath
) && !IsDevicePathEnd(devpath
)) {
112 if (IsDevicePathType(imgpath
, MEDIA_DEVICE_PATH
) &&
113 IsDevicePathType(devpath
, MEDIA_DEVICE_PATH
))
116 if (!nodes_match(imgpath
, devpath
))
119 imgpath
= NextDevicePathNode(imgpath
);
120 devpath
= NextDevicePathNode(devpath
);
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
);
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.
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
) {
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",
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
);
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
);
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
,
185 return snprintf(buf
, size
, "msg(0x%02x)",
189 case HARDWARE_DEVICE_PATH
:
190 switch (devpath
->SubType
) {
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
);
199 return snprintf(buf
, size
, "hw(0x%02x)",
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
)) {
210 return snprintf(buf
, size
, "pciroot(0x%x)",
213 return snprintf(buf
, size
, "pcieroot(0x%x)",
216 return snprintf(buf
, size
, "floppy(0x%x)",
219 return snprintf(buf
, size
, "keyboard(0x%x)",
222 return snprintf(buf
, size
, "serial(0x%x)",
225 return snprintf(buf
, size
, "parallelport(0x%x)",
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
,
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)",
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
);
253 return snprintf(buf
, size
, "media(0x%02x)",
256 case BBS_DEVICE_PATH
:
257 return snprintf(buf
, size
, "bbs(0x%02x)", devpath
->SubType
);
258 case END_DEVICE_PATH_TYPE
:
262 return snprintf(buf
, size
, "type(0x%02x, 0x%02x)", devpath
->Type
,
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
)
278 while (!IsDevicePathEnd(devpath
)) {
279 len
= snprintf(buf
, size
- used
, "%s", sep
);
285 len
= devpath_node_str(buf
, size
- used
, devpath
);
290 devpath
= NextDevicePathNode(devpath
);
298 * devpath_str is convenience method which returns the text description of
299 * devpath using a static buffer, so it isn't thread safe!
302 devpath_str(EFI_DEVICE_PATH
*devpath
)
304 static char buf
[256];
306 devpath_strlcat(buf
, sizeof(buf
), devpath
);
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.
321 load_loader(const boot_module_t
**modp
, dev_info_t
**devinfop
, void **bufp
,
322 size_t *bufsize
, BOOLEAN preferred
)
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
)
334 if (mod
->load(PATH_LOADER_EFI
, dev
, bufp
, bufsize
) ==
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.
353 size_t bufsize
, loadersize
, cmdsize
;
354 void *buf
, *loaderbuf
;
357 const boot_module_t
*mod
;
358 EFI_HANDLE loaderhandle
;
359 EFI_LOADED_IMAGE
*loaded_image
;
362 status
= load_loader(&mod
, &dev
, &loaderbuf
, &loadersize
, TRUE
);
363 if (status
!= EFI_SUCCESS
) {
364 status
= load_loader(&mod
, &dev
, &loaderbuf
, &loadersize
,
366 if (status
!= EFI_SUCCESS
) {
367 printf("Failed to load '%s'\n", PATH_LOADER_EFI
);
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.
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
);
392 memcpy(cmd
, buf
, bufsize
);
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
));
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
));
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
);
431 if ((status
= BS
->StartImage(loaderhandle
, NULL
, NULL
)) !=
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
;
444 if (loaderbuf
!= NULL
)
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.
456 probe_handle(EFI_HANDLE h
, EFI_DEVICE_PATH
*imgpath
, BOOLEAN
*preferred
)
460 EFI_DEVICE_PATH
*devpath
;
464 /* Figure out if we're dealing with an actual partition. */
465 status
= BS
->HandleProtocol(h
, &DevicePathGUID
, (void **)&devpath
);
466 if (status
== EFI_UNSUPPORTED
)
469 if (status
!= EFI_SUCCESS
) {
470 DPRINTF("\nFailed to query DevicePath (%lu)\n",
471 EFI_ERROR_CODE(status
));
475 DPRINTF("probing: %s\n", devpath_str(devpath
));
477 status
= BS
->HandleProtocol(h
, &BlockIoProtocolGUID
, (void **)&blkio
);
478 if (status
== EFI_UNSUPPORTED
)
481 if (status
!= EFI_SUCCESS
) {
482 DPRINTF("\nFailed to query BlockIoProtocol (%lu)\n",
483 EFI_ERROR_CODE(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
)) !=
497 DPRINTF("\nFailed to allocate devinfo (%lu)\n",
498 EFI_ERROR_CODE(status
));
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
522 probe_handle_status(EFI_HANDLE h
, EFI_DEVICE_PATH
*imgpath
)
525 BOOLEAN preferred
= false;
527 status
= probe_handle(h
, imgpath
, &preferred
);
531 case EFI_UNSUPPORTED
:
533 DPRINTF(" not supported\n");
538 DPRINTF(" supported (preferred)\n");
541 DPRINTF(" supported\n");
546 DPRINTF(" error (%lu)\n", EFI_ERROR_CODE(status
));
553 efi_main(EFI_HANDLE Ximage
, EFI_SYSTEM_TABLE
*Xsystab
)
556 EFI_LOADED_IMAGE
*img
;
557 EFI_DEVICE_PATH
*imgpath
;
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*/
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.
579 conout
->Reset(conout
, TRUE
);
580 max_dim
= best_mode
= 0;
582 status
= conout
->QueryMode(conout
, i
, &cols
, &rows
);
583 if (EFI_ERROR(status
))
585 if (cols
* rows
> max_dim
) {
586 max_dim
= cols
* rows
;
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();
605 /* Get all the device handles */
606 hsize
= (UINTN
)NUM_HANDLES_INIT
* sizeof(EFI_HANDLE
);
607 if ((status
= BS
->AllocatePool(EfiLoaderData
, hsize
, (void **)&handles
))
609 panic("Failed to allocate %d handles (%lu)", NUM_HANDLES_INIT
,
610 EFI_ERROR_CODE(status
));
612 status
= BS
->LocateHandle(ByProtocol
, &BlockIoProtocolGUID
, NULL
,
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
));
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
);
640 /* Determine the devpath of our image so we can prefer it. */
641 status
= BS
->HandleProtocol(IH
, &LoadedImageGUID
, (VOID
**)&img
);
643 if (status
== EFI_SUCCESS
) {
644 status
= BS
->HandleProtocol(img
->DeviceHandle
, &DevicePathGUID
,
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
);
656 /* Status summary. */
657 for (i
= 0; i
< NUM_BOOT_MODULES
; i
++) {
659 boot_modules
[i
]->status();
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.
672 add_device(dev_info_t
**devinfop
, dev_info_t
*devinfo
)
676 if (*devinfop
== NULL
) {
681 for (dev
= *devinfop
; dev
->next
!= NULL
; dev
= dev
->next
)
688 panic(const char *fmt
, ...)
709 ST
->ConOut
->OutputString(ST
->ConOut
, buf
);
713 ST
->ConOut
->OutputString(ST
->ConOut
, buf
);
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
);