boot1.c revision 329183
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 329183 2018-02-12 20:51:28Z 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; 57329114Skevansstatic EFI_GUID FreeBSDBootVarGUID = FREEBSD_BOOT_VAR_GUID; 58329183Skevansstatic EFI_GUID GlobalBootVarGUID = UEFI_BOOT_VAR_GUID; 59264391Snwhitehorn 60329140Skevans/* 61329140Skevans * Provide Malloc / Free backed by EFIs AllocatePool / FreePool which ensures 62329140Skevans * memory is correctly aligned avoiding EFI_INVALID_PARAMETER returns from 63329140Skevans * EFI methods. 64329140Skevans */ 65329140Skevansvoid * 66329140SkevansMalloc(size_t len, const char *file __unused, int line __unused) 67294060Ssmh{ 68329140Skevans void *out; 69264391Snwhitehorn 70329140Skevans if (BS->AllocatePool(EfiLoaderData, len, &out) == EFI_SUCCESS) 71329140Skevans return (out); 72294060Ssmh 73329140Skevans return (NULL); 74329140Skevans} 75294060Ssmh 76329140Skevansvoid 77329140SkevansFree(void *buf, const char *file __unused, int line __unused) 78329140Skevans{ 79329140Skevans if (buf != NULL) 80329140Skevans (void)BS->FreePool(buf); 81294060Ssmh} 82294060Ssmh 83329114Skevansstatic EFI_STATUS 84329183Skevansefi_getenv(EFI_GUID *g, const char *v, void *data, size_t *len) 85329183Skevans{ 86329183Skevans size_t ul; 87329183Skevans CHAR16 *uv; 88329183Skevans UINT32 attr; 89329183Skevans UINTN dl; 90329183Skevans EFI_STATUS rv; 91329183Skevans 92329183Skevans uv = NULL; 93329183Skevans if (utf8_to_ucs2(v, &uv, &ul) != 0) 94329183Skevans return (EFI_OUT_OF_RESOURCES); 95329183Skevans dl = *len; 96329183Skevans rv = RS->GetVariable(uv, g, &attr, &dl, data); 97329183Skevans if (rv == EFI_SUCCESS) 98329183Skevans *len = dl; 99329183Skevans free(uv); 100329183Skevans return (rv); 101329183Skevans} 102329183Skevans 103329183Skevansstatic EFI_STATUS 104329114Skevansefi_setenv_freebsd_wcs(const char *varname, CHAR16 *valstr) 105329114Skevans{ 106329114Skevans CHAR16 *var = NULL; 107329114Skevans size_t len; 108329114Skevans EFI_STATUS rv; 109329114Skevans 110329183Skevans if (utf8_to_ucs2(varname, &var, &len) != 0) 111329114Skevans return (EFI_OUT_OF_RESOURCES); 112329114Skevans rv = RS->SetVariable(var, &FreeBSDBootVarGUID, 113329114Skevans EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS, 114329114Skevans (ucs2len(valstr) + 1) * sizeof(efi_char), valstr); 115329114Skevans free(var); 116329114Skevans return (rv); 117329114Skevans} 118329114Skevans 119329140Skevans/* 120329140Skevans * nodes_match returns TRUE if the imgpath isn't NULL and the nodes match, 121329140Skevans * FALSE otherwise. 122329140Skevans */ 123329140Skevansstatic BOOLEAN 124329140Skevansnodes_match(EFI_DEVICE_PATH *imgpath, EFI_DEVICE_PATH *devpath) 125294060Ssmh{ 126329140Skevans size_t len; 127295320Ssmh 128329140Skevans if (imgpath == NULL || imgpath->Type != devpath->Type || 129329140Skevans imgpath->SubType != devpath->SubType) 130329140Skevans return (FALSE); 131295320Ssmh 132329140Skevans len = DevicePathNodeLength(imgpath); 133329140Skevans if (len != DevicePathNodeLength(devpath)) 134329140Skevans return (FALSE); 135295320Ssmh 136329140Skevans return (memcmp(imgpath, devpath, (size_t)len) == 0); 137295320Ssmh} 138295320Ssmh 139329140Skevans/* 140329140Skevans * device_paths_match returns TRUE if the imgpath isn't NULL and all nodes 141329140Skevans * in imgpath and devpath match up to their respective occurrences of a 142329140Skevans * media node, FALSE otherwise. 143329140Skevans */ 144329140Skevansstatic BOOLEAN 145329140Skevansdevice_paths_match(EFI_DEVICE_PATH *imgpath, EFI_DEVICE_PATH *devpath) 146295320Ssmh{ 147295320Ssmh 148329140Skevans if (imgpath == NULL) 149329140Skevans return (FALSE); 150295320Ssmh 151329140Skevans while (!IsDevicePathEnd(imgpath) && !IsDevicePathEnd(devpath)) { 152329140Skevans if (IsDevicePathType(imgpath, MEDIA_DEVICE_PATH) && 153329140Skevans IsDevicePathType(devpath, MEDIA_DEVICE_PATH)) 154329140Skevans return (TRUE); 155295320Ssmh 156329140Skevans if (!nodes_match(imgpath, devpath)) 157329140Skevans return (FALSE); 158295320Ssmh 159329140Skevans imgpath = NextDevicePathNode(imgpath); 160329140Skevans devpath = NextDevicePathNode(devpath); 161329140Skevans } 162295320Ssmh 163329140Skevans return (FALSE); 164295320Ssmh} 165295320Ssmh 166329140Skevans/* 167329140Skevans * devpath_last returns the last non-path end node in devpath. 168329140Skevans */ 169329140Skevansstatic EFI_DEVICE_PATH * 170329140Skevansdevpath_last(EFI_DEVICE_PATH *devpath) 171295320Ssmh{ 172295320Ssmh 173329140Skevans while (!IsDevicePathEnd(NextDevicePathNode(devpath))) 174329140Skevans devpath = NextDevicePathNode(devpath); 175295320Ssmh 176329140Skevans return (devpath); 177295320Ssmh} 178295320Ssmh 179329140Skevans/* 180329140Skevans * load_loader attempts to load the loader image data. 181329140Skevans * 182329140Skevans * It tries each module and its respective devices, identified by mod->probe, 183329140Skevans * in order until a successful load occurs at which point it returns EFI_SUCCESS 184329140Skevans * and EFI_NOT_FOUND otherwise. 185329140Skevans * 186329140Skevans * Only devices which have preferred matching the preferred parameter are tried. 187329140Skevans */ 188329140Skevansstatic EFI_STATUS 189329140Skevansload_loader(const boot_module_t **modp, dev_info_t **devinfop, void **bufp, 190329140Skevans size_t *bufsize, BOOLEAN preferred) 191295320Ssmh{ 192329140Skevans UINTN i; 193329140Skevans dev_info_t *dev; 194329140Skevans const boot_module_t *mod; 195295320Ssmh 196329140Skevans for (i = 0; i < NUM_BOOT_MODULES; i++) { 197329140Skevans mod = boot_modules[i]; 198329140Skevans for (dev = mod->devices(); dev != NULL; dev = dev->next) { 199329140Skevans if (dev->preferred != preferred) 200329140Skevans continue; 201295320Ssmh 202329140Skevans if (mod->load(PATH_LOADER_EFI, dev, bufp, bufsize) == 203329140Skevans EFI_SUCCESS) { 204329140Skevans *devinfop = dev; 205329140Skevans *modp = mod; 206329140Skevans return (EFI_SUCCESS); 207295320Ssmh } 208295320Ssmh } 209295320Ssmh } 210295320Ssmh 211295320Ssmh return (EFI_NOT_FOUND); 212295320Ssmh} 213295320Ssmh 214295320Ssmh/* 215295320Ssmh * try_boot only returns if it fails to load the loader. If it succeeds 216295320Ssmh * it simply boots, otherwise it returns the status of last EFI call. 217295320Ssmh */ 218295320Ssmhstatic EFI_STATUS 219323484Srlibbytry_boot(void) 220295320Ssmh{ 221295320Ssmh size_t bufsize, loadersize, cmdsize; 222295320Ssmh void *buf, *loaderbuf; 223294768Simp char *cmd; 224329140Skevans dev_info_t *dev; 225329140Skevans const boot_module_t *mod; 226294060Ssmh EFI_HANDLE loaderhandle; 227294060Ssmh EFI_LOADED_IMAGE *loaded_image; 228264391Snwhitehorn EFI_STATUS status; 229294060Ssmh 230329140Skevans status = load_loader(&mod, &dev, &loaderbuf, &loadersize, TRUE); 231329140Skevans if (status != EFI_SUCCESS) { 232329140Skevans status = load_loader(&mod, &dev, &loaderbuf, &loadersize, 233329140Skevans FALSE); 234295320Ssmh if (status != EFI_SUCCESS) { 235329140Skevans printf("Failed to load '%s'\n", PATH_LOADER_EFI); 236329140Skevans return (status); 237329140Skevans } 238295320Ssmh } 239295320Ssmh 240294768Simp /* 241294768Simp * Read in and parse the command line from /boot.config or /boot/config, 242294768Simp * if present. We'll pass it the next stage via a simple ASCII 243294768Simp * string. loader.efi has a hack for ASCII strings, so we'll use that to 244294768Simp * keep the size down here. We only try to read the alternate file if 245294768Simp * we get EFI_NOT_FOUND because all other errors mean that the boot_module 246294768Simp * had troubles with the filesystem. We could return early, but we'll let 247294768Simp * loading the actual kernel sort all that out. Since these files are 248294768Simp * optional, we don't report errors in trying to read them. 249294768Simp */ 250294768Simp cmd = NULL; 251294768Simp cmdsize = 0; 252329140Skevans status = mod->load(PATH_DOTCONFIG, dev, &buf, &bufsize); 253294768Simp if (status == EFI_NOT_FOUND) 254329140Skevans status = mod->load(PATH_CONFIG, dev, &buf, &bufsize); 255294768Simp if (status == EFI_SUCCESS) { 256294768Simp cmdsize = bufsize + 1; 257294768Simp cmd = malloc(cmdsize); 258295320Ssmh if (cmd == NULL) 259295320Ssmh goto errout; 260294768Simp memcpy(cmd, buf, bufsize); 261294768Simp cmd[bufsize] = '\0'; 262294768Simp free(buf); 263295320Ssmh buf = NULL; 264294768Simp } 265294768Simp 266329140Skevans if ((status = BS->LoadImage(TRUE, IH, devpath_last(dev->devpath), 267295320Ssmh loaderbuf, loadersize, &loaderhandle)) != EFI_SUCCESS) { 268329140Skevans printf("Failed to load image provided by %s, size: %zu, (%lu)\n", 269329140Skevans mod->name, loadersize, EFI_ERROR_CODE(status)); 270295320Ssmh goto errout; 271294060Ssmh } 272294060Ssmh 273329140Skevans if ((status = BS->HandleProtocol(loaderhandle, &LoadedImageGUID, 274329140Skevans (VOID**)&loaded_image)) != EFI_SUCCESS) { 275329140Skevans printf("Failed to query LoadedImage provided by %s (%lu)\n", 276329140Skevans mod->name, EFI_ERROR_CODE(status)); 277295320Ssmh goto errout; 278294060Ssmh } 279294060Ssmh 280295320Ssmh if (cmd != NULL) 281295320Ssmh printf(" command args: %s\n", cmd); 282295320Ssmh 283329140Skevans loaded_image->DeviceHandle = dev->devhandle; 284294768Simp loaded_image->LoadOptionsSize = cmdsize; 285294768Simp loaded_image->LoadOptions = cmd; 286294060Ssmh 287295320Ssmh DPRINTF("Starting '%s' in 5 seconds...", PATH_LOADER_EFI); 288295320Ssmh DSTALL(1000000); 289295320Ssmh DPRINTF("."); 290295320Ssmh DSTALL(1000000); 291295320Ssmh DPRINTF("."); 292295320Ssmh DSTALL(1000000); 293295320Ssmh DPRINTF("."); 294295320Ssmh DSTALL(1000000); 295295320Ssmh DPRINTF("."); 296295320Ssmh DSTALL(1000000); 297295320Ssmh DPRINTF(".\n"); 298295320Ssmh 299329114Skevans if ((status = BS->StartImage(loaderhandle, NULL, NULL)) != 300294060Ssmh EFI_SUCCESS) { 301329140Skevans printf("Failed to start image provided by %s (%lu)\n", 302329140Skevans mod->name, EFI_ERROR_CODE(status)); 303294768Simp loaded_image->LoadOptionsSize = 0; 304294768Simp loaded_image->LoadOptions = NULL; 305294060Ssmh } 306295320Ssmh 307295320Ssmherrout: 308295320Ssmh if (cmd != NULL) 309295320Ssmh free(cmd); 310295320Ssmh if (buf != NULL) 311295320Ssmh free(buf); 312295320Ssmh if (loaderbuf != NULL) 313295320Ssmh free(loaderbuf); 314295320Ssmh 315295320Ssmh return (status); 316294060Ssmh} 317294060Ssmh 318329140Skevans/* 319329140Skevans * probe_handle determines if the passed handle represents a logical partition 320329140Skevans * if it does it uses each module in order to probe it and if successful it 321329140Skevans * returns EFI_SUCCESS. 322329140Skevans */ 323329140Skevansstatic EFI_STATUS 324329140Skevansprobe_handle(EFI_HANDLE h, EFI_DEVICE_PATH *imgpath, BOOLEAN *preferred) 325295320Ssmh{ 326329140Skevans dev_info_t *devinfo; 327329140Skevans EFI_BLOCK_IO *blkio; 328329140Skevans EFI_DEVICE_PATH *devpath; 329329140Skevans EFI_STATUS status; 330329140Skevans UINTN i; 331295320Ssmh 332329140Skevans /* Figure out if we're dealing with an actual partition. */ 333329140Skevans status = BS->HandleProtocol(h, &DevicePathGUID, (void **)&devpath); 334329140Skevans if (status == EFI_UNSUPPORTED) 335329140Skevans return (status); 336295320Ssmh 337329140Skevans if (status != EFI_SUCCESS) { 338329140Skevans DPRINTF("\nFailed to query DevicePath (%lu)\n", 339329140Skevans EFI_ERROR_CODE(status)); 340329140Skevans return (status); 341329140Skevans } 342329140Skevans#ifdef EFI_DEBUG 343329140Skevans { 344329140Skevans CHAR16 *text = efi_devpath_name(devpath); 345329140Skevans DPRINTF("probing: %S\n", text); 346329140Skevans efi_free_devpath_name(text); 347329140Skevans } 348329114Skevans#endif 349329140Skevans status = BS->HandleProtocol(h, &BlockIoProtocolGUID, (void **)&blkio); 350329140Skevans if (status == EFI_UNSUPPORTED) 351329140Skevans return (status); 352295320Ssmh 353329140Skevans if (status != EFI_SUCCESS) { 354329140Skevans DPRINTF("\nFailed to query BlockIoProtocol (%lu)\n", 355329140Skevans EFI_ERROR_CODE(status)); 356329140Skevans return (status); 357329140Skevans } 358295320Ssmh 359329140Skevans if (!blkio->Media->LogicalPartition) 360329140Skevans return (EFI_UNSUPPORTED); 361329140Skevans 362329140Skevans *preferred = device_paths_match(imgpath, devpath); 363329140Skevans 364329140Skevans /* Run through each module, see if it can load this partition */ 365329140Skevans for (i = 0; i < NUM_BOOT_MODULES; i++) { 366329140Skevans devinfo = malloc(sizeof(*devinfo)); 367329140Skevans if (devinfo == NULL) { 368329140Skevans DPRINTF("\nFailed to allocate devinfo\n"); 369329140Skevans continue; 370329140Skevans } 371329140Skevans devinfo->dev = blkio; 372329140Skevans devinfo->devpath = devpath; 373329140Skevans devinfo->devhandle = h; 374329140Skevans devinfo->devdata = NULL; 375329140Skevans devinfo->preferred = *preferred; 376329140Skevans devinfo->next = NULL; 377329140Skevans 378329140Skevans status = boot_modules[i]->probe(devinfo); 379329140Skevans if (status == EFI_SUCCESS) 380329140Skevans return (EFI_SUCCESS); 381329140Skevans free(devinfo); 382329140Skevans } 383329140Skevans 384329140Skevans return (EFI_UNSUPPORTED); 385329140Skevans} 386329140Skevans 387329140Skevans/* 388329140Skevans * probe_handle_status calls probe_handle and outputs the returned status 389329140Skevans * of the call. 390329140Skevans */ 391329140Skevansstatic void 392329140Skevansprobe_handle_status(EFI_HANDLE h, EFI_DEVICE_PATH *imgpath) 393329140Skevans{ 394329140Skevans EFI_STATUS status; 395329140Skevans BOOLEAN preferred; 396329140Skevans 397329140Skevans preferred = FALSE; 398329140Skevans status = probe_handle(h, imgpath, &preferred); 399329140Skevans 400329140Skevans DPRINTF("probe: "); 401329140Skevans switch (status) { 402329140Skevans case EFI_UNSUPPORTED: 403329140Skevans printf("."); 404329140Skevans DPRINTF(" not supported\n"); 405329140Skevans break; 406329140Skevans case EFI_SUCCESS: 407329140Skevans if (preferred) { 408329140Skevans printf("%c", '*'); 409329140Skevans DPRINTF(" supported (preferred)\n"); 410329140Skevans } else { 411329140Skevans printf("%c", '+'); 412329140Skevans DPRINTF(" supported\n"); 413329140Skevans } 414329140Skevans break; 415329140Skevans default: 416329140Skevans printf("x"); 417329140Skevans DPRINTF(" error (%lu)\n", EFI_ERROR_CODE(status)); 418329140Skevans break; 419329140Skevans } 420329140Skevans DSTALL(500000); 421329140Skevans} 422329140Skevans 423329140SkevansEFI_STATUS 424329140Skevansefi_main(EFI_HANDLE Ximage, EFI_SYSTEM_TABLE *Xsystab) 425329140Skevans{ 426329140Skevans EFI_HANDLE *handles; 427329140Skevans EFI_LOADED_IMAGE *img; 428329140Skevans EFI_DEVICE_PATH *imgpath; 429329140Skevans EFI_STATUS status; 430329140Skevans EFI_CONSOLE_CONTROL_PROTOCOL *ConsoleControl = NULL; 431329140Skevans SIMPLE_TEXT_OUTPUT_INTERFACE *conout = NULL; 432329140Skevans UINTN i, max_dim, best_mode, cols, rows, hsize, nhandles; 433329140Skevans CHAR16 *text; 434329183Skevans UINT16 boot_current; 435329183Skevans size_t sz; 436329183Skevans UINT16 boot_order[100]; 437329140Skevans 438329140Skevans /* Basic initialization*/ 439329140Skevans ST = Xsystab; 440329140Skevans IH = Ximage; 441329140Skevans BS = ST->BootServices; 442329140Skevans RS = ST->RuntimeServices; 443329140Skevans 444329140Skevans /* Set up the console, so printf works. */ 445329140Skevans status = BS->LocateProtocol(&ConsoleControlGUID, NULL, 446329140Skevans (VOID **)&ConsoleControl); 447329140Skevans if (status == EFI_SUCCESS) 448329140Skevans (void)ConsoleControl->SetMode(ConsoleControl, 449329140Skevans EfiConsoleControlScreenText); 450281059Srpaulo /* 451281059Srpaulo * Reset the console and find the best text mode. 452281059Srpaulo */ 453329114Skevans conout = ST->ConOut; 454281059Srpaulo conout->Reset(conout, TRUE); 455281059Srpaulo max_dim = best_mode = 0; 456329140Skevans for (i = 0; ; i++) { 457293274Ssmh status = conout->QueryMode(conout, i, &cols, &rows); 458281059Srpaulo if (EFI_ERROR(status)) 459281059Srpaulo break; 460281059Srpaulo if (cols * rows > max_dim) { 461281059Srpaulo max_dim = cols * rows; 462281059Srpaulo best_mode = i; 463281059Srpaulo } 464281059Srpaulo } 465329140Skevans if (max_dim > 0) 466281059Srpaulo conout->SetMode(conout, best_mode); 467281059Srpaulo conout->EnableCursor(conout, TRUE); 468281059Srpaulo conout->ClearScreen(conout); 469271762Semaste 470294060Ssmh printf("\n>> FreeBSD EFI boot block\n"); 471294765Simp printf(" Loader path: %s\n\n", PATH_LOADER_EFI); 472329140Skevans printf(" Initializing modules:"); 473329140Skevans for (i = 0; i < NUM_BOOT_MODULES; i++) { 474329140Skevans printf(" %s", boot_modules[i]->name); 475329140Skevans if (boot_modules[i]->init != NULL) 476329140Skevans boot_modules[i]->init(); 477294060Ssmh } 478329140Skevans putchar('\n'); 479264391Snwhitehorn 480329114Skevans /* Determine the devpath of our image so we can prefer it. */ 481329140Skevans status = BS->HandleProtocol(IH, &LoadedImageGUID, (VOID**)&img); 482329114Skevans imgpath = NULL; 483329114Skevans if (status == EFI_SUCCESS) { 484329140Skevans text = efi_devpath_name(img->FilePath); 485329140Skevans if (text != NULL) { 486329140Skevans printf(" Load Path: %S\n", text); 487329140Skevans efi_setenv_freebsd_wcs("Boot1Path", text); 488329140Skevans efi_free_devpath_name(text); 489329140Skevans } 490329114Skevans 491329140Skevans status = BS->HandleProtocol(img->DeviceHandle, &DevicePathGUID, 492329114Skevans (void **)&imgpath); 493329114Skevans if (status != EFI_SUCCESS) { 494329114Skevans DPRINTF("Failed to get image DevicePath (%lu)\n", 495329114Skevans EFI_ERROR_CODE(status)); 496329114Skevans } else { 497329114Skevans text = efi_devpath_name(imgpath); 498329140Skevans if (text != NULL) { 499329140Skevans printf(" Load Device: %S\n", text); 500329140Skevans efi_setenv_freebsd_wcs("Boot1Dev", text); 501329140Skevans efi_free_devpath_name(text); 502329140Skevans } 503329114Skevans } 504329140Skevans } 505329114Skevans 506329183Skevans boot_current = 0; 507329183Skevans sz = sizeof(boot_current); 508329183Skevans efi_getenv(&GlobalBootVarGUID, "BootCurrent", &boot_current, &sz); 509329183Skevans printf(" BootCurrent: %04x\n", boot_current); 510329183Skevans 511329183Skevans sz = sizeof(boot_order); 512329183Skevans efi_getenv(&GlobalBootVarGUID, "BootOrder", &boot_order, &sz); 513329183Skevans printf(" BootOrder:"); 514329183Skevans for (i = 0; i < sz / sizeof(boot_order[0]); i++) 515329183Skevans printf(" %04x", boot_order[i]); 516329183Skevans printf("\n"); 517329183Skevans 518329183Skevans#ifdef TEST_FAILURE 519329183Skevans /* 520329183Skevans * For testing failover scenarios, it's nice to be able to fail fast. 521329183Skevans * Define TEST_FAILURE to create a boot1.efi that always fails after 522329183Skevans * reporting the boot manager protocol details. 523329183Skevans */ 524329183Skevans BS->Exit(IH, EFI_OUT_OF_RESOURCES, 0, NULL); 525329183Skevans#endif 526329183Skevans 527329140Skevans /* Get all the device handles */ 528329140Skevans hsize = (UINTN)NUM_HANDLES_INIT * sizeof(EFI_HANDLE); 529329140Skevans handles = malloc(hsize); 530329183Skevans if (handles == NULL) 531329140Skevans printf("Failed to allocate %d handles\n", NUM_HANDLES_INIT); 532329114Skevans 533329140Skevans status = BS->LocateHandle(ByProtocol, &BlockIoProtocolGUID, NULL, 534329140Skevans &hsize, handles); 535329140Skevans switch (status) { 536329140Skevans case EFI_SUCCESS: 537329140Skevans break; 538329140Skevans case EFI_BUFFER_TOO_SMALL: 539329140Skevans free(handles); 540329140Skevans handles = malloc(hsize); 541329140Skevans if (handles == NULL) 542329140Skevans efi_panic(EFI_OUT_OF_RESOURCES, "Failed to allocate %d handles\n", 543329140Skevans NUM_HANDLES_INIT); 544329140Skevans status = BS->LocateHandle(ByProtocol, &BlockIoProtocolGUID, 545329140Skevans NULL, &hsize, handles); 546329140Skevans if (status != EFI_SUCCESS) 547329140Skevans efi_panic(status, "Failed to get device handles\n"); 548329140Skevans break; 549329140Skevans default: 550329140Skevans efi_panic(status, "Failed to get device handles\n"); 551329140Skevans break; 552329140Skevans } 553264391Snwhitehorn 554329140Skevans /* Scan all partitions, probing with all modules. */ 555329140Skevans nhandles = hsize / sizeof(*handles); 556329140Skevans printf(" Probing %zu block devices...", nhandles); 557329140Skevans DPRINTF("\n"); 558329135Skevans 559329140Skevans for (i = 0; i < nhandles; i++) 560329140Skevans probe_handle_status(handles[i], imgpath); 561329140Skevans printf(" done\n"); 562329135Skevans 563329140Skevans /* Status summary. */ 564329140Skevans for (i = 0; i < NUM_BOOT_MODULES; i++) { 565329140Skevans printf(" "); 566329140Skevans boot_modules[i]->status(); 567294060Ssmh } 568264391Snwhitehorn 569295320Ssmh try_boot(); 570281058Srpaulo 571294060Ssmh /* If we get here, we're out of luck... */ 572329114Skevans efi_panic(EFI_LOAD_ERROR, "No bootable partitions found!"); 573264391Snwhitehorn} 574264391Snwhitehorn 575295320Ssmh/* 576329140Skevans * add_device adds a device to the passed devinfo list. 577329140Skevans */ 578329140Skevansvoid 579329140Skevansadd_device(dev_info_t **devinfop, dev_info_t *devinfo) 580329140Skevans{ 581329140Skevans dev_info_t *dev; 582329140Skevans 583329140Skevans if (*devinfop == NULL) { 584329140Skevans *devinfop = devinfo; 585329140Skevans return; 586329140Skevans } 587329140Skevans 588329140Skevans for (dev = *devinfop; dev->next != NULL; dev = dev->next) 589329140Skevans ; 590329140Skevans 591329140Skevans dev->next = devinfo; 592329140Skevans} 593329140Skevans 594329140Skevans/* 595329114Skevans * OK. We totally give up. Exit back to EFI with a sensible status so 596329114Skevans * it can try the next option on the list. 597329114Skevans */ 598329114Skevansstatic void 599329114Skevansefi_panic(EFI_STATUS s, const char *fmt, ...) 600264391Snwhitehorn{ 601329140Skevans va_list ap; 602264391Snwhitehorn 603329140Skevans printf("panic: "); 604329140Skevans va_start(ap, fmt); 605329140Skevans vprintf(fmt, ap); 606329140Skevans va_end(ap); 607329140Skevans printf("\n"); 608264391Snwhitehorn 609329140Skevans BS->Exit(IH, s, 0, NULL); 610264391Snwhitehorn} 611329140Skevans 612329140Skevansvoid 613329140Skevansputchar(int c) 614329140Skevans{ 615329140Skevans CHAR16 buf[2]; 616329140Skevans 617329140Skevans if (c == '\n') { 618329140Skevans buf[0] = '\r'; 619329140Skevans buf[1] = 0; 620329140Skevans ST->ConOut->OutputString(ST->ConOut, buf); 621329140Skevans } 622329140Skevans buf[0] = c; 623329140Skevans buf[1] = 0; 624329140Skevans ST->ConOut->OutputString(ST->ConOut, buf); 625329140Skevans} 626