1 /* $NetBSD: boot2.c,v 1.74 2020/07/15 12:36:30 kim Exp $ */ 2 3 /*- 4 * Copyright (c) 2008, 2009 The NetBSD Foundation, Inc. 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 NETBSD FOUNDATION, INC. AND CONTRIBUTORS 17 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 18 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 19 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 20 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 21 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 22 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 23 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 24 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 25 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 26 * POSSIBILITY OF SUCH DAMAGE. 27 */ 28 29 /* 30 * Copyright (c) 2003 31 * David Laight. All rights reserved 32 * Copyright (c) 1996, 1997, 1999 33 * Matthias Drochner. All rights reserved. 34 * Copyright (c) 1996, 1997 35 * Perry E. Metzger. All rights reserved. 36 * Copyright (c) 1997 37 * Jason R. Thorpe. All rights reserved 38 * 39 * Redistribution and use in source and binary forms, with or without 40 * modification, are permitted provided that the following conditions 41 * are met: 42 * 1. Redistributions of source code must retain the above copyright 43 * notice, this list of conditions and the following disclaimer. 44 * 2. Redistributions in binary form must reproduce the above copyright 45 * notice, this list of conditions and the following disclaimer in the 46 * documentation and/or other materials provided with the distribution. 47 * 3. All advertising materials mentioning features or use of this software 48 * must display the following acknowledgements: 49 * This product includes software developed for the NetBSD Project 50 * by Matthias Drochner. 51 * This product includes software developed for the NetBSD Project 52 * by Perry E. Metzger. 53 * 4. The names of the authors may not be used to endorse or promote products 54 * derived from this software without specific prior written permission. 55 * 56 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 57 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 58 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 59 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 60 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 61 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 62 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 63 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 64 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 65 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 66 */ 67 68 /* Based on stand/biosboot/main.c */ 69 70 #include <sys/types.h> 71 #include <sys/reboot.h> 72 #include <sys/bootblock.h> 73 74 #include <lib/libsa/stand.h> 75 #include <lib/libsa/bootcfg.h> 76 #include <lib/libsa/ufs.h> 77 #include <lib/libkern/libkern.h> 78 79 #include <libi386.h> 80 #include <bootmod.h> 81 #include <bootmenu.h> 82 #include <biosdisk.h> 83 #include <vbe.h> 84 #include "devopen.h" 85 86 #ifdef SUPPORT_PS2 87 #include <biosmca.h> 88 #endif 89 90 extern struct x86_boot_params boot_params; 91 92 extern const char bootprog_name[], bootprog_rev[], bootprog_kernrev[]; 93 94 int errno; 95 96 int boot_biosdev; 97 daddr_t boot_biossector; 98 99 static const char * const names[][2] = { 100 { "netbsd", "netbsd.gz" }, 101 { "onetbsd", "onetbsd.gz" }, 102 { "netbsd.old", "netbsd.old.gz" }, 103 }; 104 105 #define NUMNAMES (sizeof(names)/sizeof(names[0])) 106 #define DEFFILENAME names[0][0] 107 108 #ifndef NO_GPT 109 #define MAXDEVNAME 39 /* "NAME=" + 34 char part_name */ 110 #else 111 #define MAXDEVNAME 16 112 #endif 113 114 static char *default_devname; 115 static int default_unit, default_partition; 116 static const char *default_filename; 117 static const char *default_part_name; 118 119 char *sprint_bootsel(const char *); 120 static void bootit(const char *, int); 121 void print_banner(void); 122 void boot2(int, uint64_t); 123 124 void command_help(char *); 125 #if LIBSA_ENABLE_LS_OP 126 void command_ls(char *); 127 #endif 128 void command_quit(char *); 129 void command_boot(char *); 130 void command_pkboot(char *); 131 void command_dev(char *); 132 void command_consdev(char *); 133 #ifndef SMALL 134 void command_menu(char *); 135 #endif 136 void command_modules(char *); 137 void command_multiboot(char *); 138 139 const struct bootblk_command commands[] = { 140 { "help", command_help }, 141 { "?", command_help }, 142 #if LIBSA_ENABLE_LS_OP 143 { "ls", command_ls }, 144 #endif 145 { "quit", command_quit }, 146 { "boot", command_boot }, 147 { "pkboot", command_pkboot }, 148 { "dev", command_dev }, 149 { "consdev", command_consdev }, 150 #ifndef SMALL 151 { "menu", command_menu }, 152 #endif 153 { "modules", command_modules }, 154 { "load", module_add }, 155 { "multiboot", command_multiboot }, 156 { "vesa", command_vesa }, 157 { "splash", splash_add }, 158 { "rndseed", rnd_add }, 159 { "fs", fs_add }, 160 { "userconf", userconf_add }, 161 { NULL, NULL }, 162 }; 163 164 int 165 parsebootfile(const char *fname, char **fsname, char **devname, 166 int *unit, int *partition, const char **file) 167 { 168 const char *col; 169 static char savedevname[MAXDEVNAME+1]; 170 171 *fsname = "ufs"; 172 if (default_part_name == NULL) { 173 *devname = default_devname; 174 } else { 175 snprintf(savedevname, sizeof(savedevname), 176 "NAME=%s", default_part_name); 177 *devname = savedevname; 178 } 179 *unit = default_unit; 180 *partition = default_partition; 181 *file = default_filename; 182 183 if (fname == NULL) 184 return 0; 185 186 if ((col = strchr(fname, ':')) != NULL) { /* device given */ 187 int devlen; 188 int u = 0, p = 0; 189 int i = 0; 190 191 devlen = col - fname; 192 if (devlen > MAXDEVNAME) 193 return EINVAL; 194 195 #ifndef NO_GPT 196 if (strstr(fname, "NAME=") == fname) { 197 strlcpy(savedevname, fname, devlen + 1); 198 *devname = savedevname; 199 *unit = -1; 200 *partition = -1; 201 fname = col + 1; 202 goto out; 203 } 204 #endif 205 206 #define isvalidname(c) ((c) >= 'a' && (c) <= 'z') 207 if (!isvalidname(fname[i])) 208 return EINVAL; 209 do { 210 savedevname[i] = fname[i]; 211 i++; 212 } while (isvalidname(fname[i])); 213 savedevname[i] = '\0'; 214 215 #define isnum(c) ((c) >= '0' && (c) <= '9') 216 if (i < devlen) { 217 if (!isnum(fname[i])) 218 return EUNIT; 219 do { 220 u *= 10; 221 u += fname[i++] - '0'; 222 } while (isnum(fname[i])); 223 } 224 225 #define isvalidpart(c) ((c) >= 'a' && (c) <= 'z') 226 if (i < devlen) { 227 if (!isvalidpart(fname[i])) 228 return EPART; 229 p = fname[i++] - 'a'; 230 } 231 232 if (i != devlen) 233 return ENXIO; 234 235 *devname = savedevname; 236 *unit = u; 237 *partition = p; 238 fname = col + 1; 239 } 240 241 out: 242 if (*fname) 243 *file = fname; 244 245 return 0; 246 } 247 248 char * 249 sprint_bootsel(const char *filename) 250 { 251 char *fsname, *devname; 252 int unit, partition; 253 const char *file; 254 static char buf[80]; 255 256 if (parsebootfile(filename, &fsname, &devname, &unit, 257 &partition, &file) == 0) { 258 if (strstr(devname, "NAME=") == devname) 259 snprintf(buf, sizeof(buf), "%s:%s", devname, file); 260 else 261 snprintf(buf, sizeof(buf), "%s%d%c:%s", devname, unit, 262 'a' + partition, file); 263 return buf; 264 } 265 return "(invalid)"; 266 } 267 268 static void 269 clearit(void) 270 { 271 272 if (bootcfg_info.clear) 273 clear_pc_screen(); 274 } 275 276 static void 277 bootit(const char *filename, int howto) 278 { 279 if (howto & AB_VERBOSE) 280 printf("booting %s (howto 0x%x)\n", sprint_bootsel(filename), 281 howto); 282 #ifdef KERNEL_DIR 283 char path[512]; 284 strcpy(path, filename); 285 strcat(path, "/kernel"); 286 (void)exec_netbsd(path, 0, howto, boot_biosdev < 0x80, clearit); 287 #endif 288 289 if (exec_netbsd(filename, 0, howto, boot_biosdev < 0x80, clearit) < 0) 290 printf("boot: %s: %s\n", sprint_bootsel(filename), 291 strerror(errno)); 292 else 293 printf("boot returned\n"); 294 } 295 296 void 297 print_banner(void) 298 { 299 300 clearit(); 301 #ifndef SMALL 302 int n; 303 if (bootcfg_info.banner[0]) { 304 for (n = 0; n < BOOTCFG_MAXBANNER && bootcfg_info.banner[n]; 305 n++) 306 printf("%s\n", bootcfg_info.banner[n]); 307 } else { 308 #endif /* !SMALL */ 309 printf("\n" 310 ">> %s, Revision %s (from NetBSD %s)\n" 311 ">> Memory: %d/%d k\n", 312 bootprog_name, bootprog_rev, bootprog_kernrev, 313 getbasemem(), getextmem()); 314 315 #ifndef SMALL 316 } 317 #endif /* !SMALL */ 318 } 319 320 /* 321 * Called from the initial entry point boot_start in biosboot.S 322 * 323 * biosdev: BIOS drive number the system booted from 324 * biossector: Sector number of the NetBSD partition 325 */ 326 void 327 boot2(int biosdev, uint64_t biossector) 328 { 329 extern char twiddle_toggle; 330 int currname; 331 char c; 332 333 twiddle_toggle = 1; /* no twiddling until we're ready */ 334 335 initio(boot_params.bp_consdev); 336 337 #ifdef SUPPORT_PS2 338 biosmca(); 339 #endif 340 gateA20(); 341 342 boot_modules_enabled = !(boot_params.bp_flags 343 & X86_BP_FLAGS_NOMODULES); 344 if (boot_params.bp_flags & X86_BP_FLAGS_RESET_VIDEO) 345 biosvideomode(); 346 347 vbe_init(); 348 349 /* need to remember these */ 350 boot_biosdev = biosdev; 351 boot_biossector = biossector; 352 353 /* try to set default device to what BIOS tells us */ 354 bios2dev(biosdev, biossector, &default_devname, &default_unit, 355 &default_partition, &default_part_name); 356 357 /* if the user types "boot" without filename */ 358 default_filename = DEFFILENAME; 359 360 #ifndef SMALL 361 if (!(boot_params.bp_flags & X86_BP_FLAGS_NOBOOTCONF)) { 362 parsebootconf(BOOTCFG_FILENAME); 363 } else { 364 bootcfg_info.timeout = boot_params.bp_timeout; 365 } 366 367 368 /* 369 * If console set in boot.cfg, switch to it. 370 * This will print the banner, so we don't need to explicitly do it 371 */ 372 if (bootcfg_info.consdev) 373 command_consdev(bootcfg_info.consdev); 374 else 375 print_banner(); 376 377 /* Display the menu, if applicable */ 378 twiddle_toggle = 0; 379 if (bootcfg_info.nummenu > 0) { 380 /* Does not return */ 381 doboottypemenu(); 382 } 383 384 #else 385 twiddle_toggle = 0; 386 print_banner(); 387 #endif 388 389 printf("Press return to boot now, any other key for boot menu\n"); 390 for (currname = 0; currname < NUMNAMES; currname++) { 391 printf("booting %s - starting in ", 392 sprint_bootsel(names[currname][0])); 393 394 #ifdef SMALL 395 c = awaitkey(boot_params.bp_timeout, 1); 396 #else 397 c = awaitkey((bootcfg_info.timeout < 0) ? 0 398 : bootcfg_info.timeout, 1); 399 #endif 400 if ((c != '\r') && (c != '\n') && (c != '\0')) { 401 if ((boot_params.bp_flags & X86_BP_FLAGS_PASSWORD) == 0) { 402 /* do NOT ask for password */ 403 bootmenu(); /* does not return */ 404 } else { 405 /* DO ask for password */ 406 if (check_password((char *)boot_params.bp_password)) { 407 /* password ok */ 408 printf("type \"?\" or \"help\" for help.\n"); 409 bootmenu(); /* does not return */ 410 } else { 411 /* bad password */ 412 printf("Wrong password.\n"); 413 currname = 0; 414 continue; 415 } 416 } 417 } 418 419 /* 420 * try pairs of names[] entries, foo and foo.gz 421 */ 422 /* don't print "booting..." again */ 423 bootit(names[currname][0], 0); 424 /* since it failed, try compressed bootfile. */ 425 bootit(names[currname][1], AB_VERBOSE); 426 } 427 428 bootmenu(); /* does not return */ 429 } 430 431 /* ARGSUSED */ 432 void 433 command_help(char *arg) 434 { 435 436 printf("commands are:\n" 437 "boot [dev:][filename] [-12acdqsvxz]\n" 438 #ifndef NO_RAIDFRAME 439 " dev syntax is (hd|fd|cd|raid)[N[x]]\n" 440 #else 441 " dev syntax is (hd|fd|cd)[N[x]]n" 442 #endif 443 #ifndef NO_GPT 444 " or NAME=gpt_label\n" 445 #endif 446 " (ex. \"hd0a:netbsd.old -s\")\n" 447 "pkboot [dev:][filename] [-12acdqsvxz]\n" 448 #if LIBSA_ENABLE_LS_OP 449 "ls [dev:][path]\n" 450 #endif 451 "dev [dev:]\n" 452 "consdev {pc|{com[0123]|com[0123]kbd|auto}[,{speed}]}\n" 453 "vesa {modenum|on|off|enabled|disabled|list}\n" 454 #ifndef SMALL 455 "menu (reenters boot menu, if defined in boot.cfg)\n" 456 #endif 457 "modules {on|off|enabled|disabled}\n" 458 "load {path_to_module}\n" 459 "multiboot [dev:][filename] [<args>]\n" 460 "splash {path_to_image_file}\n" 461 "userconf {command}\n" 462 "rndseed {path_to_rndseed_file}\n" 463 "help|?\n" 464 "quit\n"); 465 } 466 467 #if LIBSA_ENABLE_LS_OP 468 void 469 command_ls(char *arg) 470 { 471 const char *save = default_filename; 472 473 default_filename = "/"; 474 ls(arg); 475 default_filename = save; 476 } 477 #endif 478 479 /* ARGSUSED */ 480 void 481 command_quit(char *arg) 482 { 483 484 printf("Exiting...\n"); 485 delay(1000000); 486 reboot(); 487 /* Note: we shouldn't get to this point! */ 488 panic("Could not reboot!"); 489 } 490 491 void 492 command_boot(char *arg) 493 { 494 char *filename; 495 int howto; 496 497 if (!parseboot(arg, &filename, &howto)) 498 return; 499 500 if (filename != NULL) { 501 bootit(filename, howto); 502 } else { 503 int i; 504 505 #ifndef SMALL 506 if (howto == 0) 507 bootdefault(); 508 #endif 509 for (i = 0; i < NUMNAMES; i++) { 510 bootit(names[i][0], howto); 511 bootit(names[i][1], howto); 512 } 513 } 514 } 515 516 void 517 command_pkboot(char *arg) 518 { 519 extern int has_prekern; 520 has_prekern = 1; 521 command_boot(arg); 522 has_prekern = 0; 523 } 524 525 void 526 command_dev(char *arg) 527 { 528 static char savedevname[MAXDEVNAME + 1]; 529 char *fsname, *devname; 530 const char *file; /* dummy */ 531 532 if (*arg == '\0') { 533 biosdisk_probe(); 534 535 #ifndef NO_GPT 536 if (default_part_name) 537 printf("default NAME=%s on %s%d\n", default_part_name, 538 default_devname, default_unit); 539 else 540 #endif 541 printf("default %s%d%c\n", 542 default_devname, default_unit, 543 'a' + default_partition); 544 return; 545 } 546 547 if (strchr(arg, ':') == NULL || 548 parsebootfile(arg, &fsname, &devname, &default_unit, 549 &default_partition, &file)) { 550 command_help(NULL); 551 return; 552 } 553 554 /* put to own static storage */ 555 strncpy(savedevname, devname, MAXDEVNAME + 1); 556 default_devname = savedevname; 557 558 /* +5 to skip leading NAME= */ 559 if (strstr(devname, "NAME=") == devname) 560 default_part_name = default_devname + 5; 561 } 562 563 static const struct cons_devs { 564 const char *name; 565 u_int tag; 566 } cons_devs[] = { 567 { "pc", CONSDEV_PC }, 568 { "com0", CONSDEV_COM0 }, 569 { "com1", CONSDEV_COM1 }, 570 { "com2", CONSDEV_COM2 }, 571 { "com3", CONSDEV_COM3 }, 572 { "com0kbd", CONSDEV_COM0KBD }, 573 { "com1kbd", CONSDEV_COM1KBD }, 574 { "com2kbd", CONSDEV_COM2KBD }, 575 { "com3kbd", CONSDEV_COM3KBD }, 576 { "auto", CONSDEV_AUTO }, 577 { NULL, 0 } 578 }; 579 580 void 581 command_consdev(char *arg) 582 { 583 const struct cons_devs *cdp; 584 char *sep; 585 int speed; 586 587 sep = strchr(arg, ','); 588 if (sep != NULL) 589 *sep++ = '\0'; 590 591 for (cdp = cons_devs; cdp->name; cdp++) { 592 if (strcmp(arg, cdp->name) != 0) 593 continue; 594 595 if (sep != NULL) { 596 if (cdp->tag == CONSDEV_PC) 597 goto error; 598 599 speed = atoi(sep); 600 if (speed < 0) 601 goto error; 602 boot_params.bp_conspeed = speed; 603 } 604 605 initio(cdp->tag); 606 print_banner(); 607 return; 608 } 609 error: 610 printf("invalid console device.\n"); 611 } 612 613 #ifndef SMALL 614 /* ARGSUSED */ 615 void 616 command_menu(char *arg) 617 { 618 619 if (bootcfg_info.nummenu > 0) { 620 /* Does not return */ 621 doboottypemenu(); 622 } else { 623 printf("No menu defined in boot.cfg\n"); 624 } 625 } 626 #endif /* !SMALL */ 627 628 void 629 command_modules(char *arg) 630 { 631 632 if (strcmp(arg, "enabled") == 0 || 633 strcmp(arg, "on") == 0) 634 boot_modules_enabled = true; 635 else if (strcmp(arg, "disabled") == 0 || 636 strcmp(arg, "off") == 0) 637 boot_modules_enabled = false; 638 else 639 printf("invalid flag, must be 'enabled' or 'disabled'.\n"); 640 } 641 642 void 643 command_multiboot(char *arg) 644 { 645 char *filename; 646 647 filename = arg; 648 if (exec_multiboot(filename, gettrailer(arg)) < 0) 649 printf("multiboot: %s: %s\n", sprint_bootsel(filename), 650 strerror(errno)); 651 else 652 printf("boot returned\n"); 653 } 654 655