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 void *buf, *loaderbuf; 370 char *cmd; 371 dev_info_t *dev; 372 const boot_module_t *mod; 373 EFI_HANDLE loaderhandle; 374 EFI_LOADED_IMAGE *loaded_image; 375 EFI_STATUS status; 376 377 status = load_loader(&mod, &dev, &loaderbuf, &loadersize, TRUE); 378 if (status != EFI_SUCCESS) { 379 status = load_loader(&mod, &dev, &loaderbuf, &loadersize, 380 FALSE); 381 if (status != EFI_SUCCESS) { 382 printf("Failed to load '%s' or '%s'\n", 383 PATH_LOADER, PATH_LOADER_ALT); 384 return (status); 385 } 386 } 387 388 /* 389 * Read in and parse the command line from /boot.config or /boot/config, 390 * if present. We'll pass it the next stage via a simple ASCII 391 * string. loader.efi has a hack for ASCII strings, so we'll use that to 392 * keep the size down here. We only try to read the alternate file if 393 * we get EFI_NOT_FOUND because all other errors mean that the boot_module 394 * had troubles with the filesystem. We could return early, but we'll let 395 * loading the actual kernel sort all that out. Since these files are 396 * optional, we don't report errors in trying to read them. 397 */ 398 cmd = NULL; 399 cmdsize = 0; 400 status = mod->load(PATH_DOTCONFIG, dev, &buf, &bufsize); 401 if (status == EFI_NOT_FOUND) 402 status = mod->load(PATH_CONFIG, dev, &buf, &bufsize); 403 if (status == EFI_SUCCESS) { 404 cmdsize = bufsize + 1; 405 cmd = malloc(cmdsize); 406 if (cmd == NULL) 407 goto errout; 408 memcpy(cmd, buf, bufsize); 409 cmd[bufsize] = '\0'; 410 free(buf); 411 buf = NULL; 412 } 413 414 if ((status = BS->LoadImage(TRUE, IH, devpath_last(dev->devpath), 415 loaderbuf, loadersize, &loaderhandle)) != EFI_SUCCESS) { 416 printf("Failed to load image provided by %s, size: %zu, (%llu)\n", 417 mod->name, loadersize, status); 418 goto errout; 419 } 420 421 if ((status = OpenProtocolByHandle(loaderhandle, &LoadedImageGUID, 422 (VOID**)&loaded_image)) != EFI_SUCCESS) { 423 printf("Failed to query LoadedImage provided by %s (%llu)\n", 424 mod->name, status); 425 goto errout; 426 } 427 428 if (cmd != NULL) 429 printf(" command args: %s\n", cmd); 430 431 loaded_image->DeviceHandle = dev->devhandle; 432 loaded_image->LoadOptionsSize = cmdsize; 433 loaded_image->LoadOptions = cmd; 434 435 DPRINTF("Starting '%s' in 5 seconds...", PATH_LOADER_EFI); 436 DSTALL(1000000); 437 DPRINTF("."); 438 DSTALL(1000000); 439 DPRINTF("."); 440 DSTALL(1000000); 441 DPRINTF("."); 442 DSTALL(1000000); 443 DPRINTF("."); 444 DSTALL(1000000); 445 DPRINTF(".\n"); 446 447 if ((status = BS->StartImage(loaderhandle, NULL, NULL)) != 448 EFI_SUCCESS) { 449 printf("Failed to start image provided by %s (%llu)\n", 450 mod->name, status); 451 loaded_image->LoadOptionsSize = 0; 452 loaded_image->LoadOptions = NULL; 453 } 454 455 errout: 456 if (cmd != NULL) 457 free(cmd); 458 if (buf != NULL) 459 free(buf); 460 if (loaderbuf != NULL) 461 free(loaderbuf); 462 463 return (status); 464 } 465 466 /* 467 * probe_handle determines if the passed handle represents a logical partition 468 * if it does it uses each module in order to probe it and if successful it 469 * returns EFI_SUCCESS. 470 */ 471 static EFI_STATUS 472 probe_handle(EFI_HANDLE h, EFI_DEVICE_PATH *imgpath, BOOLEAN *preferred) 473 { 474 dev_info_t *devinfo; 475 EFI_BLOCK_IO *blkio; 476 EFI_DEVICE_PATH *devpath; 477 EFI_STATUS status; 478 UINTN i; 479 480 /* Figure out if we're dealing with an actual partition. */ 481 status = OpenProtocolByHandle(h, &DevicePathGUID, (void **)&devpath); 482 if (status == EFI_UNSUPPORTED) 483 return (status); 484 485 if (status != EFI_SUCCESS) { 486 DPRINTF("\nFailed to query DevicePath (%llu)\n", 487 status); 488 return (status); 489 } 490 491 DPRINTF("probing: %s\n", devpath_str(devpath)); 492 493 status = OpenProtocolByHandle(h, &BlockIoProtocolGUID, 494 (void **)&blkio); 495 if (status == EFI_UNSUPPORTED) 496 return (status); 497 498 if (status != EFI_SUCCESS) { 499 DPRINTF("\nFailed to query BlockIoProtocol (%llu)\n", 500 status); 501 return (status); 502 } 503 504 if (!blkio->Media->LogicalPartition) 505 return (EFI_UNSUPPORTED); 506 507 *preferred = device_paths_match(imgpath, devpath); 508 509 /* Run through each module, see if it can load this partition */ 510 for (i = 0; i < NUM_BOOT_MODULES; i++) { 511 if (boot_modules[i] == NULL) 512 continue; 513 514 if ((status = BS->AllocatePool(EfiLoaderData, 515 sizeof(*devinfo), (void **)&devinfo)) != 516 EFI_SUCCESS) { 517 DPRINTF("\nFailed to allocate devinfo (%llu)\n", 518 status); 519 continue; 520 } 521 devinfo->dev = blkio; 522 devinfo->devpath = devpath; 523 devinfo->devhandle = h; 524 devinfo->devdata = NULL; 525 devinfo->preferred = *preferred; 526 devinfo->next = NULL; 527 528 status = boot_modules[i]->probe(devinfo); 529 if (status == EFI_SUCCESS) 530 return (EFI_SUCCESS); 531 (void)BS->FreePool(devinfo); 532 } 533 534 return (EFI_UNSUPPORTED); 535 } 536 537 /* 538 * probe_handle_status calls probe_handle and outputs the returned status 539 * of the call. 540 */ 541 static void 542 probe_handle_status(EFI_HANDLE h, EFI_DEVICE_PATH *imgpath) 543 { 544 EFI_STATUS status; 545 BOOLEAN preferred; 546 547 preferred = FALSE; 548 status = probe_handle(h, imgpath, &preferred); 549 550 DPRINTF("probe: "); 551 switch (status) { 552 case EFI_UNSUPPORTED: 553 printf("."); 554 DPRINTF(" not supported\n"); 555 break; 556 case EFI_SUCCESS: 557 if (preferred) { 558 printf("%c", '*'); 559 DPRINTF(" supported (preferred)\n"); 560 } else { 561 printf("%c", '+'); 562 DPRINTF(" supported\n"); 563 } 564 break; 565 default: 566 printf("x"); 567 DPRINTF(" error (%llu)\n", status); 568 break; 569 } 570 DSTALL(500000); 571 } 572 573 EFI_STATUS 574 efi_main(EFI_HANDLE Ximage, EFI_SYSTEM_TABLE *Xsystab) 575 { 576 EFI_HANDLE *handles; 577 EFI_LOADED_IMAGE *img; 578 EFI_DEVICE_PATH *imgpath; 579 EFI_STATUS status; 580 EFI_CONSOLE_CONTROL_PROTOCOL *ConsoleControl = NULL; 581 SIMPLE_TEXT_OUTPUT_INTERFACE *conout = NULL; 582 UINTN i, max_dim, best_mode, cols, rows, hsize, nhandles; 583 584 /* Basic initialization*/ 585 ST = Xsystab; 586 IH = Ximage; 587 BS = ST->BootServices; 588 RS = ST->RuntimeServices; 589 590 /* Set up the console, so printf works. */ 591 status = BS->LocateProtocol(&ConsoleControlGUID, NULL, 592 (VOID **)&ConsoleControl); 593 if (status == EFI_SUCCESS) 594 (void)ConsoleControl->SetMode(ConsoleControl, 595 EfiConsoleControlScreenText); 596 /* 597 * Reset the console and find the best text mode. 598 */ 599 conout = ST->ConOut; 600 conout->Reset(conout, TRUE); 601 max_dim = best_mode = 0; 602 for (i = 0; ; i++) { 603 status = conout->QueryMode(conout, i, &cols, &rows); 604 if (EFI_ERROR(status)) { 605 /* Mode 1 (80x50) can be unsupported on some hw. */ 606 if (i == 1) 607 continue; 608 else 609 break; 610 } 611 if (cols * rows > max_dim) { 612 max_dim = cols * rows; 613 best_mode = i; 614 } 615 } 616 if (max_dim > 0) 617 conout->SetMode(conout, best_mode); 618 conout->EnableCursor(conout, TRUE); 619 conout->ClearScreen(conout); 620 621 printf("\n>> DragonFly EFI boot block\n"); 622 printf(" Loader path: %s:%s\n\n", PATH_LOADER, PATH_LOADER_ALT); 623 printf(" Initializing modules:"); 624 for (i = 0; i < NUM_BOOT_MODULES; i++) { 625 if (boot_modules[i] == NULL) 626 continue; 627 628 printf(" %s", boot_modules[i]->name); 629 if (boot_modules[i]->init != NULL) 630 boot_modules[i]->init(); 631 } 632 putchar('\n'); 633 634 /* Get all the device handles */ 635 hsize = (UINTN)NUM_HANDLES_INIT * sizeof(EFI_HANDLE); 636 if ((status = BS->AllocatePool(EfiLoaderData, hsize, (void **)&handles)) 637 != EFI_SUCCESS) 638 panic("Failed to allocate %d handles (%llu)", NUM_HANDLES_INIT, 639 status); 640 641 status = BS->LocateHandle(ByProtocol, &BlockIoProtocolGUID, NULL, 642 &hsize, handles); 643 switch (status) { 644 case EFI_SUCCESS: 645 break; 646 case EFI_BUFFER_TOO_SMALL: 647 (void)BS->FreePool(handles); 648 if ((status = BS->AllocatePool(EfiLoaderData, hsize, 649 (void **)&handles)) != EFI_SUCCESS) { 650 panic("Failed to allocate %llu handles (%llu)", hsize / 651 sizeof(*handles), status); 652 } 653 status = BS->LocateHandle(ByProtocol, &BlockIoProtocolGUID, 654 NULL, &hsize, handles); 655 if (status != EFI_SUCCESS) 656 panic("Failed to get device handles (%llu)\n", 657 status); 658 break; 659 default: 660 panic("Failed to get device handles (%llu)", 661 status); 662 } 663 664 /* Scan all partitions, probing with all modules. */ 665 nhandles = hsize / sizeof(*handles); 666 printf(" Probing %llu block devices...", nhandles); 667 DPRINTF("\n"); 668 669 /* Determine the devpath of our image so we can prefer it. */ 670 status = OpenProtocolByHandle(IH, &LoadedImageGUID, (VOID**)&img); 671 imgpath = NULL; 672 if (status == EFI_SUCCESS) { 673 status = OpenProtocolByHandle(img->DeviceHandle, 674 &DevicePathGUID, (void **)&imgpath); 675 if (status != EFI_SUCCESS) 676 DPRINTF("Failed to get image DevicePath (%llu)\n", 677 status); 678 DPRINTF("boot1 imagepath: %s\n", devpath_str(imgpath)); 679 } 680 681 for (i = 0; i < nhandles; i++) 682 probe_handle_status(handles[i], imgpath); 683 printf(" done\n"); 684 685 /* Status summary. */ 686 for (i = 0; i < NUM_BOOT_MODULES; i++) { 687 if (boot_modules[i] != NULL) { 688 printf(" "); 689 boot_modules[i]->status(); 690 } 691 } 692 693 try_boot(); 694 695 /* If we get here, we're out of luck... */ 696 panic("No bootable partitions found!"); 697 } 698 699 /* 700 * add_device adds a device to the passed devinfo list. 701 */ 702 void 703 add_device(dev_info_t **devinfop, dev_info_t *devinfo) 704 { 705 dev_info_t *dev; 706 707 if (*devinfop == NULL) { 708 *devinfop = devinfo; 709 return; 710 } 711 712 for (dev = *devinfop; dev->next != NULL; dev = dev->next) 713 ; 714 715 dev->next = devinfo; 716 } 717 718 void 719 panic(const char *fmt, ...) 720 { 721 va_list ap; 722 723 printf("panic: "); 724 va_start(ap, fmt); 725 vprintf(fmt, ap); 726 va_end(ap); 727 printf("\n"); 728 729 while (1) {} 730 } 731 732 void 733 putchar(int c) 734 { 735 CHAR16 buf[2]; 736 737 if (c == '\n') { 738 buf[0] = '\r'; 739 buf[1] = 0; 740 ST->ConOut->OutputString(ST->ConOut, buf); 741 } 742 buf[0] = c; 743 buf[1] = 0; 744 ST->ConOut->OutputString(ST->ConOut, buf); 745 } 746