boot1.c revision 323484
1264391Snwhitehorn/*- 2264391Snwhitehorn * Copyright (c) 1998 Robert Nordier 3264391Snwhitehorn * All rights reserved. 4264391Snwhitehorn * Copyright (c) 2001 Robert Drehmel 5264391Snwhitehorn * All rights reserved. 6264404Snwhitehorn * Copyright (c) 2014 Nathan Whitehorn 7264404Snwhitehorn * All rights reserved. 8294060Ssmh * Copyright (c) 2015 Eric McCorkle 9294060Ssmh * All rights reserved. 10264391Snwhitehorn * 11264391Snwhitehorn * Redistribution and use in source and binary forms are freely 12264391Snwhitehorn * permitted provided that the above copyright notice and this 13264391Snwhitehorn * paragraph and the following disclaimer are duplicated in all 14264391Snwhitehorn * such forms. 15264391Snwhitehorn * 16264391Snwhitehorn * This software is provided "AS IS" and without any express or 17264391Snwhitehorn * implied warranties, including, without limitation, the implied 18264391Snwhitehorn * warranties of merchantability and fitness for a particular 19264391Snwhitehorn * purpose. 20264391Snwhitehorn */ 21264391Snwhitehorn 22264391Snwhitehorn#include <sys/cdefs.h> 23264391Snwhitehorn__FBSDID("$FreeBSD: stable/11/sys/boot/efi/boot1/boot1.c 323484 2017-09-12 06:19:19Z rlibby $"); 24264391Snwhitehorn 25264391Snwhitehorn#include <sys/param.h> 26264391Snwhitehorn#include <machine/elf.h> 27264391Snwhitehorn#include <machine/stdarg.h> 28293460Ssmh#include <stand.h> 29264391Snwhitehorn 30264391Snwhitehorn#include <efi.h> 31271762Semaste#include <eficonsctl.h> 32264391Snwhitehorn 33294060Ssmh#include "boot_module.h" 34294765Simp#include "paths.h" 35294060Ssmh 36294060Ssmhstatic const boot_module_t *boot_modules[] = 37294060Ssmh{ 38294068Ssmh#ifdef EFI_ZFS_BOOT 39294068Ssmh &zfs_module, 40294068Ssmh#endif 41294060Ssmh#ifdef EFI_UFS_BOOT 42294060Ssmh &ufs_module 43294060Ssmh#endif 44294060Ssmh}; 45264391Snwhitehorn 46323484Srlibby#define NUM_BOOT_MODULES nitems(boot_modules) 47294060Ssmh/* The initial number of handles used to query EFI for partitions. */ 48294060Ssmh#define NUM_HANDLES_INIT 24 49294060Ssmh 50293724SsmhEFI_STATUS efi_main(EFI_HANDLE Ximage, EFI_SYSTEM_TABLE* Xsystab); 51264391Snwhitehorn 52294060SsmhEFI_SYSTEM_TABLE *systab; 53294060SsmhEFI_BOOT_SERVICES *bs; 54281169Sandrewstatic EFI_HANDLE *image; 55264391Snwhitehorn 56264391Snwhitehornstatic EFI_GUID BlockIoProtocolGUID = BLOCK_IO_PROTOCOL; 57264391Snwhitehornstatic EFI_GUID DevicePathGUID = DEVICE_PATH_PROTOCOL; 58264391Snwhitehornstatic EFI_GUID LoadedImageGUID = LOADED_IMAGE_PROTOCOL; 59271762Semastestatic EFI_GUID ConsoleControlGUID = EFI_CONSOLE_CONTROL_PROTOCOL_GUID; 60264391Snwhitehorn 61294060Ssmh/* 62294060Ssmh * Provide Malloc / Free backed by EFIs AllocatePool / FreePool which ensures 63294060Ssmh * memory is correctly aligned avoiding EFI_INVALID_PARAMETER returns from 64294060Ssmh * EFI methods. 65294060Ssmh */ 66294060Ssmhvoid * 67294060SsmhMalloc(size_t len, const char *file __unused, int line __unused) 68294060Ssmh{ 69294060Ssmh void *out; 70264391Snwhitehorn 71294060Ssmh if (bs->AllocatePool(EfiLoaderData, len, &out) == EFI_SUCCESS) 72294060Ssmh return (out); 73294060Ssmh 74294060Ssmh return (NULL); 75294060Ssmh} 76294060Ssmh 77294060Ssmhvoid 78294060SsmhFree(void *buf, const char *file __unused, int line __unused) 79264391Snwhitehorn{ 80294060Ssmh (void)bs->FreePool(buf); 81294060Ssmh} 82294060Ssmh 83294060Ssmh/* 84295320Ssmh * nodes_match returns TRUE if the imgpath isn't NULL and the nodes match, 85295320Ssmh * FALSE otherwise. 86294060Ssmh */ 87295320Ssmhstatic BOOLEAN 88295320Ssmhnodes_match(EFI_DEVICE_PATH *imgpath, EFI_DEVICE_PATH *devpath) 89294060Ssmh{ 90295320Ssmh int len; 91295320Ssmh 92295320Ssmh if (imgpath == NULL || imgpath->Type != devpath->Type || 93295320Ssmh imgpath->SubType != devpath->SubType) 94295320Ssmh return (FALSE); 95295320Ssmh 96295320Ssmh len = DevicePathNodeLength(imgpath); 97295320Ssmh if (len != DevicePathNodeLength(devpath)) 98295320Ssmh return (FALSE); 99295320Ssmh 100295320Ssmh return (memcmp(imgpath, devpath, (size_t)len) == 0); 101295320Ssmh} 102295320Ssmh 103295320Ssmh/* 104295320Ssmh * device_paths_match returns TRUE if the imgpath isn't NULL and all nodes 105298826Spfg * in imgpath and devpath match up to their respective occurrences of a 106298826Spfg * media node, FALSE otherwise. 107295320Ssmh */ 108295320Ssmhstatic BOOLEAN 109295320Ssmhdevice_paths_match(EFI_DEVICE_PATH *imgpath, EFI_DEVICE_PATH *devpath) 110295320Ssmh{ 111295320Ssmh 112295320Ssmh if (imgpath == NULL) 113295320Ssmh return (FALSE); 114295320Ssmh 115295320Ssmh while (!IsDevicePathEnd(imgpath) && !IsDevicePathEnd(devpath)) { 116295320Ssmh if (IsDevicePathType(imgpath, MEDIA_DEVICE_PATH) && 117295320Ssmh IsDevicePathType(devpath, MEDIA_DEVICE_PATH)) 118295320Ssmh return (TRUE); 119295320Ssmh 120295320Ssmh if (!nodes_match(imgpath, devpath)) 121295320Ssmh return (FALSE); 122295320Ssmh 123295320Ssmh imgpath = NextDevicePathNode(imgpath); 124295320Ssmh devpath = NextDevicePathNode(devpath); 125295320Ssmh } 126295320Ssmh 127295320Ssmh return (FALSE); 128295320Ssmh} 129295320Ssmh 130295320Ssmh/* 131295320Ssmh * devpath_last returns the last non-path end node in devpath. 132295320Ssmh */ 133295320Ssmhstatic EFI_DEVICE_PATH * 134295320Ssmhdevpath_last(EFI_DEVICE_PATH *devpath) 135295320Ssmh{ 136295320Ssmh 137295320Ssmh while (!IsDevicePathEnd(NextDevicePathNode(devpath))) 138295320Ssmh devpath = NextDevicePathNode(devpath); 139295320Ssmh 140295320Ssmh return (devpath); 141295320Ssmh} 142295320Ssmh 143295320Ssmh/* 144295320Ssmh * devpath_node_str is a basic output method for a devpath node which 145295320Ssmh * only understands a subset of the available sub types. 146295320Ssmh * 147295320Ssmh * If we switch to UEFI 2.x then we should update it to use: 148295320Ssmh * EFI_DEVICE_PATH_TO_TEXT_PROTOCOL. 149295320Ssmh */ 150295320Ssmhstatic int 151295320Ssmhdevpath_node_str(char *buf, size_t size, EFI_DEVICE_PATH *devpath) 152295320Ssmh{ 153295320Ssmh 154295320Ssmh switch (devpath->Type) { 155295320Ssmh case MESSAGING_DEVICE_PATH: 156295320Ssmh switch (devpath->SubType) { 157295320Ssmh case MSG_ATAPI_DP: { 158295320Ssmh ATAPI_DEVICE_PATH *atapi; 159295320Ssmh 160295320Ssmh atapi = (ATAPI_DEVICE_PATH *)(void *)devpath; 161295320Ssmh return snprintf(buf, size, "ata(%s,%s,0x%x)", 162295320Ssmh (atapi->PrimarySecondary == 1) ? "Sec" : "Pri", 163295320Ssmh (atapi->SlaveMaster == 1) ? "Slave" : "Master", 164295320Ssmh atapi->Lun); 165295320Ssmh } 166295320Ssmh case MSG_USB_DP: { 167295320Ssmh USB_DEVICE_PATH *usb; 168295320Ssmh 169295320Ssmh usb = (USB_DEVICE_PATH *)devpath; 170295320Ssmh return snprintf(buf, size, "usb(0x%02x,0x%02x)", 171295320Ssmh usb->ParentPortNumber, usb->InterfaceNumber); 172295320Ssmh } 173295320Ssmh case MSG_SCSI_DP: { 174295320Ssmh SCSI_DEVICE_PATH *scsi; 175295320Ssmh 176295320Ssmh scsi = (SCSI_DEVICE_PATH *)(void *)devpath; 177295320Ssmh return snprintf(buf, size, "scsi(0x%02x,0x%02x)", 178295320Ssmh scsi->Pun, scsi->Lun); 179295320Ssmh } 180295320Ssmh case MSG_SATA_DP: { 181295320Ssmh SATA_DEVICE_PATH *sata; 182295320Ssmh 183295320Ssmh sata = (SATA_DEVICE_PATH *)(void *)devpath; 184295320Ssmh return snprintf(buf, size, "sata(0x%x,0x%x,0x%x)", 185295320Ssmh sata->HBAPortNumber, sata->PortMultiplierPortNumber, 186295320Ssmh sata->Lun); 187295320Ssmh } 188295320Ssmh default: 189295320Ssmh return snprintf(buf, size, "msg(0x%02x)", 190295320Ssmh devpath->SubType); 191295320Ssmh } 192295320Ssmh break; 193295320Ssmh case HARDWARE_DEVICE_PATH: 194295320Ssmh switch (devpath->SubType) { 195295320Ssmh case HW_PCI_DP: { 196295320Ssmh PCI_DEVICE_PATH *pci; 197295320Ssmh 198295320Ssmh pci = (PCI_DEVICE_PATH *)devpath; 199295320Ssmh return snprintf(buf, size, "pci(0x%02x,0x%02x)", 200295320Ssmh pci->Device, pci->Function); 201295320Ssmh } 202295320Ssmh default: 203295320Ssmh return snprintf(buf, size, "hw(0x%02x)", 204295320Ssmh devpath->SubType); 205295320Ssmh } 206295320Ssmh break; 207295320Ssmh case ACPI_DEVICE_PATH: { 208295320Ssmh ACPI_HID_DEVICE_PATH *acpi; 209295320Ssmh 210295320Ssmh acpi = (ACPI_HID_DEVICE_PATH *)(void *)devpath; 211295320Ssmh if ((acpi->HID & PNP_EISA_ID_MASK) == PNP_EISA_ID_CONST) { 212295320Ssmh switch (EISA_ID_TO_NUM(acpi->HID)) { 213295320Ssmh case 0x0a03: 214295320Ssmh return snprintf(buf, size, "pciroot(0x%x)", 215295320Ssmh acpi->UID); 216295320Ssmh case 0x0a08: 217295320Ssmh return snprintf(buf, size, "pcieroot(0x%x)", 218295320Ssmh acpi->UID); 219295320Ssmh case 0x0604: 220295320Ssmh return snprintf(buf, size, "floppy(0x%x)", 221295320Ssmh acpi->UID); 222295320Ssmh case 0x0301: 223295320Ssmh return snprintf(buf, size, "keyboard(0x%x)", 224295320Ssmh acpi->UID); 225295320Ssmh case 0x0501: 226295320Ssmh return snprintf(buf, size, "serial(0x%x)", 227295320Ssmh acpi->UID); 228295320Ssmh case 0x0401: 229295320Ssmh return snprintf(buf, size, "parallelport(0x%x)", 230295320Ssmh acpi->UID); 231295320Ssmh default: 232295320Ssmh return snprintf(buf, size, "acpi(pnp%04x,0x%x)", 233295320Ssmh EISA_ID_TO_NUM(acpi->HID), acpi->UID); 234295320Ssmh } 235295320Ssmh } 236295320Ssmh 237295320Ssmh return snprintf(buf, size, "acpi(0x%08x,0x%x)", acpi->HID, 238295320Ssmh acpi->UID); 239295320Ssmh } 240295320Ssmh case MEDIA_DEVICE_PATH: 241295320Ssmh switch (devpath->SubType) { 242295320Ssmh case MEDIA_CDROM_DP: { 243295320Ssmh CDROM_DEVICE_PATH *cdrom; 244295320Ssmh 245295320Ssmh cdrom = (CDROM_DEVICE_PATH *)(void *)devpath; 246295320Ssmh return snprintf(buf, size, "cdrom(%x)", 247295320Ssmh cdrom->BootEntry); 248295320Ssmh } 249295320Ssmh case MEDIA_HARDDRIVE_DP: { 250295320Ssmh HARDDRIVE_DEVICE_PATH *hd; 251295320Ssmh 252295320Ssmh hd = (HARDDRIVE_DEVICE_PATH *)(void *)devpath; 253295320Ssmh return snprintf(buf, size, "hd(%x)", 254295320Ssmh hd->PartitionNumber); 255295320Ssmh } 256295320Ssmh default: 257295320Ssmh return snprintf(buf, size, "media(0x%02x)", 258295320Ssmh devpath->SubType); 259295320Ssmh } 260295320Ssmh case BBS_DEVICE_PATH: 261295320Ssmh return snprintf(buf, size, "bbs(0x%02x)", devpath->SubType); 262295320Ssmh case END_DEVICE_PATH_TYPE: 263295320Ssmh return (0); 264295320Ssmh } 265295320Ssmh 266295320Ssmh return snprintf(buf, size, "type(0x%02x, 0x%02x)", devpath->Type, 267295320Ssmh devpath->SubType); 268295320Ssmh} 269295320Ssmh 270295320Ssmh/* 271295320Ssmh * devpath_strlcat appends a text description of devpath to buf but not more 272295320Ssmh * than size - 1 characters followed by NUL-terminator. 273295320Ssmh */ 274295320Ssmhint 275295320Ssmhdevpath_strlcat(char *buf, size_t size, EFI_DEVICE_PATH *devpath) 276295320Ssmh{ 277295320Ssmh size_t len, used; 278295320Ssmh const char *sep; 279295320Ssmh 280295320Ssmh sep = ""; 281295320Ssmh used = 0; 282295320Ssmh while (!IsDevicePathEnd(devpath)) { 283295320Ssmh len = snprintf(buf, size - used, "%s", sep); 284295320Ssmh used += len; 285295320Ssmh if (used > size) 286295320Ssmh return (used); 287295320Ssmh buf += len; 288295320Ssmh 289295320Ssmh len = devpath_node_str(buf, size - used, devpath); 290295320Ssmh used += len; 291295320Ssmh if (used > size) 292295320Ssmh return (used); 293295320Ssmh buf += len; 294295320Ssmh devpath = NextDevicePathNode(devpath); 295295320Ssmh sep = ":"; 296295320Ssmh } 297295320Ssmh 298295320Ssmh return (used); 299295320Ssmh} 300295320Ssmh 301295320Ssmh/* 302295320Ssmh * devpath_str is convenience method which returns the text description of 303295320Ssmh * devpath using a static buffer, so it isn't thread safe! 304295320Ssmh */ 305295320Ssmhchar * 306295320Ssmhdevpath_str(EFI_DEVICE_PATH *devpath) 307295320Ssmh{ 308295320Ssmh static char buf[256]; 309295320Ssmh 310295320Ssmh devpath_strlcat(buf, sizeof(buf), devpath); 311295320Ssmh 312295320Ssmh return buf; 313295320Ssmh} 314295320Ssmh 315295320Ssmh/* 316295320Ssmh * load_loader attempts to load the loader image data. 317295320Ssmh * 318295320Ssmh * It tries each module and its respective devices, identified by mod->probe, 319295320Ssmh * in order until a successful load occurs at which point it returns EFI_SUCCESS 320295320Ssmh * and EFI_NOT_FOUND otherwise. 321295320Ssmh * 322295320Ssmh * Only devices which have preferred matching the preferred parameter are tried. 323295320Ssmh */ 324295320Ssmhstatic EFI_STATUS 325295320Ssmhload_loader(const boot_module_t **modp, dev_info_t **devinfop, void **bufp, 326295320Ssmh size_t *bufsize, BOOLEAN preferred) 327295320Ssmh{ 328295320Ssmh UINTN i; 329295320Ssmh dev_info_t *dev; 330295320Ssmh const boot_module_t *mod; 331295320Ssmh 332295320Ssmh for (i = 0; i < NUM_BOOT_MODULES; i++) { 333295320Ssmh mod = boot_modules[i]; 334295320Ssmh for (dev = mod->devices(); dev != NULL; dev = dev->next) { 335295320Ssmh if (dev->preferred != preferred) 336295320Ssmh continue; 337295320Ssmh 338295320Ssmh if (mod->load(PATH_LOADER_EFI, dev, bufp, bufsize) == 339295320Ssmh EFI_SUCCESS) { 340295320Ssmh *devinfop = dev; 341295320Ssmh *modp = mod; 342295320Ssmh return (EFI_SUCCESS); 343295320Ssmh } 344295320Ssmh } 345295320Ssmh } 346295320Ssmh 347295320Ssmh return (EFI_NOT_FOUND); 348295320Ssmh} 349295320Ssmh 350295320Ssmh/* 351295320Ssmh * try_boot only returns if it fails to load the loader. If it succeeds 352295320Ssmh * it simply boots, otherwise it returns the status of last EFI call. 353295320Ssmh */ 354295320Ssmhstatic EFI_STATUS 355323484Srlibbytry_boot(void) 356295320Ssmh{ 357295320Ssmh size_t bufsize, loadersize, cmdsize; 358295320Ssmh void *buf, *loaderbuf; 359294768Simp char *cmd; 360294060Ssmh dev_info_t *dev; 361295320Ssmh const boot_module_t *mod; 362294060Ssmh EFI_HANDLE loaderhandle; 363294060Ssmh EFI_LOADED_IMAGE *loaded_image; 364264391Snwhitehorn EFI_STATUS status; 365294060Ssmh 366295320Ssmh status = load_loader(&mod, &dev, &loaderbuf, &loadersize, TRUE); 367295320Ssmh if (status != EFI_SUCCESS) { 368295320Ssmh status = load_loader(&mod, &dev, &loaderbuf, &loadersize, 369295320Ssmh FALSE); 370295320Ssmh if (status != EFI_SUCCESS) { 371295320Ssmh printf("Failed to load '%s'\n", PATH_LOADER_EFI); 372295320Ssmh return (status); 373295320Ssmh } 374295320Ssmh } 375295320Ssmh 376294768Simp /* 377294768Simp * Read in and parse the command line from /boot.config or /boot/config, 378294768Simp * if present. We'll pass it the next stage via a simple ASCII 379294768Simp * string. loader.efi has a hack for ASCII strings, so we'll use that to 380294768Simp * keep the size down here. We only try to read the alternate file if 381294768Simp * we get EFI_NOT_FOUND because all other errors mean that the boot_module 382294768Simp * had troubles with the filesystem. We could return early, but we'll let 383294768Simp * loading the actual kernel sort all that out. Since these files are 384294768Simp * optional, we don't report errors in trying to read them. 385294768Simp */ 386294768Simp cmd = NULL; 387294768Simp cmdsize = 0; 388295320Ssmh status = mod->load(PATH_DOTCONFIG, dev, &buf, &bufsize); 389294768Simp if (status == EFI_NOT_FOUND) 390295320Ssmh status = mod->load(PATH_CONFIG, dev, &buf, &bufsize); 391294768Simp if (status == EFI_SUCCESS) { 392294768Simp cmdsize = bufsize + 1; 393294768Simp cmd = malloc(cmdsize); 394295320Ssmh if (cmd == NULL) 395295320Ssmh goto errout; 396294768Simp memcpy(cmd, buf, bufsize); 397294768Simp cmd[bufsize] = '\0'; 398294768Simp free(buf); 399295320Ssmh buf = NULL; 400294768Simp } 401294768Simp 402295320Ssmh if ((status = bs->LoadImage(TRUE, image, devpath_last(dev->devpath), 403295320Ssmh loaderbuf, loadersize, &loaderhandle)) != EFI_SUCCESS) { 404294060Ssmh printf("Failed to load image provided by %s, size: %zu, (%lu)\n", 405296713Sandrew mod->name, loadersize, EFI_ERROR_CODE(status)); 406295320Ssmh goto errout; 407294060Ssmh } 408294060Ssmh 409294060Ssmh if ((status = bs->HandleProtocol(loaderhandle, &LoadedImageGUID, 410294060Ssmh (VOID**)&loaded_image)) != EFI_SUCCESS) { 411294060Ssmh printf("Failed to query LoadedImage provided by %s (%lu)\n", 412294060Ssmh mod->name, EFI_ERROR_CODE(status)); 413295320Ssmh goto errout; 414294060Ssmh } 415294060Ssmh 416295320Ssmh if (cmd != NULL) 417295320Ssmh printf(" command args: %s\n", cmd); 418295320Ssmh 419294060Ssmh loaded_image->DeviceHandle = dev->devhandle; 420294768Simp loaded_image->LoadOptionsSize = cmdsize; 421294768Simp loaded_image->LoadOptions = cmd; 422294060Ssmh 423295320Ssmh DPRINTF("Starting '%s' in 5 seconds...", PATH_LOADER_EFI); 424295320Ssmh DSTALL(1000000); 425295320Ssmh DPRINTF("."); 426295320Ssmh DSTALL(1000000); 427295320Ssmh DPRINTF("."); 428295320Ssmh DSTALL(1000000); 429295320Ssmh DPRINTF("."); 430295320Ssmh DSTALL(1000000); 431295320Ssmh DPRINTF("."); 432295320Ssmh DSTALL(1000000); 433295320Ssmh DPRINTF(".\n"); 434295320Ssmh 435294060Ssmh if ((status = bs->StartImage(loaderhandle, NULL, NULL)) != 436294060Ssmh EFI_SUCCESS) { 437294284Semaste printf("Failed to start image provided by %s (%lu)\n", 438294284Semaste mod->name, EFI_ERROR_CODE(status)); 439294768Simp loaded_image->LoadOptionsSize = 0; 440294768Simp loaded_image->LoadOptions = NULL; 441294060Ssmh } 442295320Ssmh 443295320Ssmherrout: 444295320Ssmh if (cmd != NULL) 445295320Ssmh free(cmd); 446295320Ssmh if (buf != NULL) 447295320Ssmh free(buf); 448295320Ssmh if (loaderbuf != NULL) 449295320Ssmh free(loaderbuf); 450295320Ssmh 451295320Ssmh return (status); 452294060Ssmh} 453294060Ssmh 454295320Ssmh/* 455295320Ssmh * probe_handle determines if the passed handle represents a logical partition 456295320Ssmh * if it does it uses each module in order to probe it and if successful it 457295320Ssmh * returns EFI_SUCCESS. 458295320Ssmh */ 459295320Ssmhstatic EFI_STATUS 460295320Ssmhprobe_handle(EFI_HANDLE h, EFI_DEVICE_PATH *imgpath, BOOLEAN *preferred) 461295320Ssmh{ 462295320Ssmh dev_info_t *devinfo; 463295320Ssmh EFI_BLOCK_IO *blkio; 464295320Ssmh EFI_DEVICE_PATH *devpath; 465295320Ssmh EFI_STATUS status; 466295320Ssmh UINTN i; 467295320Ssmh 468295320Ssmh /* Figure out if we're dealing with an actual partition. */ 469295320Ssmh status = bs->HandleProtocol(h, &DevicePathGUID, (void **)&devpath); 470295320Ssmh if (status == EFI_UNSUPPORTED) 471295320Ssmh return (status); 472295320Ssmh 473295320Ssmh if (status != EFI_SUCCESS) { 474295320Ssmh DPRINTF("\nFailed to query DevicePath (%lu)\n", 475295320Ssmh EFI_ERROR_CODE(status)); 476295320Ssmh return (status); 477295320Ssmh } 478295320Ssmh 479295320Ssmh DPRINTF("probing: %s\n", devpath_str(devpath)); 480295320Ssmh 481295320Ssmh status = bs->HandleProtocol(h, &BlockIoProtocolGUID, (void **)&blkio); 482295320Ssmh if (status == EFI_UNSUPPORTED) 483295320Ssmh return (status); 484295320Ssmh 485295320Ssmh if (status != EFI_SUCCESS) { 486295320Ssmh DPRINTF("\nFailed to query BlockIoProtocol (%lu)\n", 487295320Ssmh EFI_ERROR_CODE(status)); 488295320Ssmh return (status); 489295320Ssmh } 490295320Ssmh 491295320Ssmh if (!blkio->Media->LogicalPartition) 492295320Ssmh return (EFI_UNSUPPORTED); 493295320Ssmh 494295320Ssmh *preferred = device_paths_match(imgpath, devpath); 495295320Ssmh 496295320Ssmh /* Run through each module, see if it can load this partition */ 497295320Ssmh for (i = 0; i < NUM_BOOT_MODULES; i++) { 498295320Ssmh if ((status = bs->AllocatePool(EfiLoaderData, 499295320Ssmh sizeof(*devinfo), (void **)&devinfo)) != 500295320Ssmh EFI_SUCCESS) { 501295320Ssmh DPRINTF("\nFailed to allocate devinfo (%lu)\n", 502295320Ssmh EFI_ERROR_CODE(status)); 503295320Ssmh continue; 504295320Ssmh } 505295320Ssmh devinfo->dev = blkio; 506295320Ssmh devinfo->devpath = devpath; 507295320Ssmh devinfo->devhandle = h; 508295320Ssmh devinfo->devdata = NULL; 509295320Ssmh devinfo->preferred = *preferred; 510295320Ssmh devinfo->next = NULL; 511295320Ssmh 512295320Ssmh status = boot_modules[i]->probe(devinfo); 513295320Ssmh if (status == EFI_SUCCESS) 514295320Ssmh return (EFI_SUCCESS); 515295320Ssmh (void)bs->FreePool(devinfo); 516295320Ssmh } 517295320Ssmh 518295320Ssmh return (EFI_UNSUPPORTED); 519295320Ssmh} 520295320Ssmh 521295320Ssmh/* 522295320Ssmh * probe_handle_status calls probe_handle and outputs the returned status 523295320Ssmh * of the call. 524295320Ssmh */ 525295320Ssmhstatic void 526295320Ssmhprobe_handle_status(EFI_HANDLE h, EFI_DEVICE_PATH *imgpath) 527295320Ssmh{ 528295320Ssmh EFI_STATUS status; 529295320Ssmh BOOLEAN preferred; 530295320Ssmh 531295320Ssmh status = probe_handle(h, imgpath, &preferred); 532295320Ssmh 533295320Ssmh DPRINTF("probe: "); 534295320Ssmh switch (status) { 535295320Ssmh case EFI_UNSUPPORTED: 536295320Ssmh printf("."); 537295320Ssmh DPRINTF(" not supported\n"); 538295320Ssmh break; 539295320Ssmh case EFI_SUCCESS: 540295320Ssmh if (preferred) { 541295320Ssmh printf("%c", '*'); 542295320Ssmh DPRINTF(" supported (preferred)\n"); 543295320Ssmh } else { 544295320Ssmh printf("%c", '+'); 545295320Ssmh DPRINTF(" supported\n"); 546295320Ssmh } 547295320Ssmh break; 548295320Ssmh default: 549295320Ssmh printf("x"); 550295320Ssmh DPRINTF(" error (%lu)\n", EFI_ERROR_CODE(status)); 551295320Ssmh break; 552295320Ssmh } 553295320Ssmh DSTALL(500000); 554295320Ssmh} 555295320Ssmh 556294060SsmhEFI_STATUS 557294060Ssmhefi_main(EFI_HANDLE Ximage, EFI_SYSTEM_TABLE *Xsystab) 558294060Ssmh{ 559294060Ssmh EFI_HANDLE *handles; 560295320Ssmh EFI_LOADED_IMAGE *img; 561295320Ssmh EFI_DEVICE_PATH *imgpath; 562294060Ssmh EFI_STATUS status; 563271762Semaste EFI_CONSOLE_CONTROL_PROTOCOL *ConsoleControl = NULL; 564281059Srpaulo SIMPLE_TEXT_OUTPUT_INTERFACE *conout = NULL; 565294060Ssmh UINTN i, max_dim, best_mode, cols, rows, hsize, nhandles; 566264391Snwhitehorn 567294060Ssmh /* Basic initialization*/ 568264391Snwhitehorn systab = Xsystab; 569264391Snwhitehorn image = Ximage; 570294060Ssmh bs = Xsystab->BootServices; 571264391Snwhitehorn 572294060Ssmh /* Set up the console, so printf works. */ 573294060Ssmh status = bs->LocateProtocol(&ConsoleControlGUID, NULL, 574271762Semaste (VOID **)&ConsoleControl); 575271762Semaste if (status == EFI_SUCCESS) 576271762Semaste (void)ConsoleControl->SetMode(ConsoleControl, 577271762Semaste EfiConsoleControlScreenText); 578281059Srpaulo /* 579281059Srpaulo * Reset the console and find the best text mode. 580281059Srpaulo */ 581281059Srpaulo conout = systab->ConOut; 582281059Srpaulo conout->Reset(conout, TRUE); 583281059Srpaulo max_dim = best_mode = 0; 584281059Srpaulo for (i = 0; ; i++) { 585293274Ssmh status = conout->QueryMode(conout, i, &cols, &rows); 586281059Srpaulo if (EFI_ERROR(status)) 587281059Srpaulo break; 588281059Srpaulo if (cols * rows > max_dim) { 589281059Srpaulo max_dim = cols * rows; 590281059Srpaulo best_mode = i; 591281059Srpaulo } 592281059Srpaulo } 593281059Srpaulo if (max_dim > 0) 594281059Srpaulo conout->SetMode(conout, best_mode); 595281059Srpaulo conout->EnableCursor(conout, TRUE); 596281059Srpaulo conout->ClearScreen(conout); 597271762Semaste 598294060Ssmh printf("\n>> FreeBSD EFI boot block\n"); 599294765Simp printf(" Loader path: %s\n\n", PATH_LOADER_EFI); 600294060Ssmh printf(" Initializing modules:"); 601294060Ssmh for (i = 0; i < NUM_BOOT_MODULES; i++) { 602294060Ssmh printf(" %s", boot_modules[i]->name); 603294060Ssmh if (boot_modules[i]->init != NULL) 604294060Ssmh boot_modules[i]->init(); 605294060Ssmh } 606294060Ssmh putchar('\n'); 607264391Snwhitehorn 608294060Ssmh /* Get all the device handles */ 609294060Ssmh hsize = (UINTN)NUM_HANDLES_INIT * sizeof(EFI_HANDLE); 610294060Ssmh if ((status = bs->AllocatePool(EfiLoaderData, hsize, (void **)&handles)) 611294060Ssmh != EFI_SUCCESS) 612294060Ssmh panic("Failed to allocate %d handles (%lu)", NUM_HANDLES_INIT, 613294060Ssmh EFI_ERROR_CODE(status)); 614264391Snwhitehorn 615294060Ssmh status = bs->LocateHandle(ByProtocol, &BlockIoProtocolGUID, NULL, 616294060Ssmh &hsize, handles); 617294060Ssmh switch (status) { 618294060Ssmh case EFI_SUCCESS: 619294060Ssmh break; 620294060Ssmh case EFI_BUFFER_TOO_SMALL: 621294060Ssmh (void)bs->FreePool(handles); 622294060Ssmh if ((status = bs->AllocatePool(EfiLoaderData, hsize, 623302335Semaste (void **)&handles)) != EFI_SUCCESS) { 624294060Ssmh panic("Failed to allocate %zu handles (%lu)", hsize / 625294060Ssmh sizeof(*handles), EFI_ERROR_CODE(status)); 626294060Ssmh } 627294060Ssmh status = bs->LocateHandle(ByProtocol, &BlockIoProtocolGUID, 628294060Ssmh NULL, &hsize, handles); 629294060Ssmh if (status != EFI_SUCCESS) 630294060Ssmh panic("Failed to get device handles (%lu)\n", 631294060Ssmh EFI_ERROR_CODE(status)); 632294060Ssmh break; 633294060Ssmh default: 634294060Ssmh panic("Failed to get device handles (%lu)", 635294060Ssmh EFI_ERROR_CODE(status)); 636294060Ssmh } 637264391Snwhitehorn 638294060Ssmh /* Scan all partitions, probing with all modules. */ 639294060Ssmh nhandles = hsize / sizeof(*handles); 640294060Ssmh printf(" Probing %zu block devices...", nhandles); 641295320Ssmh DPRINTF("\n"); 642295320Ssmh 643295320Ssmh /* Determine the devpath of our image so we can prefer it. */ 644295320Ssmh status = bs->HandleProtocol(image, &LoadedImageGUID, (VOID**)&img); 645295320Ssmh imgpath = NULL; 646295320Ssmh if (status == EFI_SUCCESS) { 647295320Ssmh status = bs->HandleProtocol(img->DeviceHandle, &DevicePathGUID, 648295320Ssmh (void **)&imgpath); 649295320Ssmh if (status != EFI_SUCCESS) 650295320Ssmh DPRINTF("Failed to get image DevicePath (%lu)\n", 651295320Ssmh EFI_ERROR_CODE(status)); 652295320Ssmh DPRINTF("boot1 imagepath: %s\n", devpath_str(imgpath)); 653264391Snwhitehorn } 654295320Ssmh 655295320Ssmh for (i = 0; i < nhandles; i++) 656295320Ssmh probe_handle_status(handles[i], imgpath); 657294060Ssmh printf(" done\n"); 658264391Snwhitehorn 659294060Ssmh /* Status summary. */ 660294060Ssmh for (i = 0; i < NUM_BOOT_MODULES; i++) { 661323484Srlibby printf(" "); 662323484Srlibby boot_modules[i]->status(); 663294060Ssmh } 664264391Snwhitehorn 665295320Ssmh try_boot(); 666281058Srpaulo 667294060Ssmh /* If we get here, we're out of luck... */ 668294060Ssmh panic("No bootable partitions found!"); 669264391Snwhitehorn} 670264391Snwhitehorn 671295320Ssmh/* 672295320Ssmh * add_device adds a device to the passed devinfo list. 673295320Ssmh */ 674294060Ssmhvoid 675294060Ssmhadd_device(dev_info_t **devinfop, dev_info_t *devinfo) 676264391Snwhitehorn{ 677294060Ssmh dev_info_t *dev; 678264391Snwhitehorn 679294060Ssmh if (*devinfop == NULL) { 680294060Ssmh *devinfop = devinfo; 681264391Snwhitehorn return; 682264391Snwhitehorn } 683264391Snwhitehorn 684294060Ssmh for (dev = *devinfop; dev->next != NULL; dev = dev->next) 685294060Ssmh ; 686281058Srpaulo 687294060Ssmh dev->next = devinfo; 688264391Snwhitehorn} 689264391Snwhitehorn 690293460Ssmhvoid 691264391Snwhitehornpanic(const char *fmt, ...) 692264391Snwhitehorn{ 693264391Snwhitehorn va_list ap; 694264391Snwhitehorn 695293460Ssmh printf("panic: "); 696264391Snwhitehorn va_start(ap, fmt); 697293460Ssmh vprintf(fmt, ap); 698264391Snwhitehorn va_end(ap); 699293460Ssmh printf("\n"); 700264391Snwhitehorn 701264391Snwhitehorn while (1) {} 702264391Snwhitehorn} 703264391Snwhitehorn 704293460Ssmhvoid 705293460Ssmhputchar(int c) 706264391Snwhitehorn{ 707264391Snwhitehorn CHAR16 buf[2]; 708264391Snwhitehorn 709264391Snwhitehorn if (c == '\n') { 710264391Snwhitehorn buf[0] = '\r'; 711264391Snwhitehorn buf[1] = 0; 712264391Snwhitehorn systab->ConOut->OutputString(systab->ConOut, buf); 713264391Snwhitehorn } 714264391Snwhitehorn buf[0] = c; 715264391Snwhitehorn buf[1] = 0; 716264391Snwhitehorn systab->ConOut->OutputString(systab->ConOut, buf); 717264391Snwhitehorn} 718