1 /* 2 * Copyright (c) 2008-2010 Rui Paulo 3 * Copyright (c) 2006 Marcel Moolenaar 4 * All rights reserved. 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions 8 * are met: 9 * 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 17 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 18 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 19 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 20 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 21 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 22 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 23 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 25 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26 */ 27 28 #include <sys/cdefs.h> 29 30 #include <sys/disk.h> 31 #include <sys/param.h> 32 #include <sys/reboot.h> 33 #include <sys/boot.h> 34 #include <sys/consplat.h> 35 #include <stand.h> 36 #include <inttypes.h> 37 #include <string.h> 38 #include <setjmp.h> 39 #include <disk.h> 40 41 #include <efi.h> 42 #include <efilib.h> 43 #include <efigpt.h> 44 45 #include <uuid.h> 46 47 #include <bootstrap.h> 48 #include <gfx_fb.h> 49 #include <smbios.h> 50 51 #include <libzfs.h> 52 #include <efizfs.h> 53 54 #include "loader_efi.h" 55 56 struct arch_switch archsw; /* MI/MD interface boundary */ 57 58 EFI_GUID devid = DEVICE_PATH_PROTOCOL; 59 EFI_GUID imgid = LOADED_IMAGE_PROTOCOL; 60 EFI_GUID smbios = SMBIOS_TABLE_GUID; 61 EFI_GUID smbios3 = SMBIOS3_TABLE_GUID; 62 EFI_GUID inputid = SIMPLE_TEXT_INPUT_PROTOCOL; 63 64 extern void acpi_detect(void); 65 extern void efi_getsmap(void); 66 67 static EFI_LOADED_IMAGE *img; 68 69 /* 70 * Number of seconds to wait for a keystroke before exiting with failure 71 * in the event no currdev is found. -2 means always break, -1 means 72 * never break, 0 means poll once and then reboot, > 0 means wait for 73 * that many seconds. "fail_timeout" can be set in the environment as 74 * well. 75 */ 76 static int fail_timeout = 5; 77 78 bool 79 efi_zfs_is_preferred(EFI_HANDLE *h) 80 { 81 EFI_DEVICE_PATH *devpath, *dp, *node; 82 HARDDRIVE_DEVICE_PATH *hd; 83 bool ret; 84 extern UINT64 start_sector; /* from mb_header.S */ 85 86 /* This check is true for chainloader case. */ 87 if (h == img->DeviceHandle) 88 return (true); 89 90 /* 91 * Make sure the image was loaded from the hard disk. 92 */ 93 devpath = efi_lookup_devpath(img->DeviceHandle); 94 if (devpath == NULL) 95 return (false); 96 node = efi_devpath_last_node(devpath); 97 if (node == NULL) 98 return (false); 99 if (DevicePathType(node) != MEDIA_DEVICE_PATH || 100 (DevicePathSubType(node) != MEDIA_FILEPATH_DP && 101 DevicePathSubType(node) != MEDIA_HARDDRIVE_DP)) { 102 return (false); 103 } 104 105 /* 106 * XXX We ignore the MEDIA_FILEPATH_DP here for now as it is 107 * used on arm and we do not support arm. 108 */ 109 ret = false; 110 dp = efi_devpath_trim(devpath); 111 devpath = NULL; 112 if (dp == NULL) 113 goto done; 114 115 devpath = efi_lookup_devpath(h); 116 if (devpath == NULL) 117 goto done; 118 hd = (HARDDRIVE_DEVICE_PATH *)efi_devpath_last_node(devpath); 119 if (hd == NULL) { 120 devpath = NULL; 121 goto done; 122 } 123 devpath = efi_devpath_trim(devpath); 124 if (devpath == NULL) 125 goto done; 126 127 if (!efi_devpath_match(dp, devpath)) 128 goto done; 129 130 /* It is the same disk, do we have partition start? */ 131 if (start_sector == 0) 132 ret = true; 133 else if (start_sector == hd->PartitionStart) 134 ret = true; 135 136 done: 137 free(dp); 138 free(devpath); 139 return (ret); 140 } 141 142 static bool 143 has_keyboard(void) 144 { 145 EFI_STATUS status; 146 EFI_DEVICE_PATH *path; 147 EFI_HANDLE *hin, *hin_end, *walker; 148 UINTN sz; 149 bool retval = false; 150 151 /* 152 * Find all the handles that support the SIMPLE_TEXT_INPUT_PROTOCOL and 153 * do the typical dance to get the right sized buffer. 154 */ 155 sz = 0; 156 hin = NULL; 157 status = BS->LocateHandle(ByProtocol, &inputid, 0, &sz, 0); 158 if (status == EFI_BUFFER_TOO_SMALL) { 159 hin = (EFI_HANDLE *)malloc(sz); 160 status = BS->LocateHandle(ByProtocol, &inputid, 0, &sz, 161 hin); 162 if (EFI_ERROR(status)) 163 free(hin); 164 } 165 if (EFI_ERROR(status)) 166 return (retval); 167 168 /* 169 * Look at each of the handles. If it supports the device path protocol, 170 * use it to get the device path for this handle. Then see if that 171 * device path matches either the USB device path for keyboards or the 172 * legacy device path for keyboards. 173 */ 174 hin_end = &hin[sz / sizeof (*hin)]; 175 for (walker = hin; walker < hin_end; walker++) { 176 status = OpenProtocolByHandle(*walker, &devid, (void **)&path); 177 if (EFI_ERROR(status)) 178 continue; 179 180 while (!IsDevicePathEnd(path)) { 181 /* 182 * Check for the ACPI keyboard node. All PNP3xx nodes 183 * are keyboards of different flavors. Note: It is 184 * unclear of there's always a keyboard node when 185 * there's a keyboard controller, or if there's only one 186 * when a keyboard is detected at boot. 187 */ 188 if (DevicePathType(path) == ACPI_DEVICE_PATH && 189 (DevicePathSubType(path) == ACPI_DP || 190 DevicePathSubType(path) == ACPI_EXTENDED_DP)) { 191 ACPI_HID_DEVICE_PATH *acpi; 192 193 acpi = (ACPI_HID_DEVICE_PATH *)(void *)path; 194 if ((EISA_ID_TO_NUM(acpi->HID) & 0xff00) == 195 0x300 && 196 (acpi->HID & 0xffff) == PNP_EISA_ID_CONST) { 197 retval = true; 198 goto out; 199 } 200 /* 201 * Check for USB keyboard node, if present. Unlike a 202 * PS/2 keyboard, these definitely only appear when 203 * connected to the system. 204 */ 205 } else if (DevicePathType(path) == 206 MESSAGING_DEVICE_PATH && 207 DevicePathSubType(path) == MSG_USB_CLASS_DP) { 208 USB_CLASS_DEVICE_PATH *usb; 209 210 /* 211 * Check for: 212 * DeviceClass: HID 213 * DeviceSubClass: Boot devices 214 * DeviceProtocol: Boot keyboards 215 */ 216 usb = (USB_CLASS_DEVICE_PATH *)(void *)path; 217 if (usb->DeviceClass == 3 && 218 usb->DeviceSubClass == 1 && 219 usb->DeviceProtocol == 1) { 220 retval = true; 221 goto out; 222 } 223 } 224 path = NextDevicePathNode(path); 225 } 226 } 227 out: 228 free(hin); 229 return (retval); 230 } 231 232 static void 233 set_currdev_devdesc(struct devdesc *currdev) 234 { 235 char *devname; 236 237 devname = efi_fmtdev(currdev); 238 239 printf("Setting currdev to %s\n", devname); 240 241 env_setenv("currdev", EV_VOLATILE, devname, efi_setcurrdev, 242 env_nounset); 243 env_setenv("loaddev", EV_VOLATILE, devname, env_noset, env_nounset); 244 } 245 246 static void 247 set_currdev_devsw(struct devsw *dev, int unit) 248 { 249 struct devdesc currdev; 250 251 currdev.d_dev = dev; 252 currdev.d_unit = unit; 253 254 set_currdev_devdesc(&currdev); 255 } 256 257 static void 258 set_currdev_pdinfo(pdinfo_t *dp) 259 { 260 261 /* 262 * Disks are special: they have partitions. if the parent 263 * pointer is non-null, we're a partition not a full disk 264 * and we need to adjust currdev appropriately. 265 */ 266 if (dp->pd_devsw->dv_type == DEVT_DISK) { 267 struct disk_devdesc currdev; 268 269 currdev.dd.d_dev = dp->pd_devsw; 270 if (dp->pd_parent == NULL) { 271 currdev.dd.d_unit = dp->pd_unit; 272 currdev.d_slice = D_SLICENONE; 273 currdev.d_partition = D_PARTNONE; 274 } else { 275 currdev.dd.d_unit = dp->pd_parent->pd_unit; 276 currdev.d_slice = dp->pd_unit; 277 currdev.d_partition = D_PARTISGPT; /* Assumes GPT */ 278 } 279 set_currdev_devdesc((struct devdesc *)&currdev); 280 } else { 281 set_currdev_devsw(dp->pd_devsw, dp->pd_unit); 282 } 283 } 284 285 static bool 286 sanity_check_currdev(void) 287 { 288 struct stat st; 289 290 return (stat("/boot/defaults/loader.conf", &st) == 0); 291 } 292 293 static bool 294 probe_zfs_currdev(uint64_t guid) 295 { 296 struct zfs_devdesc currdev; 297 298 currdev.dd.d_dev = &zfs_dev; 299 currdev.dd.d_unit = 0; 300 currdev.pool_guid = guid; 301 currdev.root_guid = 0; 302 set_currdev_devdesc((struct devdesc *)&currdev); 303 304 return (sanity_check_currdev()); 305 } 306 307 static bool 308 try_as_currdev(pdinfo_t *pp) 309 { 310 uint64_t guid; 311 312 /* 313 * If there's a zpool on this device, try it as a ZFS 314 * filesystem, which has somewhat different setup than all 315 * other types of fs due to imperfect loader integration. 316 * This all stems from ZFS being both a device (zpool) and 317 * a filesystem, plus the boot env feature. 318 */ 319 if (efizfs_get_guid_by_handle(pp->pd_handle, &guid)) 320 return (probe_zfs_currdev(guid)); 321 322 /* 323 * All other filesystems just need the pdinfo 324 * initialized in the standard way. 325 */ 326 set_currdev_pdinfo(pp); 327 return (sanity_check_currdev()); 328 } 329 330 static bool 331 find_currdev(EFI_LOADED_IMAGE *img) 332 { 333 pdinfo_t *dp, *pp; 334 EFI_DEVICE_PATH *devpath, *copy; 335 EFI_HANDLE h; 336 CHAR16 *text; 337 struct devsw *dev; 338 int unit; 339 uint64_t extra; 340 341 /* 342 * Did efi_zfs_probe() detect the boot pool? If so, use the zpool 343 * it found, if it's sane. ZFS is the only thing that looks for 344 * disks and pools to boot. 345 */ 346 if (pool_guid != 0) { 347 printf("Trying ZFS pool\n"); 348 if (probe_zfs_currdev(pool_guid)) 349 return (true); 350 } 351 352 /* 353 * Try to find the block device by its handle based on the 354 * image we're booting. If we can't find a sane partition, 355 * search all the other partitions of the disk. We do not 356 * search other disks because it's a violation of the UEFI 357 * boot protocol to do so. We fail and let UEFI go on to 358 * the next candidate. 359 */ 360 dp = efiblk_get_pdinfo_by_handle(img->DeviceHandle); 361 if (dp != NULL) { 362 text = efi_devpath_name(dp->pd_devpath); 363 if (text != NULL) { 364 printf("Trying ESP: %S\n", text); 365 efi_free_devpath_name(text); 366 } 367 set_currdev_pdinfo(dp); 368 if (sanity_check_currdev()) 369 return (true); 370 if (dp->pd_parent != NULL) { 371 dp = dp->pd_parent; 372 STAILQ_FOREACH(pp, &dp->pd_part, pd_link) { 373 text = efi_devpath_name(pp->pd_devpath); 374 if (text != NULL) { 375 printf("And now the part: %S\n", text); 376 efi_free_devpath_name(text); 377 } 378 /* 379 * Roll up the ZFS special case 380 * for those partitions that have 381 * zpools on them 382 */ 383 if (try_as_currdev(pp)) 384 return (true); 385 } 386 } 387 } else { 388 printf("Can't find device by handle\n"); 389 } 390 391 /* 392 * Try the device handle from our loaded image first. If that 393 * fails, use the device path from the loaded image and see if 394 * any of the nodes in that path match one of the enumerated 395 * handles. Currently, this handle list is only for netboot. 396 */ 397 if (efi_handle_lookup(img->DeviceHandle, &dev, &unit, &extra) == 0) { 398 set_currdev_devsw(dev, unit); 399 if (sanity_check_currdev()) 400 return (true); 401 } 402 403 copy = NULL; 404 devpath = efi_lookup_image_devpath(IH); 405 while (devpath != NULL) { 406 h = efi_devpath_handle(devpath); 407 if (h == NULL) 408 break; 409 410 free(copy); 411 copy = NULL; 412 413 if (efi_handle_lookup(h, &dev, &unit, &extra) == 0) { 414 set_currdev_devsw(dev, unit); 415 if (sanity_check_currdev()) 416 return (true); 417 } 418 419 devpath = efi_lookup_devpath(h); 420 if (devpath != NULL) { 421 copy = efi_devpath_trim(devpath); 422 devpath = copy; 423 } 424 } 425 free(copy); 426 427 return (false); 428 } 429 430 static bool 431 interactive_interrupt(const char *msg) 432 { 433 time_t now, then, last; 434 435 last = 0; 436 now = then = getsecs(); 437 printf("%s\n", msg); 438 if (fail_timeout == -2) /* Always break to OK */ 439 return (true); 440 if (fail_timeout == -1) /* Never break to OK */ 441 return (false); 442 do { 443 if (last != now) { 444 printf("press any key to interrupt reboot " 445 "in %d seconds\r", 446 fail_timeout - (int)(now - then)); 447 last = now; 448 } 449 450 /* XXX no pause or timeout wait for char */ 451 if (ischar()) 452 return (true); 453 now = getsecs(); 454 } while (now - then < fail_timeout); 455 return (false); 456 } 457 458 EFI_STATUS 459 main(int argc, CHAR16 *argv[]) 460 { 461 char var[128]; 462 int i, j, howto; 463 bool vargood; 464 void *ptr; 465 bool has_kbd; 466 char *s; 467 EFI_DEVICE_PATH *imgpath; 468 CHAR16 *text; 469 EFI_STATUS status; 470 UINT16 boot_current; 471 size_t sz; 472 UINT16 boot_order[100]; 473 474 archsw.arch_autoload = efi_autoload; 475 archsw.arch_getdev = efi_getdev; 476 archsw.arch_copyin = efi_copyin; 477 archsw.arch_copyout = efi_copyout; 478 archsw.arch_readin = efi_readin; 479 archsw.arch_loadaddr = efi_loadaddr; 480 archsw.arch_free_loadaddr = efi_free_loadaddr; 481 /* Note this needs to be set before ZFS init. */ 482 archsw.arch_zfs_probe = efi_zfs_probe; 483 484 /* Get our loaded image protocol interface structure. */ 485 (void) OpenProtocolByHandle(IH, &imgid, (void **)&img); 486 487 /* Init the time source */ 488 efi_time_init(); 489 490 has_kbd = has_keyboard(); 491 492 /* 493 * XXX Chicken-and-egg problem; we want to have console output 494 * early, but some console attributes may depend on reading from 495 * eg. the boot device, which we can't do yet. We can use 496 * printf() etc. once this is done. 497 */ 498 cons_probe(); 499 efi_getsmap(); 500 501 /* 502 * Initialise the block cache. Set the upper limit. 503 */ 504 bcache_init(32768, 512); 505 506 /* 507 * Parse the args to set the console settings, etc 508 * iPXE may be setup to pass these in. Or the optional argument in the 509 * boot environment was used to pass these arguments in (in which case 510 * neither /boot.config nor /boot/config are consulted). 511 * 512 * Loop through the args, and for each one that contains an '=' that is 513 * not the first character, add it to the environment. This allows 514 * loader and kernel env vars to be passed on the command line. Convert 515 * args from UCS-2 to ASCII (16 to 8 bit) as they are copied (though 516 * this method is flawed for non-ASCII characters). 517 */ 518 howto = 0; 519 for (i = 1; i < argc; i++) { 520 if (argv[i][0] == '-') { 521 for (j = 1; argv[i][j] != 0; j++) { 522 int ch; 523 524 ch = argv[i][j]; 525 switch (ch) { 526 case 'a': 527 howto |= RB_ASKNAME; 528 break; 529 case 'd': 530 howto |= RB_KDB; 531 break; 532 case 'D': 533 howto |= RB_MULTIPLE; 534 break; 535 case 'h': 536 howto |= RB_SERIAL; 537 break; 538 case 'm': 539 howto |= RB_MUTE; 540 break; 541 case 'p': 542 howto |= RB_PAUSE; 543 break; 544 case 'P': 545 if (!has_kbd) { 546 howto |= RB_SERIAL; 547 howto |= RB_MULTIPLE; 548 } 549 break; 550 case 'r': 551 howto |= RB_DFLTROOT; 552 break; 553 case 's': 554 howto |= RB_SINGLE; 555 break; 556 case 'S': 557 if (argv[i][j + 1] == 0) { 558 if (i + 1 == argc) { 559 strncpy(var, "115200", 560 sizeof (var)); 561 } else { 562 CHAR16 *ptr; 563 ptr = &argv[i + 1][0]; 564 cpy16to8(ptr, var, 565 sizeof (var)); 566 } 567 i++; 568 } else { 569 cpy16to8(&argv[i][j + 1], var, 570 sizeof (var)); 571 } 572 strncat(var, ",8,n,1,-", sizeof (var)); 573 setenv("ttya-mode", var, 1); 574 break; 575 case 'v': 576 howto |= RB_VERBOSE; 577 break; 578 } 579 } 580 } else { 581 vargood = false; 582 for (j = 0; argv[i][j] != 0; j++) { 583 if (j == sizeof (var)) { 584 vargood = false; 585 break; 586 } 587 if (j > 0 && argv[i][j] == '=') 588 vargood = true; 589 var[j] = (char)argv[i][j]; 590 } 591 if (vargood) { 592 var[j] = 0; 593 putenv(var); 594 } 595 } 596 } 597 for (i = 0; howto_names[i].ev != NULL; i++) 598 if (howto & howto_names[i].mask) 599 setenv(howto_names[i].ev, "YES", 1); 600 601 /* 602 * XXX we need fallback to this stuff after looking at the ConIn, 603 * ConOut and ConErr variables. 604 */ 605 if (howto & RB_MULTIPLE) { 606 if (howto & RB_SERIAL) 607 setenv("console", "ttya text", 1); 608 else 609 setenv("console", "text ttya", 1); 610 } else if (howto & RB_SERIAL) { 611 setenv("console", "ttya", 1); 612 } else 613 setenv("console", "text", 1); 614 615 if ((s = getenv("fail_timeout")) != NULL) 616 fail_timeout = strtol(s, NULL, 10); 617 618 /* 619 * Scan the BLOCK IO MEDIA handles then 620 * march through the device switch probing for things. 621 */ 622 if ((i = efipart_inithandles()) == 0) { 623 for (i = 0; devsw[i] != NULL; i++) 624 if (devsw[i]->dv_init != NULL) 625 (devsw[i]->dv_init)(); 626 } else 627 printf("efipart_inithandles failed %d, expect failures", i); 628 629 printf("Command line arguments:"); 630 for (i = 0; i < argc; i++) { 631 printf(" %S", argv[i]); 632 } 633 printf("\n"); 634 635 printf("Image base: 0x%lx\n", (unsigned long)img->ImageBase); 636 printf("EFI version: %d.%02d\n", ST->Hdr.Revision >> 16, 637 ST->Hdr.Revision & 0xffff); 638 printf("EFI Firmware: %S (rev %d.%02d)\n", ST->FirmwareVendor, 639 ST->FirmwareRevision >> 16, ST->FirmwareRevision & 0xffff); 640 641 printf("\n%s", bootprog_info); 642 643 /* Determine the devpath of our image so we can prefer it. */ 644 text = efi_devpath_name(img->FilePath); 645 if (text != NULL) { 646 printf(" Load Path: %S\n", text); 647 efi_setenv_illumos_wcs("LoaderPath", text); 648 efi_free_devpath_name(text); 649 } 650 651 status = OpenProtocolByHandle(img->DeviceHandle, &devid, 652 (void **)&imgpath); 653 if (status == EFI_SUCCESS) { 654 text = efi_devpath_name(imgpath); 655 if (text != NULL) { 656 printf(" Load Device: %S\n", text); 657 efi_setenv_illumos_wcs("LoaderDev", text); 658 efi_free_devpath_name(text); 659 } 660 } 661 662 boot_current = 0; 663 sz = sizeof (boot_current); 664 efi_global_getenv("BootCurrent", &boot_current, &sz); 665 printf(" BootCurrent: %04x\n", boot_current); 666 667 sz = sizeof (boot_order); 668 efi_global_getenv("BootOrder", &boot_order, &sz); 669 printf(" BootOrder:"); 670 for (i = 0; i < sz / sizeof (boot_order[0]); i++) 671 printf(" %04x%s", boot_order[i], 672 boot_order[i] == boot_current ? "[*]" : ""); 673 printf("\n"); 674 675 /* 676 * Disable the watchdog timer. By default the boot manager sets 677 * the timer to 5 minutes before invoking a boot option. If we 678 * want to return to the boot manager, we have to disable the 679 * watchdog timer and since we're an interactive program, we don't 680 * want to wait until the user types "quit". The timer may have 681 * fired by then. We don't care if this fails. It does not prevent 682 * normal functioning in any way... 683 */ 684 BS->SetWatchdogTimer(0, 0, 0, NULL); 685 686 /* 687 * Try and find a good currdev based on the image that was booted. 688 * It might be desirable here to have a short pause to allow falling 689 * through to the boot loader instead of returning instantly to follow 690 * the boot protocol and also allow an escape hatch for users wishing 691 * to try something different. 692 */ 693 if (!find_currdev(img)) 694 if (!interactive_interrupt("Failed to find bootable partition")) 695 return (EFI_NOT_FOUND); 696 697 autoload_font(); /* Set up the font list for console. */ 698 efi_init_environment(); 699 setenv("ISADIR", "amd64", 1); /* we only build 64bit */ 700 bi_isadir(); /* set ISADIR */ 701 acpi_detect(); 702 703 if ((ptr = efi_get_table(&smbios3)) == NULL) 704 ptr = efi_get_table(&smbios); 705 smbios_detect(ptr); 706 707 interact(NULL); /* doesn't return */ 708 709 return (EFI_SUCCESS); /* keep compiler happy */ 710 } 711 712 COMMAND_SET(reboot, "reboot", "reboot the system", command_reboot); 713 714 static int 715 command_reboot(int argc __unused, char *argv[] __unused) 716 { 717 int i; 718 719 for (i = 0; devsw[i] != NULL; ++i) 720 if (devsw[i]->dv_cleanup != NULL) 721 (devsw[i]->dv_cleanup)(); 722 723 RS->ResetSystem(EfiResetCold, EFI_SUCCESS, 0, NULL); 724 725 /* NOTREACHED */ 726 return (CMD_ERROR); 727 } 728 729 COMMAND_SET(poweroff, "poweroff", "power off the system", command_poweroff); 730 731 static int 732 command_poweroff(int argc __unused, char *argv[] __unused) 733 { 734 int i; 735 736 for (i = 0; devsw[i] != NULL; ++i) 737 if (devsw[i]->dv_cleanup != NULL) 738 (devsw[i]->dv_cleanup)(); 739 740 RS->ResetSystem(EfiResetShutdown, EFI_SUCCESS, 0, NULL); 741 742 /* NOTREACHED */ 743 return (CMD_ERROR); 744 } 745 746 COMMAND_SET(memmap, "memmap", "print memory map", command_memmap); 747 748 static int 749 command_memmap(int argc __unused, char *argv[] __unused) 750 { 751 UINTN sz; 752 EFI_MEMORY_DESCRIPTOR *map, *p; 753 UINTN key, dsz; 754 UINT32 dver; 755 EFI_STATUS status; 756 int i, ndesc; 757 int rv = 0; 758 char line[80]; 759 760 sz = 0; 761 status = BS->GetMemoryMap(&sz, 0, &key, &dsz, &dver); 762 if (status != EFI_BUFFER_TOO_SMALL) { 763 printf("Can't determine memory map size\n"); 764 return (CMD_ERROR); 765 } 766 map = malloc(sz); 767 status = BS->GetMemoryMap(&sz, map, &key, &dsz, &dver); 768 if (EFI_ERROR(status)) { 769 printf("Can't read memory map\n"); 770 return (CMD_ERROR); 771 } 772 773 ndesc = sz / dsz; 774 snprintf(line, 80, "%23s %12s %12s %8s %4s\n", 775 "Type", "Physical", "Virtual", "#Pages", "Attr"); 776 pager_open(); 777 rv = pager_output(line); 778 if (rv) { 779 pager_close(); 780 return (CMD_OK); 781 } 782 783 for (i = 0, p = map; i < ndesc; 784 i++, p = NextMemoryDescriptor(p, dsz)) { 785 snprintf(line, 80, "%23s %012jx %012jx %08jx ", 786 efi_memory_type(p->Type), p->PhysicalStart, 787 p->VirtualStart, p->NumberOfPages); 788 rv = pager_output(line); 789 if (rv) 790 break; 791 792 if (p->Attribute & EFI_MEMORY_UC) 793 printf("UC "); 794 if (p->Attribute & EFI_MEMORY_WC) 795 printf("WC "); 796 if (p->Attribute & EFI_MEMORY_WT) 797 printf("WT "); 798 if (p->Attribute & EFI_MEMORY_WB) 799 printf("WB "); 800 if (p->Attribute & EFI_MEMORY_UCE) 801 printf("UCE "); 802 if (p->Attribute & EFI_MEMORY_WP) 803 printf("WP "); 804 if (p->Attribute & EFI_MEMORY_RP) 805 printf("RP "); 806 if (p->Attribute & EFI_MEMORY_XP) 807 printf("XP "); 808 if (p->Attribute & EFI_MEMORY_NV) 809 printf("NV "); 810 if (p->Attribute & EFI_MEMORY_MORE_RELIABLE) 811 printf("MR "); 812 if (p->Attribute & EFI_MEMORY_RO) 813 printf("RO "); 814 rv = pager_output("\n"); 815 if (rv) 816 break; 817 } 818 819 pager_close(); 820 return (CMD_OK); 821 } 822 823 COMMAND_SET(configuration, "configuration", "print configuration tables", 824 command_configuration); 825 826 static int 827 command_configuration(int argc __unused, char *argv[] __unused) 828 { 829 UINTN i; 830 char *name; 831 832 printf("NumberOfTableEntries=%lu\n", 833 (unsigned long)ST->NumberOfTableEntries); 834 for (i = 0; i < ST->NumberOfTableEntries; i++) { 835 EFI_GUID *guid; 836 837 printf(" "); 838 guid = &ST->ConfigurationTable[i].VendorGuid; 839 840 if (efi_guid_to_name(guid, &name) == true) { 841 printf(name); 842 free(name); 843 } else { 844 printf("Error while translating UUID to name"); 845 } 846 printf(" at %p\n", ST->ConfigurationTable[i].VendorTable); 847 } 848 849 return (CMD_OK); 850 } 851 852 853 COMMAND_SET(mode, "mode", "change or display EFI text modes", command_mode); 854 855 static int 856 command_mode(int argc, char *argv[]) 857 { 858 UINTN cols, rows; 859 unsigned int mode; 860 int i; 861 char *cp; 862 EFI_STATUS status; 863 SIMPLE_TEXT_OUTPUT_INTERFACE *conout; 864 EFI_CONSOLE_CONTROL_SCREEN_MODE sm; 865 866 if (plat_stdout_is_framebuffer()) 867 sm = EfiConsoleControlScreenGraphics; 868 else 869 sm = EfiConsoleControlScreenText; 870 871 conout = ST->ConOut; 872 873 if (argc > 1) { 874 mode = strtol(argv[1], &cp, 0); 875 if (cp[0] != '\0') { 876 printf("Invalid mode\n"); 877 return (CMD_ERROR); 878 } 879 status = conout->QueryMode(conout, mode, &cols, &rows); 880 if (EFI_ERROR(status)) { 881 printf("invalid mode %d\n", mode); 882 return (CMD_ERROR); 883 } 884 status = conout->SetMode(conout, mode); 885 if (EFI_ERROR(status)) { 886 printf("couldn't set mode %d\n", mode); 887 return (CMD_ERROR); 888 } 889 plat_cons_update_mode(sm); 890 return (CMD_OK); 891 } 892 893 printf("Current mode: %d\n", conout->Mode->Mode); 894 for (i = 0; i <= conout->Mode->MaxMode; i++) { 895 status = conout->QueryMode(conout, i, &cols, &rows); 896 if (EFI_ERROR(status)) 897 continue; 898 printf("Mode %d: %u columns, %u rows\n", i, (unsigned)cols, 899 (unsigned)rows); 900 } 901 902 if (i != 0) 903 printf("Select a mode with the command \"mode <number>\"\n"); 904 905 return (CMD_OK); 906 } 907 908 COMMAND_SET(lsefi, "lsefi", "list EFI handles", command_lsefi); 909 910 static int 911 command_lsefi(int argc __unused, char *argv[] __unused) 912 { 913 char *name; 914 EFI_HANDLE *buffer = NULL; 915 EFI_HANDLE handle; 916 UINTN bufsz = 0, i, j; 917 EFI_STATUS status; 918 int ret = 0; 919 920 status = BS->LocateHandle(AllHandles, NULL, NULL, &bufsz, buffer); 921 if (status != EFI_BUFFER_TOO_SMALL) { 922 snprintf(command_errbuf, sizeof (command_errbuf), 923 "unexpected error: %lld", (long long)status); 924 return (CMD_ERROR); 925 } 926 if ((buffer = malloc(bufsz)) == NULL) { 927 sprintf(command_errbuf, "out of memory"); 928 return (CMD_ERROR); 929 } 930 931 status = BS->LocateHandle(AllHandles, NULL, NULL, &bufsz, buffer); 932 if (EFI_ERROR(status)) { 933 free(buffer); 934 snprintf(command_errbuf, sizeof (command_errbuf), 935 "LocateHandle() error: %lld", (long long)status); 936 return (CMD_ERROR); 937 } 938 939 pager_open(); 940 for (i = 0; i < (bufsz / sizeof (EFI_HANDLE)); i++) { 941 UINTN nproto = 0; 942 EFI_GUID **protocols = NULL; 943 944 handle = buffer[i]; 945 printf("Handle %p", handle); 946 if (pager_output("\n")) 947 break; 948 /* device path */ 949 950 status = BS->ProtocolsPerHandle(handle, &protocols, &nproto); 951 if (EFI_ERROR(status)) { 952 snprintf(command_errbuf, sizeof (command_errbuf), 953 "ProtocolsPerHandle() error: %lld", 954 (long long)status); 955 continue; 956 } 957 958 for (j = 0; j < nproto; j++) { 959 if (efi_guid_to_name(protocols[j], &name) == true) { 960 printf(" %s", name); 961 free(name); 962 } else { 963 printf("Error while translating UUID to name"); 964 } 965 if ((ret = pager_output("\n")) != 0) 966 break; 967 } 968 BS->FreePool(protocols); 969 if (ret != 0) 970 break; 971 } 972 pager_close(); 973 free(buffer); 974 return (CMD_OK); 975 } 976 977 COMMAND_SET(lszfs, "lszfs", "list child datasets of a zfs dataset", 978 command_lszfs); 979 980 static int 981 command_lszfs(int argc, char *argv[]) 982 { 983 int err; 984 985 if (argc != 2) { 986 command_errmsg = "wrong number of arguments"; 987 return (CMD_ERROR); 988 } 989 990 err = zfs_list(argv[1]); 991 if (err != 0) { 992 command_errmsg = strerror(err); 993 return (CMD_ERROR); 994 } 995 return (CMD_OK); 996 } 997 998 #ifdef LOADER_FDT_SUPPORT 999 extern int command_fdt_internal(int argc, char *argv[]); 1000 1001 /* 1002 * Since proper fdt command handling function is defined in fdt_loader_cmd.c, 1003 * and declaring it as extern is in contradiction with COMMAND_SET() macro 1004 * (which uses static pointer), we're defining wrapper function, which 1005 * calls the proper fdt handling routine. 1006 */ 1007 static int 1008 command_fdt(int argc, char *argv[]) 1009 { 1010 return (command_fdt_internal(argc, argv)); 1011 } 1012 1013 COMMAND_SET(fdt, "fdt", "flattened device tree handling", command_fdt); 1014 #endif 1015 1016 /* 1017 * Chain load another efi loader. 1018 */ 1019 static int 1020 command_chain(int argc, char *argv[]) 1021 { 1022 EFI_GUID LoadedImageGUID = LOADED_IMAGE_PROTOCOL; 1023 EFI_HANDLE loaderhandle; 1024 EFI_LOADED_IMAGE *loaded_image; 1025 EFI_STATUS status; 1026 struct stat st; 1027 struct devdesc *dev; 1028 char *name, *path; 1029 void *buf; 1030 int fd; 1031 1032 if (argc < 2) { 1033 command_errmsg = "wrong number of arguments"; 1034 return (CMD_ERROR); 1035 } 1036 1037 name = argv[1]; 1038 1039 if ((fd = open(name, O_RDONLY)) < 0) { 1040 command_errmsg = "no such file"; 1041 return (CMD_ERROR); 1042 } 1043 1044 if (fstat(fd, &st) < -1) { 1045 command_errmsg = "stat failed"; 1046 close(fd); 1047 return (CMD_ERROR); 1048 } 1049 1050 status = BS->AllocatePool(EfiLoaderCode, (UINTN)st.st_size, &buf); 1051 if (status != EFI_SUCCESS) { 1052 command_errmsg = "failed to allocate buffer"; 1053 close(fd); 1054 return (CMD_ERROR); 1055 } 1056 if (read(fd, buf, st.st_size) != st.st_size) { 1057 command_errmsg = "error while reading the file"; 1058 (void) BS->FreePool(buf); 1059 close(fd); 1060 return (CMD_ERROR); 1061 } 1062 close(fd); 1063 status = BS->LoadImage(FALSE, IH, NULL, buf, st.st_size, &loaderhandle); 1064 (void) BS->FreePool(buf); 1065 if (status != EFI_SUCCESS) { 1066 command_errmsg = "LoadImage failed"; 1067 return (CMD_ERROR); 1068 } 1069 status = OpenProtocolByHandle(loaderhandle, &LoadedImageGUID, 1070 (void **)&loaded_image); 1071 1072 if (argc > 2) { 1073 int i, len = 0; 1074 CHAR16 *argp; 1075 1076 for (i = 2; i < argc; i++) 1077 len += strlen(argv[i]) + 1; 1078 1079 len *= sizeof (*argp); 1080 loaded_image->LoadOptions = argp = malloc(len); 1081 if (loaded_image->LoadOptions == NULL) { 1082 (void) BS->UnloadImage(loaded_image); 1083 return (CMD_ERROR); 1084 } 1085 loaded_image->LoadOptionsSize = len; 1086 for (i = 2; i < argc; i++) { 1087 char *ptr = argv[i]; 1088 while (*ptr) 1089 *(argp++) = *(ptr++); 1090 *(argp++) = ' '; 1091 } 1092 *(--argv) = 0; 1093 } 1094 1095 if (efi_getdev((void **)&dev, name, (const char **)&path) == 0) { 1096 struct zfs_devdesc *z_dev; 1097 struct disk_devdesc *d_dev; 1098 pdinfo_t *hd, *pd; 1099 1100 switch (dev->d_dev->dv_type) { 1101 case DEVT_ZFS: 1102 z_dev = (struct zfs_devdesc *)dev; 1103 loaded_image->DeviceHandle = 1104 efizfs_get_handle_by_guid(z_dev->pool_guid); 1105 break; 1106 case DEVT_NET: 1107 loaded_image->DeviceHandle = 1108 efi_find_handle(dev->d_dev, dev->d_unit); 1109 break; 1110 default: 1111 hd = efiblk_get_pdinfo(dev); 1112 if (STAILQ_EMPTY(&hd->pd_part)) { 1113 loaded_image->DeviceHandle = hd->pd_handle; 1114 break; 1115 } 1116 d_dev = (struct disk_devdesc *)dev; 1117 STAILQ_FOREACH(pd, &hd->pd_part, pd_link) { 1118 /* 1119 * d_partition should be 255 1120 */ 1121 if (pd->pd_unit == d_dev->d_slice) { 1122 loaded_image->DeviceHandle = 1123 pd->pd_handle; 1124 break; 1125 } 1126 } 1127 break; 1128 } 1129 } 1130 1131 dev_cleanup(); 1132 status = BS->StartImage(loaderhandle, NULL, NULL); 1133 if (status != EFI_SUCCESS) { 1134 command_errmsg = "StartImage failed"; 1135 free(loaded_image->LoadOptions); 1136 loaded_image->LoadOptions = NULL; 1137 status = BS->UnloadImage(loaded_image); 1138 return (CMD_ERROR); 1139 } 1140 1141 return (CMD_ERROR); /* not reached */ 1142 } 1143 1144 COMMAND_SET(chain, "chain", "chain load file", command_chain); 1145