1: /* 2: * Copyright (c) 1986 Regents of the University of California. 3: * All rights reserved. The Berkeley software License Agreement 4: * specifies the terms and conditions for redistribution. 5: * 6: * @(#)boot.c 3.0 (2.11BSD) 1996/5/9 7: */ 8: #include "../h/param.h" 9: #include "../machine/seg.h" 10: #include "../machine/koverlay.h" 11: #include "../h/reboot.h" 12: #include "saio.h" 13: #include <a.out.h> 14: 15: #undef btoc /* to save space */ 16: #define KB * 1024L 17: 18: #define KISD0 ((u_short *) 0172300) 19: #define KISD3 ((u_short *) 0172306) 20: #define KDSD0 ((u_short *) 0172320) 21: #undef KISA0 22: #define KISA0 ((u_short *) 0172340) 23: #define KISA3 ((u_short *) 0172346) 24: #define KDSA0 ((u_short *) 0172360) 25: 26: #define SEG_DATA 01 27: #define SEG_TEXT 02 28: #define SEG_OVLY 04 29: 30: extern caddr_t *bootcsr; /* csr of boot controller */ 31: extern int bootctlr; /* boot controller number */ 32: extern int bootopts; /* boot options from previous incarnation */ 33: extern int bootdev; /* makedev(major,unit) booted from */ 34: extern int checkword; /* one's complements of bootopts */ 35: extern int cputype; /* 24, 40, 44, 45, 70, or 73 */ 36: extern bool_t ksep; /* is kernel mode currently separated */ 37: extern bool_t sep_id; /* does the cpu support separate I/D? */ 38: extern int ndevsw; /* number of devices in devsw[] */ 39: extern char ADJcsr[]; /* adjustments for ROM csr addresses */ 40: extern char *itoa(); 41: extern char *index(); 42: extern struct devsw devsw[]; /* device table */ 43: extern struct iob iob[]; /* I/O descriptor table */ 44: 45: char module[] = "Boot"; /* this program's name (used by trap) */ 46: bool_t overlaid = 0; 47: u_short pdrproto[16 + NOVL] = {0}; 48: struct exec exec; 49: struct ovlhdr ovlhdr; 50: int bootdebug; 51: unsigned btoc(); 52: 53: struct loadmap { 54: int seg_type; 55: long seg_len; 56: }; 57: struct loadtable { 58: short lt_magic; 59: struct loadmap *lt_map; 60: }; 61: 62: struct loadmap load407[] = { 63: SEG_DATA, 56 KB, 64: 0, 0 KB 65: }; 66: struct loadmap load410[] = { 67: SEG_TEXT, 48 KB, 68: SEG_DATA, 56 KB, 69: 0, 0 KB 70: }; 71: struct loadmap load411[] = { 72: SEG_DATA, 56 KB, 73: SEG_TEXT, 64 KB, 74: 0, 0 KB 75: }; 76: struct loadmap load430[] = { 77: SEG_TEXT, 16 KB, /* minumum, 8 KB + 1 */ 78: SEG_OVLY, 8 KB, /* 1 */ 79: SEG_DATA, 24 KB, 80: SEG_OVLY, 8 KB, /* 2 */ 81: SEG_OVLY, 8 KB, /* 3 */ 82: SEG_OVLY, 8 KB, /* 4 */ 83: SEG_OVLY, 8 KB, /* 5 */ 84: SEG_OVLY, 8 KB, /* 6 */ 85: SEG_OVLY, 8 KB, /* 7 */ 86: SEG_OVLY, 8 KB, /* 8 */ 87: SEG_OVLY, 8 KB, /* 9 */ 88: SEG_OVLY, 8 KB, /* 10 */ 89: SEG_OVLY, 8 KB, /* 11 */ 90: SEG_OVLY, 8 KB, /* 12 */ 91: SEG_OVLY, 8 KB, /* 13 */ 92: SEG_OVLY, 8 KB, /* 14 */ 93: SEG_OVLY, 8 KB, /* 15 */ 94: 0, 0 KB 95: }; 96: struct loadmap load431[] = { 97: SEG_DATA, 56 KB, /* minumum, 48 KB + 1 */ 98: SEG_TEXT, 56 KB, 99: SEG_OVLY, 8 KB, /* 1 */ 100: SEG_OVLY, 8 KB, /* 2 */ 101: SEG_OVLY, 8 KB, /* 3 */ 102: SEG_OVLY, 8 KB, /* 4 */ 103: SEG_OVLY, 8 KB, /* 5 */ 104: SEG_OVLY, 8 KB, /* 6 */ 105: SEG_OVLY, 8 KB, /* 7 */ 106: SEG_OVLY, 8 KB, /* 8 */ 107: SEG_OVLY, 8 KB, /* 9 */ 108: SEG_OVLY, 8 KB, /* 10 */ 109: SEG_OVLY, 8 KB, /* 11 */ 110: SEG_OVLY, 8 KB, /* 12 */ 111: SEG_OVLY, 8 KB, /* 13 */ 112: SEG_OVLY, 8 KB, /* 14 */ 113: SEG_OVLY, 8 KB, /* 15 */ 114: 0, 0 KB 115: }; 116: 117: struct loadtable loadtable[] = { 118: A_MAGIC1, load407, 119: A_MAGIC2, load410, 120: A_MAGIC3, load411, 121: A_MAGIC5, load430, 122: A_MAGIC6, load431 123: }; 124: 125: main() 126: { 127: register int i, j, maj; 128: int retry = 0, unit, part; 129: caddr_t *adjcsr; 130: struct loadtable *setup(); 131: struct iob *file; 132: char *cp, *defname = "unix", line[64], defdev[64]; 133: 134: maj = major(bootdev); 135: if (maj >= ndevsw) 136: _stop("bad major"); /* can't happen */ 137: adjcsr = (caddr_t *)((short)bootcsr - ADJcsr[maj]); 138: 139: for (i = 0; devsw[maj].dv_csr != (caddr_t) -1; i++) { 140: if (adjcsr == devsw[maj].dv_csr[i]) 141: break; 142: if (devsw[maj].dv_csr[i] == 0) { 143: devsw[maj].dv_csr[i] = adjcsr; 144: break; 145: } 146: } 147: 148: if (devsw[maj].dv_csr[i] == (caddr_t *) -1) 149: _stop("no free csr slots"); 150: bootdev &= ~(3 << 6); 151: bootdev |= (i << 6); /* controller # to bits 6&7 */ 152: bootctlr = i; 153: unit = (minor(bootdev) >> 3) & 7; 154: part = minor(bootdev) & 7; 155: 156: printf("\n%d%s from %s(%d,%d,%d) at 0%o\n", cputype, module, 157: devsw[major(bootdev)].dv_name, bootctlr, unit, part, bootcsr); 158: 159: strcpy(defdev, devsw[major(bootdev)].dv_name); 160: strcat(defdev, "("); 161: strcat(defdev, itoa(bootctlr)); 162: strcat(defdev, ","); 163: strcat(defdev, itoa(unit)); 164: strcat(defdev, ","); 165: strcat(defdev, itoa(part)); 166: strcat(defdev, ")"); 167: 168: /* 169: * The machine language will have gotten the bootopts 170: * if we're an autoboot and will pass them along. 171: * If r2 (checkword) was the complement of bootopts, 172: * this is an automatic reboot, otherwise do it the hard way. 173: */ 174: if (checkword != ~bootopts) 175: bootopts = RB_SINGLE | RB_ASKNAME; 176: j = -1; 177: do { 178: if (bootopts & RB_ASKNAME) { 179: another: 180: printf(": "); 181: gets(line); 182: cp = line; 183: if (*cp == '-') 184: { 185: dobootopts(cp, &bootopts); 186: goto another; 187: } 188: } else { 189: strcpy(line, defdev); 190: strcat(line, defname); 191: printf(": %s\n", line); 192: } 193: if (line[0] == '\0') { 194: strcpy(line, defdev); 195: strcat(line, defname); 196: printf(": %s\n", line); 197: } 198: /* 199: * If a plain filename (/unix) is entered then prepend the default 200: * device, e.g. ra(0,1,0) to the filename. 201: */ 202: cp = index(line, ')'); 203: if (!cp) 204: { 205: bcopy(line, line + strlen(defdev), strlen(line) + 1); 206: bcopy(defdev, line, strlen(defdev)); 207: } 208: j = -1; 209: if (cp = index(line, ' ')) 210: { 211: if ((bootflags(cp, &bootopts, "bootfile")) == -1) 212: { 213: bootopts |= RB_ASKNAME; 214: continue; 215: } 216: *cp = '\0'; 217: } 218: i = open(line, 0); 219: if (i >= 0) { 220: file = &iob[i - 3]; /* -3 for pseudo stdin/o/e */ 221: j = checkunix(i, setup(i)); 222: (void) close(i); 223: } 224: if (++retry > 2) 225: bootopts = RB_SINGLE | RB_ASKNAME; 226: } while (j < 0); 227: i = file->i_ino.i_dev; 228: bootdev = makedev(i, 229: ((file->i_ctlr << 6) | (file->i_unit << 3) | file->i_part)); 230: bootcsr = devsw[i].dv_csr[file->i_ctlr]; 231: bootcsr = (caddr_t *)((short)bootcsr + ADJcsr[i]); 232: printf("%s: bootdev=0%o bootcsr=0%o\n", module, bootdev, bootcsr); 233: } 234: 235: struct loadtable * 236: setup(io) 237: register io; 238: { 239: register i; 240: 241: exec.a_magic = getw(io); 242: exec.a_text = (unsigned) getw(io); 243: exec.a_data = (unsigned) getw(io); 244: exec.a_bss = (unsigned) getw(io); 245: 246: /* 247: * Space over the remainder of the exec header. We do this 248: * instead of seeking because the input might be a tape which 249: * doesn't know how to seek. 250: */ 251: getw(io); getw(io); getw(io); getw(io); 252: 253: /* 254: * If overlaid, get overlay header. 255: */ 256: if (exec.a_magic == A_MAGIC5 || exec.a_magic == A_MAGIC6) { 257: overlaid++; 258: ovlhdr.max_ovl = getw(io); 259: for (i = 0; i < NOVL; i++) 260: ovlhdr.ov_siz[i] = (unsigned) getw(io); 261: } 262: for (i = 0; i < sizeof(loadtable) / sizeof(struct loadtable); i++) 263: if (loadtable[i].lt_magic == exec.a_magic) 264: return(&loadtable[i]); 265: printf("Bad magic # 0%o\n", exec.a_magic); 266: return((struct loadtable *) NULL); 267: } 268: 269: checkunix(io, lt) 270: struct loadtable *lt; 271: { 272: char *segname, *toosmall = "Base too small, %dK min\n"; 273: register int ovseg, segtype; 274: register unsigned seglen; 275: struct loadmap *lm = lt->lt_map; 276: 277: if (lt == (struct loadtable *) NULL) 278: return(-1); 279: 280: /* 281: * Check and set I & D space requirements. 282: */ 283: if (exec.a_magic == A_MAGIC3 || exec.a_magic == A_MAGIC6) 284: if (!sep_id) { 285: printf("Can't load split I&D files\n"); 286: return(-1); 287: } else 288: setsep(); 289: else 290: if (sep_id) 291: setnosep(); 292: 293: /* 294: * Check the sizes of each segment. 295: */ 296: ovseg = 0; 297: while (segtype = lm->seg_type) { 298: switch (segtype) { 299: case SEG_TEXT: 300: /* 301: * Round text size to nearest page. 302: */ 303: if (exec.a_magic == A_MAGIC2) 304: seglen = ctob(stoc(ctos(btoc(exec.a_text)))); 305: else 306: seglen = exec.a_text; 307: segname = "Text"; 308: break; 309: 310: case SEG_DATA: 311: seglen = exec.a_data + exec.a_bss; 312: segname = "Data"; 313: if (exec.a_magic == A_MAGIC1) 314: seglen += exec.a_text; 315: else 316: /* 317: * Force a complaint if the file 318: * won't fit. It's here instead 319: * of in the SEG_TEXT case above 320: * because it's more likely to be 321: * a data overflow problem. 322: */ 323: if (exec.a_magic == A_MAGIC2) 324: seglen += ctob(stoc(ctos(btoc(exec.a_text)))); 325: break; 326: 327: case SEG_OVLY: 328: seglen = ovlhdr.ov_siz[ovseg]; 329: segname = "Overlay"; 330: ovseg++; 331: break; 332: 333: default: 334: /* 335: * This ``cannot happen.'' 336: */ 337: printf("seg type botch: %d\n", segtype); 338: return(-1); 339: /*NOTREACHED*/ 340: } 341: 342: seglen = ctob(btoc(seglen)); 343: if (((long) seglen) > lm->seg_len) { 344: if (segtype == SEG_OVLY) 345: printf("%s %d over by %D bytes", segname, ovseg, lm->seg_len -((long) seglen)); 346: else 347: printf("%s over by %D bytes", segname, lm->seg_len -((long) seglen)); 348: return(-1); 349: } 350: if (segtype == SEG_TEXT) 351: switch (exec.a_magic) { 352: case A_MAGIC5: 353: if (seglen <= 8 KB) { 354: printf(toosmall, 8); 355: return(-1); 356: } 357: break; 358: case A_MAGIC6: 359: if (seglen <= 48 KB) { 360: printf(toosmall, 48); 361: return(-1); 362: } 363: break; 364: default: 365: break; 366: } 367: lm++; 368: } 369: copyunix(io, lt); 370: setregs(lt); 371: return(0); 372: } 373: 374: copyunix(io, lt) 375: register io; 376: struct loadtable *lt; 377: { 378: int i; 379: bool_t donedata = 0; 380: register int addr; 381: register unsigned seglen; 382: off_t segoff; 383: int segtype; 384: int nseg, phys, ovseg; 385: struct loadmap *lm = lt->lt_map; 386: 387: /* 388: * Load the segments and set up prototype PDRs. 389: */ 390: nseg = 0; 391: phys = 0; 392: ovseg = 0; 393: lm = lt->lt_map; 394: while (segtype = lm++->seg_type) { 395: segoff = (off_t) N_TXTOFF(exec); 396: switch (segtype) { 397: case SEG_TEXT: 398: seglen = exec.a_text; 399: break; 400: 401: case SEG_DATA: 402: seglen = exec.a_data; 403: /* 404: * If this is a 0407 style object, the text 405: * and data are loaded together. 406: */ 407: if (exec.a_magic != A_MAGIC1) { 408: segoff += (off_t) exec.a_text; 409: if (overlaid) 410: for (i = 0; i < NOVL; i++) 411: segoff += (off_t) ovlhdr.ov_siz[i]; 412: } else 413: seglen += exec.a_text; 414: donedata++; 415: break; 416: 417: case SEG_OVLY: 418: seglen = ovlhdr.ov_siz[ovseg]; 419: segoff += (off_t) exec.a_text; 420: for (i = 0; i < ovseg; i++) 421: segoff += (off_t) ovlhdr.ov_siz[i]; 422: ovseg++; 423: break; 424: default: 425: printf("copyunix: bad seg type %d\n", segtype); 426: seglen=0; 427: break; 428: } 429: 430: if (!seglen) 431: continue; 432: setseg(phys); 433: /* 434: * ARGH! Despite (or in spite of) the earlier cautions against seeking and 435: * tape devices here is an 'lseek' that caused problems loading split I/D 436: * images from tape! 437: */ 438: if (exec.a_magic != A_MAGIC1) 439: (void) lseek(io, segoff, 0); 440: for (addr = 0; addr < seglen; addr += 2) 441: mtpi(getw(io), addr); 442: 443: if (segtype == SEG_DATA) { 444: clrseg(addr, exec.a_bss); 445: seglen += exec.a_bss; 446: } 447: 448: pdrproto[nseg++] = btoc(seglen); 449: if (!donedata) 450: seglen = ctob(stoc(ctos(btoc(seglen)))); 451: phys += btoc(seglen); 452: } 453: } 454: 455: /* 456: * Set the real segmentation registers. 457: */ 458: setregs(lt) 459: struct loadtable *lt; 460: { 461: register i; 462: register u_short *par_base, *pdr_base; 463: bool_t donedata = 0; 464: int phys, segtype; 465: int nseg, ntextpgs, novlypgs, npages, pagelen; 466: struct loadmap *lm = lt->lt_map; 467: 468: nseg = 0; 469: phys = 0; 470: ntextpgs = 0; 471: novlypgs = 0; 472: 473: setseg(0); 474: if (exec.a_magic == A_MAGIC1) 475: return; 476: 477: /* 478: * First deny access to all except I/O page. 479: */ 480: par_base = KISA0; 481: pdr_base = KISD0; 482: for (i = 0; i <(ksep ? 8 : 7); i++) { 483: *par_base++ = 0; 484: *pdr_base++ = NOACC; 485: } 486: if (ksep) { 487: par_base = KDSA0; 488: pdr_base = KDSD0; 489: for (i = 0; i < 7; i++) { 490: *par_base++ = 0; 491: *pdr_base++ = NOACC; 492: } 493: } 494: if (overlaid) { 495: /* 496: * We must write the prototype overlay register table. 497: * N.B.: we assume that the table lies in the first 8k 498: * of kernel virtual space, and the appropriate page lies 499: * at physical 0. 500: */ 501: if (ksep) 502: *KDSD0 = ((128 -1) << 8) | RW; 503: else 504: *KISD0 = ((128 -1) << 8) | RW; 505: par_base = &(((u_short *) OVLY_TABLE_BASE)[0]); 506: pdr_base = &(((u_short *) OVLY_TABLE_BASE)[1 + NOVL]); 507: for (i = 0; i < NOVL; i++) { 508: mtpd(0, par_base++); 509: mtpd(NOACC, pdr_base++); 510: } 511: } 512: 513: /* 514: * Now set all registers which should be nonzero. 515: */ 516: lm = lt->lt_map; 517: while (segtype = lm++->seg_type) { 518: if (!(npages = ctos(pdrproto[nseg]))) 519: continue; 520: 521: switch (segtype) { 522: case SEG_TEXT: 523: /* 524: * Text always starts at KI0; 525: */ 526: par_base = KISA0; 527: pdr_base = KISD0; 528: ntextpgs += npages; 529: break; 530: 531: case SEG_DATA: 532: if (overlaid) 533: if (ksep) { 534: par_base = I_DATA_PAR_BASE; 535: pdr_base = I_DATA_PDR_BASE; 536: } else { 537: par_base = N_DATA_PAR_BASE; 538: pdr_base = N_DATA_PDR_BASE; 539: } 540: else 541: if (ksep) { 542: par_base = KDSA0; 543: pdr_base = KDSD0; 544: } else { 545: par_base = &KISA0[ntextpgs + novlypgs]; 546: pdr_base = &KISD0[ntextpgs + novlypgs]; 547: } 548: donedata++; 549: break; 550: 551: case SEG_OVLY: 552: par_base = &(((u_short *) OVLY_TABLE_BASE)[1 + novlypgs]); 553: pdr_base = &(((u_short *) OVLY_TABLE_BASE)[1 + NOVL + 1 + novlypgs]); 554: novlypgs += npages; 555: break; 556: } 557: 558: for (i = 0; i < npages; i++) { 559: pagelen = MIN(btoc((int)(8 KB)), pdrproto[nseg]); 560: if (segtype == SEG_OVLY) { 561: mtpd(phys, par_base); 562: mtpd(((pagelen - 1) << 8) | RO, pdr_base); 563: } else { 564: *par_base = phys; 565: if (segtype == SEG_TEXT) 566: if (ksep) 567: *pdr_base = ((pagelen - 1) << 8) | RO; 568: else 569: /* 570: * Nonseparate kernels will 571: * write into text page 0 572: * when first booted. 573: */ 574: if (i == 0) 575: *pdr_base = ((pagelen - 1) << 8) | RW; 576: else 577: *pdr_base = ((pagelen - 1) << 8) | RO; 578: else 579: *pdr_base = ((pagelen - 1) << 8) | RW; 580: } 581: par_base++, pdr_base++; 582: if (donedata) 583: phys += pagelen; 584: else 585: phys += stoc(ctos(pagelen)); 586: pdrproto[nseg] -= pagelen; 587: } 588: nseg++; 589: } 590: 591: /* 592: * Phys now contains the address of the start of 593: * free memory. We set K[ID]6 now or systrap to 594: * kernel mode will clobber text at 0140000. 595: */ 596: if (ksep) { 597: KDSA0[6] = phys; 598: KDSD0[6] = (stoc(1) - 1) << 8 | RW; 599: } else { 600: KISA0[6] = phys; 601: KISD0[6] = (stoc(1) - 1) << 8 | RW; 602: } 603: if (overlaid) 604: mtpd(phys, &(((u_short *) OVLY_TABLE_BASE)[1 + NOVL + 1 + NOVL])); 605: } 606: 607: unsigned 608: btoc(nclicks) 609: register unsigned nclicks; 610: { 611: return((unsigned)(((((long) nclicks) + ((long) 63)) >> 6))); 612: } 613: 614: /* 615: * Couldn't use getopt(3) for a couple reasons: 1) because that would end up 616: * dragging in way too much of libc.a, and 2) the code to build argc 617: * and argv would be almost as large as the parsing routines themselves. 618: */ 619: 620: char * 621: arg(cp) 622: register char *cp; 623: { 624: 625: if ((cp = index(cp, ' ')) == NULL) 626: return(NULL); 627: while (*cp == ' ' || *cp == '\t') 628: cp++; 629: if (*cp == '\0') 630: return(NULL); 631: return(cp); 632: } 633: 634: /* 635: * Flags to boot may be present in two places. 1) At the ': ' prompt enter 636: * a line starting with "-bootflags". 2) After the filename. For example, 637: * to turn on the autoconfig debug flag: 638: * 639: * : -bootflags -D 640: * 641: * To force the kernel to use the compiled in root device (which also affects 642: * swapdev, pipedev and possibly dumpdev): 643: * 644: * : -bootflags -R 645: * 646: * To specify flags on the filename line place the options after the filename: 647: * 648: * : ra(0,0)unix -D -s 649: * 650: * will cause the kernel to use the compiled in root device (rather than auto 651: * matically switching to the load device) and enter single user mode. 652: * 653: * Bootflags may also be specified as a decimal number (you will need the 654: * sys/reboot.h file to look up the RB_* flags in). Turning all bootflags off 655: * is the special case: 656: * 657: * : -bootflags 0 658: * 659: * There is a general purpose 'debug' flag word ("bootdebug") which can be 660: * set to any arbitrary 16 bit value. This can be used when debugging a 661: * driver for example. 662: * 663: * : -bootdebug 16 664: */ 665: 666: #define BOOTFLAGS "-bootflags" 667: #define BOOTDEBUG "-bootdebug" 668: 669: dobootopts(cp, opt) 670: register char *cp; 671: int *opt; 672: { 673: char *bflags = BOOTFLAGS; 674: char *bdebug = BOOTDEBUG; 675: 676: if (strncmp(cp, bdebug, sizeof (BOOTDEBUG) - 1) == 0) 677: { 678: if (cp = arg(cp)) 679: bootdebug = atoi(cp); 680: else 681: printf("%s = %u\n", bdebug, bootdebug); 682: return(0); 683: } 684: if (strncmp(cp, bflags, sizeof (BOOTFLAGS) - 1) == 0) 685: { 686: if (cp = arg(cp)) 687: (void) bootflags(cp, &bootopts, bflags); 688: else 689: printf("%s = %u\n", bflags, bootopts); 690: return(0); 691: } 692: printf("bad cmd: %s\n", cp); 693: return(0); 694: } 695: 696: bootflags(cp, pflags, tag) 697: register char *cp; 698: int *pflags; 699: char *tag; 700: { 701: int first = 1; 702: int flags = 0; 703: 704: while (*cp) 705: { 706: while (*cp == ' ') 707: cp++; 708: if (*cp == '\0') 709: break; 710: if (*cp == '-') 711: { 712: first = 0; 713: while (*++cp) 714: switch (*cp) 715: { 716: case ' ': 717: goto nextarg; 718: case 'a': 719: flags |= RB_ASKNAME; 720: break; 721: case 'D': 722: flags |= RB_AUTODEBUG; 723: break; 724: case 'r': 725: flags |= RB_RDONLY; 726: break; 727: case 'R': 728: flags |= RB_DFLTROOT; 729: break; 730: case 's': 731: flags |= RB_SINGLE; 732: break; 733: default: 734: goto usage; 735: } 736: continue; 737: } 738: if (first && *cp >= '0' && *cp <= '9') 739: { 740: *pflags = atoi(cp); 741: return(0); 742: } 743: goto usage; 744: 745: nextarg: ; 746: } 747: if (first == 0) 748: *pflags = flags; 749: return(0); 750: usage: 751: printf("usage: %s [ -aDrRs ]\n", tag); 752: return(-1); 753: }