/*-
* Copyright (c) 1998 Robert Nordier
* All rights reserved.
* Copyright (c) 2001 Robert Drehmel
* All rights reserved.
* Copyright (c) 2014 Nathan Whitehorn
* All rights reserved.
* Copyright (c) 2015 Eric McCorkle
* All rights reserved.
*
* Redistribution and use in source and binary forms are freely
* permitted provided that the above copyright notice and this
* paragraph and the following disclaimer are duplicated in all
* such forms.
*
* This software is provided "AS IS" and without any express or
* implied warranties, including, without limitation, the implied
* warranties of merchantability and fitness for a particular
* purpose.
*/
__FBSDID("$FreeBSD$");
#include <stand.h>
#include <efi.h>
#include <eficonsctl.h>
#include <bootstrap.h>
#include "boot_module.h"
#include "paths.h"
};
{
#ifdef EFI_ZFS_BOOT
#endif
#ifdef EFI_UFS_BOOT
#endif
};
/* The initial number of handles used to query EFI for partitions. */
/*
* Provide Malloc / Free backed by EFIs AllocatePool / FreePool which ensures
* memory is correctly aligned avoiding EFI_INVALID_PARAMETER returns from
* EFI methods.
*/
void *
{
void *out;
return (out);
return (NULL);
}
void
{
}
/*
* nodes_match returns TRUE if the imgpath isn't NULL and the nodes match,
* FALSE otherwise.
*/
static BOOLEAN
{
int len;
return (FALSE);
return (FALSE);
}
/*
* device_paths_match returns TRUE if the imgpath isn't NULL and all nodes
* in imgpath and devpath match up to their respect occurances of a media
* node, FALSE otherwise.
*/
static BOOLEAN
{
return (FALSE);
return (TRUE);
return (FALSE);
}
return (FALSE);
}
/*
* devpath_last returns the last non-path end node in devpath.
*/
static EFI_DEVICE_PATH *
{
return (devpath);
}
/*
* devpath_node_str is a basic output method for a devpath node which
* only understands a subset of the available sub types.
*
* If we switch to UEFI 2.x then we should update it to use:
* EFI_DEVICE_PATH_TO_TEXT_PROTOCOL.
*/
static int
{
case MESSAGING_DEVICE_PATH:
case MSG_ATAPI_DP: {
}
case MSG_USB_DP: {
}
case MSG_SCSI_DP: {
}
case MSG_SATA_DP: {
}
default:
}
break;
case HARDWARE_DEVICE_PATH:
case HW_PCI_DP: {
}
default:
}
break;
case ACPI_DEVICE_PATH: {
case 0x0a03:
case 0x0a08:
case 0x0604:
case 0x0301:
case 0x0501:
case 0x0401:
default:
}
}
}
case MEDIA_DEVICE_PATH:
case MEDIA_CDROM_DP: {
}
case MEDIA_HARDDRIVE_DP: {
}
default:
}
case BBS_DEVICE_PATH:
case END_DEVICE_PATH_TYPE:
return (0);
}
}
/*
* devpath_strlcat appends a text description of devpath to buf but not more
* than size - 1 characters followed by NUL-terminator.
*/
int
{
const char *sep;
sep = "";
used = 0;
while (!IsDevicePathEnd(devpath)) {
return (used);
return (used);
sep = ":";
}
return (used);
}
/*
* devpath_str is convenience method which returns the text description of
* devpath using a static buffer, so it isn't thread safe!
*/
char *
{
return buf;
}
/*
* load_loader attempts to load the loader image data.
*
* It tries each module and its respective devices, identified by mod->probe,
* in order until a successful load occurs at which point it returns EFI_SUCCESS
* and EFI_NOT_FOUND otherwise.
*
* Only devices which have preferred matching the preferred parameter are tried.
*/
static EFI_STATUS
{
UINTN i;
for (i = 0; i < NUM_BOOT_MODULES; i++) {
if (boot_modules[i] == NULL)
continue;
mod = boot_modules[i];
continue;
EFI_SUCCESS) {
return (EFI_SUCCESS);
}
}
}
return (EFI_NOT_FOUND);
}
/*
* try_boot only returns if it fails to load the loader. If it succeeds
* it simply boots, otherwise it returns the status of last EFI call.
*/
static EFI_STATUS
try_boot(void)
{
char *cmd;
if (status != EFI_SUCCESS) {
FALSE);
if (status != EFI_SUCCESS) {
return (status);
}
}
/*
* if present. We'll pass it the next stage via a simple ASCII
* string. loader.efi has a hack for ASCII strings, so we'll use that to
* keep the size down here. We only try to read the alternate file if
* we get EFI_NOT_FOUND because all other errors mean that the boot_module
* had troubles with the filesystem. We could return early, but we'll let
* loading the actual kernel sort all that out. Since these files are
* optional, we don't report errors in trying to read them.
*/
cmdsize = 0;
if (status == EFI_NOT_FOUND)
if (status == EFI_SUCCESS) {
goto errout;
}
printf("Failed to load image provided by %s, size: %zu, (%lu)\n",
goto errout;
}
printf("Failed to query LoadedImage provided by %s (%lu)\n",
goto errout;
}
DSTALL(1000000);
DPRINTF(".");
DSTALL(1000000);
DPRINTF(".");
DSTALL(1000000);
DPRINTF(".");
DSTALL(1000000);
DPRINTF(".");
DSTALL(1000000);
DPRINTF(".\n");
EFI_SUCCESS) {
printf("Failed to start image provided by %s (%lu)\n",
loaded_image->LoadOptionsSize = 0;
}
return (status);
}
/*
* probe_handle determines if the passed handle represents a logical partition
* if it does it uses each module in order to probe it and if successful it
* returns EFI_SUCCESS.
*/
static EFI_STATUS
{
UINTN i;
/* Figure out if we're dealing with an actual partition. */
if (status == EFI_UNSUPPORTED)
return (status);
if (status != EFI_SUCCESS) {
DPRINTF("\nFailed to query DevicePath (%lu)\n",
return (status);
}
if (status == EFI_UNSUPPORTED)
return (status);
if (status != EFI_SUCCESS) {
DPRINTF("\nFailed to query BlockIoProtocol (%lu)\n",
return (status);
}
return (EFI_UNSUPPORTED);
/* Run through each module, see if it can load this partition */
for (i = 0; i < NUM_BOOT_MODULES; i++) {
if (boot_modules[i] == NULL)
continue;
EFI_SUCCESS) {
DPRINTF("\nFailed to allocate devinfo (%lu)\n",
continue;
}
if (status == EFI_SUCCESS)
return (EFI_SUCCESS);
}
return (EFI_UNSUPPORTED);
}
/*
* probe_handle_status calls probe_handle and outputs the returned status
* of the call.
*/
static void
{
DPRINTF("probe: ");
switch (status) {
case EFI_UNSUPPORTED:
printf(".");
DPRINTF(" not supported\n");
break;
case EFI_SUCCESS:
if (preferred) {
DPRINTF(" supported (preferred)\n");
} else {
DPRINTF(" supported\n");
}
break;
default:
printf("x");
break;
}
DSTALL(500000);
}
{
/* Basic initialization*/
/* Set up the console, so printf works. */
(VOID **)&ConsoleControl);
if (status == EFI_SUCCESS)
/*
* Reset the console and find the best text mode.
*/
for (i = 0; ; i++) {
break;
best_mode = i;
}
}
if (max_dim > 0)
printf("\n>> illumos EFI boot block\n");
printf(" Initializing modules:");
for (i = 0; i < NUM_BOOT_MODULES; i++) {
if (boot_modules[i] == NULL)
continue;
boot_modules[i]->init();
}
putchar('\n');
/* Get all the device handles */
!= EFI_SUCCESS)
switch (status) {
case EFI_SUCCESS:
break;
case EFI_BUFFER_TOO_SMALL:
(void **)&handles) != EFI_SUCCESS)) {
}
if (status != EFI_SUCCESS)
panic("Failed to get device handles (%lu)\n",
break;
default:
panic("Failed to get device handles (%lu)",
}
/* Scan all partitions, probing with all modules. */
DPRINTF("\n");
/* Determine the devpath of our image so we can prefer it. */
if (status == EFI_SUCCESS) {
(void **)&imgpath);
if (status != EFI_SUCCESS)
DPRINTF("Failed to get image DevicePath (%lu)\n",
}
for (i = 0; i < nhandles; i++)
printf(" done\n");
/* Status summary. */
for (i = 0; i < NUM_BOOT_MODULES; i++) {
if (boot_modules[i] != NULL) {
printf(" ");
boot_modules[i]->status();
}
}
try_boot();
/* If we get here, we're out of luck... */
panic("No bootable partitions found!");
}
/*
* add_device adds a device to the passed devinfo list.
*/
void
{
return;
}
;
}
void
{
printf("panic: ");
printf("\n");
while (1) {}
}
void
putchar(int c)
{
if (c == '\n') {
buf[0] = '\r';
buf[1] = 0;
}
buf[0] = c;
buf[1] = 0;
}
int
getchar(void)
{
if (status == EFI_NOT_READY) {
}
return (key.UnicodeChar);
}