1 /* $NetBSD: boot2.c,v 1.63 2014/06/28 09:16:18 rtr 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 <vbe.h> 83 #include "devopen.h" 84 85 #ifdef SUPPORT_PS2 86 #include <biosmca.h> 87 #endif 88 89 extern struct x86_boot_params boot_params; 90 91 extern const char bootprog_name[], bootprog_rev[], bootprog_kernrev[]; 92 93 int errno; 94 95 int boot_biosdev; 96 daddr_t boot_biossector; 97 98 static const char * const names[][2] = { 99 { "netbsd", "netbsd.gz" }, 100 { "onetbsd", "onetbsd.gz" }, 101 { "netbsd.old", "netbsd.old.gz" }, 102 }; 103 104 #define NUMNAMES (sizeof(names)/sizeof(names[0])) 105 #define DEFFILENAME names[0][0] 106 107 #define MAXDEVNAME 16 108 109 static char *default_devname; 110 static int default_unit, default_partition; 111 static const char *default_filename; 112 113 char *sprint_bootsel(const char *); 114 void bootit(const char *, int, int); 115 void print_banner(void); 116 void boot2(int, uint64_t); 117 118 void command_help(char *); 119 #if LIBSA_ENABLE_LS_OP 120 void command_ls(char *); 121 #endif 122 void command_quit(char *); 123 void command_boot(char *); 124 void command_dev(char *); 125 void command_consdev(char *); 126 #ifndef SMALL 127 void command_menu(char *); 128 #endif 129 void command_modules(char *); 130 void command_multiboot(char *); 131 132 const struct bootblk_command commands[] = { 133 { "help", command_help }, 134 { "?", command_help }, 135 #if LIBSA_ENABLE_LS_OP 136 { "ls", command_ls }, 137 #endif 138 { "quit", command_quit }, 139 { "boot", command_boot }, 140 { "dev", command_dev }, 141 { "consdev", command_consdev }, 142 #ifndef SMALL 143 { "menu", command_menu }, 144 #endif 145 { "modules", command_modules }, 146 { "load", module_add }, 147 { "multiboot", command_multiboot }, 148 { "vesa", command_vesa }, 149 { "splash", splash_add }, 150 { "rndseed", rnd_add }, 151 { "fs", fs_add }, 152 { "userconf", userconf_add }, 153 { NULL, NULL }, 154 }; 155 156 int 157 parsebootfile(const char *fname, char **fsname, char **devname, 158 int *unit, int *partition, const char **file) 159 { 160 const char *col; 161 162 *fsname = "ufs"; 163 *devname = default_devname; 164 *unit = default_unit; 165 *partition = default_partition; 166 *file = default_filename; 167 168 if (fname == NULL) 169 return 0; 170 171 if ((col = strchr(fname, ':')) != NULL) { /* device given */ 172 static char savedevname[MAXDEVNAME+1]; 173 int devlen; 174 int u = 0, p = 0; 175 int i = 0; 176 177 devlen = col - fname; 178 if (devlen > MAXDEVNAME) 179 return EINVAL; 180 181 #define isvalidname(c) ((c) >= 'a' && (c) <= 'z') 182 if (!isvalidname(fname[i])) 183 return EINVAL; 184 do { 185 savedevname[i] = fname[i]; 186 i++; 187 } while (isvalidname(fname[i])); 188 savedevname[i] = '\0'; 189 190 #define isnum(c) ((c) >= '0' && (c) <= '9') 191 if (i < devlen) { 192 if (!isnum(fname[i])) 193 return EUNIT; 194 do { 195 u *= 10; 196 u += fname[i++] - '0'; 197 } while (isnum(fname[i])); 198 } 199 200 #define isvalidpart(c) ((c) >= 'a' && (c) <= 'z') 201 if (i < devlen) { 202 if (!isvalidpart(fname[i])) 203 return EPART; 204 p = fname[i++] - 'a'; 205 } 206 207 if (i != devlen) 208 return ENXIO; 209 210 *devname = savedevname; 211 *unit = u; 212 *partition = p; 213 fname = col + 1; 214 } 215 216 if (*fname) 217 *file = fname; 218 219 return 0; 220 } 221 222 char * 223 sprint_bootsel(const char *filename) 224 { 225 char *fsname, *devname; 226 int unit, partition; 227 const char *file; 228 static char buf[80]; 229 230 if (parsebootfile(filename, &fsname, &devname, &unit, 231 &partition, &file) == 0) { 232 snprintf(buf, sizeof(buf), "%s%d%c:%s", devname, unit, 233 'a' + partition, file); 234 return buf; 235 } 236 return "(invalid)"; 237 } 238 239 static void 240 clearit(void) 241 { 242 243 if (bootcfg_info.clear) 244 clear_pc_screen(); 245 } 246 247 void 248 bootit(const char *filename, int howto, int tell) 249 { 250 251 if (tell) { 252 printf("booting %s", sprint_bootsel(filename)); 253 if (howto) 254 printf(" (howto 0x%x)", howto); 255 printf("\n"); 256 } 257 258 if (exec_netbsd(filename, 0, howto, boot_biosdev < 0x80, clearit) < 0) 259 printf("boot: %s: %s\n", sprint_bootsel(filename), 260 strerror(errno)); 261 else 262 printf("boot returned\n"); 263 } 264 265 void 266 print_banner(void) 267 { 268 269 clearit(); 270 #ifndef SMALL 271 int n; 272 if (bootcfg_info.banner[0]) { 273 for (n = 0; bootcfg_info.banner[n] 274 && n < BOOTCFG_MAXBANNER; n++) 275 printf("%s\n", bootcfg_info.banner[n]); 276 } else { 277 #endif /* !SMALL */ 278 printf("\n" 279 ">> %s, Revision %s (from NetBSD %s)\n" 280 ">> Memory: %d/%d k\n", 281 bootprog_name, bootprog_rev, bootprog_kernrev, 282 getbasemem(), getextmem()); 283 284 #ifndef SMALL 285 } 286 #endif /* !SMALL */ 287 } 288 289 /* 290 * Called from the initial entry point boot_start in biosboot.S 291 * 292 * biosdev: BIOS drive number the system booted from 293 * biossector: Sector number of the NetBSD partition 294 */ 295 void 296 boot2(int biosdev, uint64_t biossector) 297 { 298 extern char twiddle_toggle; 299 int currname; 300 char c; 301 302 twiddle_toggle = 1; /* no twiddling until we're ready */ 303 304 initio(boot_params.bp_consdev); 305 306 #ifdef SUPPORT_PS2 307 biosmca(); 308 #endif 309 gateA20(); 310 311 boot_modules_enabled = !(boot_params.bp_flags 312 & X86_BP_FLAGS_NOMODULES); 313 if (boot_params.bp_flags & X86_BP_FLAGS_RESET_VIDEO) 314 biosvideomode(); 315 316 vbe_init(); 317 318 /* need to remember these */ 319 boot_biosdev = biosdev; 320 boot_biossector = biossector; 321 322 /* try to set default device to what BIOS tells us */ 323 bios2dev(biosdev, biossector, &default_devname, &default_unit, 324 &default_partition); 325 326 /* if the user types "boot" without filename */ 327 default_filename = DEFFILENAME; 328 329 #ifndef SMALL 330 if (!(boot_params.bp_flags & X86_BP_FLAGS_NOBOOTCONF)) { 331 parsebootconf(BOOTCFG_FILENAME); 332 } else { 333 bootcfg_info.timeout = boot_params.bp_timeout; 334 } 335 336 337 /* 338 * If console set in boot.cfg, switch to it. 339 * This will print the banner, so we don't need to explicitly do it 340 */ 341 if (bootcfg_info.consdev) 342 command_consdev(bootcfg_info.consdev); 343 else 344 print_banner(); 345 346 /* Display the menu, if applicable */ 347 twiddle_toggle = 0; 348 if (bootcfg_info.nummenu > 0) { 349 /* Does not return */ 350 doboottypemenu(); 351 } 352 353 #else 354 twiddle_toggle = 0; 355 print_banner(); 356 #endif 357 358 printf("Press return to boot now, any other key for boot menu\n"); 359 for (currname = 0; currname < NUMNAMES; currname++) { 360 printf("booting %s - starting in ", 361 sprint_bootsel(names[currname][0])); 362 363 #ifdef SMALL 364 c = awaitkey(boot_params.bp_timeout, 1); 365 #else 366 c = awaitkey((bootcfg_info.timeout < 0) ? 0 367 : bootcfg_info.timeout, 1); 368 #endif 369 if ((c != '\r') && (c != '\n') && (c != '\0')) { 370 if ((boot_params.bp_flags & X86_BP_FLAGS_PASSWORD) == 0) { 371 /* do NOT ask for password */ 372 bootmenu(); /* does not return */ 373 } else { 374 /* DO ask for password */ 375 if (check_password((char *)boot_params.bp_password)) { 376 /* password ok */ 377 printf("type \"?\" or \"help\" for help.\n"); 378 bootmenu(); /* does not return */ 379 } else { 380 /* bad password */ 381 printf("Wrong password.\n"); 382 currname = 0; 383 continue; 384 } 385 } 386 } 387 388 /* 389 * try pairs of names[] entries, foo and foo.gz 390 */ 391 /* don't print "booting..." again */ 392 bootit(names[currname][0], 0, 0); 393 /* since it failed, try compressed bootfile. */ 394 bootit(names[currname][1], 0, 1); 395 } 396 397 bootmenu(); /* does not return */ 398 } 399 400 /* ARGSUSED */ 401 void 402 command_help(char *arg) 403 { 404 405 printf("commands are:\n" 406 "boot [xdNx:][filename] [-12acdqsvxz]\n" 407 " (ex. \"hd0a:netbsd.old -s\"\n" 408 #if LIBSA_ENABLE_LS_OP 409 "ls [path]\n" 410 #endif 411 "dev xd[N[x]]:\n" 412 "consdev {pc|com[0123]|com[0123]kbd|auto}\n" 413 "vesa {modenum|on|off|enabled|disabled|list}\n" 414 #ifndef SMALL 415 "menu (reenters boot menu, if defined in boot.cfg)\n" 416 #endif 417 "modules {on|off|enabled|disabled}\n" 418 "load {path_to_module}\n" 419 "multiboot [xdNx:][filename] [<args>]\n" 420 "userconf {command}\n" 421 "rndseed {path_to_rndseed_file}\n" 422 "help|?\n" 423 "quit\n"); 424 } 425 426 #if LIBSA_ENABLE_LS_OP 427 void 428 command_ls(char *arg) 429 { 430 const char *save = default_filename; 431 432 default_filename = "/"; 433 ls(arg); 434 default_filename = save; 435 } 436 #endif 437 438 /* ARGSUSED */ 439 void 440 command_quit(char *arg) 441 { 442 443 printf("Exiting...\n"); 444 delay(1000000); 445 reboot(); 446 /* Note: we shouldn't get to this point! */ 447 panic("Could not reboot!"); 448 } 449 450 void 451 command_boot(char *arg) 452 { 453 char *filename; 454 int howto, tell; 455 456 if (!parseboot(arg, &filename, &howto)) 457 return; 458 459 tell = ((howto & AB_VERBOSE) != 0); 460 if (filename != NULL) { 461 bootit(filename, howto, tell); 462 } else { 463 int i; 464 465 #ifndef SMALL 466 bootdefault(); 467 #endif 468 for (i = 0; i < NUMNAMES; i++) { 469 bootit(names[i][0], howto, tell); 470 bootit(names[i][1], howto, tell); 471 } 472 } 473 } 474 475 void 476 command_dev(char *arg) 477 { 478 static char savedevname[MAXDEVNAME + 1]; 479 char *fsname, *devname; 480 const char *file; /* dummy */ 481 482 if (*arg == '\0') { 483 biosdisk_probe(); 484 printf("default %s%d%c\n", default_devname, default_unit, 485 'a' + default_partition); 486 return; 487 } 488 489 if (strchr(arg, ':') == NULL || 490 parsebootfile(arg, &fsname, &devname, &default_unit, 491 &default_partition, &file)) { 492 command_help(NULL); 493 return; 494 } 495 496 /* put to own static storage */ 497 strncpy(savedevname, devname, MAXDEVNAME + 1); 498 default_devname = savedevname; 499 } 500 501 static const struct cons_devs { 502 const char *name; 503 u_int tag; 504 } cons_devs[] = { 505 { "pc", CONSDEV_PC }, 506 { "com0", CONSDEV_COM0 }, 507 { "com1", CONSDEV_COM1 }, 508 { "com2", CONSDEV_COM2 }, 509 { "com3", CONSDEV_COM3 }, 510 { "com0kbd", CONSDEV_COM0KBD }, 511 { "com1kbd", CONSDEV_COM1KBD }, 512 { "com2kbd", CONSDEV_COM2KBD }, 513 { "com3kbd", CONSDEV_COM3KBD }, 514 { "auto", CONSDEV_AUTO }, 515 { NULL, 0 } 516 }; 517 518 void 519 command_consdev(char *arg) 520 { 521 const struct cons_devs *cdp; 522 523 for (cdp = cons_devs; cdp->name; cdp++) { 524 if (strcmp(arg, cdp->name) == 0) { 525 initio(cdp->tag); 526 print_banner(); 527 return; 528 } 529 } 530 printf("invalid console device.\n"); 531 } 532 533 #ifndef SMALL 534 /* ARGSUSED */ 535 void 536 command_menu(char *arg) 537 { 538 539 if (bootcfg_info.nummenu > 0) { 540 /* Does not return */ 541 doboottypemenu(); 542 } else { 543 printf("No menu defined in boot.cfg\n"); 544 } 545 } 546 #endif /* !SMALL */ 547 548 void 549 command_modules(char *arg) 550 { 551 552 if (strcmp(arg, "enabled") == 0 || 553 strcmp(arg, "on") == 0) 554 boot_modules_enabled = true; 555 else if (strcmp(arg, "disabled") == 0 || 556 strcmp(arg, "off") == 0) 557 boot_modules_enabled = false; 558 else 559 printf("invalid flag, must be 'enabled' or 'disabled'.\n"); 560 } 561 562 void 563 command_multiboot(char *arg) 564 { 565 char *filename; 566 567 filename = arg; 568 if (exec_multiboot(filename, gettrailer(arg)) < 0) 569 printf("multiboot: %s: %s\n", sprint_bootsel(filename), 570 strerror(errno)); 571 else 572 printf("boot returned\n"); 573 } 574 575