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