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