Home | History | Annotate | Line # | Download | only in boot
      1 /*	$NetBSD: boot2.c,v 1.64 2015/01/16 03:45:53 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/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 static void bootit(const char *, 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 static void
    248 bootit(const char *filename, int howto)
    249 {
    250 	if (howto & AB_VERBOSE)
    251 		printf("booting %s (howto 0x%x)\n", sprint_bootsel(filename),
    252 		    howto);
    253 
    254 	if (exec_netbsd(filename, 0, howto, boot_biosdev < 0x80, clearit) < 0)
    255 		printf("boot: %s: %s\n", sprint_bootsel(filename),
    256 		       strerror(errno));
    257 	else
    258 		printf("boot returned\n");
    259 }
    260 
    261 void
    262 print_banner(void)
    263 {
    264 
    265 	clearit();
    266 #ifndef SMALL
    267 	int n;
    268 	if (bootcfg_info.banner[0]) {
    269 		for (n = 0; bootcfg_info.banner[n]
    270 		    && n < BOOTCFG_MAXBANNER; n++)
    271 			printf("%s\n", bootcfg_info.banner[n]);
    272 	} else {
    273 #endif /* !SMALL */
    274 		printf("\n"
    275 		       ">> %s, Revision %s (from NetBSD %s)\n"
    276 		       ">> Memory: %d/%d k\n",
    277 		       bootprog_name, bootprog_rev, bootprog_kernrev,
    278 		       getbasemem(), getextmem());
    279 
    280 #ifndef SMALL
    281 	}
    282 #endif /* !SMALL */
    283 }
    284 
    285 /*
    286  * Called from the initial entry point boot_start in biosboot.S
    287  *
    288  * biosdev: BIOS drive number the system booted from
    289  * biossector: Sector number of the NetBSD partition
    290  */
    291 void
    292 boot2(int biosdev, uint64_t biossector)
    293 {
    294 	extern char twiddle_toggle;
    295 	int currname;
    296 	char c;
    297 
    298 	twiddle_toggle = 1;	/* no twiddling until we're ready */
    299 
    300 	initio(boot_params.bp_consdev);
    301 
    302 #ifdef SUPPORT_PS2
    303 	biosmca();
    304 #endif
    305 	gateA20();
    306 
    307 	boot_modules_enabled = !(boot_params.bp_flags
    308 				 & X86_BP_FLAGS_NOMODULES);
    309 	if (boot_params.bp_flags & X86_BP_FLAGS_RESET_VIDEO)
    310 		biosvideomode();
    311 
    312 	vbe_init();
    313 
    314 	/* need to remember these */
    315 	boot_biosdev = biosdev;
    316 	boot_biossector = biossector;
    317 
    318 	/* try to set default device to what BIOS tells us */
    319 	bios2dev(biosdev, biossector, &default_devname, &default_unit,
    320 		 &default_partition);
    321 
    322 	/* if the user types "boot" without filename */
    323 	default_filename = DEFFILENAME;
    324 
    325 #ifndef SMALL
    326 	if (!(boot_params.bp_flags & X86_BP_FLAGS_NOBOOTCONF)) {
    327 		parsebootconf(BOOTCFG_FILENAME);
    328 	} else {
    329 		bootcfg_info.timeout = boot_params.bp_timeout;
    330 	}
    331 
    332 
    333 	/*
    334 	 * If console set in boot.cfg, switch to it.
    335 	 * This will print the banner, so we don't need to explicitly do it
    336 	 */
    337 	if (bootcfg_info.consdev)
    338 		command_consdev(bootcfg_info.consdev);
    339 	else
    340 		print_banner();
    341 
    342 	/* Display the menu, if applicable */
    343 	twiddle_toggle = 0;
    344 	if (bootcfg_info.nummenu > 0) {
    345 		/* Does not return */
    346 		doboottypemenu();
    347 	}
    348 
    349 #else
    350 	twiddle_toggle = 0;
    351 	print_banner();
    352 #endif
    353 
    354 	printf("Press return to boot now, any other key for boot menu\n");
    355 	for (currname = 0; currname < NUMNAMES; currname++) {
    356 		printf("booting %s - starting in ",
    357 		       sprint_bootsel(names[currname][0]));
    358 
    359 #ifdef SMALL
    360 		c = awaitkey(boot_params.bp_timeout, 1);
    361 #else
    362 		c = awaitkey((bootcfg_info.timeout < 0) ? 0
    363 		    : bootcfg_info.timeout, 1);
    364 #endif
    365 		if ((c != '\r') && (c != '\n') && (c != '\0')) {
    366 		    if ((boot_params.bp_flags & X86_BP_FLAGS_PASSWORD) == 0) {
    367 			/* do NOT ask for password */
    368 			bootmenu(); /* does not return */
    369 		    } else {
    370 			/* DO ask for password */
    371 			if (check_password((char *)boot_params.bp_password)) {
    372 			    /* password ok */
    373 			    printf("type \"?\" or \"help\" for help.\n");
    374 			    bootmenu(); /* does not return */
    375 			} else {
    376 			    /* bad password */
    377 			    printf("Wrong password.\n");
    378 			    currname = 0;
    379 			    continue;
    380 			}
    381 		    }
    382 		}
    383 
    384 		/*
    385 		 * try pairs of names[] entries, foo and foo.gz
    386 		 */
    387 		/* don't print "booting..." again */
    388 		bootit(names[currname][0], 0);
    389 		/* since it failed, try compressed bootfile. */
    390 		bootit(names[currname][1], AB_VERBOSE);
    391 	}
    392 
    393 	bootmenu();	/* does not return */
    394 }
    395 
    396 /* ARGSUSED */
    397 void
    398 command_help(char *arg)
    399 {
    400 
    401 	printf("commands are:\n"
    402 	       "boot [xdNx:][filename] [-12acdqsvxz]\n"
    403 	       "     (ex. \"hd0a:netbsd.old -s\"\n"
    404 #if LIBSA_ENABLE_LS_OP
    405 	       "ls [path]\n"
    406 #endif
    407 	       "dev xd[N[x]]:\n"
    408 	       "consdev {pc|com[0123]|com[0123]kbd|auto}\n"
    409 	       "vesa {modenum|on|off|enabled|disabled|list}\n"
    410 #ifndef SMALL
    411 	       "menu (reenters boot menu, if defined in boot.cfg)\n"
    412 #endif
    413 	       "modules {on|off|enabled|disabled}\n"
    414 	       "load {path_to_module}\n"
    415 	       "multiboot [xdNx:][filename] [<args>]\n"
    416 	       "splash {path_to_image_file}\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;
    452 
    453 	if (!parseboot(arg, &filename, &howto))
    454 		return;
    455 
    456 	if (filename != NULL) {
    457 		bootit(filename, howto);
    458 	} else {
    459 		int i;
    460 
    461 #ifndef SMALL
    462 		if (howto == 0)
    463 			bootdefault();
    464 #endif
    465 		for (i = 0; i < NUMNAMES; i++) {
    466 			bootit(names[i][0], howto);
    467 			bootit(names[i][1], howto);
    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 (bootcfg_info.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