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