1/* $NetBSD: boot.c,v 1.23 2023/05/14 09:07:54 riastradh Exp $ */ 2 3/*- 4 * Copyright (c) 2016 Kimihiro Nonaka <nonaka@netbsd.org> 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 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 REGENTS AND CONTRIBUTORS ``AS IS'' AND 17 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 20 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 21 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 22 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 24 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 26 * SUCH DAMAGE. 27 */ 28 29#include "efiboot.h" 30 31#include <sys/bootblock.h> 32#include <sys/boot_flag.h> 33#include <machine/limits.h> 34 35#include "bootcfg.h" 36#include "bootmod.h" 37#include "bootmenu.h" 38#include "biosdisk.h" 39#include "devopen.h" 40 41#ifdef _STANDALONE 42#include <bootinfo.h> 43#endif 44 45int errno; 46int boot_biosdev; 47daddr_t boot_biossector; 48 49extern const char bootprog_name[], bootprog_rev[], bootprog_kernrev[]; 50 51extern struct x86_boot_params boot_params; 52extern char twiddle_toggle; 53 54static const char * const names[][2] = { 55 { "netbsd", "netbsd.gz" }, 56 { "onetbsd", "onetbsd.gz" }, 57 { "netbsd.old", "netbsd.old.gz" }, 58}; 59 60#define NUMNAMES __arraycount(names) 61#define DEFFILENAME names[0][0] 62 63#ifndef EFIBOOTCFG_FILENAME 64#define EFIBOOTCFG_FILENAME "esp:/EFI/NetBSD/boot.cfg" 65#endif 66 67void command_help(char *); 68void command_quit(char *); 69void command_boot(char *); 70void command_pkboot(char *); 71void command_consdev(char *); 72void command_root(char *); 73void command_dev(char *); 74void command_devpath(char *); 75void command_efivar(char *); 76void command_gop(char *); 77#if LIBSA_ENABLE_LS_OP 78void command_ls(char *); 79#endif 80void command_memmap(char *); 81#ifndef SMALL 82void command_menu(char *); 83#endif 84void command_modules(char *); 85void command_multiboot(char *); 86void command_reloc(char *); 87void command_text(char *); 88void command_version(char *); 89 90const struct bootblk_command commands[] = { 91 { "help", command_help }, 92 { "?", command_help }, 93 { "quit", command_quit }, 94 { "boot", command_boot }, 95 { "pkboot", command_pkboot }, 96 { "consdev", command_consdev }, 97 { "root", command_root }, 98 { "dev", command_dev }, 99 { "devpath", command_devpath }, 100 { "efivar", command_efivar }, 101 { "fs", fs_add }, 102 { "gop", command_gop }, 103 { "load", module_add }, 104#if LIBSA_ENABLE_LS_OP 105 { "ls", command_ls }, 106#endif 107 { "memmap", command_memmap }, 108#ifndef SMALL 109 { "menu", command_menu }, 110#endif 111 { "modules", command_modules }, 112 { "multiboot", command_multiboot }, 113 { "reloc", command_reloc }, 114 { "rndseed", rnd_add }, 115 { "splash", splash_add }, 116 { "text", command_text }, 117 { "userconf", userconf_add }, 118 { "version", command_version }, 119 { NULL, NULL }, 120}; 121 122static char *default_fsname; 123static char *default_devname; 124static int default_unit, default_partition; 125static const char *default_filename; 126static const char *default_part_name; 127 128static char *sprint_bootsel(const char *); 129static void bootit(const char *, int); 130 131int 132parsebootfile(const char *fname, char **fsname, char **devname, int *unit, 133 int *partition, const char **file) 134{ 135 const char *col; 136 static char savedevname[MAXDEVNAME+1]; 137#if defined(SUPPORT_NFS) || defined(SUPPORT_TFTP) 138 const struct netboot_fstab *nf; 139#endif 140 141 *fsname = default_fsname; 142 if (default_part_name == NULL) { 143 *devname = default_devname; 144 } else { 145 snprintf(savedevname, sizeof(savedevname), 146 "NAME=%s", default_part_name); 147 *devname = savedevname; 148 } 149 *unit = default_unit; 150 *partition = default_partition; 151 *file = default_filename; 152 153 if (fname == NULL) 154 return 0; 155 156 if ((col = strchr(fname, ':')) != NULL) { /* device given */ 157 int devlen; 158 int u = 0, p = 0; 159 int i = 0; 160 161 devlen = col - fname; 162 if (devlen > MAXDEVNAME) 163 return EINVAL; 164 165 if (strstr(fname, "NAME=") == fname) { 166 strlcpy(savedevname, fname, devlen + 1); 167 *fsname = "ufs"; 168 *devname = savedevname; 169 *unit = -1; 170 *partition = -1; 171 fname = col + 1; 172 goto out; 173 } 174 175#define isvalidname(c) ((c) >= 'a' && (c) <= 'z') 176 if (!isvalidname(fname[i])) 177 return EINVAL; 178 do { 179 savedevname[i] = fname[i]; 180 i++; 181 } while (isvalidname(fname[i])); 182 savedevname[i] = '\0'; 183 184#define isnum(c) ((c) >= '0' && (c) <= '9') 185 if (i < devlen) { 186 if (!isnum(fname[i])) 187 return EUNIT; 188 do { 189 u *= 10; 190 u += fname[i++] - '0'; 191 } while (isnum(fname[i])); 192 } 193 194#define isvalidpart(c) ((c) >= 'a' && (c) <= 'z') 195 if (i < devlen) { 196 if (!isvalidpart(fname[i])) 197 return EPART; 198 p = fname[i++] - 'a'; 199 } 200 201 if (i != devlen) 202 return ENXIO; 203 204#if defined(SUPPORT_NFS) || defined(SUPPORT_TFTP) 205 nf = netboot_fstab_find(savedevname); 206 if (nf != NULL) 207 *fsname = (char *)nf->name; 208 else 209#endif 210 *fsname = "ufs"; 211 *devname = savedevname; 212 *unit = u; 213 *partition = p; 214 fname = col + 1; 215 } 216 217out: 218 if (*fname) 219 *file = fname; 220 221 return 0; 222} 223 224static char * 225snprint_bootdev(char *buf, size_t bufsize, const char *devname, int unit, 226 int partition) 227{ 228 static const char *no_partition_devs[] = { "esp", "net", "nfs", "tftp" }; 229 int i; 230 231 for (i = 0; i < __arraycount(no_partition_devs); i++) 232 if (strcmp(devname, no_partition_devs[i]) == 0) 233 break; 234 if (strstr(devname, "NAME=") == devname) 235 strlcpy(buf, devname, bufsize); 236 else 237 snprintf(buf, bufsize, "%s%d%c", devname, unit, 238 i < __arraycount(no_partition_devs) ? '\0' : 'a' + partition); 239 return buf; 240} 241 242static char * 243sprint_bootsel(const char *filename) 244{ 245 char *fsname, *devname; 246 int unit, partition; 247 const char *file; 248 static char buf[80]; 249 250 if (parsebootfile(filename, &fsname, &devname, &unit, 251 &partition, &file) == 0) { 252 snprintf(buf, sizeof(buf), "%s:%s", snprint_bootdev(buf, 253 sizeof(buf), devname, unit, partition), file); 254 return buf; 255 } 256 return "(invalid)"; 257} 258 259void 260clearit(void) 261{ 262 263 if (bootcfg_info.clear) 264 clear_pc_screen(); 265} 266 267static void 268bootit(const char *filename, int howto) 269{ 270 271 if (howto & AB_VERBOSE) 272 printf("booting %s (howto 0x%x)\n", sprint_bootsel(filename), 273 howto); 274 275 if (exec_netbsd(filename, efi_loadaddr, howto, 0, efi_cleanup) < 0) 276 printf("boot: %s: %s\n", sprint_bootsel(filename), 277 strerror(errno)); 278 else 279 printf("boot returned\n"); 280} 281 282void 283boot(void) 284{ 285 int currname; 286 int c; 287#if defined(SUPPORT_NFS) || defined(SUPPORT_TFTP) 288 const struct netboot_fstab *nf; 289#endif 290 291 boot_modules_enabled = !(boot_params.bp_flags & X86_BP_FLAGS_NOMODULES); 292 293 /* try to set default device to what BIOS tells us */ 294 bios2dev(boot_biosdev, boot_biossector, &default_devname, &default_unit, 295 &default_partition, &default_part_name); 296 297 /* if the user types "boot" without filename */ 298 default_filename = DEFFILENAME; 299 300#if defined(SUPPORT_NFS) || defined(SUPPORT_TFTP) 301 nf = netboot_fstab_find(default_devname); 302 if (nf != NULL) 303 default_fsname = (char *)nf->name; 304 else 305#endif 306 default_fsname = "ufs"; 307 308 if (!(boot_params.bp_flags & X86_BP_FLAGS_NOBOOTCONF)) { 309#ifdef EFIBOOTCFG_FILENAME 310 int rv = EINVAL; 311 if (efi_bootdp_type != BOOT_DEVICE_TYPE_NET) 312 rv = parsebootconf(EFIBOOTCFG_FILENAME); 313 if (rv) 314#endif 315 parsebootconf(BOOTCFG_FILENAME); 316 } else { 317 bootcfg_info.timeout = boot_params.bp_timeout; 318 } 319 320 /* 321 * If console set in boot.cfg, switch to it. 322 * This will print the banner, so we don't need to explicitly do it 323 */ 324 if (bootcfg_info.consdev) { 325 command_consdev(bootcfg_info.consdev); 326 } else { 327 clearit(); 328 print_bootcfg_banner(bootprog_name, bootprog_rev); 329 } 330 331 /* Display the menu, if applicable */ 332 twiddle_toggle = 0; 333 if (bootcfg_info.nummenu > 0) { 334 /* Does not return */ 335 doboottypemenu(); 336 } 337 338 printf("Press return to boot now, any other key for boot menu\n"); 339 for (currname = 0; currname < NUMNAMES; currname++) { 340 printf("booting %s - starting in ", 341 sprint_bootsel(names[currname][0])); 342 343 c = awaitkey((bootcfg_info.timeout < 0) ? 0 344 : bootcfg_info.timeout, 1); 345 if ((c != '\r') && (c != '\n') && (c != '\0')) { 346 if ((boot_params.bp_flags & X86_BP_FLAGS_PASSWORD) == 0) { 347 /* do NOT ask for password */ 348 bootmenu(); /* does not return */ 349 } else { 350 /* DO ask for password */ 351 if (check_password((char *)boot_params.bp_password)) { 352 /* password ok */ 353 printf("type \"?\" or \"help\" for help.\n"); 354 bootmenu(); /* does not return */ 355 } else { 356 /* bad password */ 357 printf("Wrong password.\n"); 358 currname = 0; 359 continue; 360 } 361 } 362 } 363 364 /* 365 * try pairs of names[] entries, foo and foo.gz 366 */ 367 /* don't print "booting..." again */ 368 bootit(names[currname][0], 0); 369 /* since it failed, try compressed bootfile. */ 370 bootit(names[currname][1], AB_VERBOSE); 371 } 372 373 bootmenu(); /* does not return */ 374} 375 376/* ARGSUSED */ 377void 378command_help(char *arg) 379{ 380 381 printf("commands are:\n" 382 "boot [dev:][filename] [-12acdqsvxz]\n" 383#ifndef NO_RAIDFRAME 384 " dev syntax is (hd|fd|cd|raid)[N[x]]\n" 385#else 386 " dev syntax is (hd|fd|cd)[N[x]]\n" 387#endif 388#ifndef NO_GPT 389 " or NAME=gpt_label\n" 390#endif 391 " (ex. \"hd0a:netbsd.old -s\")\n" 392 "pkboot [dev:][filename] [-12acdqsvxz]\n" 393 "dev [dev:]\n" 394 "consdev {pc|com[0123][,{speed}]|com,{ioport}[,{speed}]}\n" 395 "root {spec}\n" 396 " spec can be disk, e.g. wd0, sd0\n" 397 " or string like wedge:name\n" 398 "devpath\n" 399 "efivar\n" 400 "gop [{modenum|list}]\n" 401 "load {path_to_module}\n" 402#if LIBSA_ENABLE_LS_OP 403 "ls [dev:][path]\n" 404#endif 405 "memmap [{sorted|unsorted|compact}]\n" 406#ifndef SMALL 407 "menu (reenters boot menu, if defined in boot.cfg)\n" 408#endif 409 "modules {on|off|enabled|disabled}\n" 410 "multiboot [dev:][filename] [<args>]\n" 411 "reloc {address|none|default}\n" 412 "rndseed {path_to_rndseed_file}\n" 413 "splash {path_to_image_file}\n" 414 "text [{modenum|list}]\n" 415 "userconf {command}\n" 416 "version\n" 417 "help|?\n" 418 "quit\n"); 419} 420 421#if LIBSA_ENABLE_LS_OP 422void 423command_ls(char *arg) 424{ 425 const char *save = default_filename; 426 427 default_filename = "/"; 428 ls(arg); 429 default_filename = save; 430} 431#endif 432 433/* ARGSUSED */ 434void 435command_quit(char *arg) 436{ 437 438 printf("Exiting...\n"); 439 delay(1 * 1000 * 1000); 440 reboot(); 441 /* Note: we shouldn't get to this point! */ 442 panic("Could not reboot!"); 443} 444 445void 446command_boot(char *arg) 447{ 448 char *filename; 449 int howto; 450 451 if (!parseboot(arg, &filename, &howto)) 452 return; 453 454 if (filename != NULL) { 455 bootit(filename, howto); 456 } else { 457 int i; 458 459 for (i = 0; i < NUMNAMES; i++) { 460 bootit(names[i][0], howto); 461 bootit(names[i][1], howto); 462 } 463 } 464} 465 466void 467command_pkboot(char *arg) 468{ 469 extern int has_prekern; 470 has_prekern = 1; 471 command_boot(arg); 472 has_prekern = 0; 473} 474 475void 476command_dev(char *arg) 477{ 478 static char savedevname[MAXDEVNAME + 1]; 479 char buf[80]; 480 char *devname; 481 const char *file; /* dummy */ 482 483 if (*arg == '\0') { 484 efi_disk_show(); 485 efi_net_show(); 486 487 if (default_part_name != NULL) 488 printf("default NAME=%s\n", default_part_name); 489 else 490 printf("default %s\n", 491 snprint_bootdev(buf, sizeof(buf), 492 default_devname, default_unit, 493 default_partition)); 494 return; 495 } 496 497 if (strchr(arg, ':') == NULL || 498 parsebootfile(arg, &default_fsname, &devname, &default_unit, 499 &default_partition, &file)) { 500 command_help(NULL); 501 return; 502 } 503 504 /* put to own static storage */ 505 strncpy(savedevname, devname, MAXDEVNAME + 1); 506 default_devname = savedevname; 507 508 /* +5 to skip leading NAME= */ 509 if (strstr(devname, "NAME=") == devname) 510 default_part_name = default_devname + 5; 511} 512 513static const struct cons_devs { 514 const char *name; 515 u_int tag; 516 int ioport; 517} cons_devs[] = { 518 { "pc", CONSDEV_PC, 0 }, 519 { "com0", CONSDEV_COM0, 0 }, 520 { "com1", CONSDEV_COM1, 0 }, 521 { "com2", CONSDEV_COM2, 0 }, 522 { "com3", CONSDEV_COM3, 0 }, 523 { "com0kbd", CONSDEV_COM0KBD, 0 }, 524 { "com1kbd", CONSDEV_COM1KBD, 0 }, 525 { "com2kbd", CONSDEV_COM2KBD, 0 }, 526 { "com3kbd", CONSDEV_COM3KBD, 0 }, 527 { "com", CONSDEV_COM0, -1 }, 528 { "auto", CONSDEV_AUTO, 0 }, 529 { NULL, 0 } 530}; 531 532void 533command_consdev(char *arg) 534{ 535 const struct cons_devs *cdp; 536 char *sep, *sep2 = NULL; 537 int ioport, speed = 0; 538 539 if (*arg == '\0') { 540 efi_cons_show(); 541 return; 542 } 543 544 sep = strchr(arg, ','); 545 if (sep != NULL) { 546 *sep++ = '\0'; 547 sep2 = strchr(sep, ','); 548 if (sep2 != NULL) 549 *sep2++ = '\0'; 550 } 551 552 for (cdp = cons_devs; cdp->name; cdp++) { 553 if (strcmp(arg, cdp->name) == 0) { 554 ioport = cdp->ioport; 555 if (cdp->tag == CONSDEV_PC || cdp->tag == CONSDEV_AUTO) { 556 if (sep != NULL || sep2 != NULL) 557 goto error; 558 } else { 559 /* com? */ 560 if (ioport == -1) { 561 if (sep != NULL) { 562 u_long t = strtoul(sep, NULL, 0); 563 if (t > INT_MAX) 564 goto error; 565 ioport = (int)t; 566 } 567 if (sep2 != NULL) { 568 speed = atoi(sep2); 569 if (speed < 0) 570 goto error; 571 } 572 } else { 573 if (sep != NULL) { 574 speed = atoi(sep); 575 if (speed < 0) 576 goto error; 577 } 578 if (sep2 != NULL) 579 goto error; 580 } 581 } 582 efi_consinit(cdp->tag, ioport, speed); 583 clearit(); 584 print_bootcfg_banner(bootprog_name, bootprog_rev); 585 return; 586 } 587 } 588error: 589 printf("invalid console device.\n"); 590} 591 592void 593command_root(char *arg) 594{ 595 struct btinfo_rootdevice *biv = &bi_root; 596 597 strncpy(biv->devname, arg, sizeof(biv->devname)); 598 if (biv->devname[sizeof(biv->devname)-1] != '\0') { 599 biv->devname[sizeof(biv->devname)-1] = '\0'; 600 printf("truncated to %s\n",biv->devname); 601 } 602} 603 604 605#ifndef SMALL 606/* ARGSUSED */ 607void 608command_menu(char *arg) 609{ 610 611 if (bootcfg_info.nummenu > 0) { 612 /* Does not return */ 613 doboottypemenu(); 614 } else 615 printf("No menu defined in boot.cfg\n"); 616} 617#endif /* !SMALL */ 618 619void 620command_modules(char *arg) 621{ 622 623 if (strcmp(arg, "enabled") == 0 || 624 strcmp(arg, "on") == 0) 625 boot_modules_enabled = true; 626 else if (strcmp(arg, "disabled") == 0 || 627 strcmp(arg, "off") == 0) 628 boot_modules_enabled = false; 629 else 630 printf("invalid flag, must be 'enabled' or 'disabled'.\n"); 631} 632 633void 634command_multiboot(char *arg) 635{ 636 char *filename; 637 638 filename = arg; 639 if (exec_multiboot(filename, gettrailer(arg)) < 0) 640 printf("multiboot: %s: %s\n", sprint_bootsel(filename), 641 strerror(errno)); 642 else 643 printf("boot returned\n"); 644} 645 646void 647command_reloc(char *arg) 648{ 649 char *ep; 650 651 if (*arg == '\0') { 652 switch (efi_reloc_type) { 653 case RELOC_NONE: 654 printf("reloc: none\n"); 655 break; 656 case RELOC_ADDR: 657 printf("reloc: %p\n", (void *)efi_kernel_reloc); 658 break; 659 case RELOC_DEFAULT: 660 default: 661 printf("reloc: default\n"); 662 break; 663 } 664 goto out; 665 } 666 667 if (strcmp(arg, "default") == 0) { 668 efi_reloc_type = RELOC_DEFAULT; 669 goto out; 670 } 671 672 if (strcmp(arg, "none") == 0) { 673 efi_reloc_type = RELOC_NONE; 674 goto out; 675 } 676 677 errno = 0; 678 efi_kernel_reloc = strtoul(arg, &ep, 0); 679 if (ep == arg || *ep != '\0' || errno) 680 printf("could not parse address \"%s\"\n", arg); 681 else 682 efi_reloc_type = RELOC_ADDR; 683out: 684 return; 685 686} 687 688void 689command_version(char *arg) 690{ 691 CHAR16 *path; 692 char *upath, *ufirmware; 693 int rv; 694 695 if (strcmp(arg, "full") == 0) { 696 printf("ImageBase: 0x%" PRIxPTR "\n", 697 (uintptr_t)efi_li->ImageBase); 698 printf("Stack: 0x%" PRIxPTR "\n", efi_main_sp); 699 printf("EFI version: %d.%02d\n", 700 ST->Hdr.Revision >> 16, ST->Hdr.Revision & 0xffff); 701 ufirmware = NULL; 702 rv = ucs2_to_utf8(ST->FirmwareVendor, &ufirmware); 703 if (rv == 0) { 704 printf("EFI Firmware: %s (rev %d.%02d)\n", ufirmware, 705 ST->FirmwareRevision >> 16, 706 ST->FirmwareRevision & 0xffff); 707 FreePool(ufirmware); 708 } 709 path = DevicePathToStr(efi_bootdp); 710 upath = NULL; 711 rv = ucs2_to_utf8(path, &upath); 712 FreePool(path); 713 if (rv == 0) { 714 printf("Boot DevicePath: %d:%d:%s\n", 715 DevicePathType(efi_bootdp), 716 DevicePathSubType(efi_bootdp), upath); 717 FreePool(upath); 718 } 719 } 720 721 printf("\n" 722 ">> %s, Revision %s (from NetBSD %s)\n" 723 ">> Memory: %d/%d k\n", 724 bootprog_name, bootprog_rev, bootprog_kernrev, 725 getbasemem(), getextmem()); 726} 727 728void 729command_memmap(char *arg) 730{ 731 bool sorted = true; 732 bool compact = false; 733 734 if (*arg == '\0' || strcmp(arg, "sorted") == 0) 735 /* Already sorted is true. */; 736 else if (strcmp(arg, "unsorted") == 0) 737 sorted = false; 738 else if (strcmp(arg, "compact") == 0) 739 compact = true; 740 else { 741 printf("invalid flag, " 742 "must be 'sorted', 'unsorted' or 'compact'.\n"); 743 return; 744 } 745 746 efi_memory_show_map(sorted, compact); 747} 748 749void 750command_devpath(char *arg) 751{ 752 EFI_STATUS status; 753 UINTN i, nhandles; 754 EFI_HANDLE *handles; 755 EFI_DEVICE_PATH *dp0, *dp; 756 CHAR16 *path; 757 char *upath; 758 UINTN cols, rows, row = 0; 759 int rv; 760 761 status = uefi_call_wrapper(ST->ConOut->QueryMode, 4, ST->ConOut, 762 ST->ConOut->Mode->Mode, &cols, &rows); 763 if (EFI_ERROR(status) || rows <= 2) 764 rows = 0; 765 else 766 rows -= 2; 767 768 /* 769 * all devices. 770 */ 771 status = LibLocateHandle(ByProtocol, &DevicePathProtocol, NULL, 772 &nhandles, &handles); 773 if (EFI_ERROR(status)) 774 return; 775 776 for (i = 0; i < nhandles; i++) { 777 status = uefi_call_wrapper(BS->HandleProtocol, 3, handles[i], 778 &DevicePathProtocol, (void **)&dp0); 779 if (EFI_ERROR(status)) 780 break; 781 782 printf("DevicePathType %d\n", DevicePathType(dp0)); 783 if (++row >= rows) { 784 row = 0; 785 printf("Press Any Key to continue :"); 786 (void) awaitkey(-1, 0); 787 printf("\n"); 788 } 789 for (dp = dp0; 790 !IsDevicePathEnd(dp); 791 dp = NextDevicePathNode(dp)) { 792 793 path = DevicePathToStr(dp); 794 upath = NULL; 795 rv = ucs2_to_utf8(path, &upath); 796 FreePool(path); 797 if (rv) { 798 printf("convert failed\n"); 799 break; 800 } 801 802 printf("%d:%d:%s\n", DevicePathType(dp), 803 DevicePathSubType(dp), upath); 804 FreePool(upath); 805 806 if (++row >= rows) { 807 row = 0; 808 printf("Press Any Key to continue :"); 809 (void) awaitkey(-1, 0); 810 printf("\n"); 811 } 812 } 813 } 814} 815 816 817void 818command_efivar(char *arg) 819{ 820 static const char header[] = 821 "GUID Variable Name Value\n" 822 "==================================== ==================== ========\n"; 823 EFI_STATUS status; 824 UINTN sz = 64, osz; 825 CHAR16 *name = NULL, *tmp, *val, guid[128]; 826 char *uname, *uval, *uguid; 827 EFI_GUID vendor; 828 UINTN cols, rows, row = 0; 829 int rv; 830 831 status = uefi_call_wrapper(ST->ConOut->QueryMode, 4, ST->ConOut, 832 ST->ConOut->Mode->Mode, &cols, &rows); 833 if (EFI_ERROR(status) || rows <= 2) 834 rows = 0; 835 else 836 rows -= 2; 837 838 name = AllocatePool(sz); 839 if (name == NULL) { 840 printf("memory allocation failed: %" PRIuMAX" bytes\n", 841 (uintmax_t)sz); 842 return; 843 } 844 845 SetMem(name, sz, 0); 846 vendor = NullGuid; 847 848 printf("%s", header); 849 for (;;) { 850 osz = sz; 851 status = uefi_call_wrapper(RT->GetNextVariableName, 3, 852 &sz, name, &vendor); 853 if (EFI_ERROR(status)) { 854 if (status == EFI_NOT_FOUND) 855 break; 856 if (status != EFI_BUFFER_TOO_SMALL) { 857 printf("GetNextVariableName failed: %" PRIxMAX "\n", 858 (uintmax_t)status); 859 break; 860 } 861 862 tmp = AllocatePool(sz); 863 if (tmp == NULL) { 864 printf("memory allocation failed: %" PRIuMAX 865 "bytes\n", (uintmax_t)sz); 866 break; 867 } 868 SetMem(tmp, sz, 0); 869 CopyMem(tmp, name, osz); 870 FreePool(name); 871 name = tmp; 872 continue; 873 } 874 875 val = LibGetVariable(name, &vendor); 876 if (val != NULL) { 877 uval = NULL; 878 rv = ucs2_to_utf8(val, &uval); 879 FreePool(val); 880 if (rv) { 881 printf("value convert failed\n"); 882 break; 883 } 884 } else 885 uval = NULL; 886 uname = NULL; 887 rv = ucs2_to_utf8(name, &uname); 888 if (rv) { 889 printf("name convert failed\n"); 890 FreePool(uval); 891 break; 892 } 893 GuidToString(guid, &vendor); 894 uguid = NULL; 895 rv = ucs2_to_utf8(guid, &uguid); 896 if (rv) { 897 printf("GUID convert failed\n"); 898 FreePool(uval); 899 FreePool(uname); 900 break; 901 } 902 printf("%-35s %-20s %s\n", uguid, uname, uval ? uval : "(null)"); 903 FreePool(uguid); 904 FreePool(uname); 905 if (uval != NULL) 906 FreePool(uval); 907 908 if (++row >= rows) { 909 row = 0; 910 printf("Press Any Key to continue :"); 911 (void) awaitkey(-1, 0); 912 printf("\n"); 913 } 914 } 915 916 FreePool(name); 917} 918