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