1 /* $NetBSD: boot2.c,v 1.2 2011/01/22 19:19:19 joerg 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 sprintf(buf, "%s%d%c:%s", devname, unit, 'a' + partition, file); 187 return (buf); 188 } 189 return ("(invalid)"); 190 } 191 192 void 193 bootit(const char *filename, int howto, int tell) 194 { 195 196 if (tell) { 197 printf("booting %s", sprint_bootsel(filename)); 198 if (howto) 199 printf(" (howto 0x%x)", howto); 200 printf("\n"); 201 } 202 203 if (exec_netbsd(filename, howto) < 0) { 204 printf("boot: %s: %s\n", sprint_bootsel(filename), 205 strerror(errno)); 206 } else { 207 printf("boot returned\n"); 208 } 209 } 210 211 void 212 print_banner(void) 213 { 214 extern const char bootprog_name[]; 215 extern const char bootprog_rev[]; 216 217 printf("\n"); 218 printf(">> %s, Revision %s\n", bootprog_name, bootprog_rev); 219 } 220 221 void 222 boot2(uint32_t boot_biossector) 223 { 224 int currname; 225 int c; 226 227 /* Initialize hardware */ 228 tick_init(); 229 230 /* Initialize console */ 231 cninit(boot_params.bp_consdev); 232 233 print_banner(); 234 235 /* try to set default device to what BIOS tells us */ 236 bios2dev(0x40, &default_devname, &default_unit, 237 boot_biossector, &default_partition); 238 239 /* if the user types "boot" without filename */ 240 default_filename = DEFFILENAME; 241 242 printf("Press return to boot now, any other key for boot menu\n"); 243 currname = 0; 244 for (;;) { 245 printf("booting %s - starting in ", 246 sprint_bootsel(names[currname][0])); 247 248 c = awaitkey(boot_params.bp_timeout, 1); 249 if ((c != '\r') && (c != '\n') && (c != '\0')) { 250 printf("type \"?\" or \"help\" for help.\n"); 251 bootmenu(); /* does not return */ 252 } 253 254 /* 255 * try pairs of names[] entries, foo and foo.gz 256 */ 257 /* don't print "booting..." again */ 258 bootit(names[currname][0], 0, 0); 259 /* since it failed, try compressed bootfile. */ 260 bootit(names[currname][1], 0, 1); 261 /* since it failed, try switching bootfile. */ 262 currname = (currname + 1) % NUMNAMES; 263 } 264 } 265 266 int 267 exec_netbsd(const char *file, int howto) 268 { 269 static char bibuf[BOOTINFO_MAXSIZE]; 270 u_long marks[MARK_MAX]; 271 int fd; 272 273 BI_ALLOC(6); /* XXX */ 274 275 marks[MARK_START] = 0; /* loadaddr */ 276 if ((fd = loadfile(file, marks, LOAD_KERNEL)) == -1) 277 goto out; 278 279 printf("Start @ 0x%lx [%ld=0x%lx-0x%lx]...\n", marks[MARK_ENTRY], 280 marks[MARK_NSYM], marks[MARK_SYM], marks[MARK_END]); 281 282 { 283 struct btinfo_common *help; 284 char *p; 285 int i; 286 287 p = bibuf; 288 memcpy(p, &bootinfo->nentries, sizeof(bootinfo->nentries)); 289 p += sizeof(bootinfo->nentries); 290 for (i = 0; i < bootinfo->nentries; i++) { 291 help = (struct btinfo_common *)(bootinfo->entry[i]); 292 memcpy(p, help, help->len); 293 p += help->len; 294 } 295 } 296 297 cache_flush(); 298 cache_disable(); 299 300 (*(void (*)(int, void *))marks[MARK_ENTRY])(howto, bibuf); 301 panic("exec returned"); 302 303 out: 304 BI_FREE(); 305 bootinfo = 0; 306 return (-1); 307 } 308 309 /* 310 * boot menu 311 */ 312 /* ARGSUSED */ 313 static void 314 bootcmd_help(char *arg) 315 { 316 317 printf("commands are:\n" 318 "boot [xdNx:][filename] [-acdqsv]\n" 319 " (ex. \"hd0a:netbsd.old -s\"\n" 320 "ls [path]\n" 321 "help|?\n" 322 "halt\n" 323 "quit\n"); 324 } 325 326 static void 327 bootcmd_ls(char *arg) 328 { 329 const char *save = default_filename; 330 331 default_filename = "/"; 332 ufs_ls(arg); 333 default_filename = save; 334 } 335 336 /* ARGSUSED */ 337 static void 338 bootcmd_quit(char *arg) 339 { 340 341 printf("Exiting...\n"); 342 delay(1000); 343 reboot(); 344 /* Note: we shouldn't get to this point! */ 345 panic("Could not reboot!"); 346 exit(0); 347 } 348 349 /* ARGSUSED */ 350 static void 351 bootcmd_halt(char *arg) 352 { 353 354 printf("Exiting...\n"); 355 delay(1000); 356 halt(); 357 /* Note: we shouldn't get to this point! */ 358 panic("Could not halt!"); 359 exit(0); 360 } 361 362 static void 363 bootcmd_boot(char *arg) 364 { 365 char *filename; 366 int howto; 367 368 if (parseboot(arg, &filename, &howto)) { 369 bootit(filename, howto, 1); 370 } 371 } 372 373 /* ARGSUSED */ 374 static void 375 bootcmd_monitor(char *arg) 376 { 377 378 db_monitor(); 379 printf("\n"); 380 } 381 382 static void 383 docommand(const struct bootblk_command * const cmds, char *arg) 384 { 385 char *options; 386 int i; 387 388 options = gettrailer(arg); 389 390 for (i = 0; cmds[i].c_name != NULL; i++) { 391 if (strcmp(arg, cmds[i].c_name) == 0) { 392 (*cmds[i].c_fn)(options); 393 return; 394 } 395 } 396 397 printf("unknown command\n"); 398 bootcmd_help(NULL); 399 } 400 401 void 402 bootmenu(void) 403 { 404 char input[256]; 405 char *c; 406 407 for (;;) { 408 c = input; 409 410 input[0] = '\0'; 411 printf("> "); 412 gets(input); 413 414 /* 415 * Skip leading whitespace. 416 */ 417 while (*c == ' ') { 418 c++; 419 } 420 if (*c != '\0') { 421 docommand(bootcmds, c); 422 } 423 } 424 } 425 426 /* 427 * from arch/i386/stand/lib/parseutil.c 428 */ 429 /* 430 * chops the head from the arguments and returns the arguments if any, 431 * or possibly an empty string. 432 */ 433 static char * 434 gettrailer(char *arg) 435 { 436 char *options; 437 438 if ((options = strchr(arg, ' ')) == NULL) 439 return (""); 440 else 441 *options++ = '\0'; 442 443 /* trim leading blanks */ 444 while (*options && *options == ' ') 445 options++; 446 447 return (options); 448 } 449 450 static int 451 parseopts(const char *opts, int *howto) 452 { 453 int r, tmpopt = 0; 454 455 opts++; /* skip - */ 456 while (*opts && *opts != ' ') { 457 r = 0; 458 BOOT_FLAG(*opts, r); 459 if (r == 0) { 460 printf("-%c: unknown flag\n", *opts); 461 bootcmd_help(NULL); 462 return (0); 463 } 464 tmpopt |= r; 465 opts++; 466 } 467 468 *howto = tmpopt; 469 return (1); 470 } 471 472 static int 473 parseboot(char *arg, char **filename, int *howto) 474 { 475 char *opts = NULL; 476 477 *filename = 0; 478 *howto = 0; 479 480 /* if there were no arguments */ 481 if (*arg == NULL) 482 return (1); 483 484 /* format is... */ 485 /* [[xxNx:]filename] [-adqsv] */ 486 487 /* check for just args */ 488 if (arg[0] == '-') { 489 opts = arg; 490 } else { 491 /* there's a file name */ 492 *filename = arg; 493 494 opts = gettrailer(arg); 495 if (*opts == NULL) { 496 opts = NULL; 497 } else if (*opts != '-') { 498 printf("invalid arguments\n"); 499 bootcmd_help(NULL); 500 return (0); 501 } 502 } 503 504 /* at this point, we have dealt with filenames. */ 505 506 /* now, deal with options */ 507 if (opts) { 508 if (parseopts(opts, howto) == 0) { 509 return (0); 510 } 511 } 512 return (1); 513 } 514 515 /* 516 * for common/lib/libc/arch/sh3/gen/udivsi3.S 517 */ 518 int raise(int sig); 519 520 /*ARGSUSED*/ 521 int 522 raise(int sig) 523 { 524 525 return 0; 526 } 527