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 __FBSDID("$FreeBSD$"); 30 31 #include <sys/param.h> 32 #include <sys/reboot.h> 33 #include <sys/boot.h> 34 #include <stand.h> 35 #include <string.h> 36 #include <setjmp.h> 37 38 #include <efi.h> 39 #include <efilib.h> 40 #include <efigpt.h> 41 42 #include <bootstrap.h> 43 #include <smbios.h> 44 45 #ifdef EFI_ZFS_BOOT 46 #include <libzfs.h> 47 #endif 48 49 #include "loader_efi.h" 50 51 extern char bootprog_name[]; 52 extern char bootprog_rev[]; 53 extern char bootprog_date[]; 54 extern char bootprog_maker[]; 55 56 struct arch_switch archsw; /* MI/MD interface boundary */ 57 58 EFI_GUID acpi = ACPI_TABLE_GUID; 59 EFI_GUID acpi20 = ACPI_20_TABLE_GUID; 60 EFI_GUID devid = DEVICE_PATH_PROTOCOL; 61 EFI_GUID imgid = LOADED_IMAGE_PROTOCOL; 62 EFI_GUID mps = MPS_TABLE_GUID; 63 EFI_GUID netid = EFI_SIMPLE_NETWORK_PROTOCOL; 64 EFI_GUID smbios = SMBIOS_TABLE_GUID; 65 EFI_GUID smbios3 = SMBIOS3_TABLE_GUID; 66 EFI_GUID dxe = DXE_SERVICES_TABLE_GUID; 67 EFI_GUID hoblist = HOB_LIST_TABLE_GUID; 68 EFI_GUID memtype = MEMORY_TYPE_INFORMATION_TABLE_GUID; 69 EFI_GUID debugimg = DEBUG_IMAGE_INFO_TABLE_GUID; 70 EFI_GUID fdtdtb = FDT_TABLE_GUID; 71 EFI_GUID inputid = SIMPLE_TEXT_INPUT_PROTOCOL; 72 EFI_GUID serial_io = SERIAL_IO_PROTOCOL; 73 74 extern void acpi_detect(const caddr_t); 75 void efi_serial_init(void); 76 #ifdef EFI_ZFS_BOOT 77 static void efi_zfs_probe(void); 78 #endif 79 80 /* 81 * Need this because EFI uses UTF-16 unicode string constants, but we 82 * use UTF-8. We can't use printf due to the possiblity of \0 and we 83 * don't support support wide characters either. 84 */ 85 static void 86 print_str16(const CHAR16 *str) 87 { 88 int i; 89 90 for (i = 0; str[i]; i++) 91 printf("%c", (char)str[i]); 92 } 93 94 static void 95 cp16to8(const CHAR16 *src, char *dst, size_t len) 96 { 97 size_t i; 98 99 for (i = 0; i < len && src[i]; i++) 100 dst[i] = (char)src[i]; 101 } 102 103 static int 104 has_keyboard(void) 105 { 106 EFI_STATUS status; 107 EFI_DEVICE_PATH *path; 108 EFI_HANDLE *hin, *hin_end, *walker; 109 UINTN sz; 110 int retval = 0; 111 112 /* 113 * Find all the handles that support the SIMPLE_TEXT_INPUT_PROTOCOL and 114 * do the typical dance to get the right sized buffer. 115 */ 116 sz = 0; 117 hin = NULL; 118 status = BS->LocateHandle(ByProtocol, &inputid, 0, &sz, 0); 119 if (status == EFI_BUFFER_TOO_SMALL) { 120 hin = (EFI_HANDLE *)malloc(sz); 121 status = BS->LocateHandle(ByProtocol, &inputid, 0, &sz, 122 hin); 123 if (EFI_ERROR(status)) 124 free(hin); 125 } 126 if (EFI_ERROR(status)) 127 return retval; 128 129 /* 130 * Look at each of the handles. If it supports the device path protocol, 131 * use it to get the device path for this handle. Then see if that 132 * device path matches either the USB device path for keyboards or the 133 * legacy device path for keyboards. 134 */ 135 hin_end = &hin[sz / sizeof(*hin)]; 136 for (walker = hin; walker < hin_end; walker++) { 137 status = BS->HandleProtocol(*walker, &devid, (VOID **)&path); 138 if (EFI_ERROR(status)) 139 continue; 140 141 while (!IsDevicePathEnd(path)) { 142 /* 143 * Check for the ACPI keyboard node. All PNP3xx nodes 144 * are keyboards of different flavors. Note: It is 145 * unclear of there's always a keyboard node when 146 * there's a keyboard controller, or if there's only one 147 * when a keyboard is detected at boot. 148 */ 149 if (DevicePathType(path) == ACPI_DEVICE_PATH && 150 (DevicePathSubType(path) == ACPI_DP || 151 DevicePathSubType(path) == ACPI_EXTENDED_DP)) { 152 ACPI_HID_DEVICE_PATH *acpi; 153 154 acpi = (ACPI_HID_DEVICE_PATH *)(void *)path; 155 if ((EISA_ID_TO_NUM(acpi->HID) & 0xff00) == 0x300 && 156 (acpi->HID & 0xffff) == PNP_EISA_ID_CONST) { 157 retval = 1; 158 goto out; 159 } 160 /* 161 * Check for USB keyboard node, if present. Unlike a 162 * PS/2 keyboard, these definitely only appear when 163 * connected to the system. 164 */ 165 } else if (DevicePathType(path) == MESSAGING_DEVICE_PATH && 166 DevicePathSubType(path) == MSG_USB_CLASS_DP) { 167 USB_CLASS_DEVICE_PATH *usb; 168 169 usb = (USB_CLASS_DEVICE_PATH *)(void *)path; 170 if (usb->DeviceClass == 3 && /* HID */ 171 usb->DeviceSubClass == 1 && /* Boot devices */ 172 usb->DeviceProtocol == 1) { /* Boot keyboards */ 173 retval = 1; 174 goto out; 175 } 176 } 177 path = NextDevicePathNode(path); 178 } 179 } 180 out: 181 free(hin); 182 return retval; 183 } 184 185 EFI_STATUS 186 main(int argc, CHAR16 *argv[]) 187 { 188 char var[128]; 189 EFI_LOADED_IMAGE *img; 190 EFI_GUID *guid; 191 int i, j, vargood, unit, howto; 192 struct devsw *dev; 193 uint64_t pool_guid; 194 UINTN k; 195 int has_kbd; 196 197 archsw.arch_autoload = efi_autoload; 198 archsw.arch_getdev = efi_getdev; 199 archsw.arch_copyin = efi_copyin; 200 archsw.arch_copyout = efi_copyout; 201 archsw.arch_readin = efi_readin; 202 #ifdef EFI_ZFS_BOOT 203 /* Note this needs to be set before ZFS init. */ 204 archsw.arch_zfs_probe = efi_zfs_probe; 205 #endif 206 207 has_kbd = has_keyboard(); 208 209 /* 210 * XXX Chicken-and-egg problem; we want to have console output 211 * early, but some console attributes may depend on reading from 212 * eg. the boot device, which we can't do yet. We can use 213 * printf() etc. once this is done. 214 */ 215 cons_probe(); 216 217 /* 218 * Initialise the block cache. Set the upper limit. 219 */ 220 bcache_init(32768, 512); 221 222 /* 223 * Parse the args to set the console settings, etc 224 * boot1.efi passes these in, if it can read /boot.config or /boot/config 225 * or iPXE may be setup to pass these in. 226 * 227 * Loop through the args, and for each one that contains an '=' that is 228 * not the first character, add it to the environment. This allows 229 * loader and kernel env vars to be passed on the command line. Convert 230 * args from UCS-2 to ASCII (16 to 8 bit) as they are copied. 231 */ 232 howto = 0; 233 for (i = 1; i < argc; i++) { 234 if (argv[i][0] == '-') { 235 for (j = 1; argv[i][j] != 0; j++) { 236 int ch; 237 238 ch = argv[i][j]; 239 switch (ch) { 240 case 'a': 241 howto |= RB_ASKNAME; 242 break; 243 case 'd': 244 howto |= RB_KDB; 245 break; 246 case 'D': 247 howto |= RB_MULTIPLE; 248 break; 249 case 'h': 250 howto |= RB_SERIAL; 251 break; 252 case 'm': 253 howto |= RB_MUTE; 254 break; 255 case 'p': 256 howto |= RB_PAUSE; 257 break; 258 case 'P': 259 if (!has_kbd) 260 howto |= RB_SERIAL | RB_MULTIPLE; 261 break; 262 case 'r': 263 howto |= RB_DFLTROOT; 264 break; 265 case 's': 266 howto |= RB_SINGLE; 267 break; 268 case 'S': 269 if (argv[i][j + 1] == 0) { 270 if (i + 1 == argc) { 271 setenv("comconsole_speed", "115200", 1); 272 } else { 273 cp16to8(&argv[i + 1][0], var, 274 sizeof(var)); 275 setenv("comconsole_speedspeed", var, 1); 276 } 277 i++; 278 break; 279 } else { 280 cp16to8(&argv[i][j + 1], var, 281 sizeof(var)); 282 setenv("comconsole_speed", var, 1); 283 break; 284 } 285 case 'v': 286 howto |= RB_VERBOSE; 287 break; 288 } 289 } 290 } else { 291 vargood = 0; 292 for (j = 0; argv[i][j] != 0; j++) { 293 if (j == sizeof(var)) { 294 vargood = 0; 295 break; 296 } 297 if (j > 0 && argv[i][j] == '=') 298 vargood = 1; 299 var[j] = (char)argv[i][j]; 300 } 301 if (vargood) { 302 var[j] = 0; 303 putenv(var); 304 } 305 } 306 } 307 for (i = 0; howto_names[i].ev != NULL; i++) 308 if (howto & howto_names[i].mask) 309 setenv(howto_names[i].ev, "YES", 1); 310 if (howto & RB_MULTIPLE) { 311 if (howto & RB_SERIAL) 312 setenv("console", "ttya text" , 1); 313 else 314 setenv("console", "text ttya" , 1); 315 } else if (howto & RB_SERIAL) { 316 setenv("console", "ttya" , 1); 317 } 318 319 if (efi_copy_init()) { 320 printf("failed to allocate staging area\n"); 321 return (EFI_BUFFER_TOO_SMALL); 322 } 323 324 /* 325 * March through the device switch probing for things. 326 */ 327 for (i = 0; devsw[i] != NULL; i++) 328 if (devsw[i]->dv_init != NULL) 329 (devsw[i]->dv_init)(); 330 331 /* Get our loaded image protocol interface structure. */ 332 BS->HandleProtocol(IH, &imgid, (VOID**)&img); 333 334 printf("Command line arguments:"); 335 for (i = 0; i < argc; i++) { 336 printf(" "); 337 print_str16(argv[i]); 338 } 339 printf("\n"); 340 341 printf("Image base: 0x%lx\n", (u_long)img->ImageBase); 342 printf("EFI version: %d.%02d\n", ST->Hdr.Revision >> 16, 343 ST->Hdr.Revision & 0xffff); 344 printf("EFI Firmware: "); 345 /* printf doesn't understand EFI Unicode */ 346 ST->ConOut->OutputString(ST->ConOut, ST->FirmwareVendor); 347 printf(" (rev %d.%02d)\n", ST->FirmwareRevision >> 16, 348 ST->FirmwareRevision & 0xffff); 349 350 printf("\n"); 351 printf("%s, Revision %s\n", bootprog_name, bootprog_rev); 352 printf("(%s, %s)\n", bootprog_maker, bootprog_date); 353 354 /* 355 * Disable the watchdog timer. By default the boot manager sets 356 * the timer to 5 minutes before invoking a boot option. If we 357 * want to return to the boot manager, we have to disable the 358 * watchdog timer and since we're an interactive program, we don't 359 * want to wait until the user types "quit". The timer may have 360 * fired by then. We don't care if this fails. It does not prevent 361 * normal functioning in any way... 362 */ 363 BS->SetWatchdogTimer(0, 0, 0, NULL); 364 365 if (efi_handle_lookup(img->DeviceHandle, &dev, &unit, &pool_guid) != 0) 366 return (EFI_NOT_FOUND); 367 368 switch (dev->dv_type) { 369 #ifdef EFI_ZFS_BOOT 370 case DEVT_ZFS: { 371 struct zfs_devdesc currdev; 372 373 currdev.d_dev = dev; 374 currdev.d_unit = unit; 375 currdev.d_type = currdev.d_dev->dv_type; 376 currdev.d_opendata = NULL; 377 currdev.pool_guid = pool_guid; 378 currdev.root_guid = 0; 379 env_setenv("currdev", EV_VOLATILE, efi_fmtdev(&currdev), 380 efi_setcurrdev, env_nounset); 381 env_setenv("loaddev", EV_VOLATILE, efi_fmtdev(&currdev), env_noset, 382 env_nounset); 383 #ifdef __FreeBSD__ 384 init_zfs_bootenv(zfs_fmtdev(&currdev)); 385 #endif 386 break; 387 } 388 #endif 389 default: { 390 struct devdesc currdev; 391 392 currdev.d_dev = dev; 393 currdev.d_unit = unit; 394 currdev.d_opendata = NULL; 395 currdev.d_type = currdev.d_dev->dv_type; 396 env_setenv("currdev", EV_VOLATILE, efi_fmtdev(&currdev), 397 efi_setcurrdev, env_nounset); 398 env_setenv("loaddev", EV_VOLATILE, efi_fmtdev(&currdev), env_noset, 399 env_nounset); 400 break; 401 } 402 } 403 404 setenv("LINES", "24", 1); /* optional */ 405 setenv("COLUMNS", "80", 1); /* optional */ 406 setenv("ISADIR", "amd64", 1); /* we only build 64bit */ 407 408 for (k = 0; k < ST->NumberOfTableEntries; k++) { 409 guid = &ST->ConfigurationTable[k].VendorGuid; 410 if (!memcmp(guid, &smbios, sizeof(EFI_GUID)) || 411 !memcmp(guid, &smbios3, sizeof(EFI_GUID))) { 412 smbios_detect(ST->ConfigurationTable[k].VendorTable); 413 continue; 414 } 415 if (!memcmp(guid, &acpi20, sizeof(EFI_GUID))) { 416 acpi_detect(ST->ConfigurationTable[k].VendorTable); 417 } 418 } 419 420 efi_serial_init(); /* detect and set up serial ports */ 421 interact(NULL); /* doesn't return */ 422 423 return (EFI_SUCCESS); /* keep compiler happy */ 424 } 425 426 COMMAND_SET(reboot, "reboot", "reboot the system", command_reboot); 427 428 static int 429 command_reboot(int argc __attribute((unused)), 430 char *argv[] __attribute((unused))) 431 { 432 int i; 433 const CHAR16 *msg = L"Reboot from the loader"; 434 435 for (i = 0; devsw[i] != NULL; ++i) 436 if (devsw[i]->dv_cleanup != NULL) 437 (devsw[i]->dv_cleanup)(); 438 439 RS->ResetSystem(EfiResetCold, EFI_SUCCESS, 23, (CHAR16 *)msg); 440 441 /* NOTREACHED */ 442 return (CMD_ERROR); 443 } 444 445 COMMAND_SET(memmap, "memmap", "print memory map", command_memmap); 446 447 static int 448 command_memmap(int argc __attribute((unused)), 449 char *argv[] __attribute((unused))) 450 { 451 UINTN sz; 452 EFI_MEMORY_DESCRIPTOR *map, *p; 453 UINTN key, dsz; 454 UINT32 dver; 455 EFI_STATUS status; 456 int i, ndesc; 457 int rv = 0; 458 char line[80]; 459 static const char *types[] = { 460 "Reserved", 461 "LoaderCode", 462 "LoaderData", 463 "BootServicesCode", 464 "BootServicesData", 465 "RuntimeServicesCode", 466 "RuntimeServicesData", 467 "ConventionalMemory", 468 "UnusableMemory", 469 "ACPIReclaimMemory", 470 "ACPIMemoryNVS", 471 "MemoryMappedIO", 472 "MemoryMappedIOPortSpace", 473 "PalCode" 474 }; 475 476 sz = 0; 477 status = BS->GetMemoryMap(&sz, 0, &key, &dsz, &dver); 478 if (status != EFI_BUFFER_TOO_SMALL) { 479 printf("Can't determine memory map size\n"); 480 return (CMD_ERROR); 481 } 482 map = malloc(sz); 483 status = BS->GetMemoryMap(&sz, map, &key, &dsz, &dver); 484 if (EFI_ERROR(status)) { 485 printf("Can't read memory map\n"); 486 return (CMD_ERROR); 487 } 488 489 ndesc = sz / dsz; 490 snprintf(line, 80, "%23s %12s %12s %8s %4s\n", 491 "Type", "Physical", "Virtual", "#Pages", "Attr"); 492 pager_open(); 493 rv = pager_output(line); 494 if (rv) { 495 pager_close(); 496 return (CMD_OK); 497 } 498 499 for (i = 0, p = map; i < ndesc; 500 i++, p = NextMemoryDescriptor(p, dsz)) { 501 snprintf(line, 80, "%23s %012lx %012lx %08lx ", 502 types[p->Type], 503 p->PhysicalStart, 504 p->VirtualStart, 505 p->NumberOfPages); 506 rv = pager_output(line); 507 if (rv) 508 break; 509 510 if (p->Attribute & EFI_MEMORY_UC) 511 printf("UC "); 512 if (p->Attribute & EFI_MEMORY_WC) 513 printf("WC "); 514 if (p->Attribute & EFI_MEMORY_WT) 515 printf("WT "); 516 if (p->Attribute & EFI_MEMORY_WB) 517 printf("WB "); 518 if (p->Attribute & EFI_MEMORY_UCE) 519 printf("UCE "); 520 if (p->Attribute & EFI_MEMORY_WP) 521 printf("WP "); 522 if (p->Attribute & EFI_MEMORY_RP) 523 printf("RP "); 524 if (p->Attribute & EFI_MEMORY_XP) 525 printf("XP "); 526 rv = pager_output("\n"); 527 if (rv) 528 break; 529 } 530 531 pager_close(); 532 return (CMD_OK); 533 } 534 535 COMMAND_SET(configuration, "configuration", "print configuration tables", 536 command_configuration); 537 538 static const char * 539 guid_to_string(EFI_GUID *guid) 540 { 541 static char buf[40]; 542 543 sprintf(buf, "%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x", 544 guid->Data1, guid->Data2, guid->Data3, guid->Data4[0], 545 guid->Data4[1], guid->Data4[2], guid->Data4[3], guid->Data4[4], 546 guid->Data4[5], guid->Data4[6], guid->Data4[7]); 547 return (buf); 548 } 549 550 static int 551 command_configuration(int argc __attribute((unused)), 552 char *argv[] __attribute((unused))) 553 { 554 UINTN i; 555 556 printf("NumberOfTableEntries=%lu\n", 557 (unsigned long)ST->NumberOfTableEntries); 558 for (i = 0; i < ST->NumberOfTableEntries; i++) { 559 EFI_GUID *guid; 560 561 printf(" "); 562 guid = &ST->ConfigurationTable[i].VendorGuid; 563 if (!memcmp(guid, &mps, sizeof(EFI_GUID))) 564 printf("MPS Table"); 565 else if (!memcmp(guid, &acpi, sizeof(EFI_GUID))) 566 printf("ACPI Table"); 567 else if (!memcmp(guid, &acpi20, sizeof(EFI_GUID))) 568 printf("ACPI 2.0 Table"); 569 else if (!memcmp(guid, &smbios, sizeof(EFI_GUID))) 570 printf("SMBIOS Table"); 571 else if (!memcmp(guid, &smbios3, sizeof(EFI_GUID))) 572 printf("SMBIOS3 Table"); 573 else if (!memcmp(guid, &dxe, sizeof(EFI_GUID))) 574 printf("DXE Table"); 575 else if (!memcmp(guid, &hoblist, sizeof(EFI_GUID))) 576 printf("HOB List Table"); 577 else if (!memcmp(guid, &memtype, sizeof(EFI_GUID))) 578 printf("Memory Type Information Table"); 579 else if (!memcmp(guid, &debugimg, sizeof(EFI_GUID))) 580 printf("Debug Image Info Table"); 581 else if (!memcmp(guid, &fdtdtb, sizeof(EFI_GUID))) 582 printf("FDT Table"); 583 else 584 printf("Unknown Table (%s)", guid_to_string(guid)); 585 printf(" at %p\n", ST->ConfigurationTable[i].VendorTable); 586 } 587 588 return (CMD_OK); 589 } 590 591 592 COMMAND_SET(mode, "mode", "change or display EFI text modes", command_mode); 593 594 static int 595 command_mode(int argc, char *argv[]) 596 { 597 UINTN cols, rows; 598 unsigned int mode; 599 int i; 600 char *cp; 601 char rowenv[8]; 602 EFI_STATUS status; 603 SIMPLE_TEXT_OUTPUT_INTERFACE *conout; 604 extern void HO(void); 605 606 conout = ST->ConOut; 607 608 if (argc > 1) { 609 mode = strtol(argv[1], &cp, 0); 610 if (cp[0] != '\0') { 611 printf("Invalid mode\n"); 612 return (CMD_ERROR); 613 } 614 status = conout->QueryMode(conout, mode, &cols, &rows); 615 if (EFI_ERROR(status)) { 616 printf("invalid mode %d\n", mode); 617 return (CMD_ERROR); 618 } 619 status = conout->SetMode(conout, mode); 620 if (EFI_ERROR(status)) { 621 printf("couldn't set mode %d\n", mode); 622 return (CMD_ERROR); 623 } 624 sprintf(rowenv, "%u", (unsigned)rows); 625 setenv("LINES", rowenv, 1); 626 sprintf(rowenv, "%u", (unsigned)cols); 627 setenv("COLUMNS", rowenv, 1); 628 HO(); /* set cursor */ 629 return (CMD_OK); 630 } 631 632 printf("Current mode: %d\n", conout->Mode->Mode); 633 for (i = 0; i <= conout->Mode->MaxMode; i++) { 634 status = conout->QueryMode(conout, i, &cols, &rows); 635 if (EFI_ERROR(status)) 636 continue; 637 printf("Mode %d: %u columns, %u rows\n", i, (unsigned)cols, 638 (unsigned)rows); 639 } 640 641 if (i != 0) 642 printf("Select a mode with the command \"mode <number>\"\n"); 643 644 return (CMD_OK); 645 } 646 647 648 COMMAND_SET(nvram, "nvram", "get NVRAM variables", command_nvram); 649 650 static int 651 command_nvram(int argc __attribute((unused)), 652 char *argv[] __attribute((unused))) 653 { 654 CHAR16 var[128]; 655 UINT8 *data; /* value is in bytes */ 656 EFI_STATUS status; 657 EFI_GUID varguid = { 0,0,0,{0,0,0,0,0,0,0,0} }; 658 UINTN varsz, datasz, i; 659 UINT32 attr; 660 SIMPLE_TEXT_OUTPUT_INTERFACE *conout; 661 662 conout = ST->ConOut; 663 664 pager_open(); 665 var[0] = 0; /* Initiate the enumeration */ 666 varsz = 128; 667 668 for (status = RS->GetNextVariableName(&varsz, var, &varguid); 669 status != EFI_NOT_FOUND; 670 status = RS->GetNextVariableName(&varsz, var, &varguid)) { 671 672 /* 673 * as term emu is keeping track on cursor, use putchar(). 674 */ 675 for (i = 0; var[i] != 0; i++) 676 putchar(var[i]); 677 varsz = 128; /* GetNextVariableName() did change it. */ 678 679 printf(": Attributes:"); 680 datasz = 0; 681 status = RS->GetVariable(var, &varguid, &attr, &datasz, NULL); 682 if ((data = malloc(datasz)) == NULL) 683 break; 684 status = RS->GetVariable(var, &varguid, &attr, &datasz, data); 685 if (EFI_ERROR(status)) 686 printf("<error retrieving variable>"); 687 else { 688 if (attr & EFI_VARIABLE_NON_VOLATILE) 689 printf(" NV"); 690 if (attr & EFI_VARIABLE_BOOTSERVICE_ACCESS) 691 printf(" BS"); 692 if (attr & EFI_VARIABLE_RUNTIME_ACCESS) 693 printf(" RS"); 694 if (attr & EFI_VARIABLE_HARDWARE_ERROR_RECORD) 695 printf(" HR"); 696 if (attr & EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS) 697 printf(" AW"); 698 if (attr & 699 EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS) 700 printf(" TW"); 701 702 printf(": DataLength: %lld", (long long)datasz); 703 } 704 free(data); 705 if (pager_output("\n")) 706 break; 707 } 708 709 pager_close(); 710 return (CMD_OK); 711 } 712 713 struct protocol_name { 714 EFI_GUID guid; 715 const char *name; 716 } proto_names[] = { 717 { DEVICE_PATH_PROTOCOL, "device path" }, 718 { BLOCK_IO_PROTOCOL, "block io" }, 719 { DISK_IO_PROTOCOL, "disk io" }, 720 { EFI_DISK_INFO_PROTOCOL_GUID, "disk info" }, 721 { SIMPLE_FILE_SYSTEM_PROTOCOL, "simple fs" }, 722 { LOAD_FILE_PROTOCOL, "load file" }, 723 { DEVICE_IO_PROTOCOL, "device io" }, 724 { UNICODE_COLLATION_PROTOCOL, "unicode collation" }, 725 { EFI_UNICODE_COLLATION2_PROTOCOL_GUID, "unicode collation2" }, 726 { EFI_SIMPLE_NETWORK_PROTOCOL, "simple network" }, 727 { SIMPLE_TEXT_OUTPUT_PROTOCOL, "simple text output" }, 728 { SIMPLE_TEXT_INPUT_PROTOCOL, "simple text input" }, 729 { EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL_GUID, "simple text ex input" }, 730 { EFI_CONSOLE_CONTROL_PROTOCOL_GUID, "console control" }, 731 { EFI_CONSOLE_IN_DEVICE_GUID, "stdin" }, 732 { EFI_CONSOLE_OUT_DEVICE_GUID, "stdout" }, 733 { EFI_STANDARD_ERROR_DEVICE_GUID, "stderr" }, 734 { EFI_GRAPHICS_OUTPUT_PROTOCOL_GUID, "GOP" }, 735 { EFI_UGA_DRAW_PROTOCOL_GUID, "UGA draw" }, 736 { EFI_PXE_BASE_CODE_PROTOCOL, "PXE base code" }, 737 { EFI_PXE_BASE_CODE_CALLBACK_PROTOCOL, "PXE base code callback" }, 738 { SERIAL_IO_PROTOCOL, "serial io" }, 739 { LOADED_IMAGE_PROTOCOL, "loaded image" }, 740 { EFI_LOADED_IMAGE_DEVICE_PATH_PROTOCOL_GUID, 741 "loaded image device path" }, 742 { EFI_ISA_IO_PROTOCOL_GUID, "ISA io" }, 743 { EFI_IDE_CONTROLLER_INIT_PROTOCOL_GUID, "IDE controller init" }, 744 { EFI_ISA_ACPI_PROTOCOL_GUID, "ISA ACPI" }, 745 { EFI_PCI_IO_PROTOCOL_GUID, "PCI" }, 746 { EFI_PCI_ROOT_IO_GUID, "PCI root" }, 747 { EFI_PCI_ENUMERATION_COMPLETE_GUID, "PCI enumeration" }, 748 { EFI_DRIVER_DIAGNOSTICS_PROTOCOL_GUID, "Driver diagnostics" }, 749 { EFI_DRIVER_DIAGNOSTICS2_PROTOCOL_GUID, "Driver diagnostics2" }, 750 { EFI_SIMPLE_POINTER_PROTOCOL_GUID, "simple pointer" }, 751 { EFI_ABSOLUTE_POINTER_PROTOCOL_GUID, "absolute pointer" }, 752 { EFI_VLAN_CONFIG_PROTOCOL_GUID, "VLAN config" }, 753 { EFI_ARP_SERVICE_BINDING_PROTOCOL_GUID, "ARP service binding" }, 754 { EFI_ARP_PROTOCOL_GUID, "ARP" }, 755 { EFI_IP4_SERVICE_BINDING_PROTOCOL, "IPv4 service binding" }, 756 { EFI_IP4_PROTOCOL, "IPv4" }, 757 { EFI_IP4_CONFIG_PROTOCOL_GUID, "IPv4 config" }, 758 { EFI_IP6_SERVICE_BINDING_PROTOCOL, "IPv6 service binding" }, 759 { EFI_IP6_PROTOCOL, "IPv6" }, 760 { EFI_IP6_CONFIG_PROTOCOL_GUID, "IPv6 config" }, 761 { EFI_UDP4_PROTOCOL, "UDPv4" }, 762 { EFI_UDP4_SERVICE_BINDING_PROTOCOL, "UDPv4 service binding" }, 763 { EFI_UDP6_PROTOCOL, "UDPv6" }, 764 { EFI_UDP6_SERVICE_BINDING_PROTOCOL, "UDPv6 service binding" }, 765 { EFI_TCP4_PROTOCOL, "TCPv4" }, 766 { EFI_TCP4_SERVICE_BINDING_PROTOCOL, "TCPv4 service binding" }, 767 { EFI_TCP6_PROTOCOL, "TCPv6" }, 768 { EFI_TCP6_SERVICE_BINDING_PROTOCOL, "TCPv6 service binding" }, 769 { EFI_PART_TYPE_EFI_SYSTEM_PART_GUID, "EFI System partition" }, 770 { EFI_PART_TYPE_LEGACY_MBR_GUID, "MBR legacy" }, 771 { EFI_DEVICE_TREE_GUID, "device tree" }, 772 { EFI_USB_IO_PROTOCOL_GUID, "USB io" }, 773 { EFI_USB2_HC_PROTOCOL_GUID, "USB2 HC" }, 774 { EFI_COMPONENT_NAME_PROTOCOL_GUID, "component name" }, 775 { EFI_COMPONENT_NAME2_PROTOCOL_GUID, "component name2" }, 776 { EFI_DRIVER_BINDING_PROTOCOL_GUID, "driver binding" }, 777 { EFI_DRIVER_CONFIGURATION_PROTOCOL_GUID, "driver configuration" }, 778 { EFI_DRIVER_CONFIGURATION2_PROTOCOL_GUID, "driver configuration2" }, 779 { EFI_DECOMPRESS_PROTOCOL_GUID, "decompress" }, 780 { EFI_EBC_INTERPRETER_PROTOCOL_GUID, "ebc interpreter" }, 781 { EFI_NETWORK_INTERFACE_IDENTIFIER_PROTOCOL, 782 "network interface identifier" }, 783 { EFI_NETWORK_INTERFACE_IDENTIFIER_PROTOCOL_31, 784 "network interface identifier_31" }, 785 { EFI_MANAGED_NETWORK_SERVICE_BINDING_PROTOCOL_GUID, 786 "managed network service binding" }, 787 { EFI_MANAGED_NETWORK_PROTOCOL_GUID, "managed network" }, 788 { EFI_FORM_BROWSER2_PROTOCOL_GUID, "form browser" }, 789 { EFI_HII_CONFIG_ROUTING_PROTOCOL_GUID, "HII config routing" }, 790 { EFI_HII_DATABASE_PROTOCOL_GUID, "HII database" }, 791 { EFI_HII_STRING_PROTOCOL_GUID, "HII string" }, 792 { EFI_HII_IMAGE_PROTOCOL_GUID, "HII image" }, 793 { EFI_HII_FONT_PROTOCOL_GUID, "HII font" }, 794 { EFI_HII_CONFIGURATION_ACCESS_PROTOCOL_GUID, "HII config" }, 795 { EFI_MTFTP4_SERVICE_BINDING_PROTOCOL_GUID, "MTFTP4 service binding" }, 796 { EFI_MTFTP4_PROTOCOL_GUID, "MTFTP4" }, 797 { EFI_MTFTP6_SERVICE_BINDING_PROTOCOL_GUID, "MTFTP6 service binding" }, 798 { EFI_MTFTP6_PROTOCOL_GUID, "MTFTP6" }, 799 { EFI_DHCP4_SERVICE_BINDING_PROTOCOL_GUID, "DHCP4 service binding" }, 800 { EFI_DHCP4_PROTOCOL_GUID, "DHCP4" }, 801 { EFI_DHCP6_SERVICE_BINDING_PROTOCOL_GUID, "DHCP6 service binding" }, 802 { EFI_DHCP6_PROTOCOL_GUID, "DHCP6" }, 803 { EFI_SCSI_IO_PROTOCOL_GUID, "SCSI io" }, 804 { EFI_SCSI_PASS_THRU_PROTOCOL_GUID, "SCSI pass thru" }, 805 { EFI_EXT_SCSI_PASS_THRU_PROTOCOL_GUID, "SCSI pass thru ext" }, 806 { EFI_CAPSULE_ARCH_PROTOCOL_GUID, "Capsule arch" }, 807 { EFI_MONOTONIC_COUNTER_ARCH_PROTOCOL_GUID, "monotonic counter arch" }, 808 { EFI_REALTIME_CLOCK_ARCH_PROTOCOL_GUID, "realtime clock arch" }, 809 { EFI_VARIABLE_ARCH_PROTOCOL_GUID, "variable arch" }, 810 { EFI_VARIABLE_WRITE_ARCH_PROTOCOL_GUID, "variable write arch" }, 811 { EFI_WATCHDOG_TIMER_ARCH_PROTOCOL_GUID, "watchdog timer arch" }, 812 { EFI_MP_SERVICES_PROTOCOL_GUID, "MP services" }, 813 { EFI_ACPI_SUPPORT_PROTOCOL_GUID, "ACPI support" }, 814 { EFI_BDS_ARCH_PROTOCOL_GUID, "BDS arch" }, 815 { EFI_METRONOME_ARCH_PROTOCOL_GUID, "metronome arch" }, 816 { EFI_TIMER_ARCH_PROTOCOL_GUID, "timer arch" }, 817 { EFI_DPC_PROTOCOL_GUID, "DPC" }, 818 { EFI_PRINT2_PROTOCOL_GUID, "print2" }, 819 { EFI_DEVICE_PATH_TO_TEXT_PROTOCOL_GUID, "device path to text" }, 820 { EFI_RESET_ARCH_PROTOCOL_GUID, "reset arch" }, 821 { EFI_CPU_ARCH_PROTOCOL_GUID, "CPU arch" }, 822 { EFI_CPU_IO2_PROTOCOL_GUID, "CPU IO2" }, 823 { EFI_LEGACY_8259_PROTOCOL_GUID, "Legacy 8259" }, 824 { EFI_SECURITY_ARCH_PROTOCOL_GUID, "Security arch" }, 825 { EFI_SECURITY2_ARCH_PROTOCOL_GUID, "Security2 arch" }, 826 { EFI_RUNTIME_ARCH_PROTOCOL_GUID, "Runtime arch" }, 827 { EFI_STATUS_CODE_RUNTIME_PROTOCOL_GUID, "status code runtime" }, 828 { EFI_DATA_HUB_PROTOCOL_GUID, "data hub" }, 829 { PCD_PROTOCOL_GUID, "PCD" }, 830 { EFI_PCD_PROTOCOL_GUID, "EFI PCD" }, 831 { EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL_GUID, "firmware volume block" }, 832 { EFI_FIRMWARE_VOLUME2_PROTOCOL_GUID, "firmware volume2" }, 833 { EFI_FIRMWARE_VOLUME_DISPATCH_PROTOCOL_GUID, 834 "firmware volume dispatch" }, 835 { LZMA_COMPRESS_GUID, "lzma compress" }, 836 { { 0,0,0,{0,0,0,0,0,0,0,0} }, NULL } /* must be last entry */ 837 }; 838 839 COMMAND_SET(lsefi, "lsefi", "list EFI handles", command_lsefi); 840 841 static int 842 command_lsefi(int argc __attribute((unused)), 843 char *argv[] __attribute((unused))) 844 { 845 EFI_HANDLE *buffer = NULL; 846 EFI_HANDLE handle; 847 UINTN bufsz = 0, i, j; 848 EFI_STATUS status; 849 int k, ret; 850 851 status = BS->LocateHandle(AllHandles, NULL, NULL, &bufsz, buffer); 852 if (status != EFI_BUFFER_TOO_SMALL) { 853 snprintf(command_errbuf, sizeof (command_errbuf), 854 "unexpected error: %lld", (long long)status); 855 return (CMD_ERROR); 856 } 857 if ((buffer = malloc(bufsz)) == NULL) { 858 sprintf(command_errbuf, "out of memory"); 859 return (CMD_ERROR); 860 } 861 862 status = BS->LocateHandle(AllHandles, NULL, NULL, &bufsz, buffer); 863 if (EFI_ERROR(status)) { 864 free(buffer); 865 snprintf(command_errbuf, sizeof (command_errbuf), 866 "LocateHandle() error: %lld", (long long)status); 867 return (CMD_ERROR); 868 } 869 870 pager_open(); 871 for (i = 0; i < (bufsz / sizeof (EFI_HANDLE)); i++) { 872 UINTN nproto = 0; 873 EFI_GUID **protocols = NULL; 874 875 handle = buffer[i]; 876 printf("Handle %p", handle); 877 if (pager_output("\n")) 878 break; 879 /* device path */ 880 881 status = BS->ProtocolsPerHandle(handle, &protocols, &nproto); 882 if (EFI_ERROR(status)) { 883 snprintf(command_errbuf, sizeof (command_errbuf), 884 "ProtocolsPerHandle() error: %lld", 885 (long long)status); 886 continue; 887 } 888 for (j = 0; j < nproto; j++) { 889 for (k = 0; proto_names[k].name != NULL; k++) 890 if (memcmp(protocols[j], &proto_names[k].guid, 891 sizeof (proto_names[k].guid)) == 0) 892 break; 893 if (proto_names[k].name != NULL) 894 printf(" %s", proto_names[k].name); 895 else 896 printf(" %s", guid_to_string(protocols[j])); 897 ret = pager_output("\n"); 898 if (ret) 899 break; 900 } 901 BS->FreePool(protocols); 902 if (ret) 903 break; 904 } 905 pager_close(); 906 free(buffer); 907 return (CMD_OK); 908 } 909 910 #ifdef EFI_ZFS_BOOT 911 COMMAND_SET(lszfs, "lszfs", "list child datasets of a zfs dataset", 912 command_lszfs); 913 914 static int 915 command_lszfs(int argc, char *argv[]) 916 { 917 int err; 918 919 if (argc != 2) { 920 command_errmsg = "wrong number of arguments"; 921 return (CMD_ERROR); 922 } 923 924 err = zfs_list(argv[1]); 925 if (err != 0) { 926 command_errmsg = strerror(err); 927 return (CMD_ERROR); 928 } 929 return (CMD_OK); 930 } 931 932 #ifdef __FreeBSD__ 933 COMMAND_SET(reloadbe, "reloadbe", "refresh the list of ZFS Boot Environments", 934 command_reloadbe); 935 936 static int 937 command_reloadbe(int argc, char *argv[]) 938 { 939 int err; 940 char *root; 941 942 if (argc > 2) { 943 command_errmsg = "wrong number of arguments"; 944 return (CMD_ERROR); 945 } 946 947 if (argc == 2) { 948 err = zfs_bootenv(argv[1]); 949 } else { 950 root = getenv("zfs_be_root"); 951 if (root == NULL) { 952 return (CMD_OK); 953 } 954 err = zfs_bootenv(root); 955 } 956 957 if (err != 0) { 958 command_errmsg = strerror(err); 959 return (CMD_ERROR); 960 } 961 962 return (CMD_OK); 963 } 964 #endif /* __FreeBSD__ */ 965 #endif 966 967 void 968 efi_serial_init(void) 969 { 970 EFI_HANDLE *buffer = NULL; 971 UINTN bufsz = 0, i; 972 EFI_STATUS status; 973 int serial = 0; 974 975 /* 976 * get buffer size 977 */ 978 status = BS->LocateHandle(ByProtocol, &serial_io, NULL, &bufsz, buffer); 979 if (status != EFI_BUFFER_TOO_SMALL) { 980 snprintf(command_errbuf, sizeof (command_errbuf), 981 "unexpected error: %lld", (long long)status); 982 return; 983 } 984 if ((buffer = malloc(bufsz)) == NULL) { 985 sprintf(command_errbuf, "out of memory"); 986 return; 987 } 988 989 /* 990 * get handle array 991 */ 992 status = BS->LocateHandle(ByProtocol, &serial_io, NULL, &bufsz, buffer); 993 if (EFI_ERROR(status)) { 994 free(buffer); 995 snprintf(command_errbuf, sizeof (command_errbuf), 996 "LocateHandle() error: %lld", (long long)status); 997 return; 998 } 999 1000 for (i = 0; i < (bufsz / sizeof (EFI_HANDLE)); i++) { 1001 SERIAL_IO_INTERFACE *sio; 1002 status = BS->OpenProtocol(buffer[i], &serial_io, (void**)&sio, 1003 IH, NULL, EFI_OPEN_PROTOCOL_GET_PROTOCOL); 1004 if (EFI_ERROR(status)) { 1005 snprintf(command_errbuf, sizeof (command_errbuf), 1006 "OpenProtocol() error: %lld", (long long)status); 1007 } 1008 printf("serial# %d\n", serial++); 1009 } 1010 1011 free(buffer); 1012 } 1013 1014 #ifdef LOADER_FDT_SUPPORT 1015 extern int command_fdt_internal(int argc, char *argv[]); 1016 1017 /* 1018 * Since proper fdt command handling function is defined in fdt_loader_cmd.c, 1019 * and declaring it as extern is in contradiction with COMMAND_SET() macro 1020 * (which uses static pointer), we're defining wrapper function, which 1021 * calls the proper fdt handling routine. 1022 */ 1023 static int 1024 command_fdt(int argc, char *argv[]) 1025 { 1026 return (command_fdt_internal(argc, argv)); 1027 } 1028 1029 COMMAND_SET(fdt, "fdt", "flattened device tree handling", command_fdt); 1030 #endif 1031 1032 #ifdef EFI_ZFS_BOOT 1033 static void 1034 efi_zfs_probe(void) 1035 { 1036 EFI_HANDLE h; 1037 u_int unit; 1038 int i; 1039 char dname[SPECNAMELEN + 1]; 1040 uint64_t guid; 1041 1042 unit = 0; 1043 h = efi_find_handle(&efipart_dev, 0); 1044 for (i = 0; h != NULL; h = efi_find_handle(&efipart_dev, ++i)) { 1045 snprintf(dname, sizeof(dname), "%s%d:", efipart_dev.dv_name, i); 1046 if (zfs_probe_dev(dname, &guid) == 0) 1047 (void)efi_handle_update_dev(h, &zfs_dev, unit++, guid); 1048 } 1049 } 1050 #endif 1051