Changeset View
Changeset View
Standalone View
Standalone View
sys/boot/efi/boot1/boot1.c
Show First 20 Lines • Show All 44 Lines • ▼ Show 20 Lines | |||||
#define NUM_BOOT_MODULES (sizeof(boot_modules) / sizeof(boot_module_t*)) | #define NUM_BOOT_MODULES (sizeof(boot_modules) / sizeof(boot_module_t*)) | ||||
/* The initial number of handles used to query EFI for partitions. */ | /* The initial number of handles used to query EFI for partitions. */ | ||||
#define NUM_HANDLES_INIT 24 | #define NUM_HANDLES_INIT 24 | ||||
void putchar(int c); | void putchar(int c); | ||||
EFI_STATUS efi_main(EFI_HANDLE Ximage, EFI_SYSTEM_TABLE* Xsystab); | EFI_STATUS efi_main(EFI_HANDLE Ximage, EFI_SYSTEM_TABLE* Xsystab); | ||||
static void try_load(const boot_module_t* mod); | |||||
static EFI_STATUS probe_handle(EFI_HANDLE h); | |||||
EFI_SYSTEM_TABLE *systab; | EFI_SYSTEM_TABLE *systab; | ||||
EFI_BOOT_SERVICES *bs; | EFI_BOOT_SERVICES *bs; | ||||
static EFI_HANDLE *image; | static EFI_HANDLE *image; | ||||
static EFI_GUID BlockIoProtocolGUID = BLOCK_IO_PROTOCOL; | static EFI_GUID BlockIoProtocolGUID = BLOCK_IO_PROTOCOL; | ||||
static EFI_GUID DevicePathGUID = DEVICE_PATH_PROTOCOL; | static EFI_GUID DevicePathGUID = DEVICE_PATH_PROTOCOL; | ||||
static EFI_GUID LoadedImageGUID = LOADED_IMAGE_PROTOCOL; | static EFI_GUID LoadedImageGUID = LOADED_IMAGE_PROTOCOL; | ||||
static EFI_GUID ConsoleControlGUID = EFI_CONSOLE_CONTROL_PROTOCOL_GUID; | static EFI_GUID ConsoleControlGUID = EFI_CONSOLE_CONTROL_PROTOCOL_GUID; | ||||
Show All 16 Lines | |||||
void | void | ||||
Free(void *buf, const char *file __unused, int line __unused) | Free(void *buf, const char *file __unused, int line __unused) | ||||
{ | { | ||||
(void)bs->FreePool(buf); | (void)bs->FreePool(buf); | ||||
} | } | ||||
/* | /* | ||||
* This function only returns if it fails to load the kernel. If it | * nodes_match returns TRUE if the imgpath isn't NULL and the nodes match, | ||||
* succeeds, it simply boots the kernel. | * FALSE otherwise. | ||||
*/ | */ | ||||
void | static BOOLEAN | ||||
try_load(const boot_module_t *mod) | nodes_match(EFI_DEVICE_PATH *imgpath, EFI_DEVICE_PATH *devpath) | ||||
{ | { | ||||
size_t bufsize, cmdsize; | int len; | ||||
void *buf; | |||||
if (imgpath == NULL || imgpath->Type != devpath->Type || | |||||
imgpath->SubType != devpath->SubType) | |||||
return (FALSE); | |||||
len = DevicePathNodeLength(imgpath); | |||||
if (len != DevicePathNodeLength(devpath)) | |||||
return (FALSE); | |||||
return (memcmp(imgpath, devpath, (size_t)len) == 0); | |||||
} | |||||
/* | |||||
* 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 | |||||
device_paths_match(EFI_DEVICE_PATH *imgpath, EFI_DEVICE_PATH *devpath) | |||||
{ | |||||
if (imgpath == NULL) | |||||
return (FALSE); | |||||
while (!IsDevicePathEnd(imgpath) && !IsDevicePathEnd(devpath)) { | |||||
if (!nodes_match(imgpath, devpath)) | |||||
return (FALSE); | |||||
if (IsDevicePathType(imgpath, MEDIA_DEVICE_PATH) && | |||||
IsDevicePathType(devpath, MEDIA_DEVICE_PATH)) | |||||
return (TRUE); | |||||
imgpath = NextDevicePathNode(imgpath); | |||||
devpath = NextDevicePathNode(devpath); | |||||
} | |||||
return (FALSE); | |||||
} | |||||
/* | |||||
* devpath_last returns the last non-path end node in devpath. | |||||
*/ | |||||
static EFI_DEVICE_PATH * | |||||
devpath_last(EFI_DEVICE_PATH *devpath) | |||||
{ | |||||
while (!IsDevicePathEnd(NextDevicePathNode(devpath))) | |||||
devpath = NextDevicePathNode(devpath); | |||||
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 | |||||
devpath_node_str(char *buf, size_t size, EFI_DEVICE_PATH *devpath) | |||||
{ | |||||
switch (devpath->Type) { | |||||
case MESSAGING_DEVICE_PATH: | |||||
switch (devpath->SubType) { | |||||
case MSG_ATAPI_DP: { | |||||
ATAPI_DEVICE_PATH *atapi; | |||||
atapi = (ATAPI_DEVICE_PATH *)(void *)devpath; | |||||
return snprintf(buf, size, "ata(%s,%s,0x%x)", | |||||
(atapi->PrimarySecondary == 1) ? "Sec" : "Pri", | |||||
(atapi->SlaveMaster == 1) ? "Slave" : "Master", | |||||
atapi->Lun); | |||||
} | |||||
case MSG_USB_DP: { | |||||
USB_DEVICE_PATH *usb; | |||||
usb = (USB_DEVICE_PATH *)devpath; | |||||
return snprintf(buf, size, "usb(0x%02x,0x%02x)", | |||||
usb->ParentPortNumber, usb->InterfaceNumber); | |||||
} | |||||
case MSG_SCSI_DP: { | |||||
SCSI_DEVICE_PATH *scsi; | |||||
scsi = (SCSI_DEVICE_PATH *)(void *)devpath; | |||||
return snprintf(buf, size, "scsi(0x%02x,0x%02x)", | |||||
scsi->Pun, scsi->Lun); | |||||
} | |||||
case MSG_SATA_DP: { | |||||
SATA_DEVICE_PATH *sata; | |||||
sata = (SATA_DEVICE_PATH *)(void *)devpath; | |||||
return snprintf(buf, size, "sata(0x%x,0x%x,0x%x)", | |||||
sata->HBAPortNumber, sata->PortMultiplierPortNumber, | |||||
sata->Lun); | |||||
} | |||||
default: | |||||
return snprintf(buf, size, "msg(0x%02x)", | |||||
devpath->SubType); | |||||
} | |||||
break; | |||||
case HARDWARE_DEVICE_PATH: | |||||
switch (devpath->SubType) { | |||||
case HW_PCI_DP: { | |||||
PCI_DEVICE_PATH *pci; | |||||
pci = (PCI_DEVICE_PATH *)devpath; | |||||
return snprintf(buf, size, "pci(0x%02x,0x%02x)", | |||||
pci->Device, pci->Function); | |||||
} | |||||
default: | |||||
return snprintf(buf, size, "hw(0x%02x)", | |||||
devpath->SubType); | |||||
} | |||||
break; | |||||
case ACPI_DEVICE_PATH: { | |||||
ACPI_HID_DEVICE_PATH *acpi; | |||||
acpi = (ACPI_HID_DEVICE_PATH *)(void *)devpath; | |||||
if ((acpi->HID & PNP_EISA_ID_MASK) == PNP_EISA_ID_CONST) { | |||||
switch (EISA_ID_TO_NUM(acpi->HID)) { | |||||
case 0x0a03: | |||||
return snprintf(buf, size, "pciroot(0x%x)", | |||||
acpi->UID); | |||||
case 0x0a08: | |||||
return snprintf(buf, size, "pcieroot(0x%x)", | |||||
acpi->UID); | |||||
case 0x0604: | |||||
return snprintf(buf, size, "floppy(0x%x)", | |||||
acpi->UID); | |||||
case 0x0301: | |||||
return snprintf(buf, size, "keyboard(0x%x)", | |||||
acpi->UID); | |||||
case 0x0501: | |||||
return snprintf(buf, size, "serial(0x%x)", | |||||
acpi->UID); | |||||
case 0x0401: | |||||
return snprintf(buf, size, "parallelport(0x%x)", | |||||
acpi->UID); | |||||
default: | |||||
return snprintf(buf, size, "acpi(pnp%04x,0x%x)", | |||||
EISA_ID_TO_NUM(acpi->HID), acpi->UID); | |||||
} | |||||
} | |||||
return snprintf(buf, size, "acpi(0x%08x,0x%x)", acpi->HID, | |||||
acpi->UID); | |||||
} | |||||
case MEDIA_DEVICE_PATH: | |||||
switch (devpath->SubType) { | |||||
case MEDIA_CDROM_DP: { | |||||
CDROM_DEVICE_PATH *cdrom; | |||||
cdrom = (CDROM_DEVICE_PATH *)(void *)devpath; | |||||
return snprintf(buf, size, "cdrom(%x)", | |||||
cdrom->BootEntry); | |||||
} | |||||
case MEDIA_HARDDRIVE_DP: { | |||||
HARDDRIVE_DEVICE_PATH *hd; | |||||
hd = (HARDDRIVE_DEVICE_PATH *)(void *)devpath; | |||||
return snprintf(buf, size, "hd(%x)", | |||||
hd->PartitionNumber); | |||||
} | |||||
default: | |||||
return snprintf(buf, size, "media(0x%02x)", | |||||
devpath->SubType); | |||||
} | |||||
case BBS_DEVICE_PATH: | |||||
return snprintf(buf, size, "bbs(0x%02x)", devpath->SubType); | |||||
case END_DEVICE_PATH_TYPE: | |||||
return (0); | |||||
} | |||||
return snprintf(buf, size, "type(0x%02x, 0x%02x)", devpath->Type, | |||||
devpath->SubType); | |||||
} | |||||
/* | |||||
* devpath_strlcat appends a text description of devpath to buf but not more | |||||
* than size - 1 characters followed by NUL-terminator. | |||||
*/ | |||||
int | |||||
devpath_strlcat(char *buf, size_t size, EFI_DEVICE_PATH *devpath) | |||||
{ | |||||
size_t len, used; | |||||
const char *sep; | |||||
sep = ""; | |||||
used = 0; | |||||
while (!IsDevicePathEnd(devpath)) { | |||||
len = snprintf(buf, size - used, "%s", sep); | |||||
used += len; | |||||
if (used > size) | |||||
return (used); | |||||
buf += len; | |||||
len = devpath_node_str(buf, size - used, devpath); | |||||
used += len; | |||||
if (used > size) | |||||
return (used); | |||||
buf += len; | |||||
devpath = NextDevicePathNode(devpath); | |||||
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 * | |||||
devpath_str(EFI_DEVICE_PATH *devpath) | |||||
{ | |||||
static char buf[256]; | |||||
devpath_strlcat(buf, sizeof(buf), devpath); | |||||
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 | |||||
load_loader(const boot_module_t **modp, dev_info_t **devinfop, void **bufp, | |||||
size_t *bufsize, BOOLEAN preferred) | |||||
{ | |||||
UINTN i; | |||||
dev_info_t *dev; | |||||
const boot_module_t *mod; | |||||
for (i = 0; i < NUM_BOOT_MODULES; i++) { | |||||
if (boot_modules[i] == NULL) | |||||
continue; | |||||
mod = boot_modules[i]; | |||||
for (dev = mod->devices(); dev != NULL; dev = dev->next) { | |||||
if (dev->preferred != preferred) | |||||
continue; | |||||
if (mod->load(PATH_LOADER_EFI, dev, bufp, bufsize) == | |||||
EFI_SUCCESS) { | |||||
*devinfop = dev; | |||||
*modp = mod; | |||||
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() | |||||
{ | |||||
size_t bufsize, loadersize, cmdsize; | |||||
void *buf, *loaderbuf; | |||||
char *cmd; | char *cmd; | ||||
dev_info_t *dev; | dev_info_t *dev; | ||||
const boot_module_t *mod; | |||||
EFI_HANDLE loaderhandle; | EFI_HANDLE loaderhandle; | ||||
EFI_LOADED_IMAGE *loaded_image; | EFI_LOADED_IMAGE *loaded_image; | ||||
EFI_STATUS status; | EFI_STATUS status; | ||||
status = load_loader(&mod, &dev, &loaderbuf, &loadersize, TRUE); | |||||
if (status != EFI_SUCCESS) { | |||||
status = load_loader(&mod, &dev, &loaderbuf, &loadersize, | |||||
FALSE); | |||||
if (status != EFI_SUCCESS) { | |||||
printf("Failed to load '%s'\n", PATH_LOADER_EFI); | |||||
return (status); | |||||
} | |||||
} | |||||
/* | /* | ||||
* Read in and parse the command line from /boot.config or /boot/config, | * Read in and parse the command line from /boot.config or /boot/config, | ||||
* if present. We'll pass it the next stage via a simple ASCII | * 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 | * 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 | * 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 | * 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 | * 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 | * loading the actual kernel sort all that out. Since these files are | ||||
* optional, we don't report errors in trying to read them. | * optional, we don't report errors in trying to read them. | ||||
*/ | */ | ||||
cmd = NULL; | cmd = NULL; | ||||
cmdsize = 0; | cmdsize = 0; | ||||
status = mod->load(PATH_DOTCONFIG, &dev, &buf, &bufsize); | status = mod->load(PATH_DOTCONFIG, dev, &buf, &bufsize); | ||||
if (status == EFI_NOT_FOUND) | if (status == EFI_NOT_FOUND) | ||||
status = mod->load(PATH_CONFIG, &dev, &buf, &bufsize); | status = mod->load(PATH_CONFIG, dev, &buf, &bufsize); | ||||
if (status == EFI_SUCCESS) { | if (status == EFI_SUCCESS) { | ||||
cmdsize = bufsize + 1; | cmdsize = bufsize + 1; | ||||
cmd = malloc(cmdsize); | cmd = malloc(cmdsize); | ||||
if (cmd == NULL) { | if (cmd == NULL) | ||||
free(buf); | goto errout; | ||||
return; | |||||
} | |||||
memcpy(cmd, buf, bufsize); | memcpy(cmd, buf, bufsize); | ||||
cmd[bufsize] = '\0'; | cmd[bufsize] = '\0'; | ||||
free(buf); | free(buf); | ||||
buf = NULL; | |||||
} | } | ||||
status = mod->load(PATH_LOADER_EFI, &dev, &buf, &bufsize); | if ((status = bs->LoadImage(TRUE, image, devpath_last(dev->devpath), | ||||
if (status == EFI_NOT_FOUND) | loaderbuf, loadersize, &loaderhandle)) != EFI_SUCCESS) { | ||||
return; | |||||
if (status != EFI_SUCCESS) { | |||||
printf("%s failed to load %s (%lu)\n", mod->name, | |||||
PATH_LOADER_EFI, EFI_ERROR_CODE(status)); | |||||
return; | |||||
} | |||||
if ((status = bs->LoadImage(TRUE, image, dev->devpath, buf, bufsize, | |||||
&loaderhandle)) != EFI_SUCCESS) { | |||||
printf("Failed to load image provided by %s, size: %zu, (%lu)\n", | printf("Failed to load image provided by %s, size: %zu, (%lu)\n", | ||||
mod->name, bufsize, EFI_ERROR_CODE(status)); | mod->name, bufsize, EFI_ERROR_CODE(status)); | ||||
return; | goto errout; | ||||
} | } | ||||
if (cmd != NULL) | |||||
printf(" command args: %s\n", cmd); | |||||
if ((status = bs->HandleProtocol(loaderhandle, &LoadedImageGUID, | if ((status = bs->HandleProtocol(loaderhandle, &LoadedImageGUID, | ||||
(VOID**)&loaded_image)) != EFI_SUCCESS) { | (VOID**)&loaded_image)) != EFI_SUCCESS) { | ||||
printf("Failed to query LoadedImage provided by %s (%lu)\n", | printf("Failed to query LoadedImage provided by %s (%lu)\n", | ||||
mod->name, EFI_ERROR_CODE(status)); | mod->name, EFI_ERROR_CODE(status)); | ||||
return; | goto errout; | ||||
} | } | ||||
if (cmd != NULL) | |||||
printf(" command args: %s\n", cmd); | |||||
loaded_image->DeviceHandle = dev->devhandle; | loaded_image->DeviceHandle = dev->devhandle; | ||||
loaded_image->LoadOptionsSize = cmdsize; | loaded_image->LoadOptionsSize = cmdsize; | ||||
loaded_image->LoadOptions = cmd; | loaded_image->LoadOptions = cmd; | ||||
DPRINTF("Starting '%s' in 5 seconds...", PATH_LOADER_EFI); | |||||
DSTALL(1000000); | |||||
DPRINTF("."); | |||||
DSTALL(1000000); | |||||
DPRINTF("."); | |||||
DSTALL(1000000); | |||||
DPRINTF("."); | |||||
DSTALL(1000000); | |||||
DPRINTF("."); | |||||
DSTALL(1000000); | |||||
DPRINTF(".\n"); | |||||
if ((status = bs->StartImage(loaderhandle, NULL, NULL)) != | if ((status = bs->StartImage(loaderhandle, NULL, NULL)) != | ||||
EFI_SUCCESS) { | EFI_SUCCESS) { | ||||
printf("Failed to start image provided by %s (%lu)\n", | printf("Failed to start image provided by %s (%lu)\n", | ||||
mod->name, EFI_ERROR_CODE(status)); | mod->name, EFI_ERROR_CODE(status)); | ||||
free(cmd); | |||||
loaded_image->LoadOptionsSize = 0; | loaded_image->LoadOptionsSize = 0; | ||||
loaded_image->LoadOptions = NULL; | loaded_image->LoadOptions = NULL; | ||||
return; | |||||
} | } | ||||
errout: | |||||
if (cmd != NULL) | |||||
free(cmd); | |||||
if (buf != NULL) | |||||
free(buf); | |||||
if (loaderbuf != NULL) | |||||
free(loaderbuf); | |||||
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 | |||||
probe_handle(EFI_HANDLE h, EFI_DEVICE_PATH *imgpath, BOOLEAN *preferred) | |||||
{ | |||||
dev_info_t *devinfo; | |||||
EFI_BLOCK_IO *blkio; | |||||
EFI_DEVICE_PATH *devpath; | |||||
EFI_STATUS status; | |||||
UINTN i; | |||||
/* Figure out if we're dealing with an actual partition. */ | |||||
status = bs->HandleProtocol(h, &DevicePathGUID, (void **)&devpath); | |||||
if (status == EFI_UNSUPPORTED) | |||||
return (status); | |||||
if (status != EFI_SUCCESS) { | |||||
DPRINTF("\nFailed to query DevicePath (%lu)\n", | |||||
EFI_ERROR_CODE(status)); | |||||
return (status); | |||||
} | |||||
DPRINTF("probing: %s\n", devpath_str(devpath)); | |||||
status = bs->HandleProtocol(h, &BlockIoProtocolGUID, (void **)&blkio); | |||||
if (status == EFI_UNSUPPORTED) | |||||
return (status); | |||||
if (status != EFI_SUCCESS) { | |||||
DPRINTF("\nFailed to query BlockIoProtocol (%lu)\n", | |||||
EFI_ERROR_CODE(status)); | |||||
return (status); | |||||
} | |||||
if (!blkio->Media->LogicalPartition) | |||||
return (EFI_UNSUPPORTED); | |||||
*preferred = device_paths_match(imgpath, devpath); | |||||
/* 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; | |||||
if ((status = bs->AllocatePool(EfiLoaderData, | |||||
sizeof(*devinfo), (void **)&devinfo)) != | |||||
EFI_SUCCESS) { | |||||
DPRINTF("\nFailed to allocate devinfo (%lu)\n", | |||||
EFI_ERROR_CODE(status)); | |||||
continue; | |||||
} | |||||
devinfo->dev = blkio; | |||||
devinfo->devpath = devpath; | |||||
devinfo->devhandle = h; | |||||
devinfo->devdata = NULL; | |||||
devinfo->preferred = *preferred; | |||||
devinfo->next = NULL; | |||||
status = boot_modules[i]->probe(devinfo); | |||||
if (status == EFI_SUCCESS) | |||||
return (EFI_SUCCESS); | |||||
(void)bs->FreePool(devinfo); | |||||
} | |||||
return (EFI_UNSUPPORTED); | |||||
} | |||||
/* | |||||
* probe_handle_status calls probe_handle and outputs the returned status | |||||
* of the call. | |||||
*/ | |||||
static void | |||||
probe_handle_status(EFI_HANDLE h, EFI_DEVICE_PATH *imgpath) | |||||
{ | |||||
EFI_STATUS status; | |||||
BOOLEAN preferred; | |||||
status = probe_handle(h, imgpath, &preferred); | |||||
DPRINTF("probe: "); | |||||
switch (status) { | |||||
case EFI_UNSUPPORTED: | |||||
printf("."); | |||||
DPRINTF(" not supported\n"); | |||||
break; | |||||
case EFI_SUCCESS: | |||||
if (preferred) { | |||||
printf("%c", '*'); | |||||
DPRINTF(" supported (preferred)\n"); | |||||
} else { | |||||
printf("%c", '+'); | |||||
DPRINTF(" supported\n"); | |||||
} | |||||
break; | |||||
default: | |||||
printf("x"); | |||||
DPRINTF(" error (%lu)\n", EFI_ERROR_CODE(status)); | |||||
break; | |||||
} | |||||
DSTALL(500000); | |||||
} | |||||
EFI_STATUS | EFI_STATUS | ||||
efi_main(EFI_HANDLE Ximage, EFI_SYSTEM_TABLE *Xsystab) | efi_main(EFI_HANDLE Ximage, EFI_SYSTEM_TABLE *Xsystab) | ||||
{ | { | ||||
EFI_HANDLE *handles; | EFI_HANDLE *handles; | ||||
EFI_LOADED_IMAGE *img; | |||||
EFI_DEVICE_PATH *imgpath; | |||||
EFI_STATUS status; | EFI_STATUS status; | ||||
EFI_CONSOLE_CONTROL_PROTOCOL *ConsoleControl = NULL; | EFI_CONSOLE_CONTROL_PROTOCOL *ConsoleControl = NULL; | ||||
SIMPLE_TEXT_OUTPUT_INTERFACE *conout = NULL; | SIMPLE_TEXT_OUTPUT_INTERFACE *conout = NULL; | ||||
UINTN i, max_dim, best_mode, cols, rows, hsize, nhandles; | UINTN i, max_dim, best_mode, cols, rows, hsize, nhandles; | ||||
/* Basic initialization*/ | /* Basic initialization*/ | ||||
systab = Xsystab; | systab = Xsystab; | ||||
image = Ximage; | image = Ximage; | ||||
▲ Show 20 Lines • Show All 66 Lines • ▼ Show 20 Lines | efi_main(EFI_HANDLE Ximage, EFI_SYSTEM_TABLE *Xsystab) | ||||
default: | default: | ||||
panic("Failed to get device handles (%lu)", | panic("Failed to get device handles (%lu)", | ||||
EFI_ERROR_CODE(status)); | EFI_ERROR_CODE(status)); | ||||
} | } | ||||
/* Scan all partitions, probing with all modules. */ | /* Scan all partitions, probing with all modules. */ | ||||
nhandles = hsize / sizeof(*handles); | nhandles = hsize / sizeof(*handles); | ||||
printf(" Probing %zu block devices...", nhandles); | printf(" Probing %zu block devices...", nhandles); | ||||
for (i = 0; i < nhandles; i++) { | DPRINTF("\n"); | ||||
status = probe_handle(handles[i]); | |||||
switch (status) { | /* Determine the devpath of our image so we can prefer it. */ | ||||
case EFI_UNSUPPORTED: | status = bs->HandleProtocol(image, &LoadedImageGUID, (VOID**)&img); | ||||
printf("."); | imgpath = NULL; | ||||
break; | if (status == EFI_SUCCESS) { | ||||
case EFI_SUCCESS: | status = bs->HandleProtocol(img->DeviceHandle, &DevicePathGUID, | ||||
printf("+"); | (void **)&imgpath); | ||||
break; | if (status != EFI_SUCCESS) | ||||
default: | DPRINTF("Failed to get image DevicePath (%lu)\n", | ||||
printf("x"); | EFI_ERROR_CODE(status)); | ||||
break; | DPRINTF("boot1 imagepath: %s\n", devpath_str(imgpath)); | ||||
} | } | ||||
} | |||||
for (i = 0; i < nhandles; i++) | |||||
probe_handle_status(handles[i], imgpath); | |||||
printf(" done\n"); | printf(" done\n"); | ||||
/* Status summary. */ | /* Status summary. */ | ||||
for (i = 0; i < NUM_BOOT_MODULES; i++) { | for (i = 0; i < NUM_BOOT_MODULES; i++) { | ||||
if (boot_modules[i] != NULL) { | if (boot_modules[i] != NULL) { | ||||
printf(" "); | printf(" "); | ||||
boot_modules[i]->status(); | boot_modules[i]->status(); | ||||
} | } | ||||
} | } | ||||
/* Select a partition to boot by trying each module in order. */ | try_boot(); | ||||
for (i = 0; i < NUM_BOOT_MODULES; i++) | |||||
if (boot_modules[i] != NULL) | |||||
try_load(boot_modules[i]); | |||||
/* If we get here, we're out of luck... */ | /* If we get here, we're out of luck... */ | ||||
panic("No bootable partitions found!"); | panic("No bootable partitions found!"); | ||||
} | } | ||||
static EFI_STATUS | /* | ||||
probe_handle(EFI_HANDLE h) | * add_device adds a device to the passed devinfo list. | ||||
{ | */ | ||||
dev_info_t *devinfo; | |||||
EFI_BLOCK_IO *blkio; | |||||
EFI_DEVICE_PATH *devpath; | |||||
EFI_STATUS status; | |||||
UINTN i; | |||||
/* Figure out if we're dealing with an actual partition. */ | |||||
status = bs->HandleProtocol(h, &DevicePathGUID, (void **)&devpath); | |||||
if (status == EFI_UNSUPPORTED) | |||||
return (status); | |||||
if (status != EFI_SUCCESS) { | |||||
DPRINTF("\nFailed to query DevicePath (%lu)\n", | |||||
EFI_ERROR_CODE(status)); | |||||
return (status); | |||||
} | |||||
while (!IsDevicePathEnd(NextDevicePathNode(devpath))) | |||||
devpath = NextDevicePathNode(devpath); | |||||
status = bs->HandleProtocol(h, &BlockIoProtocolGUID, (void **)&blkio); | |||||
if (status == EFI_UNSUPPORTED) | |||||
return (status); | |||||
if (status != EFI_SUCCESS) { | |||||
DPRINTF("\nFailed to query BlockIoProtocol (%lu)\n", | |||||
EFI_ERROR_CODE(status)); | |||||
return (status); | |||||
} | |||||
if (!blkio->Media->LogicalPartition) | |||||
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; | |||||
if ((status = bs->AllocatePool(EfiLoaderData, | |||||
sizeof(*devinfo), (void **)&devinfo)) != | |||||
EFI_SUCCESS) { | |||||
DPRINTF("\nFailed to allocate devinfo (%lu)\n", | |||||
EFI_ERROR_CODE(status)); | |||||
continue; | |||||
} | |||||
devinfo->dev = blkio; | |||||
devinfo->devpath = devpath; | |||||
devinfo->devhandle = h; | |||||
devinfo->devdata = NULL; | |||||
devinfo->next = NULL; | |||||
status = boot_modules[i]->probe(devinfo); | |||||
if (status == EFI_SUCCESS) | |||||
return (EFI_SUCCESS); | |||||
(void)bs->FreePool(devinfo); | |||||
} | |||||
return (EFI_UNSUPPORTED); | |||||
} | |||||
void | void | ||||
add_device(dev_info_t **devinfop, dev_info_t *devinfo) | add_device(dev_info_t **devinfop, dev_info_t *devinfo) | ||||
{ | { | ||||
dev_info_t *dev; | dev_info_t *dev; | ||||
if (*devinfop == NULL) { | if (*devinfop == NULL) { | ||||
*devinfop = devinfo; | *devinfop = devinfo; | ||||
return; | return; | ||||
Show All 36 Lines |