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
);