boot1.c revision 329114
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 329114 2018-02-11 02:27:50Z 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> 32329114Skevanstypedef CHAR16 efi_char; 33329114Skevans#include <efichar.h> 34264391Snwhitehorn 35294060Ssmh#include "boot_module.h" 36294765Simp#include "paths.h" 37294060Ssmh 38329114Skevansstatic void efi_panic(EFI_STATUS s, const char *fmt, ...) __dead2 __printflike(2, 3); 39329114Skevans 40294060Ssmhstatic const boot_module_t *boot_modules[] = 41294060Ssmh{ 42294068Ssmh#ifdef EFI_ZFS_BOOT 43294068Ssmh &zfs_module, 44294068Ssmh#endif 45294060Ssmh#ifdef EFI_UFS_BOOT 46294060Ssmh &ufs_module 47294060Ssmh#endif 48294060Ssmh}; 49264391Snwhitehorn 50323484Srlibby#define NUM_BOOT_MODULES nitems(boot_modules) 51294060Ssmh/* The initial number of handles used to query EFI for partitions. */ 52294060Ssmh#define NUM_HANDLES_INIT 24 53294060Ssmh 54264391Snwhitehornstatic EFI_GUID BlockIoProtocolGUID = BLOCK_IO_PROTOCOL; 55264391Snwhitehornstatic EFI_GUID DevicePathGUID = DEVICE_PATH_PROTOCOL; 56264391Snwhitehornstatic EFI_GUID LoadedImageGUID = LOADED_IMAGE_PROTOCOL; 57271762Semastestatic EFI_GUID ConsoleControlGUID = EFI_CONSOLE_CONTROL_PROTOCOL_GUID; 58329114Skevansstatic EFI_GUID FreeBSDBootVarGUID = FREEBSD_BOOT_VAR_GUID; 59264391Snwhitehorn 60294060Ssmh/* 61294060Ssmh * Provide Malloc / Free backed by EFIs AllocatePool / FreePool which ensures 62294060Ssmh * memory is correctly aligned avoiding EFI_INVALID_PARAMETER returns from 63294060Ssmh * EFI methods. 64294060Ssmh */ 65294060Ssmhvoid * 66294060SsmhMalloc(size_t len, const char *file __unused, int line __unused) 67294060Ssmh{ 68294060Ssmh void *out; 69264391Snwhitehorn 70329114Skevans if (BS->AllocatePool(EfiLoaderData, len, &out) == EFI_SUCCESS) 71294060Ssmh return (out); 72294060Ssmh 73294060Ssmh return (NULL); 74294060Ssmh} 75294060Ssmh 76294060Ssmhvoid 77294060SsmhFree(void *buf, const char *file __unused, int line __unused) 78264391Snwhitehorn{ 79329010Skevans if (buf != NULL) 80329114Skevans (void)BS->FreePool(buf); 81294060Ssmh} 82294060Ssmh 83329114Skevansstatic EFI_STATUS 84329114Skevansefi_setenv_freebsd_wcs(const char *varname, CHAR16 *valstr) 85329114Skevans{ 86329114Skevans CHAR16 *var = NULL; 87329114Skevans size_t len; 88329114Skevans EFI_STATUS rv; 89329114Skevans 90329114Skevans utf8_to_ucs2(varname, &var, &len); 91329114Skevans if (var == NULL) 92329114Skevans return (EFI_OUT_OF_RESOURCES); 93329114Skevans rv = RS->SetVariable(var, &FreeBSDBootVarGUID, 94329114Skevans EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS, 95329114Skevans (ucs2len(valstr) + 1) * sizeof(efi_char), valstr); 96329114Skevans free(var); 97329114Skevans return (rv); 98329114Skevans} 99329114Skevans 100294060Ssmh/* 101295320Ssmh * nodes_match returns TRUE if the imgpath isn't NULL and the nodes match, 102295320Ssmh * FALSE otherwise. 103294060Ssmh */ 104295320Ssmhstatic BOOLEAN 105295320Ssmhnodes_match(EFI_DEVICE_PATH *imgpath, EFI_DEVICE_PATH *devpath) 106294060Ssmh{ 107329114Skevans size_t len; 108295320Ssmh 109295320Ssmh if (imgpath == NULL || imgpath->Type != devpath->Type || 110295320Ssmh imgpath->SubType != devpath->SubType) 111295320Ssmh return (FALSE); 112295320Ssmh 113295320Ssmh len = DevicePathNodeLength(imgpath); 114295320Ssmh if (len != DevicePathNodeLength(devpath)) 115295320Ssmh return (FALSE); 116295320Ssmh 117295320Ssmh return (memcmp(imgpath, devpath, (size_t)len) == 0); 118295320Ssmh} 119295320Ssmh 120295320Ssmh/* 121295320Ssmh * device_paths_match returns TRUE if the imgpath isn't NULL and all nodes 122298826Spfg * in imgpath and devpath match up to their respective occurrences of a 123298826Spfg * media node, FALSE otherwise. 124295320Ssmh */ 125295320Ssmhstatic BOOLEAN 126295320Ssmhdevice_paths_match(EFI_DEVICE_PATH *imgpath, EFI_DEVICE_PATH *devpath) 127295320Ssmh{ 128295320Ssmh 129295320Ssmh if (imgpath == NULL) 130295320Ssmh return (FALSE); 131295320Ssmh 132295320Ssmh while (!IsDevicePathEnd(imgpath) && !IsDevicePathEnd(devpath)) { 133295320Ssmh if (IsDevicePathType(imgpath, MEDIA_DEVICE_PATH) && 134295320Ssmh IsDevicePathType(devpath, MEDIA_DEVICE_PATH)) 135295320Ssmh return (TRUE); 136295320Ssmh 137295320Ssmh if (!nodes_match(imgpath, devpath)) 138295320Ssmh return (FALSE); 139295320Ssmh 140295320Ssmh imgpath = NextDevicePathNode(imgpath); 141295320Ssmh devpath = NextDevicePathNode(devpath); 142295320Ssmh } 143295320Ssmh 144295320Ssmh return (FALSE); 145295320Ssmh} 146295320Ssmh 147295320Ssmh/* 148295320Ssmh * devpath_last returns the last non-path end node in devpath. 149295320Ssmh */ 150295320Ssmhstatic EFI_DEVICE_PATH * 151295320Ssmhdevpath_last(EFI_DEVICE_PATH *devpath) 152295320Ssmh{ 153295320Ssmh 154295320Ssmh while (!IsDevicePathEnd(NextDevicePathNode(devpath))) 155295320Ssmh devpath = NextDevicePathNode(devpath); 156295320Ssmh 157295320Ssmh return (devpath); 158295320Ssmh} 159295320Ssmh 160295320Ssmh/* 161295320Ssmh * load_loader attempts to load the loader image data. 162295320Ssmh * 163295320Ssmh * It tries each module and its respective devices, identified by mod->probe, 164295320Ssmh * in order until a successful load occurs at which point it returns EFI_SUCCESS 165295320Ssmh * and EFI_NOT_FOUND otherwise. 166295320Ssmh * 167295320Ssmh * Only devices which have preferred matching the preferred parameter are tried. 168295320Ssmh */ 169295320Ssmhstatic EFI_STATUS 170295320Ssmhload_loader(const boot_module_t **modp, dev_info_t **devinfop, void **bufp, 171295320Ssmh size_t *bufsize, BOOLEAN preferred) 172295320Ssmh{ 173295320Ssmh UINTN i; 174295320Ssmh dev_info_t *dev; 175295320Ssmh const boot_module_t *mod; 176295320Ssmh 177295320Ssmh for (i = 0; i < NUM_BOOT_MODULES; i++) { 178295320Ssmh mod = boot_modules[i]; 179295320Ssmh for (dev = mod->devices(); dev != NULL; dev = dev->next) { 180295320Ssmh if (dev->preferred != preferred) 181295320Ssmh continue; 182295320Ssmh 183295320Ssmh if (mod->load(PATH_LOADER_EFI, dev, bufp, bufsize) == 184295320Ssmh EFI_SUCCESS) { 185295320Ssmh *devinfop = dev; 186295320Ssmh *modp = mod; 187295320Ssmh return (EFI_SUCCESS); 188295320Ssmh } 189295320Ssmh } 190295320Ssmh } 191295320Ssmh 192295320Ssmh return (EFI_NOT_FOUND); 193295320Ssmh} 194295320Ssmh 195295320Ssmh/* 196295320Ssmh * try_boot only returns if it fails to load the loader. If it succeeds 197295320Ssmh * it simply boots, otherwise it returns the status of last EFI call. 198295320Ssmh */ 199295320Ssmhstatic EFI_STATUS 200323484Srlibbytry_boot(void) 201295320Ssmh{ 202295320Ssmh size_t bufsize, loadersize, cmdsize; 203295320Ssmh void *buf, *loaderbuf; 204294768Simp char *cmd; 205294060Ssmh dev_info_t *dev; 206295320Ssmh const boot_module_t *mod; 207294060Ssmh EFI_HANDLE loaderhandle; 208294060Ssmh EFI_LOADED_IMAGE *loaded_image; 209264391Snwhitehorn EFI_STATUS status; 210294060Ssmh 211295320Ssmh status = load_loader(&mod, &dev, &loaderbuf, &loadersize, TRUE); 212295320Ssmh if (status != EFI_SUCCESS) { 213295320Ssmh status = load_loader(&mod, &dev, &loaderbuf, &loadersize, 214295320Ssmh FALSE); 215295320Ssmh if (status != EFI_SUCCESS) { 216295320Ssmh printf("Failed to load '%s'\n", PATH_LOADER_EFI); 217295320Ssmh return (status); 218295320Ssmh } 219295320Ssmh } 220295320Ssmh 221294768Simp /* 222294768Simp * Read in and parse the command line from /boot.config or /boot/config, 223294768Simp * if present. We'll pass it the next stage via a simple ASCII 224294768Simp * string. loader.efi has a hack for ASCII strings, so we'll use that to 225294768Simp * keep the size down here. We only try to read the alternate file if 226294768Simp * we get EFI_NOT_FOUND because all other errors mean that the boot_module 227294768Simp * had troubles with the filesystem. We could return early, but we'll let 228294768Simp * loading the actual kernel sort all that out. Since these files are 229294768Simp * optional, we don't report errors in trying to read them. 230294768Simp */ 231294768Simp cmd = NULL; 232294768Simp cmdsize = 0; 233295320Ssmh status = mod->load(PATH_DOTCONFIG, dev, &buf, &bufsize); 234294768Simp if (status == EFI_NOT_FOUND) 235295320Ssmh status = mod->load(PATH_CONFIG, dev, &buf, &bufsize); 236294768Simp if (status == EFI_SUCCESS) { 237294768Simp cmdsize = bufsize + 1; 238294768Simp cmd = malloc(cmdsize); 239295320Ssmh if (cmd == NULL) 240295320Ssmh goto errout; 241294768Simp memcpy(cmd, buf, bufsize); 242294768Simp cmd[bufsize] = '\0'; 243294768Simp free(buf); 244295320Ssmh buf = NULL; 245294768Simp } 246294768Simp 247329114Skevans if ((status = BS->LoadImage(TRUE, IH, devpath_last(dev->devpath), 248295320Ssmh loaderbuf, loadersize, &loaderhandle)) != EFI_SUCCESS) { 249294060Ssmh printf("Failed to load image provided by %s, size: %zu, (%lu)\n", 250296713Sandrew mod->name, loadersize, EFI_ERROR_CODE(status)); 251295320Ssmh goto errout; 252294060Ssmh } 253294060Ssmh 254329114Skevans if ((status = BS->HandleProtocol(loaderhandle, &LoadedImageGUID, 255294060Ssmh (VOID**)&loaded_image)) != EFI_SUCCESS) { 256294060Ssmh printf("Failed to query LoadedImage provided by %s (%lu)\n", 257294060Ssmh mod->name, EFI_ERROR_CODE(status)); 258295320Ssmh goto errout; 259294060Ssmh } 260294060Ssmh 261295320Ssmh if (cmd != NULL) 262295320Ssmh printf(" command args: %s\n", cmd); 263295320Ssmh 264294060Ssmh loaded_image->DeviceHandle = dev->devhandle; 265294768Simp loaded_image->LoadOptionsSize = cmdsize; 266294768Simp loaded_image->LoadOptions = cmd; 267294060Ssmh 268295320Ssmh DPRINTF("Starting '%s' in 5 seconds...", PATH_LOADER_EFI); 269295320Ssmh DSTALL(1000000); 270295320Ssmh DPRINTF("."); 271295320Ssmh DSTALL(1000000); 272295320Ssmh DPRINTF("."); 273295320Ssmh DSTALL(1000000); 274295320Ssmh DPRINTF("."); 275295320Ssmh DSTALL(1000000); 276295320Ssmh DPRINTF("."); 277295320Ssmh DSTALL(1000000); 278295320Ssmh DPRINTF(".\n"); 279295320Ssmh 280329114Skevans if ((status = BS->StartImage(loaderhandle, NULL, NULL)) != 281294060Ssmh EFI_SUCCESS) { 282294284Semaste printf("Failed to start image provided by %s (%lu)\n", 283294284Semaste mod->name, EFI_ERROR_CODE(status)); 284294768Simp loaded_image->LoadOptionsSize = 0; 285294768Simp loaded_image->LoadOptions = NULL; 286294060Ssmh } 287295320Ssmh 288295320Ssmherrout: 289295320Ssmh if (cmd != NULL) 290295320Ssmh free(cmd); 291295320Ssmh if (buf != NULL) 292295320Ssmh free(buf); 293295320Ssmh if (loaderbuf != NULL) 294295320Ssmh free(loaderbuf); 295295320Ssmh 296295320Ssmh return (status); 297294060Ssmh} 298294060Ssmh 299295320Ssmh/* 300295320Ssmh * probe_handle determines if the passed handle represents a logical partition 301295320Ssmh * if it does it uses each module in order to probe it and if successful it 302295320Ssmh * returns EFI_SUCCESS. 303295320Ssmh */ 304295320Ssmhstatic EFI_STATUS 305295320Ssmhprobe_handle(EFI_HANDLE h, EFI_DEVICE_PATH *imgpath, BOOLEAN *preferred) 306295320Ssmh{ 307295320Ssmh dev_info_t *devinfo; 308295320Ssmh EFI_BLOCK_IO *blkio; 309295320Ssmh EFI_DEVICE_PATH *devpath; 310295320Ssmh EFI_STATUS status; 311295320Ssmh UINTN i; 312295320Ssmh 313295320Ssmh /* Figure out if we're dealing with an actual partition. */ 314329114Skevans status = BS->HandleProtocol(h, &DevicePathGUID, (void **)&devpath); 315295320Ssmh if (status == EFI_UNSUPPORTED) 316295320Ssmh return (status); 317295320Ssmh 318295320Ssmh if (status != EFI_SUCCESS) { 319295320Ssmh DPRINTF("\nFailed to query DevicePath (%lu)\n", 320295320Ssmh EFI_ERROR_CODE(status)); 321295320Ssmh return (status); 322295320Ssmh } 323329114Skevans#ifdef EFI_DEBUG 324329114Skevans { 325329114Skevans CHAR16 *text = efi_devpath_name(devpath); 326329114Skevans DPRINTF("probing: %S\n", text); 327329114Skevans efi_free_devpath_name(text); 328329114Skevans } 329329114Skevans#endif 330329114Skevans status = BS->HandleProtocol(h, &BlockIoProtocolGUID, (void **)&blkio); 331295320Ssmh if (status == EFI_UNSUPPORTED) 332295320Ssmh return (status); 333295320Ssmh 334295320Ssmh if (status != EFI_SUCCESS) { 335295320Ssmh DPRINTF("\nFailed to query BlockIoProtocol (%lu)\n", 336295320Ssmh EFI_ERROR_CODE(status)); 337295320Ssmh return (status); 338295320Ssmh } 339295320Ssmh 340295320Ssmh if (!blkio->Media->LogicalPartition) 341295320Ssmh return (EFI_UNSUPPORTED); 342295320Ssmh 343295320Ssmh *preferred = device_paths_match(imgpath, devpath); 344295320Ssmh 345295320Ssmh /* Run through each module, see if it can load this partition */ 346295320Ssmh for (i = 0; i < NUM_BOOT_MODULES; i++) { 347329114Skevans devinfo = malloc(sizeof(*devinfo)); 348329114Skevans if (devinfo == NULL) { 349329114Skevans DPRINTF("\nFailed to allocate devinfo\n"); 350295320Ssmh continue; 351295320Ssmh } 352295320Ssmh devinfo->dev = blkio; 353295320Ssmh devinfo->devpath = devpath; 354295320Ssmh devinfo->devhandle = h; 355295320Ssmh devinfo->devdata = NULL; 356295320Ssmh devinfo->preferred = *preferred; 357295320Ssmh devinfo->next = NULL; 358295320Ssmh 359295320Ssmh status = boot_modules[i]->probe(devinfo); 360295320Ssmh if (status == EFI_SUCCESS) 361295320Ssmh return (EFI_SUCCESS); 362329114Skevans free(devinfo); 363295320Ssmh } 364295320Ssmh 365295320Ssmh return (EFI_UNSUPPORTED); 366295320Ssmh} 367295320Ssmh 368295320Ssmh/* 369295320Ssmh * probe_handle_status calls probe_handle and outputs the returned status 370295320Ssmh * of the call. 371295320Ssmh */ 372295320Ssmhstatic void 373295320Ssmhprobe_handle_status(EFI_HANDLE h, EFI_DEVICE_PATH *imgpath) 374295320Ssmh{ 375295320Ssmh EFI_STATUS status; 376295320Ssmh BOOLEAN preferred; 377295320Ssmh 378329100Skevans preferred = FALSE; 379295320Ssmh status = probe_handle(h, imgpath, &preferred); 380295320Ssmh 381295320Ssmh DPRINTF("probe: "); 382295320Ssmh switch (status) { 383295320Ssmh case EFI_UNSUPPORTED: 384295320Ssmh printf("."); 385295320Ssmh DPRINTF(" not supported\n"); 386295320Ssmh break; 387295320Ssmh case EFI_SUCCESS: 388295320Ssmh if (preferred) { 389295320Ssmh printf("%c", '*'); 390295320Ssmh DPRINTF(" supported (preferred)\n"); 391295320Ssmh } else { 392295320Ssmh printf("%c", '+'); 393295320Ssmh DPRINTF(" supported\n"); 394295320Ssmh } 395295320Ssmh break; 396295320Ssmh default: 397295320Ssmh printf("x"); 398295320Ssmh DPRINTF(" error (%lu)\n", EFI_ERROR_CODE(status)); 399295320Ssmh break; 400295320Ssmh } 401295320Ssmh DSTALL(500000); 402295320Ssmh} 403295320Ssmh 404294060SsmhEFI_STATUS 405294060Ssmhefi_main(EFI_HANDLE Ximage, EFI_SYSTEM_TABLE *Xsystab) 406294060Ssmh{ 407294060Ssmh EFI_HANDLE *handles; 408295320Ssmh EFI_LOADED_IMAGE *img; 409295320Ssmh EFI_DEVICE_PATH *imgpath; 410294060Ssmh EFI_STATUS status; 411271762Semaste EFI_CONSOLE_CONTROL_PROTOCOL *ConsoleControl = NULL; 412281059Srpaulo SIMPLE_TEXT_OUTPUT_INTERFACE *conout = NULL; 413294060Ssmh UINTN i, max_dim, best_mode, cols, rows, hsize, nhandles; 414329114Skevans CHAR16 *text; 415264391Snwhitehorn 416294060Ssmh /* Basic initialization*/ 417329114Skevans ST = Xsystab; 418329114Skevans IH = Ximage; 419329114Skevans BS = ST->BootServices; 420329114Skevans RS = ST->RuntimeServices; 421264391Snwhitehorn 422294060Ssmh /* Set up the console, so printf works. */ 423329114Skevans status = BS->LocateProtocol(&ConsoleControlGUID, NULL, 424271762Semaste (VOID **)&ConsoleControl); 425271762Semaste if (status == EFI_SUCCESS) 426271762Semaste (void)ConsoleControl->SetMode(ConsoleControl, 427271762Semaste EfiConsoleControlScreenText); 428281059Srpaulo /* 429281059Srpaulo * Reset the console and find the best text mode. 430281059Srpaulo */ 431329114Skevans conout = ST->ConOut; 432281059Srpaulo conout->Reset(conout, TRUE); 433281059Srpaulo max_dim = best_mode = 0; 434281059Srpaulo for (i = 0; ; i++) { 435293274Ssmh status = conout->QueryMode(conout, i, &cols, &rows); 436281059Srpaulo if (EFI_ERROR(status)) 437281059Srpaulo break; 438281059Srpaulo if (cols * rows > max_dim) { 439281059Srpaulo max_dim = cols * rows; 440281059Srpaulo best_mode = i; 441281059Srpaulo } 442281059Srpaulo } 443281059Srpaulo if (max_dim > 0) 444281059Srpaulo conout->SetMode(conout, best_mode); 445281059Srpaulo conout->EnableCursor(conout, TRUE); 446281059Srpaulo conout->ClearScreen(conout); 447271762Semaste 448294060Ssmh printf("\n>> FreeBSD EFI boot block\n"); 449294765Simp printf(" Loader path: %s\n\n", PATH_LOADER_EFI); 450294060Ssmh printf(" Initializing modules:"); 451294060Ssmh for (i = 0; i < NUM_BOOT_MODULES; i++) { 452294060Ssmh printf(" %s", boot_modules[i]->name); 453294060Ssmh if (boot_modules[i]->init != NULL) 454294060Ssmh boot_modules[i]->init(); 455294060Ssmh } 456294060Ssmh putchar('\n'); 457264391Snwhitehorn 458329114Skevans /* Determine the devpath of our image so we can prefer it. */ 459329114Skevans status = BS->HandleProtocol(IH, &LoadedImageGUID, (VOID**)&img); 460329114Skevans imgpath = NULL; 461329114Skevans if (status == EFI_SUCCESS) { 462329114Skevans text = efi_devpath_name(img->FilePath); 463329114Skevans printf(" Load Path: %S\n", text); 464329114Skevans efi_setenv_freebsd_wcs("Boot1Path", text); 465329114Skevans efi_free_devpath_name(text); 466329114Skevans 467329114Skevans status = BS->HandleProtocol(img->DeviceHandle, &DevicePathGUID, 468329114Skevans (void **)&imgpath); 469329114Skevans if (status != EFI_SUCCESS) { 470329114Skevans DPRINTF("Failed to get image DevicePath (%lu)\n", 471329114Skevans EFI_ERROR_CODE(status)); 472329114Skevans } else { 473329114Skevans text = efi_devpath_name(imgpath); 474329114Skevans printf(" Load Device: %S\n", text); 475329114Skevans efi_setenv_freebsd_wcs("Boot1Dev", text); 476329114Skevans efi_free_devpath_name(text); 477329114Skevans } 478329114Skevans 479329114Skevans } 480329114Skevans 481294060Ssmh /* Get all the device handles */ 482294060Ssmh hsize = (UINTN)NUM_HANDLES_INIT * sizeof(EFI_HANDLE); 483329114Skevans handles = malloc(hsize); 484329114Skevans if (handles == NULL) { 485329114Skevans printf("Failed to allocate %d handles\n", NUM_HANDLES_INIT); 486329114Skevans } 487264391Snwhitehorn 488329114Skevans status = BS->LocateHandle(ByProtocol, &BlockIoProtocolGUID, NULL, 489294060Ssmh &hsize, handles); 490294060Ssmh switch (status) { 491294060Ssmh case EFI_SUCCESS: 492294060Ssmh break; 493294060Ssmh case EFI_BUFFER_TOO_SMALL: 494329114Skevans free(handles); 495329114Skevans handles = malloc(hsize); 496329114Skevans if (handles == NULL) 497329114Skevans efi_panic(EFI_OUT_OF_RESOURCES, "Failed to allocate %d handles\n", 498329114Skevans NUM_HANDLES_INIT); 499329114Skevans status = BS->LocateHandle(ByProtocol, &BlockIoProtocolGUID, 500294060Ssmh NULL, &hsize, handles); 501294060Ssmh if (status != EFI_SUCCESS) 502329114Skevans efi_panic(status, "Failed to get device handles\n"); 503294060Ssmh break; 504294060Ssmh default: 505329114Skevans efi_panic(status, "Failed to get device handles\n"); 506329114Skevans break; 507294060Ssmh } 508264391Snwhitehorn 509294060Ssmh /* Scan all partitions, probing with all modules. */ 510294060Ssmh nhandles = hsize / sizeof(*handles); 511294060Ssmh printf(" Probing %zu block devices...", nhandles); 512295320Ssmh DPRINTF("\n"); 513295320Ssmh 514295320Ssmh for (i = 0; i < nhandles; i++) 515295320Ssmh probe_handle_status(handles[i], imgpath); 516294060Ssmh printf(" done\n"); 517264391Snwhitehorn 518294060Ssmh /* Status summary. */ 519294060Ssmh for (i = 0; i < NUM_BOOT_MODULES; i++) { 520323484Srlibby printf(" "); 521323484Srlibby boot_modules[i]->status(); 522294060Ssmh } 523264391Snwhitehorn 524295320Ssmh try_boot(); 525281058Srpaulo 526294060Ssmh /* If we get here, we're out of luck... */ 527329114Skevans efi_panic(EFI_LOAD_ERROR, "No bootable partitions found!"); 528264391Snwhitehorn} 529264391Snwhitehorn 530295320Ssmh/* 531295320Ssmh * add_device adds a device to the passed devinfo list. 532295320Ssmh */ 533294060Ssmhvoid 534294060Ssmhadd_device(dev_info_t **devinfop, dev_info_t *devinfo) 535264391Snwhitehorn{ 536294060Ssmh dev_info_t *dev; 537264391Snwhitehorn 538294060Ssmh if (*devinfop == NULL) { 539294060Ssmh *devinfop = devinfo; 540264391Snwhitehorn return; 541264391Snwhitehorn } 542264391Snwhitehorn 543294060Ssmh for (dev = *devinfop; dev->next != NULL; dev = dev->next) 544294060Ssmh ; 545281058Srpaulo 546294060Ssmh dev->next = devinfo; 547264391Snwhitehorn} 548264391Snwhitehorn 549329114Skevans/* 550329114Skevans * OK. We totally give up. Exit back to EFI with a sensible status so 551329114Skevans * it can try the next option on the list. 552329114Skevans */ 553329114Skevansstatic void 554329114Skevansefi_panic(EFI_STATUS s, const char *fmt, ...) 555264391Snwhitehorn{ 556264391Snwhitehorn va_list ap; 557264391Snwhitehorn 558293460Ssmh printf("panic: "); 559264391Snwhitehorn va_start(ap, fmt); 560293460Ssmh vprintf(fmt, ap); 561264391Snwhitehorn va_end(ap); 562293460Ssmh printf("\n"); 563264391Snwhitehorn 564329114Skevans BS->Exit(IH, s, 0, NULL); 565264391Snwhitehorn} 566264391Snwhitehorn 567293460Ssmhvoid 568293460Ssmhputchar(int c) 569264391Snwhitehorn{ 570264391Snwhitehorn CHAR16 buf[2]; 571264391Snwhitehorn 572264391Snwhitehorn if (c == '\n') { 573264391Snwhitehorn buf[0] = '\r'; 574264391Snwhitehorn buf[1] = 0; 575329114Skevans ST->ConOut->OutputString(ST->ConOut, buf); 576264391Snwhitehorn } 577264391Snwhitehorn buf[0] = c; 578264391Snwhitehorn buf[1] = 0; 579329114Skevans ST->ConOut->OutputString(ST->ConOut, buf); 580264391Snwhitehorn} 581