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/stand/efi/boot1/boot1.c 332156 2018-04-06 21:50:09Z kevans $"); 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> 32329114Skevans#include <efichar.h> 33264391Snwhitehorn 34329140Skevans#include "boot_module.h" 35294765Simp#include "paths.h" 36294060Ssmh 37329114Skevansstatic void efi_panic(EFI_STATUS s, const char *fmt, ...) __dead2 __printflike(2, 3); 38329114Skevans 39329140Skevansstatic const boot_module_t *boot_modules[] = 40329140Skevans{ 41294068Ssmh#ifdef EFI_ZFS_BOOT 42329140Skevans &zfs_module, 43294068Ssmh#endif 44294060Ssmh#ifdef EFI_UFS_BOOT 45329140Skevans &ufs_module 46294060Ssmh#endif 47294060Ssmh}; 48264391Snwhitehorn 49329140Skevans#define NUM_BOOT_MODULES nitems(boot_modules) 50294060Ssmh/* The initial number of handles used to query EFI for partitions. */ 51294060Ssmh#define NUM_HANDLES_INIT 24 52294060Ssmh 53329140Skevansstatic EFI_GUID BlockIoProtocolGUID = BLOCK_IO_PROTOCOL; 54264391Snwhitehornstatic EFI_GUID DevicePathGUID = DEVICE_PATH_PROTOCOL; 55264391Snwhitehornstatic EFI_GUID LoadedImageGUID = LOADED_IMAGE_PROTOCOL; 56329140Skevansstatic EFI_GUID ConsoleControlGUID = EFI_CONSOLE_CONTROL_PROTOCOL_GUID; 57264391Snwhitehorn 58329140Skevans/* 59329140Skevans * Provide Malloc / Free backed by EFIs AllocatePool / FreePool which ensures 60329140Skevans * memory is correctly aligned avoiding EFI_INVALID_PARAMETER returns from 61329140Skevans * EFI methods. 62329140Skevans */ 63329140Skevansvoid * 64329140SkevansMalloc(size_t len, const char *file __unused, int line __unused) 65294060Ssmh{ 66329140Skevans void *out; 67264391Snwhitehorn 68329140Skevans if (BS->AllocatePool(EfiLoaderData, len, &out) == EFI_SUCCESS) 69329140Skevans return (out); 70294060Ssmh 71329140Skevans return (NULL); 72329140Skevans} 73294060Ssmh 74329140Skevansvoid 75329140SkevansFree(void *buf, const char *file __unused, int line __unused) 76329140Skevans{ 77329140Skevans if (buf != NULL) 78329140Skevans (void)BS->FreePool(buf); 79294060Ssmh} 80294060Ssmh 81329140Skevans/* 82329140Skevans * nodes_match returns TRUE if the imgpath isn't NULL and the nodes match, 83329140Skevans * FALSE otherwise. 84329140Skevans */ 85329140Skevansstatic BOOLEAN 86329140Skevansnodes_match(EFI_DEVICE_PATH *imgpath, EFI_DEVICE_PATH *devpath) 87294060Ssmh{ 88329140Skevans size_t len; 89295320Ssmh 90329140Skevans if (imgpath == NULL || imgpath->Type != devpath->Type || 91329140Skevans imgpath->SubType != devpath->SubType) 92329140Skevans return (FALSE); 93295320Ssmh 94329140Skevans len = DevicePathNodeLength(imgpath); 95329140Skevans if (len != DevicePathNodeLength(devpath)) 96329140Skevans return (FALSE); 97295320Ssmh 98329140Skevans return (memcmp(imgpath, devpath, (size_t)len) == 0); 99295320Ssmh} 100295320Ssmh 101329140Skevans/* 102329140Skevans * device_paths_match returns TRUE if the imgpath isn't NULL and all nodes 103329140Skevans * in imgpath and devpath match up to their respective occurrences of a 104329140Skevans * media node, FALSE otherwise. 105329140Skevans */ 106329140Skevansstatic BOOLEAN 107329140Skevansdevice_paths_match(EFI_DEVICE_PATH *imgpath, EFI_DEVICE_PATH *devpath) 108295320Ssmh{ 109295320Ssmh 110329140Skevans if (imgpath == NULL) 111329140Skevans return (FALSE); 112295320Ssmh 113329140Skevans while (!IsDevicePathEnd(imgpath) && !IsDevicePathEnd(devpath)) { 114329140Skevans if (IsDevicePathType(imgpath, MEDIA_DEVICE_PATH) && 115329140Skevans IsDevicePathType(devpath, MEDIA_DEVICE_PATH)) 116329140Skevans return (TRUE); 117295320Ssmh 118329140Skevans if (!nodes_match(imgpath, devpath)) 119329140Skevans return (FALSE); 120295320Ssmh 121329140Skevans imgpath = NextDevicePathNode(imgpath); 122329140Skevans devpath = NextDevicePathNode(devpath); 123329140Skevans } 124295320Ssmh 125329140Skevans return (FALSE); 126295320Ssmh} 127295320Ssmh 128329140Skevans/* 129329140Skevans * devpath_last returns the last non-path end node in devpath. 130329140Skevans */ 131329140Skevansstatic EFI_DEVICE_PATH * 132329140Skevansdevpath_last(EFI_DEVICE_PATH *devpath) 133295320Ssmh{ 134295320Ssmh 135329140Skevans while (!IsDevicePathEnd(NextDevicePathNode(devpath))) 136329140Skevans devpath = NextDevicePathNode(devpath); 137295320Ssmh 138329140Skevans return (devpath); 139295320Ssmh} 140295320Ssmh 141329140Skevans/* 142329140Skevans * load_loader attempts to load the loader image data. 143329140Skevans * 144329140Skevans * It tries each module and its respective devices, identified by mod->probe, 145329140Skevans * in order until a successful load occurs at which point it returns EFI_SUCCESS 146329140Skevans * and EFI_NOT_FOUND otherwise. 147329140Skevans * 148329140Skevans * Only devices which have preferred matching the preferred parameter are tried. 149329140Skevans */ 150329140Skevansstatic EFI_STATUS 151329140Skevansload_loader(const boot_module_t **modp, dev_info_t **devinfop, void **bufp, 152329140Skevans size_t *bufsize, BOOLEAN preferred) 153295320Ssmh{ 154329140Skevans UINTN i; 155329140Skevans dev_info_t *dev; 156329140Skevans const boot_module_t *mod; 157295320Ssmh 158329140Skevans for (i = 0; i < NUM_BOOT_MODULES; i++) { 159329140Skevans mod = boot_modules[i]; 160329140Skevans for (dev = mod->devices(); dev != NULL; dev = dev->next) { 161329140Skevans if (dev->preferred != preferred) 162329140Skevans continue; 163295320Ssmh 164329140Skevans if (mod->load(PATH_LOADER_EFI, dev, bufp, bufsize) == 165329140Skevans EFI_SUCCESS) { 166329140Skevans *devinfop = dev; 167329140Skevans *modp = mod; 168329140Skevans return (EFI_SUCCESS); 169295320Ssmh } 170295320Ssmh } 171295320Ssmh } 172295320Ssmh 173295320Ssmh return (EFI_NOT_FOUND); 174295320Ssmh} 175295320Ssmh 176295320Ssmh/* 177295320Ssmh * try_boot only returns if it fails to load the loader. If it succeeds 178295320Ssmh * it simply boots, otherwise it returns the status of last EFI call. 179295320Ssmh */ 180295320Ssmhstatic EFI_STATUS 181323484Srlibbytry_boot(void) 182295320Ssmh{ 183295320Ssmh size_t bufsize, loadersize, cmdsize; 184295320Ssmh void *buf, *loaderbuf; 185294768Simp char *cmd; 186329140Skevans dev_info_t *dev; 187329140Skevans const boot_module_t *mod; 188294060Ssmh EFI_HANDLE loaderhandle; 189294060Ssmh EFI_LOADED_IMAGE *loaded_image; 190264391Snwhitehorn EFI_STATUS status; 191294060Ssmh 192329140Skevans status = load_loader(&mod, &dev, &loaderbuf, &loadersize, TRUE); 193329140Skevans if (status != EFI_SUCCESS) { 194329140Skevans status = load_loader(&mod, &dev, &loaderbuf, &loadersize, 195329140Skevans FALSE); 196295320Ssmh if (status != EFI_SUCCESS) { 197329140Skevans printf("Failed to load '%s'\n", PATH_LOADER_EFI); 198329140Skevans return (status); 199329140Skevans } 200295320Ssmh } 201295320Ssmh 202294768Simp /* 203294768Simp * Read in and parse the command line from /boot.config or /boot/config, 204294768Simp * if present. We'll pass it the next stage via a simple ASCII 205294768Simp * string. loader.efi has a hack for ASCII strings, so we'll use that to 206294768Simp * keep the size down here. We only try to read the alternate file if 207294768Simp * we get EFI_NOT_FOUND because all other errors mean that the boot_module 208294768Simp * had troubles with the filesystem. We could return early, but we'll let 209294768Simp * loading the actual kernel sort all that out. Since these files are 210294768Simp * optional, we don't report errors in trying to read them. 211294768Simp */ 212294768Simp cmd = NULL; 213294768Simp cmdsize = 0; 214329140Skevans status = mod->load(PATH_DOTCONFIG, dev, &buf, &bufsize); 215294768Simp if (status == EFI_NOT_FOUND) 216329140Skevans status = mod->load(PATH_CONFIG, dev, &buf, &bufsize); 217294768Simp if (status == EFI_SUCCESS) { 218294768Simp cmdsize = bufsize + 1; 219294768Simp cmd = malloc(cmdsize); 220295320Ssmh if (cmd == NULL) 221295320Ssmh goto errout; 222294768Simp memcpy(cmd, buf, bufsize); 223294768Simp cmd[bufsize] = '\0'; 224294768Simp free(buf); 225295320Ssmh buf = NULL; 226294768Simp } 227294768Simp 228329140Skevans if ((status = BS->LoadImage(TRUE, IH, devpath_last(dev->devpath), 229295320Ssmh loaderbuf, loadersize, &loaderhandle)) != EFI_SUCCESS) { 230329140Skevans printf("Failed to load image provided by %s, size: %zu, (%lu)\n", 231329140Skevans mod->name, loadersize, EFI_ERROR_CODE(status)); 232295320Ssmh goto errout; 233294060Ssmh } 234294060Ssmh 235329140Skevans if ((status = BS->HandleProtocol(loaderhandle, &LoadedImageGUID, 236329140Skevans (VOID**)&loaded_image)) != EFI_SUCCESS) { 237329140Skevans printf("Failed to query LoadedImage provided by %s (%lu)\n", 238329140Skevans mod->name, EFI_ERROR_CODE(status)); 239295320Ssmh goto errout; 240294060Ssmh } 241294060Ssmh 242295320Ssmh if (cmd != NULL) 243295320Ssmh printf(" command args: %s\n", cmd); 244295320Ssmh 245329140Skevans loaded_image->DeviceHandle = dev->devhandle; 246294768Simp loaded_image->LoadOptionsSize = cmdsize; 247294768Simp loaded_image->LoadOptions = cmd; 248294060Ssmh 249295320Ssmh DPRINTF("Starting '%s' in 5 seconds...", PATH_LOADER_EFI); 250295320Ssmh DSTALL(1000000); 251295320Ssmh DPRINTF("."); 252295320Ssmh DSTALL(1000000); 253295320Ssmh DPRINTF("."); 254295320Ssmh DSTALL(1000000); 255295320Ssmh DPRINTF("."); 256295320Ssmh DSTALL(1000000); 257295320Ssmh DPRINTF("."); 258295320Ssmh DSTALL(1000000); 259295320Ssmh DPRINTF(".\n"); 260295320Ssmh 261329114Skevans if ((status = BS->StartImage(loaderhandle, NULL, NULL)) != 262294060Ssmh EFI_SUCCESS) { 263329140Skevans printf("Failed to start image provided by %s (%lu)\n", 264329140Skevans mod->name, EFI_ERROR_CODE(status)); 265294768Simp loaded_image->LoadOptionsSize = 0; 266294768Simp loaded_image->LoadOptions = NULL; 267294060Ssmh } 268295320Ssmh 269295320Ssmherrout: 270295320Ssmh if (cmd != NULL) 271295320Ssmh free(cmd); 272295320Ssmh if (buf != NULL) 273295320Ssmh free(buf); 274295320Ssmh if (loaderbuf != NULL) 275295320Ssmh free(loaderbuf); 276295320Ssmh 277295320Ssmh return (status); 278294060Ssmh} 279294060Ssmh 280329140Skevans/* 281329140Skevans * probe_handle determines if the passed handle represents a logical partition 282329140Skevans * if it does it uses each module in order to probe it and if successful it 283329140Skevans * returns EFI_SUCCESS. 284329140Skevans */ 285329140Skevansstatic EFI_STATUS 286329140Skevansprobe_handle(EFI_HANDLE h, EFI_DEVICE_PATH *imgpath, BOOLEAN *preferred) 287295320Ssmh{ 288329140Skevans dev_info_t *devinfo; 289329140Skevans EFI_BLOCK_IO *blkio; 290329140Skevans EFI_DEVICE_PATH *devpath; 291329140Skevans EFI_STATUS status; 292329140Skevans UINTN i; 293295320Ssmh 294329140Skevans /* Figure out if we're dealing with an actual partition. */ 295329140Skevans status = BS->HandleProtocol(h, &DevicePathGUID, (void **)&devpath); 296329140Skevans if (status == EFI_UNSUPPORTED) 297329140Skevans return (status); 298295320Ssmh 299329140Skevans if (status != EFI_SUCCESS) { 300329140Skevans DPRINTF("\nFailed to query DevicePath (%lu)\n", 301329140Skevans EFI_ERROR_CODE(status)); 302329140Skevans return (status); 303329140Skevans } 304329140Skevans#ifdef EFI_DEBUG 305329140Skevans { 306329140Skevans CHAR16 *text = efi_devpath_name(devpath); 307329140Skevans DPRINTF("probing: %S\n", text); 308329140Skevans efi_free_devpath_name(text); 309329140Skevans } 310329114Skevans#endif 311329140Skevans status = BS->HandleProtocol(h, &BlockIoProtocolGUID, (void **)&blkio); 312329140Skevans if (status == EFI_UNSUPPORTED) 313329140Skevans return (status); 314295320Ssmh 315329140Skevans if (status != EFI_SUCCESS) { 316329140Skevans DPRINTF("\nFailed to query BlockIoProtocol (%lu)\n", 317329140Skevans EFI_ERROR_CODE(status)); 318329140Skevans return (status); 319329140Skevans } 320295320Ssmh 321329140Skevans if (!blkio->Media->LogicalPartition) 322329140Skevans return (EFI_UNSUPPORTED); 323329140Skevans 324329140Skevans *preferred = device_paths_match(imgpath, devpath); 325329140Skevans 326329140Skevans /* Run through each module, see if it can load this partition */ 327329140Skevans for (i = 0; i < NUM_BOOT_MODULES; i++) { 328329140Skevans devinfo = malloc(sizeof(*devinfo)); 329329140Skevans if (devinfo == NULL) { 330329140Skevans DPRINTF("\nFailed to allocate devinfo\n"); 331329140Skevans continue; 332329140Skevans } 333329140Skevans devinfo->dev = blkio; 334329140Skevans devinfo->devpath = devpath; 335329140Skevans devinfo->devhandle = h; 336329140Skevans devinfo->devdata = NULL; 337329140Skevans devinfo->preferred = *preferred; 338329140Skevans devinfo->next = NULL; 339329140Skevans 340329140Skevans status = boot_modules[i]->probe(devinfo); 341329140Skevans if (status == EFI_SUCCESS) 342329140Skevans return (EFI_SUCCESS); 343329140Skevans free(devinfo); 344329140Skevans } 345329140Skevans 346329140Skevans return (EFI_UNSUPPORTED); 347329140Skevans} 348329140Skevans 349329140Skevans/* 350329140Skevans * probe_handle_status calls probe_handle and outputs the returned status 351329140Skevans * of the call. 352329140Skevans */ 353329140Skevansstatic void 354329140Skevansprobe_handle_status(EFI_HANDLE h, EFI_DEVICE_PATH *imgpath) 355329140Skevans{ 356329140Skevans EFI_STATUS status; 357329140Skevans BOOLEAN preferred; 358329140Skevans 359329140Skevans preferred = FALSE; 360329140Skevans status = probe_handle(h, imgpath, &preferred); 361329140Skevans 362329140Skevans DPRINTF("probe: "); 363329140Skevans switch (status) { 364329140Skevans case EFI_UNSUPPORTED: 365329140Skevans printf("."); 366329140Skevans DPRINTF(" not supported\n"); 367329140Skevans break; 368329140Skevans case EFI_SUCCESS: 369329140Skevans if (preferred) { 370329140Skevans printf("%c", '*'); 371329140Skevans DPRINTF(" supported (preferred)\n"); 372329140Skevans } else { 373329140Skevans printf("%c", '+'); 374329140Skevans DPRINTF(" supported\n"); 375329140Skevans } 376329140Skevans break; 377329140Skevans default: 378329140Skevans printf("x"); 379329140Skevans DPRINTF(" error (%lu)\n", EFI_ERROR_CODE(status)); 380329140Skevans break; 381329140Skevans } 382329140Skevans DSTALL(500000); 383329140Skevans} 384329140Skevans 385329140SkevansEFI_STATUS 386329140Skevansefi_main(EFI_HANDLE Ximage, EFI_SYSTEM_TABLE *Xsystab) 387329140Skevans{ 388329140Skevans EFI_HANDLE *handles; 389329140Skevans EFI_LOADED_IMAGE *img; 390329140Skevans EFI_DEVICE_PATH *imgpath; 391329140Skevans EFI_STATUS status; 392329140Skevans EFI_CONSOLE_CONTROL_PROTOCOL *ConsoleControl = NULL; 393329140Skevans SIMPLE_TEXT_OUTPUT_INTERFACE *conout = NULL; 394329140Skevans UINTN i, max_dim, best_mode, cols, rows, hsize, nhandles; 395329140Skevans CHAR16 *text; 396329183Skevans UINT16 boot_current; 397329183Skevans size_t sz; 398329183Skevans UINT16 boot_order[100]; 399329140Skevans 400329140Skevans /* Basic initialization*/ 401329140Skevans ST = Xsystab; 402329140Skevans IH = Ximage; 403329140Skevans BS = ST->BootServices; 404329140Skevans RS = ST->RuntimeServices; 405329140Skevans 406329140Skevans /* Set up the console, so printf works. */ 407329140Skevans status = BS->LocateProtocol(&ConsoleControlGUID, NULL, 408329140Skevans (VOID **)&ConsoleControl); 409329140Skevans if (status == EFI_SUCCESS) 410329140Skevans (void)ConsoleControl->SetMode(ConsoleControl, 411329140Skevans EfiConsoleControlScreenText); 412281059Srpaulo /* 413281059Srpaulo * Reset the console and find the best text mode. 414281059Srpaulo */ 415329114Skevans conout = ST->ConOut; 416281059Srpaulo conout->Reset(conout, TRUE); 417281059Srpaulo max_dim = best_mode = 0; 418329140Skevans for (i = 0; ; i++) { 419293274Ssmh status = conout->QueryMode(conout, i, &cols, &rows); 420281059Srpaulo if (EFI_ERROR(status)) 421281059Srpaulo break; 422281059Srpaulo if (cols * rows > max_dim) { 423281059Srpaulo max_dim = cols * rows; 424281059Srpaulo best_mode = i; 425281059Srpaulo } 426281059Srpaulo } 427329140Skevans if (max_dim > 0) 428281059Srpaulo conout->SetMode(conout, best_mode); 429281059Srpaulo conout->EnableCursor(conout, TRUE); 430281059Srpaulo conout->ClearScreen(conout); 431271762Semaste 432294060Ssmh printf("\n>> FreeBSD EFI boot block\n"); 433294765Simp printf(" Loader path: %s\n\n", PATH_LOADER_EFI); 434329140Skevans printf(" Initializing modules:"); 435329140Skevans for (i = 0; i < NUM_BOOT_MODULES; i++) { 436329140Skevans printf(" %s", boot_modules[i]->name); 437329140Skevans if (boot_modules[i]->init != NULL) 438329140Skevans boot_modules[i]->init(); 439294060Ssmh } 440329140Skevans putchar('\n'); 441264391Snwhitehorn 442329114Skevans /* Determine the devpath of our image so we can prefer it. */ 443329140Skevans status = BS->HandleProtocol(IH, &LoadedImageGUID, (VOID**)&img); 444329114Skevans imgpath = NULL; 445329114Skevans if (status == EFI_SUCCESS) { 446329140Skevans text = efi_devpath_name(img->FilePath); 447329140Skevans if (text != NULL) { 448329140Skevans printf(" Load Path: %S\n", text); 449329140Skevans efi_setenv_freebsd_wcs("Boot1Path", text); 450329140Skevans efi_free_devpath_name(text); 451329140Skevans } 452329114Skevans 453329140Skevans status = BS->HandleProtocol(img->DeviceHandle, &DevicePathGUID, 454329114Skevans (void **)&imgpath); 455329114Skevans if (status != EFI_SUCCESS) { 456329114Skevans DPRINTF("Failed to get image DevicePath (%lu)\n", 457329114Skevans EFI_ERROR_CODE(status)); 458329114Skevans } else { 459329114Skevans text = efi_devpath_name(imgpath); 460329140Skevans if (text != NULL) { 461329140Skevans printf(" Load Device: %S\n", text); 462329140Skevans efi_setenv_freebsd_wcs("Boot1Dev", text); 463329140Skevans efi_free_devpath_name(text); 464329140Skevans } 465329114Skevans } 466329140Skevans } 467329114Skevans 468329183Skevans boot_current = 0; 469329183Skevans sz = sizeof(boot_current); 470332156Skevans if (efi_global_getenv("BootCurrent", &boot_current, &sz) == EFI_SUCCESS) { 471332156Skevans printf(" BootCurrent: %04x\n", boot_current); 472329183Skevans 473332156Skevans sz = sizeof(boot_order); 474332156Skevans if (efi_global_getenv("BootOrder", &boot_order, &sz) == EFI_SUCCESS) { 475332156Skevans printf(" BootOrder:"); 476332156Skevans for (i = 0; i < sz / sizeof(boot_order[0]); i++) 477332156Skevans printf(" %04x%s", boot_order[i], 478332156Skevans boot_order[i] == boot_current ? "[*]" : ""); 479332156Skevans printf("\n"); 480332156Skevans } 481332156Skevans } 482329183Skevans 483329183Skevans#ifdef TEST_FAILURE 484329183Skevans /* 485329183Skevans * For testing failover scenarios, it's nice to be able to fail fast. 486329183Skevans * Define TEST_FAILURE to create a boot1.efi that always fails after 487329183Skevans * reporting the boot manager protocol details. 488329183Skevans */ 489329183Skevans BS->Exit(IH, EFI_OUT_OF_RESOURCES, 0, NULL); 490329183Skevans#endif 491329183Skevans 492329140Skevans /* Get all the device handles */ 493329140Skevans hsize = (UINTN)NUM_HANDLES_INIT * sizeof(EFI_HANDLE); 494329140Skevans handles = malloc(hsize); 495329183Skevans if (handles == NULL) 496329140Skevans printf("Failed to allocate %d handles\n", NUM_HANDLES_INIT); 497329114Skevans 498329140Skevans status = BS->LocateHandle(ByProtocol, &BlockIoProtocolGUID, NULL, 499329140Skevans &hsize, handles); 500329140Skevans switch (status) { 501329140Skevans case EFI_SUCCESS: 502329140Skevans break; 503329140Skevans case EFI_BUFFER_TOO_SMALL: 504329140Skevans free(handles); 505329140Skevans handles = malloc(hsize); 506329140Skevans if (handles == NULL) 507329140Skevans efi_panic(EFI_OUT_OF_RESOURCES, "Failed to allocate %d handles\n", 508329140Skevans NUM_HANDLES_INIT); 509329140Skevans status = BS->LocateHandle(ByProtocol, &BlockIoProtocolGUID, 510329140Skevans NULL, &hsize, handles); 511329140Skevans if (status != EFI_SUCCESS) 512329140Skevans efi_panic(status, "Failed to get device handles\n"); 513329140Skevans break; 514329140Skevans default: 515329140Skevans efi_panic(status, "Failed to get device handles\n"); 516329140Skevans break; 517329140Skevans } 518264391Snwhitehorn 519329140Skevans /* Scan all partitions, probing with all modules. */ 520329140Skevans nhandles = hsize / sizeof(*handles); 521329140Skevans printf(" Probing %zu block devices...", nhandles); 522329140Skevans DPRINTF("\n"); 523329135Skevans 524329140Skevans for (i = 0; i < nhandles; i++) 525329140Skevans probe_handle_status(handles[i], imgpath); 526329140Skevans printf(" done\n"); 527329135Skevans 528329140Skevans /* Status summary. */ 529329140Skevans for (i = 0; i < NUM_BOOT_MODULES; i++) { 530329140Skevans printf(" "); 531329140Skevans boot_modules[i]->status(); 532294060Ssmh } 533264391Snwhitehorn 534295320Ssmh try_boot(); 535281058Srpaulo 536294060Ssmh /* If we get here, we're out of luck... */ 537329114Skevans efi_panic(EFI_LOAD_ERROR, "No bootable partitions found!"); 538264391Snwhitehorn} 539264391Snwhitehorn 540295320Ssmh/* 541329140Skevans * add_device adds a device to the passed devinfo list. 542329140Skevans */ 543329140Skevansvoid 544329140Skevansadd_device(dev_info_t **devinfop, dev_info_t *devinfo) 545329140Skevans{ 546329140Skevans dev_info_t *dev; 547329140Skevans 548329140Skevans if (*devinfop == NULL) { 549329140Skevans *devinfop = devinfo; 550329140Skevans return; 551329140Skevans } 552329140Skevans 553329140Skevans for (dev = *devinfop; dev->next != NULL; dev = dev->next) 554329140Skevans ; 555329140Skevans 556329140Skevans dev->next = devinfo; 557329140Skevans} 558329140Skevans 559329140Skevans/* 560329114Skevans * OK. We totally give up. Exit back to EFI with a sensible status so 561329114Skevans * it can try the next option on the list. 562329114Skevans */ 563329114Skevansstatic void 564329114Skevansefi_panic(EFI_STATUS s, const char *fmt, ...) 565264391Snwhitehorn{ 566329140Skevans va_list ap; 567264391Snwhitehorn 568329140Skevans printf("panic: "); 569329140Skevans va_start(ap, fmt); 570329140Skevans vprintf(fmt, ap); 571329140Skevans va_end(ap); 572329140Skevans printf("\n"); 573264391Snwhitehorn 574329140Skevans BS->Exit(IH, s, 0, NULL); 575264391Snwhitehorn} 576329140Skevans 577329140Skevansvoid 578329140Skevansputchar(int c) 579329140Skevans{ 580329140Skevans CHAR16 buf[2]; 581329140Skevans 582329140Skevans if (c == '\n') { 583329140Skevans buf[0] = '\r'; 584329140Skevans buf[1] = 0; 585329140Skevans ST->ConOut->OutputString(ST->ConOut, buf); 586329140Skevans } 587329140Skevans buf[0] = c; 588329140Skevans buf[1] = 0; 589329140Skevans ST->ConOut->OutputString(ST->ConOut, buf); 590329140Skevans} 591