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