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