1 /* $NetBSD: boot2.c,v 1.6 2016/06/11 06:31:49 dholland Exp $ */ 2 3 /* 4 * Copyright (c) 2003 5 * David Laight. All rights reserved 6 * Copyright (c) 1996, 1997, 1999 7 * Matthias Drochner. All rights reserved. 8 * Copyright (c) 1996, 1997 9 * Perry E. Metzger. All rights reserved. 10 * Copyright (c) 1997 11 * Jason R. Thorpe. All rights reserved 12 * 13 * Redistribution and use in source and binary forms, with or without 14 * modification, are permitted provided that the following conditions 15 * are met: 16 * 1. Redistributions of source code must retain the above copyright 17 * notice, this list of conditions and the following disclaimer. 18 * 2. Redistributions in binary form must reproduce the above copyright 19 * notice, this list of conditions and the following disclaimer in the 20 * documentation and/or other materials provided with the distribution. 21 * 3. All advertising materials mentioning features or use of this software 22 * must display the following acknowledgements: 23 * This product includes software developed for the NetBSD Project 24 * by Matthias Drochner. 25 * This product includes software developed for the NetBSD Project 26 * by Perry E. Metzger. 27 * 4. The names of the authors may not be used to endorse or promote products 28 * derived from this software without specific prior written permission. 29 * 30 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 31 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 32 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 33 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 34 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 35 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 36 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 37 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 38 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 39 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 40 */ 41 42 /* Based on stand/biosboot/main.c */ 43 44 #include <sys/types.h> 45 #include <sys/reboot.h> 46 #include <sys/bootblock.h> 47 #include <sys/boot_flag.h> 48 49 #include <lib/libsa/stand.h> 50 #include <lib/libsa/loadfile.h> 51 #include <lib/libsa/ufs.h> 52 #include <lib/libkern/libkern.h> 53 54 #include "biosdisk.h" 55 56 #include "boot.h" 57 #include "bootinfo.h" 58 #include "cons.h" 59 60 int errno; 61 62 extern struct landisk_boot_params boot_params; 63 64 static const char * const names[][2] = { 65 { "netbsd", "netbsd.gz" }, 66 { "netbsd.old", "netbsd.old.gz", }, 67 { "onetbsd", "onetbsd.gz" }, 68 }; 69 70 #define NUMNAMES (sizeof(names) / sizeof(names[0])) 71 #define DEFFILENAME names[0][0] 72 73 #define MAXDEVNAME 16 74 75 static char *default_devname; 76 static uint default_unit, default_partition; 77 static const char *default_filename; 78 79 char *sprint_bootsel(const char *filename); 80 void bootit(const char *filename, int howto, int tell); 81 void print_banner(void); 82 void boot2(uint32_t boot_biossector); 83 84 int exec_netbsd(const char *file, int howto); 85 86 static char *gettrailer(char *arg); 87 static int parseopts(const char *opts, int *howto); 88 static int parseboot(char *arg, char **filename, int *howto); 89 90 void bootmenu(void); 91 static void bootcmd_help(char *); 92 static void bootcmd_ls(char *); 93 static void bootcmd_quit(char *); 94 static void bootcmd_halt(char *); 95 static void bootcmd_boot(char *); 96 static void bootcmd_monitor(char *); 97 98 static const struct bootblk_command { 99 const char *c_name; 100 void (*c_fn)(char *arg); 101 } bootcmds[] = { 102 { "help", bootcmd_help }, 103 { "?", bootcmd_help }, 104 { "ls", bootcmd_ls }, 105 { "quit", bootcmd_quit }, 106 { "halt", bootcmd_halt }, 107 { "boot", bootcmd_boot }, 108 { "!", bootcmd_monitor }, 109 { NULL, NULL }, 110 }; 111 112 int 113 parsebootfile(const char *fname, char **devname, 114 uint *unit, uint *partition, const char **file) 115 { 116 const char *col; 117 118 *devname = default_devname; 119 *unit = default_unit; 120 *partition = default_partition; 121 *file = default_filename; 122 123 if (fname == NULL) 124 return (0); 125 126 if((col = strchr(fname, ':'))) { /* device given */ 127 static char savedevname[MAXDEVNAME+1]; 128 int devlen; 129 unsigned int u = 0, p = 0; 130 int i = 0; 131 132 devlen = col - fname; 133 if (devlen > MAXDEVNAME) 134 return (EINVAL); 135 136 #define isvalidname(c) ((c) >= 'a' && (c) <= 'z') 137 if (!isvalidname(fname[i])) 138 return (EINVAL); 139 do { 140 savedevname[i] = fname[i]; 141 i++; 142 } while (isvalidname(fname[i])); 143 savedevname[i] = '\0'; 144 145 #define isnum(c) ((c) >= '0' && (c) <= '9') 146 if (i < devlen) { 147 if (!isnum(fname[i])) 148 return (EUNIT); 149 do { 150 u *= 10; 151 u += fname[i++] - '0'; 152 } while (isnum(fname[i])); 153 } 154 155 #define isvalidpart(c) ((c) >= 'a' && (c) <= 'p') 156 if (i < devlen) { 157 if (!isvalidpart(fname[i])) 158 return (EPART); 159 p = fname[i++] - 'a'; 160 } 161 162 if (i != devlen) 163 return (ENXIO); 164 165 *devname = savedevname; 166 *unit = u; 167 *partition = p; 168 fname = col + 1; 169 } 170 171 if (*fname) 172 *file = fname; 173 174 return (0); 175 } 176 177 char * 178 sprint_bootsel(const char *filename) 179 { 180 static char buf[80]; 181 char *devname; 182 uint unit, partition; 183 const char *file; 184 185 if (parsebootfile(filename, &devname, &unit, &partition, &file) == 0) { 186 snprintf(buf, sizeof(buf), "%s%d%c:%s", devname, unit, 187 'a' + partition, file); 188 return (buf); 189 } 190 return ("(invalid)"); 191 } 192 193 void 194 bootit(const char *filename, int howto, int tell) 195 { 196 197 if (tell) { 198 printf("booting %s", sprint_bootsel(filename)); 199 if (howto) 200 printf(" (howto 0x%x)", howto); 201 printf("\n"); 202 } 203 204 if (exec_netbsd(filename, howto) < 0) { 205 printf("boot: %s: %s\n", sprint_bootsel(filename), 206 strerror(errno)); 207 } else { 208 printf("boot returned\n"); 209 } 210 } 211 212 void 213 print_banner(void) 214 { 215 extern const char bootprog_name[]; 216 extern const char bootprog_rev[]; 217 218 printf("\n"); 219 printf(">> %s, Revision %s\n", bootprog_name, bootprog_rev); 220 } 221 222 void 223 boot2(uint32_t boot_biossector) 224 { 225 int currname; 226 int c; 227 228 /* Initialize hardware */ 229 tick_init(); 230 231 /* Initialize console */ 232 cninit(boot_params.bp_consdev); 233 234 print_banner(); 235 236 /* try to set default device to what BIOS tells us */ 237 bios2dev(0x40, &default_devname, &default_unit, 238 boot_biossector, &default_partition); 239 240 /* if the user types "boot" without filename */ 241 default_filename = DEFFILENAME; 242 243 printf("Press return to boot now, any other key for boot menu\n"); 244 currname = 0; 245 for (;;) { 246 printf("booting %s - starting in ", 247 sprint_bootsel(names[currname][0])); 248 249 c = awaitkey(boot_params.bp_timeout, 1); 250 if ((c != '\r') && (c != '\n') && (c != '\0')) { 251 printf("type \"?\" or \"help\" for help.\n"); 252 bootmenu(); /* does not return */ 253 } 254 255 /* 256 * try pairs of names[] entries, foo and foo.gz 257 */ 258 /* don't print "booting..." again */ 259 bootit(names[currname][0], 0, 0); 260 /* since it failed, try compressed bootfile. */ 261 bootit(names[currname][1], 0, 1); 262 /* since it failed, try switching bootfile. */ 263 currname = (currname + 1) % NUMNAMES; 264 } 265 } 266 267 int 268 exec_netbsd(const char *file, int howto) 269 { 270 static char bibuf[BOOTINFO_MAXSIZE]; 271 u_long marks[MARK_MAX]; 272 int fd; 273 274 BI_ALLOC(6); /* XXX */ 275 276 marks[MARK_START] = 0; /* loadaddr */ 277 if ((fd = loadfile(file, marks, LOAD_KERNEL)) == -1) 278 goto out; 279 280 printf("Start @ 0x%lx [%ld=0x%lx-0x%lx]...\n", marks[MARK_ENTRY], 281 marks[MARK_NSYM], marks[MARK_SYM], marks[MARK_END]); 282 283 { 284 struct btinfo_common *help; 285 char *p; 286 int i; 287 288 p = bibuf; 289 memcpy(p, &bootinfo->nentries, sizeof(bootinfo->nentries)); 290 p += sizeof(bootinfo->nentries); 291 for (i = 0; i < bootinfo->nentries; i++) { 292 help = (struct btinfo_common *)(bootinfo->entry[i]); 293 memcpy(p, help, help->len); 294 p += help->len; 295 } 296 } 297 298 cache_flush(); 299 cache_disable(); 300 301 (*(void (*)(int, void *))marks[MARK_ENTRY])(howto, bibuf); 302 panic("exec returned"); 303 304 out: 305 BI_FREE(); 306 bootinfo = 0; 307 return (-1); 308 } 309 310 /* 311 * boot menu 312 */ 313 /* ARGSUSED */ 314 static void 315 bootcmd_help(char *arg) 316 { 317 318 printf("commands are:\n" 319 "boot [xdNx:][filename] [-acdqsv]\n" 320 " (ex. \"hd0a:netbsd.old -s\"\n" 321 "ls [path]\n" 322 "help|?\n" 323 "halt\n" 324 "quit\n"); 325 } 326 327 static void 328 bootcmd_ls(char *arg) 329 { 330 const char *save = default_filename; 331 332 default_filename = "/"; 333 ls(arg); 334 default_filename = save; 335 } 336 337 /* ARGSUSED */ 338 static void 339 bootcmd_quit(char *arg) 340 { 341 342 printf("Exiting...\n"); 343 delay(1000); 344 reboot(); 345 /* Note: we shouldn't get to this point! */ 346 panic("Could not reboot!"); 347 exit(0); 348 } 349 350 /* ARGSUSED */ 351 static void 352 bootcmd_halt(char *arg) 353 { 354 355 printf("Exiting...\n"); 356 delay(1000); 357 halt(); 358 /* Note: we shouldn't get to this point! */ 359 panic("Could not halt!"); 360 exit(0); 361 } 362 363 static void 364 bootcmd_boot(char *arg) 365 { 366 char *filename; 367 int howto; 368 369 if (parseboot(arg, &filename, &howto)) { 370 bootit(filename, howto, 1); 371 } 372 } 373 374 /* ARGSUSED */ 375 static void 376 bootcmd_monitor(char *arg) 377 { 378 379 db_monitor(); 380 printf("\n"); 381 } 382 383 static void 384 docommand(const struct bootblk_command * const cmds, char *arg) 385 { 386 char *options; 387 int i; 388 389 options = gettrailer(arg); 390 391 for (i = 0; cmds[i].c_name != NULL; i++) { 392 if (strcmp(arg, cmds[i].c_name) == 0) { 393 (*cmds[i].c_fn)(options); 394 return; 395 } 396 } 397 398 printf("unknown command\n"); 399 bootcmd_help(NULL); 400 } 401 402 void 403 bootmenu(void) 404 { 405 char input[256]; 406 char *c; 407 408 for (;;) { 409 c = input; 410 411 input[0] = '\0'; 412 printf("> "); 413 kgets(input, sizeof(input)); 414 415 /* 416 * Skip leading whitespace. 417 */ 418 while (*c == ' ') { 419 c++; 420 } 421 if (*c != '\0') { 422 docommand(bootcmds, c); 423 } 424 } 425 } 426 427 /* 428 * from arch/i386/stand/lib/parseutil.c 429 */ 430 /* 431 * chops the head from the arguments and returns the arguments if any, 432 * or possibly an empty string. 433 */ 434 static char * 435 gettrailer(char *arg) 436 { 437 char *options; 438 439 if ((options = strchr(arg, ' ')) == NULL) 440 return (""); 441 else 442 *options++ = '\0'; 443 444 /* trim leading blanks */ 445 while (*options == ' ') 446 options++; 447 448 return (options); 449 } 450 451 static int 452 parseopts(const char *opts, int *howto) 453 { 454 int r, tmpopt = 0; 455 456 opts++; /* skip - */ 457 while (*opts && *opts != ' ') { 458 r = 0; 459 BOOT_FLAG(*opts, r); 460 if (r == 0) { 461 printf("-%c: unknown flag\n", *opts); 462 bootcmd_help(NULL); 463 return (0); 464 } 465 tmpopt |= r; 466 opts++; 467 } 468 469 *howto = tmpopt; 470 return (1); 471 } 472 473 static int 474 parseboot(char *arg, char **filename, int *howto) 475 { 476 char *opts = NULL; 477 478 *filename = 0; 479 *howto = 0; 480 481 /* if there were no arguments */ 482 if (*arg == NULL) 483 return (1); 484 485 /* format is... */ 486 /* [[xxNx:]filename] [-adqsv] */ 487 488 /* check for just args */ 489 if (arg[0] == '-') { 490 opts = arg; 491 } else { 492 /* there's a file name */ 493 *filename = arg; 494 495 opts = gettrailer(arg); 496 if (*opts == NULL) { 497 opts = NULL; 498 } else if (*opts != '-') { 499 printf("invalid arguments\n"); 500 bootcmd_help(NULL); 501 return (0); 502 } 503 } 504 505 /* at this point, we have dealt with filenames. */ 506 507 /* now, deal with options */ 508 if (opts) { 509 if (parseopts(opts, howto) == 0) { 510 return (0); 511 } 512 } 513 return (1); 514 } 515 516 /* 517 * for common/lib/libc/arch/sh3/gen/udivsi3.S 518 */ 519 int raise(int sig); 520 521 /*ARGSUSED*/ 522 int 523 raise(int sig) 524 { 525 526 return 0; 527 } 528