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