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