1 /*- 2 * Copyright (c) 1998 Robert Nordier 3 * All rights reserved. 4 * Copyright (c) 2001 Robert Drehmel 5 * All rights reserved. 6 * Copyright (c) 2014 Nathan Whitehorn 7 * All rights reserved. 8 * Copyright (c) 2015 Eric McCorkle 9 * All rights reserved. 10 * 11 * Redistribution and use in source and binary forms are freely 12 * permitted provided that the above copyright notice and this 13 * paragraph and the following disclaimer are duplicated in all 14 * such forms. 15 * 16 * This software is provided "AS IS" and without any express or 17 * implied warranties, including, without limitation, the implied 18 * warranties of merchantability and fitness for a particular 19 * purpose. 20 * 21 * $FreeBSD: head/sys/boot/efi/boot1/boot1.c 296713 2016-03-12 06:50:16Z andrew $ 22 */ 23 24 #include <sys/param.h> 25 #include <machine/elf.h> 26 #include <machine/stdarg.h> 27 #include <stand.h> 28 #include <stdarg.h> 29 30 #include <efi.h> 31 #include <eficonsctl.h> 32 33 #include "boot_module.h" 34 #include "paths.h" 35 36 #define PATH_CONFIG "/boot/config" 37 #define PATH_DOTCONFIG "/boot.config" 38 #define PATH_LOADER "/loader.efi" /* /boot is dedicated */ 39 #define PATH_LOADER_ALT "/boot/loader.efi" /* /boot in root */ 40 41 static const boot_module_t *boot_modules[] = 42 { 43 #ifdef EFI_UFS_BOOT 44 &ufs_module 45 #endif 46 }; 47 48 #define NUM_BOOT_MODULES NELEM(boot_modules) 49 /* The initial number of handles used to query EFI for partitions. */ 50 #define NUM_HANDLES_INIT 24 51 52 static EFI_GUID BlockIoProtocolGUID = BLOCK_IO_PROTOCOL; 53 static EFI_GUID DevicePathGUID = DEVICE_PATH_PROTOCOL; 54 static EFI_GUID LoadedImageGUID = LOADED_IMAGE_PROTOCOL; 55 static EFI_GUID ConsoleControlGUID = EFI_CONSOLE_CONTROL_PROTOCOL_GUID; 56 57 /* 58 * XXX DragonFly's libstand doesn't provide a way to override the malloc 59 * implementation yet. 60 */ 61 #if 0 62 63 /* 64 * Provide Malloc / Free backed by EFIs AllocatePool / FreePool which ensures 65 * memory is correctly aligned avoiding EFI_INVALID_PARAMETER returns from 66 * EFI methods. 67 */ 68 void * 69 Malloc(size_t len, const char *file __unused, int line __unused) 70 { 71 void *out; 72 73 if (BS->AllocatePool(EfiLoaderData, len, &out) == EFI_SUCCESS) 74 return (out); 75 76 return (NULL); 77 } 78 79 void 80 Free(void *buf, const char *file __unused, int line __unused) 81 { 82 (void)BS->FreePool(buf); 83 } 84 85 #endif 86 87 /* 88 * nodes_match returns TRUE if the imgpath isn't NULL and the nodes match, 89 * FALSE otherwise. 90 */ 91 static BOOLEAN 92 nodes_match(EFI_DEVICE_PATH *imgpath, EFI_DEVICE_PATH *devpath) 93 { 94 size_t len; 95 96 if (imgpath == NULL || imgpath->Type != devpath->Type || 97 imgpath->SubType != devpath->SubType) 98 return (FALSE); 99 100 len = DevicePathNodeLength(imgpath); 101 if (len != DevicePathNodeLength(devpath)) 102 return (FALSE); 103 104 return (memcmp(imgpath, devpath, (size_t)len) == 0); 105 } 106 107 /* 108 * device_paths_match returns TRUE if the imgpath isn't NULL and all nodes 109 * in imgpath and devpath match up to their respect occurrences of a media 110 * node, FALSE otherwise. 111 */ 112 static BOOLEAN 113 device_paths_match(EFI_DEVICE_PATH *imgpath, EFI_DEVICE_PATH *devpath) 114 { 115 116 if (imgpath == NULL) 117 return (FALSE); 118 119 while (!IsDevicePathEnd(imgpath) && !IsDevicePathEnd(devpath)) { 120 if (IsDevicePathType(imgpath, MEDIA_DEVICE_PATH) && 121 IsDevicePathType(devpath, MEDIA_DEVICE_PATH)) 122 return (TRUE); 123 124 if (!nodes_match(imgpath, devpath)) 125 return (FALSE); 126 127 imgpath = NextDevicePathNode(imgpath); 128 devpath = NextDevicePathNode(devpath); 129 } 130 131 return (FALSE); 132 } 133 134 /* 135 * devpath_last returns the last non-path end node in devpath. 136 */ 137 static EFI_DEVICE_PATH * 138 devpath_last(EFI_DEVICE_PATH *devpath) 139 { 140 141 while (!IsDevicePathEnd(NextDevicePathNode(devpath))) 142 devpath = NextDevicePathNode(devpath); 143 144 return (devpath); 145 } 146 147 /* 148 * devpath_node_str is a basic output method for a devpath node which 149 * only understands a subset of the available sub types. 150 * 151 * If we switch to UEFI 2.x then we should update it to use: 152 * EFI_DEVICE_PATH_TO_TEXT_PROTOCOL. 153 */ 154 static int 155 devpath_node_str(char *buf, size_t size, EFI_DEVICE_PATH *devpath) 156 { 157 158 switch (devpath->Type) { 159 case MESSAGING_DEVICE_PATH: 160 switch (devpath->SubType) { 161 case MSG_ATAPI_DP: { 162 ATAPI_DEVICE_PATH *atapi; 163 164 atapi = (ATAPI_DEVICE_PATH *)(void *)devpath; 165 return snprintf(buf, size, "ata(%s,%s,0x%x)", 166 (atapi->PrimarySecondary == 1) ? "Sec" : "Pri", 167 (atapi->SlaveMaster == 1) ? "Slave" : "Master", 168 atapi->Lun); 169 } 170 case MSG_USB_DP: { 171 USB_DEVICE_PATH *usb; 172 173 usb = (USB_DEVICE_PATH *)devpath; 174 return snprintf(buf, size, "usb(0x%02x,0x%02x)", 175 usb->ParentPortNumber, usb->InterfaceNumber); 176 } 177 case MSG_SCSI_DP: { 178 SCSI_DEVICE_PATH *scsi; 179 180 scsi = (SCSI_DEVICE_PATH *)(void *)devpath; 181 return snprintf(buf, size, "scsi(0x%02x,0x%02x)", 182 scsi->Pun, scsi->Lun); 183 } 184 case MSG_SATA_DP: { 185 SATA_DEVICE_PATH *sata; 186 187 sata = (SATA_DEVICE_PATH *)(void *)devpath; 188 return snprintf(buf, size, "sata(0x%x,0x%x,0x%x)", 189 sata->HBAPortNumber, sata->PortMultiplierPortNumber, 190 sata->Lun); 191 } 192 default: 193 return snprintf(buf, size, "msg(0x%02x)", 194 devpath->SubType); 195 } 196 break; 197 case HARDWARE_DEVICE_PATH: 198 switch (devpath->SubType) { 199 case HW_PCI_DP: { 200 PCI_DEVICE_PATH *pci; 201 202 pci = (PCI_DEVICE_PATH *)devpath; 203 return snprintf(buf, size, "pci(0x%02x,0x%02x)", 204 pci->Device, pci->Function); 205 } 206 default: 207 return snprintf(buf, size, "hw(0x%02x)", 208 devpath->SubType); 209 } 210 break; 211 case ACPI_DEVICE_PATH: { 212 ACPI_HID_DEVICE_PATH *acpi; 213 214 acpi = (ACPI_HID_DEVICE_PATH *)(void *)devpath; 215 if ((acpi->HID & PNP_EISA_ID_MASK) == PNP_EISA_ID_CONST) { 216 switch (EISA_ID_TO_NUM(acpi->HID)) { 217 case 0x0a03: 218 return snprintf(buf, size, "pciroot(0x%x)", 219 acpi->UID); 220 case 0x0a08: 221 return snprintf(buf, size, "pcieroot(0x%x)", 222 acpi->UID); 223 case 0x0604: 224 return snprintf(buf, size, "floppy(0x%x)", 225 acpi->UID); 226 case 0x0301: 227 return snprintf(buf, size, "keyboard(0x%x)", 228 acpi->UID); 229 case 0x0501: 230 return snprintf(buf, size, "serial(0x%x)", 231 acpi->UID); 232 case 0x0401: 233 return snprintf(buf, size, "parallelport(0x%x)", 234 acpi->UID); 235 default: 236 return snprintf(buf, size, "acpi(pnp%04x,0x%x)", 237 EISA_ID_TO_NUM(acpi->HID), acpi->UID); 238 } 239 } 240 241 return snprintf(buf, size, "acpi(0x%08x,0x%x)", acpi->HID, 242 acpi->UID); 243 } 244 case MEDIA_DEVICE_PATH: 245 switch (devpath->SubType) { 246 case MEDIA_CDROM_DP: { 247 CDROM_DEVICE_PATH *cdrom; 248 249 cdrom = (CDROM_DEVICE_PATH *)(void *)devpath; 250 return snprintf(buf, size, "cdrom(%x)", 251 cdrom->BootEntry); 252 } 253 case MEDIA_HARDDRIVE_DP: { 254 HARDDRIVE_DEVICE_PATH *hd; 255 256 hd = (HARDDRIVE_DEVICE_PATH *)(void *)devpath; 257 return snprintf(buf, size, "hd(%x)", 258 hd->PartitionNumber); 259 } 260 default: 261 return snprintf(buf, size, "media(0x%02x)", 262 devpath->SubType); 263 } 264 case BBS_DEVICE_PATH: 265 return snprintf(buf, size, "bbs(0x%02x)", devpath->SubType); 266 case END_DEVICE_PATH_TYPE: 267 return (0); 268 } 269 270 return snprintf(buf, size, "type(0x%02x, 0x%02x)", devpath->Type, 271 devpath->SubType); 272 } 273 274 /* 275 * devpath_strlcat appends a text description of devpath to buf but not more 276 * than size - 1 characters followed by NUL-terminator. 277 */ 278 int 279 devpath_strlcat(char *buf, size_t size, EFI_DEVICE_PATH *devpath) 280 { 281 size_t len, used; 282 const char *sep; 283 284 sep = ""; 285 used = 0; 286 while (!IsDevicePathEnd(devpath)) { 287 len = snprintf(buf, size - used, "%s", sep); 288 used += len; 289 if (used > size) 290 return (used); 291 buf += len; 292 293 len = devpath_node_str(buf, size - used, devpath); 294 used += len; 295 if (used > size) 296 return (used); 297 buf += len; 298 devpath = NextDevicePathNode(devpath); 299 sep = ":"; 300 } 301 302 return (used); 303 } 304 305 /* 306 * devpath_str is convenience method which returns the text description of 307 * devpath using a static buffer, so it isn't thread safe! 308 */ 309 char * 310 devpath_str(EFI_DEVICE_PATH *devpath) 311 { 312 static char buf[256]; 313 314 devpath_strlcat(buf, sizeof(buf), devpath); 315 316 return buf; 317 } 318 319 /* 320 * load_loader attempts to load the loader image data. 321 * 322 * It tries each module and its respective devices, identified by mod->probe, 323 * in order until a successful load occurs at which point it returns EFI_SUCCESS 324 * and EFI_NOT_FOUND otherwise. 325 * 326 * Only devices which have preferred matching the preferred parameter are tried. 327 */ 328 static EFI_STATUS 329 load_loader(const boot_module_t **modp, dev_info_t **devinfop, void **bufp, 330 size_t *bufsize, BOOLEAN preferred) 331 { 332 UINTN i; 333 dev_info_t *dev; 334 const boot_module_t *mod; 335 EFI_STATUS status; 336 337 for (i = 0; i < NUM_BOOT_MODULES; i++) { 338 if (boot_modules[i] == NULL) 339 continue; 340 mod = boot_modules[i]; 341 for (dev = mod->devices(); dev != NULL; dev = dev->next) { 342 if (dev->preferred != preferred) 343 continue; 344 345 status = mod->load(PATH_LOADER, dev, bufp, bufsize); 346 if (status == EFI_NOT_FOUND) { 347 status = mod->load(PATH_LOADER_ALT, dev, bufp, 348 bufsize); 349 } 350 if (status == EFI_SUCCESS) { 351 *devinfop = dev; 352 *modp = mod; 353 return (EFI_SUCCESS); 354 } 355 } 356 } 357 358 return (EFI_NOT_FOUND); 359 } 360 361 /* 362 * try_boot only returns if it fails to load the loader. If it succeeds 363 * it simply boots, otherwise it returns the status of last EFI call. 364 */ 365 static EFI_STATUS 366 try_boot(void) 367 { 368 size_t bufsize, loadersize, cmdsize; 369 char *cmd; 370 void *buf; 371 void *loaderbuf; 372 dev_info_t *dev; 373 const boot_module_t *mod; 374 EFI_HANDLE loaderhandle; 375 EFI_LOADED_IMAGE *loaded_image; 376 EFI_STATUS status; 377 378 loaderbuf = NULL; 379 loadersize = 0; 380 381 status = load_loader(&mod, &dev, &loaderbuf, &loadersize, TRUE); 382 if (status != EFI_SUCCESS) { 383 status = load_loader(&mod, &dev, &loaderbuf, 384 &loadersize, FALSE); 385 if (status != EFI_SUCCESS) { 386 printf("Failed to load '%s' or '%s'\n", 387 PATH_LOADER, PATH_LOADER_ALT); 388 return (status); 389 } 390 } 391 392 /* 393 * Funcions might not initialize response variables on error, make 394 * sure we have sanity. 395 */ 396 cmd = NULL; 397 buf = NULL; 398 cmdsize = 0; 399 bufsize = 0; 400 401 /* 402 * Read in and parse the command line from /boot.config or 403 * /boot/config, if present. We'll pass it the next stage via a 404 * simple ASCII string. loader.efi has a hack for ASCII strings, so 405 * we'll use that to keep the size down here. We only try to read the 406 * alternate file if we get EFI_NOT_FOUND because all other errors 407 * mean that the boot_module had troubles with the filesystem. We 408 * could return early, but we'll let loading the actual kernel sort 409 * all that out. Since these files are optional, we don't report 410 * errors in trying to read them. 411 */ 412 status = mod->load(PATH_DOTCONFIG, dev, &buf, &bufsize); 413 if (status == EFI_NOT_FOUND) 414 status = mod->load(PATH_CONFIG, dev, &buf, &bufsize); 415 if (status == EFI_SUCCESS) { 416 cmdsize = bufsize + 1; 417 cmd = malloc(cmdsize); 418 if (cmd == NULL) 419 goto errout; 420 memcpy(cmd, buf, bufsize); 421 cmd[bufsize] = '\0'; 422 free(buf); 423 buf = NULL; 424 } 425 426 status = BS->LoadImage(TRUE, IH, devpath_last(dev->devpath), 427 loaderbuf, loadersize, &loaderhandle); 428 if (status != EFI_SUCCESS) { 429 printf("Failed to load image provided by %s, " 430 "size: %zu, (0x%llx)\n", 431 mod->name, loadersize, status); 432 goto errout; 433 } 434 435 status = OpenProtocolByHandle(loaderhandle, &LoadedImageGUID, 436 (VOID**)&loaded_image); 437 if (status != EFI_SUCCESS) { 438 printf("Failed to query LoadedImage provided by %s (0x%llx)\n", 439 mod->name, status); 440 goto errout; 441 } 442 443 if (cmd != NULL) 444 printf(" command args: %s\n", cmd); 445 446 loaded_image->DeviceHandle = dev->devhandle; 447 loaded_image->LoadOptionsSize = cmdsize; 448 loaded_image->LoadOptions = cmd; 449 450 DPRINTF("Starting '%s' in 5 seconds...", PATH_LOADER_EFI); 451 DSTALL(1000000); 452 DPRINTF("."); 453 DSTALL(1000000); 454 DPRINTF("."); 455 DSTALL(1000000); 456 DPRINTF("."); 457 DSTALL(1000000); 458 DPRINTF("."); 459 DSTALL(1000000); 460 DPRINTF(".\n"); 461 462 status = BS->StartImage(loaderhandle, NULL, NULL); 463 if (status != EFI_SUCCESS) { 464 printf("Failed to start image provided by %s (0x%llx)\n", 465 mod->name, status); 466 loaded_image->LoadOptionsSize = 0; 467 loaded_image->LoadOptions = NULL; 468 } 469 470 /* 471 * Note that buf and loaderbuf were allocated via boot services, 472 * not our local allocator. 473 */ 474 errout: 475 if (cmd != NULL) 476 free(cmd); 477 if (buf != NULL) 478 (void)BS->FreePool(buf); 479 if (loaderbuf != NULL) 480 (void)BS->FreePool(loaderbuf); 481 482 return (status); 483 } 484 485 /* 486 * probe_handle determines if the passed handle represents a logical partition 487 * if it does it uses each module in order to probe it and if successful it 488 * returns EFI_SUCCESS. 489 */ 490 static EFI_STATUS 491 probe_handle(EFI_HANDLE h, EFI_DEVICE_PATH *imgpath, BOOLEAN *preferred) 492 { 493 dev_info_t *devinfo; 494 EFI_BLOCK_IO *blkio; 495 EFI_DEVICE_PATH *devpath; 496 EFI_STATUS status; 497 UINTN i; 498 499 /* Figure out if we're dealing with an actual partition. */ 500 status = OpenProtocolByHandle(h, &DevicePathGUID, (void **)&devpath); 501 if (status == EFI_UNSUPPORTED) 502 return (status); 503 504 if (status != EFI_SUCCESS) { 505 DPRINTF("\nFailed to query DevicePath (0x%llx)\n", 506 status); 507 return (status); 508 } 509 510 DPRINTF("probing: %s\n", devpath_str(devpath)); 511 512 status = OpenProtocolByHandle(h, &BlockIoProtocolGUID, 513 (void **)&blkio); 514 if (status == EFI_UNSUPPORTED) 515 return (status); 516 517 if (status != EFI_SUCCESS) { 518 DPRINTF("\nFailed to query BlockIoProtocol (0x%llx)\n", 519 status); 520 return (status); 521 } 522 523 if (!blkio->Media->LogicalPartition) 524 return (EFI_UNSUPPORTED); 525 526 *preferred = device_paths_match(imgpath, devpath); 527 528 /* Run through each module, see if it can load this partition */ 529 for (i = 0; i < NUM_BOOT_MODULES; i++) { 530 if (boot_modules[i] == NULL) 531 continue; 532 533 status = BS->AllocatePool(EfiLoaderData, sizeof(*devinfo), 534 (void **)&devinfo); 535 if (status != EFI_SUCCESS) { 536 DPRINTF("\nFailed to allocate devinfo (0x%llx)\n", 537 status); 538 continue; 539 } 540 devinfo->dev = blkio; 541 devinfo->devpath = devpath; 542 devinfo->devhandle = h; 543 devinfo->devdata = NULL; 544 devinfo->preferred = *preferred; 545 devinfo->next = NULL; 546 547 status = boot_modules[i]->probe(devinfo); 548 if (status == EFI_SUCCESS) 549 return (EFI_SUCCESS); 550 (void)BS->FreePool(devinfo); 551 } 552 553 return (EFI_UNSUPPORTED); 554 } 555 556 /* 557 * probe_handle_status calls probe_handle and outputs the returned status 558 * of the call. 559 */ 560 static void 561 probe_handle_status(EFI_HANDLE h, EFI_DEVICE_PATH *imgpath) 562 { 563 EFI_STATUS status; 564 BOOLEAN preferred; 565 566 preferred = FALSE; 567 status = probe_handle(h, imgpath, &preferred); 568 569 DPRINTF("probe: "); 570 switch (status) { 571 case EFI_UNSUPPORTED: 572 printf("."); 573 DPRINTF(" not supported\n"); 574 break; 575 case EFI_SUCCESS: 576 if (preferred) { 577 printf("%c", '*'); 578 DPRINTF(" supported (preferred)\n"); 579 } else { 580 printf("%c", '+'); 581 DPRINTF(" supported\n"); 582 } 583 break; 584 default: 585 printf("x"); 586 DPRINTF(" error (0x%llx)\n", status); 587 break; 588 } 589 DSTALL(500000); 590 } 591 592 EFI_STATUS 593 efi_main(EFI_HANDLE Ximage, EFI_SYSTEM_TABLE *Xsystab) 594 { 595 EFI_HANDLE *handles; 596 EFI_LOADED_IMAGE *img; 597 EFI_DEVICE_PATH *imgpath; 598 EFI_STATUS status; 599 EFI_CONSOLE_CONTROL_PROTOCOL *ConsoleControl = NULL; 600 SIMPLE_TEXT_OUTPUT_INTERFACE *conout = NULL; 601 UINTN i, max_dim, best_mode, cols, rows, hsize, nhandles; 602 603 /* Basic initialization*/ 604 ST = Xsystab; 605 IH = Ximage; 606 BS = ST->BootServices; 607 RS = ST->RuntimeServices; 608 609 /* Set up the console, so printf works. */ 610 status = BS->LocateProtocol(&ConsoleControlGUID, NULL, 611 (VOID **)&ConsoleControl); 612 if (status == EFI_SUCCESS) 613 (void)ConsoleControl->SetMode(ConsoleControl, 614 EfiConsoleControlScreenText); 615 /* 616 * Reset the console and find the best text mode. 617 */ 618 conout = ST->ConOut; 619 conout->Reset(conout, TRUE); 620 max_dim = best_mode = 0; 621 for (i = 0; ; i++) { 622 status = conout->QueryMode(conout, i, &cols, &rows); 623 if (EFI_ERROR(status)) { 624 /* Mode 1 (80x50) can be unsupported on some hw. */ 625 if (i == 1) 626 continue; 627 else 628 break; 629 } 630 if (cols * rows > max_dim) { 631 max_dim = cols * rows; 632 best_mode = i; 633 } 634 } 635 if (max_dim > 0) 636 conout->SetMode(conout, best_mode); 637 conout->EnableCursor(conout, TRUE); 638 conout->ClearScreen(conout); 639 640 printf("\n>> DragonFly EFI boot block\n"); 641 printf(" Loader path: %s:%s\n\n", PATH_LOADER, PATH_LOADER_ALT); 642 printf(" Initializing modules:"); 643 for (i = 0; i < NUM_BOOT_MODULES; i++) { 644 if (boot_modules[i] == NULL) 645 continue; 646 647 printf(" %s", boot_modules[i]->name); 648 if (boot_modules[i]->init != NULL) 649 boot_modules[i]->init(); 650 } 651 putchar('\n'); 652 653 /* Get all the device handles */ 654 hsize = (UINTN)NUM_HANDLES_INIT * sizeof(EFI_HANDLE); 655 if ((status = BS->AllocatePool(EfiLoaderData, hsize, (void **)&handles)) 656 != EFI_SUCCESS) 657 panic("Failed to allocate %d handles (0x%llx)", NUM_HANDLES_INIT, 658 status); 659 660 status = BS->LocateHandle(ByProtocol, &BlockIoProtocolGUID, NULL, 661 &hsize, handles); 662 switch (status) { 663 case EFI_SUCCESS: 664 break; 665 case EFI_BUFFER_TOO_SMALL: 666 (void)BS->FreePool(handles); 667 if ((status = BS->AllocatePool(EfiLoaderData, hsize, 668 (void **)&handles)) != EFI_SUCCESS) { 669 panic("Failed to allocate %llu handles (0x%llx)", hsize / 670 sizeof(*handles), status); 671 } 672 status = BS->LocateHandle(ByProtocol, &BlockIoProtocolGUID, 673 NULL, &hsize, handles); 674 if (status != EFI_SUCCESS) 675 panic("Failed to get device handles (0x%llx)\n", 676 status); 677 break; 678 default: 679 panic("Failed to get device handles (0x%llx)", 680 status); 681 } 682 683 /* Scan all partitions, probing with all modules. */ 684 nhandles = hsize / sizeof(*handles); 685 printf(" Probing %llu block devices...", nhandles); 686 DPRINTF("\n"); 687 688 /* Determine the devpath of our image so we can prefer it. */ 689 status = OpenProtocolByHandle(IH, &LoadedImageGUID, (VOID**)&img); 690 imgpath = NULL; 691 if (status == EFI_SUCCESS) { 692 status = OpenProtocolByHandle(img->DeviceHandle, 693 &DevicePathGUID, 694 (void **)&imgpath); 695 if (status != EFI_SUCCESS) { 696 DPRINTF("Failed to get image DevicePath (0x%llx)\n", 697 status); 698 } 699 DPRINTF("boot1 imagepath: %s\n", devpath_str(imgpath)); 700 } 701 702 for (i = 0; i < nhandles; i++) 703 probe_handle_status(handles[i], imgpath); 704 printf(" done\n"); 705 706 /* Status summary. */ 707 for (i = 0; i < NUM_BOOT_MODULES; i++) { 708 if (boot_modules[i] != NULL) { 709 printf(" "); 710 boot_modules[i]->status(); 711 } 712 } 713 714 try_boot(); 715 716 /* If we get here, we're out of luck... */ 717 panic("No bootable partitions found!"); 718 } 719 720 /* 721 * add_device adds a device to the passed devinfo list. 722 */ 723 void 724 add_device(dev_info_t **devinfop, dev_info_t *devinfo) 725 { 726 dev_info_t *dev; 727 728 if (*devinfop == NULL) { 729 *devinfop = devinfo; 730 return; 731 } 732 733 for (dev = *devinfop; dev->next != NULL; dev = dev->next) 734 ; 735 736 dev->next = devinfo; 737 } 738 739 void 740 panic(const char *fmt, ...) 741 { 742 va_list ap; 743 744 printf("panic: "); 745 va_start(ap, fmt); 746 vprintf(fmt, ap); 747 va_end(ap); 748 printf("\n"); 749 750 while (1) {} 751 } 752 753 void 754 putchar(int c) 755 { 756 CHAR16 buf[2]; 757 758 if (c == '\n') { 759 buf[0] = '\r'; 760 buf[1] = 0; 761 ST->ConOut->OutputString(ST->ConOut, buf); 762 } 763 buf[0] = c; 764 buf[1] = 0; 765 ST->ConOut->OutputString(ST->ConOut, buf); 766 } 767