|
|
1.1 ! root 1: #ifndef lint ! 2: static char sccsid[] = "@(#)machdep.c 1.1 86/02/03 Copyr 1986 Sun Micro"; ! 3: #endif lint ! 4: ! 5: /* ! 6: * Copyright (c) 1986 by Sun Microsystems, Inc. ! 7: */ ! 8: ! 9: #include "../h/param.h" ! 10: #include "../h/systm.h" ! 11: #include "../h/dir.h" ! 12: #include "../h/user.h" ! 13: #include "../h/map.h" ! 14: #include "../h/vm.h" ! 15: #include "../h/lnode.h" ! 16: #include "../h/proc.h" ! 17: #include "../h/msgbuf.h" ! 18: #include "../h/buf.h" ! 19: #include "../h/inode.h" ! 20: #include "../h/file.h" ! 21: #include "../h/text.h" ! 22: #include "../h/callout.h" ! 23: #include "../h/cmap.h" ! 24: #include "../h/reboot.h" ! 25: ! 26: #include "../machine/mbvar.h" ! 27: #include "../machine/psl.h" ! 28: #include "../machine/reg.h" ! 29: #include "../machine/clock.h" ! 30: #include "../machine/pte.h" ! 31: #include "../machine/scb.h" ! 32: #include "../machine/mmu.h" ! 33: #include "../machine/cpu.h" ! 34: #include "../machine/eeprom.h" ! 35: #include "../machine/interreg.h" ! 36: #include "../machine/memerr.h" ! 37: #include "../machine/eccreg.h" ! 38: #include "../machine/frame.h" ! 39: ! 40: /* ! 41: * Declare these as initialized data so we can patch them. ! 42: */ ! 43: int nbuf = 0; ! 44: int nswbuf = 0; ! 45: int bufpages = 0; ! 46: int physmem = 0; /* memory size in pages, patch if you want less */ ! 47: int kernprot = 1; /* write protect kernel text */ ! 48: int msgbufinit = 0; /* message buffer has been initialized, ok to printf */ ! 49: dev_t consdev = 0; ! 50: ! 51: int (*exit_vector)() = (int (*)())0; /* Where to go when halting UNIX */ ! 52: ! 53: #define TESTVAL 0xA55A /* memory test value */ ! 54: ! 55: u_char getsegmap(), pmegallocres(); ! 56: long getpgmap(); ! 57: ! 58: #ifdef SUN3_260 ! 59: /* ! 60: * Since there is no implied ordering of the memory cards, we store ! 61: * a zero terminated list of pointers to eccreg's that are active so ! 62: * that we only look at existent memory cards during softecc() handling. ! 63: */ ! 64: struct eccreg *ecc_alive[MAX_ECC+1]; ! 65: #endif SUN3_260 ! 66: ! 67: /* ! 68: * We make use of CMAPn (the pte address) ! 69: * and CADDRn (the virtual address) ! 70: * which are both temporaries defined in locore.s, ! 71: * not preserved across context switches, ! 72: * and not to be used in interrupt routines ! 73: */ ! 74: ! 75: /* ! 76: * Machine-dependent startup code ! 77: */ ! 78: startup() ! 79: { ! 80: register int unixsize, dvmapage; ! 81: register unsigned i; ! 82: register int c; ! 83: register struct pte *pte; ! 84: register caddr_t v; ! 85: u_int firstaddr; /* next free physical page number */ ! 86: extern char start[], etext[], end[], CADDR1[], Syslimit[]; ! 87: u_char oc, u_pmeg; ! 88: u_int mapaddr; ! 89: caddr_t zmemall(); ! 90: void v_handler(); ! 91: int mon_mem; ! 92: ! 93: initscb(); /* set trap vectors */ ! 94: *INTERREG |= IR_ENA_INT; /* make sure interrupts can occur */ ! 95: firstaddr = btoc((int)end - KERNELBASE) + UPAGES; ! 96: ! 97: /* ! 98: * Initialize map of allocated page map groups. ! 99: * Must be done before mapin of unallocated segments. ! 100: */ ! 101: pmeginit(); /* init list of pmeg data structures */ ! 102: ctxinit(); /* init context data structures */ ! 103: ! 104: /* ! 105: * Reserve necessary pmegs and set segment mapping. ! 106: * It is assumed here that the pmegs for low ! 107: * memory have already been duplicated for the ! 108: * segments up in the kernel virtual address space. ! 109: */ ! 110: ! 111: /* ! 112: * invalidate to start of high mapping ! 113: */ ! 114: for (i = 0; i < KERNELBASE >> SGSHIFT; i++) ! 115: setsegmap(i, (u_char)SEGINV); ! 116: ! 117: /* reserve kernel pmegs */ ! 118: for (; i < ptos(NPAGSEG - 1 + btoc(end)); i++) ! 119: pmegreserve(getsegmap(i)); ! 120: ! 121: for (; i < (MONSTART >> SGSHIFT); i++) /* invalidate to mon start */ ! 122: setsegmap(i, (u_char)SEGINV); ! 123: ! 124: for (; i < (MONEND >> SGSHIFT); i++) /* reserve monitor pmegs */ ! 125: if ((oc = getsegmap(i)) != (u_char)SEGINV) ! 126: pmegreserve(oc); ! 127: ! 128: for (; i < NSEGMAP - 1; i++) /* invalid until last seg */ ! 129: setsegmap(i, (u_char)SEGINV); ! 130: ! 131: /* ! 132: * Last segment contains the u area itself, ! 133: * the pmeg here is reserved for all contexts. ! 134: * We also reserve the invalid pmeg itself. ! 135: */ ! 136: u_pmeg = getsegmap(NSEGMAP - 1); ! 137: pmegreserve(u_pmeg); ! 138: pmegreserve((u_char)SEGINV); ! 139: ! 140: setcputype(); /* sets cpu and dvmasize variables */ ! 141: ! 142: /* ! 143: * Make sure the memory error register is ! 144: * set up to generate interrupts on error. ! 145: */ ! 146: #if defined(SUN3_160) || defined(SUN3_50) ! 147: if (cpu == CPU_SUN3_160 || cpu == CPU_SUN3_50) ! 148: MEMREG->mr_per = PER_INTENA | PER_CHECK; ! 149: #endif defined(SUN3_160) || defined(SUN3_50) ! 150: ! 151: #ifdef SUN3_260 ! 152: if (cpu == CPU_SUN3_260) { ! 153: register struct eccreg **ecc_nxt = ecc_alive; ! 154: register struct eccreg *ecc; ! 155: ! 156: /* ! 157: * Go probe for all memory cards and perform initialization. ! 158: * The address of the cards found is stashed in ecc_alive[]. ! 159: * We assume that the cards are already enabled and the ! 160: * base addresses have been set correctly by the monitor. ! 161: */ ! 162: for (ecc = ECCREG; ecc < &ECCREG[MAX_ECC]; ecc++) { ! 163: if (peekc((char *)ecc) == -1) ! 164: continue; ! 165: ecc->eccena.ena_scrub = 1; ! 166: ecc->eccena.ena_busena = 1; ! 167: *ecc_nxt++ = ecc; ! 168: } ! 169: *ecc_nxt = (struct eccreg *)0; /* terminate list */ ! 170: ! 171: MEMREG->mr_eer = EER_INTENA | EER_CE_ENA; ! 172: } ! 173: #endif SUN3_260 ! 174: ! 175: /* ! 176: * Allocate pmegs for DVMA space ! 177: */ ! 178: for (i = ptos(btop(DVMA)); i < ptos(btop(DVMA) + dvmasize); i++) { ! 179: u_char pm = pmegallocres(); ! 180: ! 181: setsegmap(i, pm); ! 182: for (v = (caddr_t)ctob(NPAGSEG * i); ! 183: v < (caddr_t)ctob(NPAGSEG * (i+1)); ! 184: v += NBPG) ! 185: setpgmap(v, (long)0); ! 186: } ! 187: ! 188: /* ! 189: * Now go through all the other contexts and set up the segment ! 190: * maps so that all segments are mapped the same. ! 191: * We have to use a PROM routine to do this since we don't want ! 192: * to switch to a new (unmapped) context to call setsegmap()! ! 193: */ ! 194: for (c = 0; c < NCONTEXT; c++) { ! 195: if (c == KCONTEXT) ! 196: continue; ! 197: ! 198: for (v = (caddr_t)0, i = 0; ! 199: v < (caddr_t)ctob(NPAGSEG * NSEGMAP); v += NBSG, i++) ! 200: (*romp->v_setcxsegmap)(c, v, getsegmap(i)); ! 201: } ! 202: ! 203: /* ! 204: * Initialize kernel page table entries. ! 205: */ ! 206: pte = &Sysmap[0]; ! 207: ! 208: /* invalid until start except scb page which is kernel writable */ ! 209: for (v = (caddr_t)KERNELBASE; v < (caddr_t)start; v += NBPG) { ! 210: if (v == (caddr_t)&scb) ! 211: *(int *)pte = PG_V | PG_KW | getpgmap(v) & PG_PFNUM; ! 212: else ! 213: *(int *)pte = 0; ! 214: setpgmap(v, *(long *)pte++); ! 215: } ! 216: ! 217: /* set up kernel text pages */ ! 218: for (; v < (caddr_t)etext; v += NBPG) { ! 219: if (kernprot) /* is kernel to be protected? */ ! 220: *(int *)pte = PG_V | PG_KR | getpgmap(v) & PG_PFNUM; ! 221: else ! 222: *(int *)pte = PG_V | PG_KW | getpgmap(v) & PG_PFNUM; ! 223: setpgmap(v, *(long *)pte++); ! 224: } ! 225: ! 226: /* set up kernel data/bss pages to be writeable */ ! 227: for (; v < (caddr_t)end; v += NBPG) { ! 228: *(int *)pte = PG_V | PG_KW | getpgmap(v) & PG_PFNUM; ! 229: setpgmap(v, *(long *)pte++); ! 230: } ! 231: ! 232: /* invalid until end of this segment */ ! 233: i = ((u_int)end + SGOFSET) & ~SGOFSET; ! 234: for (; v < (caddr_t)i; v += NBPG) ! 235: setpgmap(v, (long)0); ! 236: ! 237: /* ! 238: * Remove user access to monitor-set-up maps. ! 239: */ ! 240: for (i = MONSTART>>SGSHIFT; i < MONEND>>SGSHIFT; i++) { ! 241: if (getsegmap(i) == SEGINV) ! 242: continue; ! 243: for (v = (caddr_t)ctob(NPAGSEG * i); ! 244: v < (caddr_t)ctob(NPAGSEG * (i+1)); ! 245: v += NBPG) ! 246: setpgmap(v, (long)(((getpgmap(v) & ~PG_PROT) | PG_KW))); ! 247: } ! 248: ! 249: /* ! 250: * Invalidate any other pages in last segment ! 251: * besides the u area, EEPROM_ADDR, CLKADDR, ! 252: * MEMREG, INTERREG and MONSHORTPAGE. This sets ! 253: * up the kernel redzone below the u area. We ! 254: * get interrupt redzone for free when the kernel ! 255: * is write protected as the interrupt stack is ! 256: * the first thing in the data area. Since u ! 257: * and MONSHORTPAGE are defined as 32 bit virtual ! 258: * addresses (to get short references to work), ! 259: * we must mask to get only the 28 bits we really ! 260: * want to look at. ! 261: */ ! 262: for (v = (caddr_t)ctob(NPAGSEG * (NSEGMAP - 1)); ! 263: v < (caddr_t)ctob(NPAGSEG * NSEGMAP); v += NBPG) { ! 264: if (((u_int)v < ((u_int)&u & 0x0FFFFFFF) || ! 265: (u_int)v >= (((u_int)&u & 0x0FFFFFFF) + UPAGES*NBPG)) && ! 266: (u_int)v != ((u_int)MONSHORTPAGE & 0x0FFFFFFF) && ! 267: (u_int)v != (u_int)EEPROM_ADDR && ! 268: (u_int)v != (u_int)CLKADDR && ! 269: (u_int)v != (u_int)MEMREG && ! 270: (u_int)v != (u_int)INTERREG) ! 271: setpgmap(v, (long)0); ! 272: } ! 273: ! 274: /* ! 275: * v_memorysize is the amount of physical memory while ! 276: * v_memoryavail is the amount of usable memory in versions ! 277: * equal or greater to 1. Mon_mem is the difference which ! 278: * is the number of pages hidden by the monitor. ! 279: */ ! 280: if (romp->v_romvec_version >= 1) ! 281: mon_mem = btop(*romp->v_memorysize - *romp->v_memoryavail); ! 282: else ! 283: mon_mem = 0; ! 284: /* ! 285: * If physmem is patched to be non-zero, use it instead of ! 286: * the monitor value unless physmem is larger than the total ! 287: * amount of memory on hand. ! 288: */ ! 289: if (physmem == 0 || physmem > btop(*romp->v_memorysize)) ! 290: physmem = btop(*romp->v_memorysize); ! 291: /* ! 292: * Adjust physmem down for the pages stolen by the monitor. ! 293: */ ! 294: physmem -= mon_mem; ! 295: maxmem = physmem; ! 296: ! 297: /* ! 298: * v_vector_cmd is the handler for new monitor vector ! 299: * command in versions equal or greater to 2. ! 300: * We install v_handler() there for Unix. ! 301: */ ! 302: if (romp->v_romvec_version >= 2) ! 303: *romp->v_vector_cmd = v_handler; ! 304: ! 305: #include "bwtwo.h" ! 306: #if NBWTWO > 0 ! 307: if (physmem > btop(OBFBADDR + FBSIZE)) ! 308: fbobmemavail = 1; ! 309: else ! 310: fbobmemavail = 0; ! 311: #else ! 312: fbobmemavail = 0; ! 313: #endif ! 314: ! 315: /* ! 316: * Determine if anything lives in DVMA bus space. ! 317: * We're paranoid and go through both the 16 bit ! 318: * and 32 bit device types. ! 319: */ ! 320: disable_dvma(); ! 321: for (dvmapage = 0; dvmapage < btoc(dvmasize); dvmapage++) { ! 322: mapin(CMAP1, btop(CADDR1), (u_int)(dvmapage | PGT_VME_D16), ! 323: 1, PG_V | PG_KW); ! 324: if (poke((short *)CADDR1, TESTVAL) == 0) ! 325: break; ! 326: mapin(CMAP1, btop(CADDR1), (u_int)(dvmapage | PGT_VME_D32), ! 327: 1, PG_V | PG_KW); ! 328: if (poke((short *)CADDR1, TESTVAL) == 0) ! 329: break; ! 330: } ! 331: enable_dvma(); ! 332: ! 333: /* ! 334: * Initialize error message buffer (in low real memory before start). ! 335: * Printf's which occur prior to this will not be captured. ! 336: */ ! 337: mapin(msgbufmap, (u_int)btop(&msgbuf), ! 338: (u_int)btop((int)start - sizeof (struct msgbuf) - KERNELBASE), ! 339: (int)btoc(sizeof (struct msgbuf)), PG_V | PG_KW); ! 340: msgbufinit = 1; ! 341: ! 342: /* ! 343: * Allocate IOPB memory space just below the message ! 344: * buffer and map it to the first pages of DVMA space. ! 345: */ ! 346: maxmem -= IOPBMEM; ! 347: for (v = (caddr_t)DVMA, i = maxmem; i < maxmem + IOPBMEM; ! 348: v += NBPG, i++) { ! 349: struct pte tmp; /* scratch pte */ ! 350: ! 351: mapin(&tmp, btop(v), i, 1, PG_V | PG_KW); ! 352: } ! 353: ! 354: /* ! 355: * Good {morning,afternoon,evening,night}. ! 356: * When printing memory, use the total including ! 357: * those hidden by the monitor (mon_mem). ! 358: */ ! 359: printf(version); ! 360: ! 361: if (dvmapage < btoc(dvmasize)) { ! 362: printf("CAN'T HAVE PERIPHERALS IN RANGE 0 - %dKB\n", ! 363: ctob(dvmasize) / 1024); ! 364: panic("dvma collision"); ! 365: } ! 366: ! 367: #ifndef lint ! 368: if ((int)start - (int)ctob(btoc(sizeof (struct msgbuf))) <= (int)&scb) ! 369: panic("msgbuf too large"); ! 370: ! 371: if (sizeof (struct user) > UPAGES * NBPG) ! 372: panic("user area too large"); ! 373: #endif lint ! 374: ! 375: if ((int)Syslimit > (CSEG << SGSHIFT)) ! 376: panic("system map tables too large"); ! 377: ! 378: /* ! 379: * Determine how many buffers to allocate. ! 380: * Use 10% of memory (not counting 512K for kernel), with min of 16. ! 381: * We allocate 1/4 as many swap buffer headers as file i/o buffers. ! 382: */ ! 383: if (bufpages == 0) ! 384: bufpages = (physmem * NBPG - 512 * 1024) / 10 / CLBYTES; ! 385: if (nbuf == 0) { ! 386: nbuf = bufpages; ! 387: if (nbuf < 16) ! 388: nbuf = 16; ! 389: } ! 390: if (bufpages > nbuf * (BUFSIZE / CLBYTES)) ! 391: bufpages = nbuf * (BUFSIZE / CLBYTES); ! 392: if (nswbuf == 0) { ! 393: nswbuf = (nbuf / 4) &~ 1; /* force even */ ! 394: if (nswbuf > 32) ! 395: nswbuf = 32; /* sanity */ ! 396: } ! 397: printf("real mem = %d nbuf = %d nswbuf = %d\n", ! 398: ctob(physmem + mon_mem), nbuf, nswbuf); ! 399: ! 400: /* ! 401: * Allocate space for system data structures. ! 402: * The first available real memory address is in "firstaddr". ! 403: * The first available kernel virtual address is in "v". ! 404: * As pages of kernel virtual memory are allocated, "v" is incremented. ! 405: * "mapaddr" is the real memory address where the tables start. ! 406: * It is used when remapping the tables later. ! 407: * In order to support the frame buffer which might appear in ! 408: * the middle of contiguous memory we adjust the map address to ! 409: * start after the end of the frame buffer. Later we will adjust ! 410: * the core map to take this hole into account. The reason for ! 411: * this is to keep all the kernel tables contiguous in virtual space. ! 412: */ ! 413: if (fbobmemavail) ! 414: mapaddr = btoc(OBFBADDR + FBSIZE); ! 415: else ! 416: mapaddr = firstaddr; ! 417: v = (caddr_t)(ctob(firstaddr) + KERNELBASE); ! 418: #define valloc(name, type, num) \ ! 419: (name) = (type *)(v); (v) = (caddr_t)((name)+(num)) ! 420: #define valloclim(name, type, num, lim) \ ! 421: (name) = (type *)(v); (v) = (caddr_t)((lim) = ((name)+(num))) ! 422: valloc(swbuf, struct buf, nswbuf); ! 423: valloclim(inode, struct inode, ninode, inodeNINODE); ! 424: valloclim(file, struct file, nfile, fileNFILE); ! 425: valloclim(proc, struct proc, nproc, procNPROC); ! 426: valloclim(text, struct text, ntext, textNTEXT); ! 427: valloclim(lnodes, struct kern_lnode, maxusers, lnodesMAXUSERS); ! 428: valloc(callout, struct callout, ncallout); ! 429: valloc(swapmap, struct map, nswapmap = nproc * 2); ! 430: valloc(argmap, struct map, ARGMAPSIZE); ! 431: valloc(kernelmap, struct map, nproc); ! 432: valloc(iopbmap, struct map, IOPBMAPSIZE); ! 433: valloc(mb_hd.mh_map, struct map, DVMAMAPSIZE); ! 434: ! 435: /* ! 436: * Now allocate space for core map ! 437: * Allow space for all of physical memory minus the amount ! 438: * dedicated to the system. The amount of physical memory ! 439: * dedicated to the system is the total virtual memory of ! 440: * the system minus the space in the buffers which is not ! 441: * allocated real memory. ! 442: */ ! 443: ncmap = physmem - firstaddr; ! 444: valloclim(cmap, struct cmap, ncmap, ecmap); ! 445: unixsize = btoc((int)(ecmap+1) - KERNELBASE); ! 446: ! 447: if ((int)unixsize > SYSPTSIZE) ! 448: panic("sys pt too small"); ! 449: ! 450: /* ! 451: * Clear allocated space, and make r/w entries ! 452: * for the space in the kernel map. ! 453: */ ! 454: if (unixsize >= physmem - 8*UPAGES) ! 455: panic("no memory"); ! 456: ! 457: pte = &Sysmap[firstaddr]; ! 458: for (i = firstaddr + btop(KERNELBASE); i < btoc(v); i++) { ! 459: mapin(pte++, i, mapaddr, 1, PG_V | PG_KW); ! 460: clearseg(mapaddr++); ! 461: } ! 462: ! 463: /* ! 464: * Initialize callouts. ! 465: */ ! 466: callfree = callout; ! 467: for (i = 1; i < ncallout; i++) ! 468: callout[i-1].c_next = &callout[i]; ! 469: ! 470: /* ! 471: * Initialize memory allocator and swap ! 472: * and user page table maps. ! 473: */ ! 474: if (fbobmemavail) { ! 475: meminit((int)firstaddr, maxmem); ! 476: memialloc((int)firstaddr, (int)btop(OBFBADDR)); ! 477: memialloc((int)(1 + mapaddr), maxmem); ! 478: } else { ! 479: meminit((int)mapaddr, maxmem); ! 480: memialloc((int)mapaddr, maxmem); ! 481: } ! 482: maxmem = freemem; ! 483: printf("avail mem = %d\n", ctob(maxmem)); ! 484: rminit(kernelmap, (long)(USRPTSIZE - CLSIZE), (long)CLSIZE, ! 485: "usrpt", nproc); ! 486: rminit(iopbmap, (long)ctob(IOPBMEM), (long)DVMA, ! 487: "IOPB space", IOPBMAPSIZE); ! 488: rminit(mb_hd.mh_map, (long)(dvmasize - IOPBMEM), (long)IOPBMEM, ! 489: "DVMA map space", DVMAMAPSIZE); ! 490: ! 491: /* ! 492: * Configure the system. ! 493: */ ! 494: bootflags(); /* get the boot options */ ! 495: configure(); /* set up devices */ ! 496: if (fbobmemavail) { ! 497: /* ! 498: * Onboard frame buffer memory still ! 499: * available, put back onto the free list. ! 500: */ ! 501: memialloc((int)btop(OBFBADDR), (int)btop(OBFBADDR + FBSIZE)); ! 502: fbobmemavail = 0; ! 503: } ! 504: bufmemall(); ! 505: uinit(); /* initialize the u area */ ! 506: (void) spl0(); /* drop priority */ ! 507: } ! 508: ! 509: /* ! 510: * set up a physical address ! 511: * into users virtual address space. ! 512: */ ! 513: sysphys() ! 514: { ! 515: ! 516: if(!suser()) ! 517: return; ! 518: u.u_error = EINVAL; ! 519: } ! 520: ! 521: /* ! 522: * This system call sets the time of year clock without touching ! 523: * the software clock. It returns the previous clock value. If ! 524: * the argument is zero or the caller is not the super-user, it ! 525: * does not change the clock. ! 526: * Since the clocks are the same on the SUN, it just calls stime. ! 527: */ ! 528: settod() ! 529: { ! 530: register struct a { ! 531: long unsigned tod; ! 532: } *uap; ! 533: ! 534: u.u_r.r_time = time; ! 535: if (uap->tod != 0 && suser()) ! 536: stime(); ! 537: } ! 538: ! 539: /* ! 540: * Allocate physical memory for system buffers ! 541: * In Ethernet memory if the right board exists & ! 542: * the root device is ND & there are no block I/O DMA devices ! 543: */ ! 544: bufmemall() ! 545: { ! 546: struct pte *pte; ! 547: long a, va; ! 548: int npages; ! 549: int i, j, base, residual; ! 550: ! 551: a = rmalloc(kernelmap, (long)(nbuf*BUFSIZE/NBPG)); ! 552: if (a == 0) ! 553: panic("no vmem for buffers"); ! 554: buffers = (caddr_t)kmxtob(a); ! 555: pte = &Usrptmap[a]; ! 556: base = bufpages / nbuf; ! 557: residual = bufpages % nbuf; ! 558: for (i = 0; i < nbuf; i++) { ! 559: if (i < residual) ! 560: npages = base+1; ! 561: else ! 562: npages = base; ! 563: /* XXX - this loop only works if CLSIZE == 1 */ ! 564: for (j = 0; j < npages; j += CLSIZE) { ! 565: if (memall(pte+j, CLSIZE, &proc[0], CSYS) == 0) ! 566: panic("no mem for buffers"); ! 567: *(int *)(pte+j) |= PG_V|PG_KW; ! 568: va = (int)kmxtob(a+j); ! 569: vmaccess(pte+j, (caddr_t)va, 1); ! 570: bzero((caddr_t)va, CLBYTES); ! 571: } ! 572: pte += BUFSIZE/CLBYTES; ! 573: a += BUFSIZE/CLBYTES; ! 574: } ! 575: /* ! 576: * Double map and then unmap the last page of the last ! 577: * buffer to insure the presence of a pmeg. ! 578: * AARRRGGGHHH. Kludge away. ! 579: */ ! 580: if (base < BUFSIZE/CLBYTES) { ! 581: pte -= BUFSIZE/CLBYTES; ! 582: va = (int)kmxtob(a-1); ! 583: pte[BUFSIZE/CLBYTES - 1] = pte[0]; ! 584: vmaccess(&pte[BUFSIZE/CLBYTES - 1], (caddr_t)va, 1); ! 585: /* now unmap without disturbing the pmeg */ ! 586: *(int *)&pte[BUFSIZE/CLBYTES - 1] = 0; ! 587: setpgmap((caddr_t)va, (long)0); ! 588: } ! 589: buf = (struct buf *)zmemall(memall, nbuf * sizeof(struct buf)); ! 590: if (buf == 0) ! 591: panic("no mem for buf headers"); ! 592: } ! 593: ! 594: struct bootf { ! 595: char let; ! 596: short bit; ! 597: } bootf[] = { ! 598: 'a', RB_ASKNAME, ! 599: 's', RB_SINGLE, ! 600: 'i', RB_INITNAME, ! 601: 'h', RB_HALT, ! 602: 0, 0, ! 603: }; ! 604: char *initname = "/etc/init"; ! 605: ! 606: /* ! 607: * Parse the boot line to determine boot flags . ! 608: */ ! 609: bootflags() ! 610: { ! 611: register struct bootparam *bp = (*romp->v_bootparam); ! 612: register char *cp; ! 613: register int i; ! 614: ! 615: cp = bp->bp_argv[1]; ! 616: if (cp && *cp++ == '-') ! 617: do { ! 618: for (i = 0; bootf[i].let; i++) { ! 619: if (*cp == bootf[i].let) { ! 620: boothowto |= bootf[i].bit; ! 621: break; ! 622: } ! 623: } ! 624: cp++; ! 625: } while (bootf[i].let && *cp); ! 626: if (boothowto & RB_INITNAME) ! 627: initname = bp->bp_argv[2]; ! 628: if (boothowto & RB_HALT) ! 629: halt("bootflags"); ! 630: } ! 631: ! 632: /* ! 633: * Start the initial user process. ! 634: * The program [initname] is invoked with one argument ! 635: * containing the boot flags. ! 636: */ ! 637: icode() ! 638: { ! 639: struct execa { ! 640: char *fname; ! 641: char **argp; ! 642: char **envp; ! 643: } *ap; ! 644: char *ucp, **uap, *arg0, *arg1; ! 645: int i; ! 646: ! 647: u.u_error = 0; /* paranoid */ ! 648: /* Make a user stack (1 page) */ ! 649: expand(1, 1); ! 650: (void) swpexpand(0, 1, &u.u_dmap, &u.u_smap); ! 651: ! 652: /* Move out the boot flag argument */ ! 653: ucp = (char *)USRSTACK; ! 654: (void) subyte(--ucp, 0); /* trailing zero */ ! 655: for (i = 0; bootf[i].let; i++) { ! 656: if (boothowto & bootf[i].bit) ! 657: (void) subyte(--ucp, bootf[i].let); ! 658: } ! 659: (void) subyte(--ucp, '-'); /* leading hyphen */ ! 660: arg1 = ucp; ! 661: ! 662: /* Move out the file name (also arg 0) */ ! 663: for (i = 0; initname[i]; i++) ! 664: ; /* size the name */ ! 665: for (; i >= 0; i--) ! 666: (void) subyte(--ucp, initname[i]); ! 667: arg0 = ucp; ! 668: ! 669: /* Move out the arg pointers */ ! 670: uap = (char **) ((int)ucp & ~(NBPW-1)); ! 671: (void) suword((caddr_t)--uap, 0); /* terminator */ ! 672: (void) suword((caddr_t)--uap, (int)arg1); ! 673: (void) suword((caddr_t)--uap, (int)arg0); ! 674: ! 675: /* Point at the arguments */ ! 676: u.u_ap = u.u_arg; ! 677: ap = (struct execa *)u.u_ap; ! 678: ap->fname = arg0; ! 679: ap->argp = uap; ! 680: ap->envp = 0; ! 681: u.u_dirp = (caddr_t)u.u_arg[0]; ! 682: ! 683: /* Now let exec do the hard work */ ! 684: exece(); ! 685: if (u.u_error) { ! 686: printf("Can't invoke %s, error %d\n", initname, u.u_error); ! 687: panic("icode"); ! 688: } ! 689: } ! 690: ! 691: /* ! 692: * Set up page tables for process 0 U pages. ! 693: * This is closely related to way the code ! 694: * in locore.s sets things up. ! 695: */ ! 696: uinit() ! 697: { ! 698: register struct pte *pte; ! 699: u_int page; ! 700: register int i; ! 701: extern char end[]; ! 702: ! 703: /* ! 704: * main() will initialize proc[0].p_p0br to u.u_pcb.pcb_p0br ! 705: * and proc[0].p_szpt to 1. All we have to do is set up ! 706: * the pcb_p{0,1}{b,l}r registers in the pcb for now. ! 707: */ ! 708: ! 709: /* initialize base and length of P0 region */ ! 710: u.u_pcb.pcb_p0br = usrpt; ! 711: u.u_pcb.pcb_p0lr = 0; /* no user text/data (P0) for proc 0 */ ! 712: ! 713: /* ! 714: * initialize base and length of P1 region, ! 715: * where the length here is for invalid pages ! 716: */ ! 717: u.u_pcb.pcb_p1br = initp1br(usrpt + 1 * NPTEPG); ! 718: u.u_pcb.pcb_p1lr = P1PAGES; /* no user stack (P1) for proc 0 */ ! 719: ! 720: /* ! 721: * Doublely map the page containing the scb to contain the ! 722: * ptes whose virtual address is usrpt. Got that? ! 723: */ ! 724: page = (u_int)(getpgmap((caddr_t)&scb) & PG_PFNUM); ! 725: mapin(&Usrptmap[0], btop(usrpt), page, 1, PG_V | PG_KW); ! 726: ! 727: /* ! 728: * Now build the software page maps to map virtual U to physical U. ! 729: * These pages have already been set up using the real pages beyond ! 730: * end by locore.s. ! 731: */ ! 732: pte = usrpt + 1 * NPTEPG - UPAGES; ! 733: page = btop((int)end + (NBPG - 1) - KERNELBASE); ! 734: for (i = 0; i < UPAGES; i++) ! 735: *(int *)pte++ = PG_V | PG_KW | page++; ! 736: } ! 737: ! 738: struct sigcontext { ! 739: int sc_sp; /* sp to restore */ ! 740: int sc_pc; /* pc to retore */ ! 741: int sc_ps; /* psl to restore */ ! 742: }; ! 743: /* ! 744: * Send an interrupt to process. ! 745: * ! 746: * When using new signals user code must do a ! 747: * sys #139 to return from the signal, which ! 748: * calls sigcleanup below, which resets the ! 749: * signal mask and the notion of onsigstack, ! 750: * and returns from the signal handler. ! 751: */ ! 752: sendsig(p, sig) ! 753: int (*p)(), sig; ! 754: { ! 755: register int usp, *regs, scp; ! 756: struct nframe { ! 757: int sig; ! 758: int code; ! 759: int scp; ! 760: } frame; ! 761: struct sigcontext sc; ! 762: ! 763: #define mask(s) (1<<((s)-1)) ! 764: regs = u.u_ar0; ! 765: ! 766: usp = regs[SP]; ! 767: usp -= sizeof (struct sigcontext); ! 768: scp = usp; ! 769: usp -= sizeof (frame); ! 770: if (usp <= USRSTACK - ctob(u.u_ssize)) ! 771: (void) grow((unsigned)usp); ! 772: if (useracc((caddr_t)usp, sizeof(frame) + sizeof(sc), B_WRITE) == 0) { ! 773: /* ! 774: * Process has trashed its stack; give it an illegal ! 775: * instruction to halt it in its tracks. ! 776: */ ! 777: u.u_signal[SIGILL] = SIG_DFL; ! 778: u.u_procp->p_siga0 &= ~(1<<(SIGILL-1)); ! 779: u.u_procp->p_siga1 &= ~(1<<(SIGILL-1)); ! 780: psignal(u.u_procp, SIGILL); ! 781: } ! 782: /* ! 783: * push sigcontext structure. ! 784: */ ! 785: sc.sc_sp = regs[SP]; ! 786: sc.sc_pc = regs[PC]; ! 787: sc.sc_ps = regs[PS]; ! 788: /* ! 789: * If trace mode was on for the user process ! 790: * when we came in here, it may have been because ! 791: * of an ast-induced trace on a trap instruction, ! 792: * in which case we do not want to restore the ! 793: * trace bit in the status register later on ! 794: * in sigcleanup(). If we were to restore it ! 795: * and another ast trap had been posted, we would ! 796: * end up marking the trace trap as a user-requested ! 797: * real trace trap and send a bogus "Trace/BPT" signal. ! 798: */ ! 799: if ((sc.sc_ps & PSL_T) && (u.u_pcb.pcb_p0lr & TRACE_AST)) ! 800: sc.sc_ps &= ~PSL_T; ! 801: (void) copyout((caddr_t)&sc, (caddr_t)scp, sizeof (sc)); ! 802: /* ! 803: * push call frame. ! 804: */ ! 805: frame.sig = sig; ! 806: if (sig == SIGILL || sig == SIGFPE || sig == SIGEMT) { ! 807: frame.code = u.u_code; ! 808: u.u_code = 0; ! 809: } else ! 810: frame.code = 0; ! 811: frame.scp = scp; ! 812: (void) copyout((caddr_t)&frame, (caddr_t)usp, sizeof (frame)); ! 813: regs[SP] = usp; ! 814: regs[PC] = (int)p; ! 815: } ! 816: ! 817: /* ! 818: * Routine to cleanup state after a signal ! 819: * has been taken. Reset signal mask and ! 820: * notion of on signal stack from context ! 821: * left there by sendsig (above). Pop these ! 822: * values and perform rti. ! 823: */ ! 824: sigcleanup() ! 825: { ! 826: struct sigcontext *scp, sc; ! 827: ! 828: scp = (struct sigcontext *)fuword((caddr_t)u.u_ar0[SP] + sizeof(int)); ! 829: if ((int)scp == -1) ! 830: return; ! 831: if (copyin((caddr_t)scp, (caddr_t)&sc, sizeof (sc))) ! 832: return; ! 833: u.u_ar0[SP] = sc.sc_sp; ! 834: u.u_ar0[PC] = sc.sc_pc; ! 835: u.u_ar0[PS] = sc.sc_ps; ! 836: u.u_ar0[PS] &= ~PSL_USERCLR; ! 837: u.u_ar0[PS] |= PSL_USERSET; ! 838: u.u_eosys = REALLYRETURN; ! 839: } ! 840: #undef mask ! 841: ! 842: int waittime = -1; ! 843: ! 844: boot(arghowto) ! 845: int arghowto; ! 846: { ! 847: register int howto; ! 848: static int prevflag = 0; ! 849: register struct buf *bp; ! 850: int iter, nbusy; ! 851: int s; ! 852: ! 853: consdev = 0; ! 854: startnmi(); ! 855: howto = arghowto; ! 856: if ((howto&RB_NOSYNC)==0 && waittime < 0 && bfreelist[0].b_forw) { ! 857: waittime = 0; ! 858: update(); ! 859: printf("syncing disks... "); ! 860: while (++waittime <= 5) ! 861: sleep((caddr_t)&lbolt, PZERO); ! 862: printf("done\n"); ! 863: } ! 864: s = spl7(); /* extreme priority */ ! 865: if (howto & RB_HALT) { ! 866: halt((char *)NULL); ! 867: /* MAYBE REACHED */ ! 868: } else { ! 869: if ((howto & RB_PANIC) && prevflag == 0) { ! 870: prevflag = 1; ! 871: dumpsys(); ! 872: ! 873: } ! 874: printf("Rebooting Unix...\n"); ! 875: (*romp->v_boot_me)(howto & RB_SINGLE ? "-s" : ""); ! 876: /*NOTREACHED*/ ! 877: } ! 878: (void) splx(s); ! 879: } ! 880: ! 881: /* ! 882: * Initialize UNIX's vector table: ! 883: * Vectors are copied from protoscb unless ! 884: * they are zero; zero means preserve whatever the ! 885: * monitor put there. If the protoscb is zero, ! 886: * then the original contents are copied into ! 887: * the scb we are setting up. ! 888: */ ! 889: initscb() ! 890: { ! 891: register int *s, *p, *f; ! 892: register int n; ! 893: struct scb *orig, *getvbr(); ! 894: ! 895: orig = getvbr(); ! 896: exit_vector = orig->scb_trap[14]; ! 897: s = (int *)&scb; ! 898: p = (int *)&protoscb; ! 899: f = (int *)orig; ! 900: for (n = sizeof (struct scb)/sizeof (int); n--; s++, p++, f++) { ! 901: if (*p) ! 902: *s = *p; ! 903: else ! 904: *s = *f; ! 905: } ! 906: setvbr(&scb); ! 907: } ! 908: ! 909: /* ! 910: * Clear a segment (page (click)). ! 911: */ ! 912: clearseg(pgno) ! 913: u_int pgno; ! 914: { ! 915: extern char CADDR1[]; ! 916: ! 917: mapin(CMAP1, btop(CADDR1), pgno, 1, PG_V | PG_KW); ! 918: bzero(CADDR1, NBPG); ! 919: } ! 920: ! 921: /* ! 922: * Copy a segment (page) from a user virtual address ! 923: * to a physical page number. ! 924: */ ! 925: copyseg(vaddr, pgno) ! 926: caddr_t vaddr; ! 927: int pgno; ! 928: { ! 929: register struct pte *pte; ! 930: register int lock; ! 931: extern char CADDR1[]; ! 932: ! 933: /* ! 934: * Make sure the user's page is valid and locked. ! 935: */ ! 936: pte = vtopte(u.u_procp, btop(vaddr)); ! 937: if (lock = !pte->pg_v) { ! 938: pagein((u_int)vaddr, &u, 1); /* return it locked */ ! 939: pte = vtopte(u.u_procp, btop(vaddr)); /* pte may move */ ! 940: } ! 941: /* ! 942: * Map the destination page into kernel address space. ! 943: */ ! 944: mapin(CMAP1, btop(CADDR1), (u_int)pgno, 1, PG_V | PG_KW); ! 945: (void) copyin(vaddr, CADDR1, CLBYTES); ! 946: if (lock) ! 947: munlock(pte->pg_pfnum); ! 948: } ! 949: ! 950: /* ! 951: * Handle "physical" block transfers. ! 952: */ ! 953: physstrat(bp, strat, pri) ! 954: register struct buf *bp; ! 955: int (*strat)(); ! 956: int pri; ! 957: { ! 958: register int npte, n; ! 959: register long a; ! 960: unsigned v; ! 961: register struct pte *pte, *kpte; ! 962: struct proc *rp; ! 963: int va, s, o; ! 964: ! 965: v = btop(bp->b_un.b_addr); ! 966: o = (int)bp->b_un.b_addr & PGOFSET; ! 967: npte = btoc(bp->b_bcount + o) + 1; ! 968: while ((a = rmalloc(kernelmap, (long)npte)) == NULL) { ! 969: kmapwnt++; ! 970: sleep((caddr_t)kernelmap, PSWP+4); ! 971: } ! 972: kpte = &Usrptmap[a]; ! 973: rp = bp->b_flags&B_DIRTY ? &proc[2] : bp->b_proc; ! 974: if ((bp->b_flags & B_PHYS) == 0) ! 975: pte = &Sysmap[btop((int)bp->b_un.b_addr - KERNELBASE)]; ! 976: else if (bp->b_flags & B_UAREA) ! 977: pte = &rp->p_addr[v]; ! 978: else if (bp->b_flags & B_PAGET) ! 979: pte = &Usrptmap[btokmx((struct pte *)bp->b_un.b_addr)]; ! 980: else ! 981: pte = vtopte(rp, v); ! 982: for (n = npte; --n != 0; kpte++, pte++) ! 983: *(int *)kpte = PG_V | PG_KW | (*(int *)pte & PG_PFNUM); ! 984: *(int *)kpte = 0; ! 985: va = (int)kmxtob(a); ! 986: vmaccess(&Usrptmap[a], (caddr_t)va, npte); ! 987: bp->b_saddr = bp->b_un.b_addr; ! 988: bp->b_un.b_addr = (caddr_t)(va | o); ! 989: bp->b_kmx = a; ! 990: bp->b_npte = npte; ! 991: (*strat)(bp); ! 992: if (bp->b_flags & B_DIRTY) ! 993: return; ! 994: s = spl6(); ! 995: while ((bp->b_flags & B_DONE) == 0) ! 996: sleep((caddr_t)bp, pri); ! 997: (void) splx(s); ! 998: bp->b_un.b_addr = bp->b_saddr; ! 999: bp->b_kmx = 0; ! 1000: bp->b_npte = 0; ! 1001: mapout(&Usrptmap[a], npte); ! 1002: rmfree(kernelmap, (long)npte, a); ! 1003: } ! 1004: ! 1005: /* ! 1006: * Halt the machine and return to the monitor ! 1007: */ ! 1008: halt(s) ! 1009: char *s; ! 1010: { ! 1011: extern struct scb *getvbr(); ! 1012: ! 1013: if (s) ! 1014: (*romp->v_printf)("(%s) ", s); ! 1015: (*romp->v_printf)("Unix Halted\n\n"); ! 1016: startnmi(); ! 1017: if (exit_vector) ! 1018: getvbr()->scb_trap[14] = exit_vector; ! 1019: asm("trap #14"); ! 1020: if (exit_vector) ! 1021: getvbr()->scb_trap[14] = protoscb.scb_trap[14]; ! 1022: stopnmi(); ! 1023: } ! 1024: ! 1025: /* ! 1026: * Print out a traceback for the caller - can be called anywhere ! 1027: * within the kernel or from the monitor by typing "g4" (for sun-2 ! 1028: * compatibility) or "w trace". This causes the monitor to call ! 1029: * the v_handler() routine which will call tracedump() for these cases. ! 1030: */ ! 1031: /*VARARGS0*/ ! 1032: tracedump(x1) ! 1033: caddr_t x1; ! 1034: { ! 1035: struct frame *fp = (struct frame *)(&x1 - 2); ! 1036: u_int tospage = btoc(fp); ! 1037: ! 1038: (*romp->v_printf)("Begin traceback...fp = %x\n", fp); ! 1039: while (btoc(fp) == tospage) { ! 1040: if (fp == fp->fr_savfp) { ! 1041: (*romp->v_printf)("FP loop at %x", fp); ! 1042: break; ! 1043: } ! 1044: (*romp->v_printf)("Called from %x, fp=%x, args=%x %x %x %x\n", ! 1045: fp->fr_savpc, fp->fr_savfp, ! 1046: fp->fr_arg[0], fp->fr_arg[1], fp->fr_arg[2], fp->fr_arg[3]); ! 1047: fp = fp->fr_savfp; ! 1048: } ! 1049: (*romp->v_printf)("End traceback...\n"); ! 1050: } ! 1051: ! 1052: /* ! 1053: * Buscheck is called by mbsetup to check to see it the requested ! 1054: * setup is a valid busmem type (i.e. VMEbus). Returns 1 if ok ! 1055: * busmem type, returns 0 if not busmem type. This routine ! 1056: * make checks and panic's if an illegal busmem type request is detected. ! 1057: */ ! 1058: buscheck(pte, npf) ! 1059: register struct pte *pte; ! 1060: register int npf; ! 1061: { ! 1062: register int i, pf; ! 1063: register int pt = *(int *)pte & PGT_MASK; ! 1064: ! 1065: if (pt == PGT_VME_D16 || pt == PGT_VME_D32) { ! 1066: pf = pte->pg_pfnum; ! 1067: if (pf < btoc(DVMASIZE)) ! 1068: panic("buscheck: busmem in DVMA range"); ! 1069: for (i = 0; i < npf; i++, pte++, pf++) { ! 1070: if ((*(int *)pte & PGT_MASK) != pt || ! 1071: pte->pg_pfnum != pf) ! 1072: panic("buscheck: request not contiguous"); ! 1073: } ! 1074: return (1); ! 1075: } ! 1076: return (0); ! 1077: } ! 1078: ! 1079: /* ! 1080: * Compute the address of an I/O device within standard address ! 1081: * ranges and return the result. This is used by DKIOCINFO ! 1082: * ioctl to get the best guess possible for the actual address ! 1083: * set on the card. ! 1084: */ ! 1085: getdevaddr(addr) ! 1086: caddr_t addr; ! 1087: { ! 1088: int off = (int)addr & PGOFSET; ! 1089: int pte = getkpgmap(addr); ! 1090: int physaddr = ((pte & PG_PFNUM) & ~PGT_MASK) * NBPG; ! 1091: ! 1092: switch (pte & PGT_MASK) { ! 1093: case PGT_VME_D16: ! 1094: case PGT_VME_D32: ! 1095: if (physaddr > VME16_BASE) { ! 1096: /* 16 bit VMEbus address */ ! 1097: physaddr -= VME16_BASE; ! 1098: } else if (physaddr > VME24_BASE) { ! 1099: /* 24 bit VMEbus address */ ! 1100: physaddr -= VME24_BASE; ! 1101: } ! 1102: /* ! 1103: * else 32 bit VMEbus address, ! 1104: * physaddr doesn't require adjustments ! 1105: */ ! 1106: break; ! 1107: ! 1108: case PGT_OBMEM: ! 1109: case PGT_OBIO: ! 1110: /* physaddr doesn't require adjustments */ ! 1111: break; ! 1112: } ! 1113: ! 1114: return (physaddr + off); ! 1115: } ! 1116: ! 1117: static int (*mon_nmi)(); /* monitor's level 7 nmi routine */ ! 1118: extern int level7(); /* Unix's level 7 nmi routine */ ! 1119: ! 1120: stopnmi() ! 1121: { ! 1122: struct scb *vbr, *getvbr(); ! 1123: ! 1124: vbr = getvbr(); ! 1125: if (vbr->scb_autovec[7 - 1] != level7) { ! 1126: #ifndef GPROF ! 1127: set_clk_mode(0, IR_ENA_CLK7); /* disable level 7 clk intr */ ! 1128: #endif !GPROF ! 1129: mon_nmi = vbr->scb_autovec[7 - 1]; /* save mon vec */ ! 1130: vbr->scb_autovec[7 - 1] = level7; /* install Unix vec */ ! 1131: } ! 1132: } ! 1133: ! 1134: startnmi() ! 1135: { ! 1136: struct scb *getvbr(); ! 1137: ! 1138: if (mon_nmi) { ! 1139: getvbr()->scb_autovec[7 - 1] = mon_nmi; /* install mon vec */ ! 1140: #ifndef GPROF ! 1141: set_clk_mode(IR_ENA_CLK7, 0); /* enable level 7 clk intr */ ! 1142: #endif !GPROF ! 1143: } ! 1144: } ! 1145: ! 1146: /* ! 1147: * Handler for monitor vector cmd - ! 1148: * For now we just implement the old "g0" and "g4" ! 1149: * commands and a printf hack. ! 1150: */ ! 1151: void ! 1152: v_handler(addr, str) ! 1153: int addr; ! 1154: char *str; ! 1155: { ! 1156: ! 1157: switch (*str) { ! 1158: case '\0': ! 1159: /* ! 1160: * No (non-hex) letter was specified on ! 1161: * command line, use only the number given ! 1162: */ ! 1163: switch (addr) { ! 1164: case 0: /* old g0 */ ! 1165: case 0xd: /* 'd'ump short hand */ ! 1166: panic("zero"); ! 1167: /*NOTREACHED*/ ! 1168: ! 1169: case 4: /* old g4 */ ! 1170: tracedump(); ! 1171: break; ! 1172: ! 1173: default: ! 1174: goto err; ! 1175: } ! 1176: break; ! 1177: ! 1178: case 'p': /* 'p'rint string command */ ! 1179: case 'P': ! 1180: (*romp->v_printf)("%s\n", (char *)addr); ! 1181: break; ! 1182: ! 1183: case '%': /* p'%'int anything a la printf */ ! 1184: (*romp->v_printf)(str, addr); ! 1185: (*romp->v_printf)("\n"); ! 1186: break; ! 1187: ! 1188: case 't': /* 't'race kernel stack */ ! 1189: case 'T': ! 1190: tracedump(); ! 1191: break; ! 1192: ! 1193: case 'u': /* d'u'mp hack ('d' look like hex) */ ! 1194: case 'U': ! 1195: if (addr == 0xd) { ! 1196: panic("zero"); ! 1197: } else ! 1198: goto err; ! 1199: break; ! 1200: ! 1201: default: ! 1202: err: ! 1203: (*romp->v_printf)("Don't understand 0x%x '%s'\n", addr, str); ! 1204: } ! 1205: } ! 1206: ! 1207: /* ! 1208: * Handle parity/ECC memory errors. XXX - use something like ! 1209: * vax to only look for soft ecc errors periodically? ! 1210: */ ! 1211: memerr() ! 1212: { ! 1213: u_char per, eer; ! 1214: char *mess = 0; ! 1215: int c; ! 1216: long pme; ! 1217: ! 1218: eer = per = MEMREG->mr_er; ! 1219: #ifdef SUN3_260 ! 1220: if (cpu == CPU_SUN3_260 && (eer & EER_ERR) == EER_CE) { ! 1221: softecc(); ! 1222: MEMREG->mr_dvma = 1; /* clear latching */ ! 1223: return; ! 1224: } ! 1225: #endif SUN3_260 ! 1226: ! 1227: /* ! 1228: * Since we are going down in flames, disable further ! 1229: * memory error interrupts to prevent confusion. ! 1230: */ ! 1231: MEMREG->mr_er &= ~ER_INTENA; ! 1232: ! 1233: #if defined(SUN3_160) || defined(SUN3_50) ! 1234: if ((cpu == CPU_SUN3_160 || cpu == CPU_SUN3_50) && ! 1235: (per & PER_ERR) != 0) { ! 1236: printf("Parity Error Register %b\n", per, PARERR_BITS); ! 1237: mess = "parity error"; ! 1238: } ! 1239: #endif defined(SUN3_160) || defined(SUN3_50) ! 1240: ! 1241: #ifdef SUN3_260 ! 1242: if ((cpu == CPU_SUN3_260) && (eer & EER_ERR) != 0) { ! 1243: printf("ECC Error Register %b\n", eer, ECCERR_BITS); ! 1244: mess = "uncorrectable ECC error"; ! 1245: } ! 1246: #endif SUN3_260 ! 1247: ! 1248: if (!mess) { ! 1249: printf("Memory Error Register %b %b\n", ! 1250: per, PARERR_BITS, eer, ECCERR_BITS); ! 1251: mess = "unknown memory error"; ! 1252: } ! 1253: ! 1254: printf("DVMA = %x, context = %x, virtual address = %x\n", ! 1255: MEMREG->mr_dvma, MEMREG->mr_ctx, MEMREG->mr_vaddr); ! 1256: ! 1257: c = getcontext(); ! 1258: setcontext((int)MEMREG->mr_ctx); ! 1259: pme = getpgmap((caddr_t)MEMREG->mr_vaddr); ! 1260: printf("pme = %x, physical address = %x\n", pme, ! 1261: ptob(((struct pte *)&pme)->pg_pfnum) + (MEMREG->mr_vaddr&PGOFSET)); ! 1262: setcontext(c); ! 1263: ! 1264: /* ! 1265: * Clear the latching by writing to the top ! 1266: * nibble of the memory address register ! 1267: */ ! 1268: MEMREG->mr_dvma = 1; ! 1269: ! 1270: panic(mess); ! 1271: /*NOTREACHED*/ ! 1272: } ! 1273: ! 1274: #ifdef SUN3_260 ! 1275: int prtsoftecc = 1; ! 1276: ! 1277: /* ! 1278: * Probe memory cards to find which one(s) had ecc error(s). ! 1279: * If prtsoftecc is non-zero, log messages regarding the failing ! 1280: * syndrome. Then clear the latching on the memory card. ! 1281: */ ! 1282: softecc() ! 1283: { ! 1284: register struct eccreg **ecc_nxt, *ecc; ! 1285: ! 1286: for (ecc_nxt = ecc_alive; *ecc_nxt != (struct eccreg *)0; ecc_nxt++) { ! 1287: ecc = *ecc_nxt; ! 1288: if (ecc->syndrome.sy_ce) { ! 1289: if (prtsoftecc) { ! 1290: printf("mem%d: soft ecc addr %x+%x=%x syn %b\n", ! 1291: ecc - ECCREG, ! 1292: (ecc->eccena.ena_addr << 22), ! 1293: (ecc->syndrome.sy_addr << 3), ! 1294: (ecc->eccena.ena_addr << 22) + ! 1295: (ecc->syndrome.sy_addr << 3), ! 1296: ecc->syndrome.sy_synd, SYNDERR_BITS); ! 1297: } ! 1298: ecc->syndrome.sy_ce = 1; /* clear latching */ ! 1299: } ! 1300: } ! 1301: } ! 1302: #endif SUN3_260
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.