/********************************************************************** * Copyright (c) Digital Equipment Corporation 1984, 1985, 1986. * * All Rights Reserved. * * Reference "/usr/src/COPYRIGHT" for applicable restrictions. * **********************************************************************/ /* * SCCSID: @(#)machdep.c 3.4 1/14/88 */ #include <sys/param.h> #include <sys/systm.h> #include <sys/acct.h> #include <sys/dir.h> #include <sys/user.h> #include <sys/inode.h> #include <sys/proc.h> #include <sys/seg.h> #include <sys/map.h> #include <sys/reg.h> #include <sys/buf.h> #include <sys/uba.h> /* * ULTRIX-11 System Version Number Definitions * * The kernel version number is stored in two forms. * It is contained in the kernel startup message * as an ascii string and encoded into bits 6->15 * of rn_ssr3 for use by the error log print program. * * rn_ssr3 encoding * * BITS 0->5 saved memory management SSR3 (lo 6 bits) * BITS 6->7 00 = V, 01 = X, 10 = Y * BITS 8->11 .# * BITS 12->15 #. * Note: The following #defines makes dealing with * this a bit easier, but takes away some of * Fred's fun with magic bit twiddling. * -Dave Borman, 4/24/84 */ #define V 0000 #define X 0100 #define Y 0200 #define VERS(a,b,c) (a|((b&017)<<12)|((c&017)<<8)) #define OS_VN VERS(V,3,1) #define SU_MSG "ULTRIX-11 Kernel V3.1" /* * UMAX limits the number of terminals available for * user logins. For the binary kits, UMAX is defined * by the makefile otherwise a default of 100 is used. * The UMAX values are intentionally strange. * * 8 (!&) 023041 * 16 (.:) 035056 * 32 (%$) 022045 * 100 (;#) 021473 * * This magic number becomes an argument to `init'. * The `boot' matches this number against its idea of UMAX. * * Fred Canter (King of strangeness!) */ #ifndef UMAX #define UMAX 021473 #endif segm seg5; /* filled in by initialization */ /* * Icode is the octal bootstrap * program executed in user mode * to bring up the system. */ int icode[] = { 0104413, /* sys exec; init; initp */ 0000016, 0000010, 0000777, /* br . */ 0000016, /* initp: init; umax; 0 */ 0000030, 0000000, 0062457, /* init: </etc/init\0> */ 0061564, 0064457, 0064556, 0000164, UMAX, /* umax: maximum number of user logins */ 0000000, /* zero to end UMAX string */ }; int szicode = sizeof(icode); memaddr bpaddr; #ifdef UCB_NET memaddr mbbase; unsigned mbsize; #endif #ifdef UCB_CLIST extern memaddr clststrt; extern int nclist; unsigned clstdesc; #endif UCB_CLIST /* * Machine-dependent startup code */ #define MPCSR ((physadr)0172100) #define LOCZERO ((physadr)0) startup() { register unsigned int i; register unsigned int maxmeml; /* * `maxmem' is the total amount of memory available. * `maxseg' is a parameter which may be used to limit * the amount of memory actually used by unix. * Both are expressed in 64 byte segments. */ saveseg5(seg5); if(maxmem > maxseg) maxmem = maxseg; realmem = maxmem; rn_ssr3 |= OS_VN; /* load kernel version number */ printf("\n%s\n", SU_MSG); /* startup message */ printf("\nrealmem = %D", ctob((long)realmem)); i = ka6->r[0] + USIZE; usermem = maxmem - i; MAPINIT(coremap, mapsize); /* initialize the core map */ mfree(coremap, usermem, i); calloinit(); /* initialize the callout table */ #define B (size_t)(((long)nbuf << BSHIFT) / ctob(1)) if ((bpaddr = malloc(coremap, B)) == 0) panic("buffers"); usermem -= B; printf("\nbuffers = %D", ctob((long)(B))); #undef B #ifdef UCB_CLIST #define C (nclist * sizeof(struct cblock)) if (C > UBPAGE) { printf("clist area too large (reducing)\n"); nclist = UBPAGE/sizeof(struct cblock); } if ((clststrt = malloc(coremap, btoc(C))) == 0) panic("clists"); usermem -= btoc(C); printf("\nclists = %D", (long)(C)); clstaddr = (long)clststrt << 6; clstdesc = ((((btoc(nclist*sizeof(struct cblock)))-1) << 8) | RW); #undef C #endif UCB_CLIST #ifdef PROFILE usermem -= msprof(); #endif PROFILE #ifdef UCB_NET if (mbsize) { if ((mbbase = malloc(coremap, btoc(mbsize))) == 0) panic("mbbase"); usermem -= btoc(mbsize); printf("\nmbufs = %D", (long)mbsize); } #endif UCB_NET /* call maus and message init routines: sysV stuff: * George Mathew 6/13/85 */ usermem -= mausinit(); usermem -= msginit(); printf("\nusermem = %D", ctob((long)usermem)); /* * Fred Canter -- dynamic allocation of maxmem. * * Will become a sysgen question. */ /* loc zero = 4 if split i/d kernel */ if(LOCZERO->r[0] == 4) maxmeml = 6528; /* 408KB for SID */ else maxmeml = 3328; /* 208KB for NSID */ /* if(MAXMEM < usermem) */ /* maxmem = MAXMEM; */ if(maxmeml < usermem) maxmem = maxmeml; else maxmem = usermem; printf("\nmaxumem = %D\n", ctob((long)maxmem)); MAPINIT(swapmap, mapsize); mfree(swapmap, nswap, 1); swplo--; /* * Set last user space address register to * point to unibus I/O space, for use by the sui/fui * calls in some of the following functions, such * as clkstart(). */ UISA->r[7] = ka6->r[1]; /* io segment */ UISD->r[7] = 077406; } #ifdef PROFILE #define SISD0 ((u_short *)0172200) #define SISD1 ((u_short *)0172202) #define SISD2 ((u_short *)0172204) #define SISD3 ((u_short *)0172206) #define SISD4 ((u_short *)0172210) #define SISD5 ((u_short *)0172212) #define SISD6 ((u_short *)0172214) #define SISA0 ((u_short *)0172240) #define SISA1 ((u_short *)0172242) #define SISA2 ((u_short *)0172244) #define SISA3 ((u_short *)0172246) #define SISA4 ((u_short *)0172250) #define SISA5 ((u_short *)0172252) #define SISA6 ((u_short *)0172254) /* * Allocate memory for system profiling. Called * once at boot time. Returns number of clicks * used by profiling. * * The system profiler uses supervisor I space registers 2 and 3 * (virtual addresses 040000 through 0100000) to hold the profile. */ static int nproclicks; memaddr proloc; msprof() { nproclicks = btoc(8192*5); proloc = malloc(coremap, nproclicks); if (proloc == 0) panic("msprof"); *SISA2 = proloc; *SISA3 = proloc + btoc(8192); *SISA4 = proloc + btoc(16384); *SISA5 = proloc + btoc(24576); *SISA6 = proloc + btoc(32768); *SISD2 = 077400|RW; *SISD3 = 077400|RW; *SISD4 = 077400|RW; *SISD5 = 077400|RW; *SISD6 = 077400|RW; *SISD0 = RW; *SISD1 = RW; esprof(); return (nproclicks); } /* * Enable system profiling. * Zero out the profile buffer and then turn the * clock (KW11-P) on. */ esprof() { clear(proloc, nproclicks); isprof(); printf("\nprofiling on"); } #endif PROFILE #ifdef SYSPHYS /* * set up a physical address * into users virtual address space. */ sysphys() { register i, s, d; register struct a { int segno; int size; int phys; } *uap; if(!suser()) return; uap = (struct a *)u.u_ap; i = uap->segno; if(i < 0 || i >= 8) goto bad; s = uap->size; if(s < 0 || s > 128) goto bad; d = u.u_uisd[i+8]; if(d != 0 && (d&ABS) == 0) goto bad; u.u_uisd[i+8] = 0; u.u_uisa[i+8] = 0; if(!u.u_sep) { u.u_uisd[i] = 0; u.u_uisa[i] = 0; } if(s) { u.u_uisd[i+8] = ((s-1)<<8) | RW|ABS; u.u_uisa[i+8] = uap->phys; if(!u.u_sep) { u.u_uisa[i] = u.u_uisa[i+8]; u.u_uisd[i] = u.u_uisd[i+8]; } } sureg(); return; bad: u.u_error = EINVAL; } #endif SYSPHYS /* * Determine which clock is attached, and start it. * panic: no clock * is printed if no clock can be found. * */ #define CLOCK1 ((physadr)0177546) #define CLOCK2 ((physadr)0172540) clkstart() { lks = CLOCK1; if(suiword((caddr_t)lks, 0) == -1) { lks = CLOCK2; if(suiword((caddr_t)lks, 0) == -1) panic("no clock"); } lks->r[0] = 0115; } /* * Let a process handle a signal by simulating an interrupt */ sendsig(p, signo) caddr_t p; { register unsigned n; n = u.u_ar0[R6] - 4; grow(n); suword((caddr_t)n+2, u.u_ar0[RPS]); suword((caddr_t)n, u.u_ar0[R7]); u.u_ar0[R6] = n; u.u_ar0[RPS] &= ~TBIT; u.u_ar0[R7] = (int)p; } /* * Simulate a return frominterrupt on return from the syscall * after popping n words of the users stack. */ dorti(n) { register int opc, ops; u.u_ar0[R6] += n * 2; if (((opc = fuword((caddr_t)u.u_ar0[R6])) == -1) || ((ops = fuword((caddr_t)(u.u_ar0[R6] + 2))) == -1)) psignal(u.u_procp, SIGSEGV); else { u.u_ar0[R6] += 4; u.u_ar0[PC] = opc; ops |= PS_CURMOD | PS_PRVMOD; /* assure user space */ ops &= ~PS_USERCLR; /* priority 0 */ u.u_ar0[RPS] = ops; } } /* * Save the current kernel mapping and set it to the normal map. * Called at interrupt time to access proc, text or file structures * or the user structure. * Called only if *KDSA5 != seg5.se_addr from the macro savemap. */ Savemap(map) register mapinfo map; { map[0].se_addr = *KDSA5; map[0].se_desc = *KDSD5; if (kdsa6) { map[1].se_addr = *KDSA6; map[1].se_desc = *KDSD6; *KDSD6 = KD6; *KDSA6 = kdsa6; } else map[1].se_desc = NOMAP; restorseg5(seg5); } /* * Restore the mapping information saved above. * Called only if map[0].se_desc != NOMAP (from macro restormap). */ Restormap(map) register mapinfo map; { *KDSA5 = map[0].se_addr; *KDSD5 = map[0].se_desc; if (map[1].se_desc != NOMAP) { *KDSD6 = map[1].se_desc; *KDSA6 = map[1].se_addr; } } /* * Map in an out-of-address space buffer. * If this is done from interrupt level, * the previous map must be saved before mapin, * and restored after mapout; e.g. * segm save; * saveseg5(save); * mapin(bp); * ... * mapout(bp); * restorseg5(save); */ #ifdef UCB_NET segm Bmapsave; #endif UCB_NET caddr_t mapin(bp) register struct buf *bp; { register caddr_t paddr; register caddr_t offset; int x; #ifdef UCB_NET saveseg5(Bmapsave); #endif UCB_NET if (bp->b_flags & B_MOUNT) x = spl5(); /* keep phys addr from changing to virt addr */ offset = ((unsigned)bp->b_un.b_addr & 077); paddr = ((unsigned)bp->b_un.b_addr >> 6) & 01777; (unsigned)paddr |= ((unsigned)bp->b_xmem << 10); if (bp->b_flags & B_MAP) /* adjust the unibus virtual addr */ paddr = paddr - (BUF_UBADDR>>6) + bpaddr; if (bp->b_flags & B_MOUNT) splx(x); mapseg5(paddr, (BSIZE << 2) | RW); return(SEG5 + offset); } mapout(bp) register struct buf *bp; { #ifndef UCB_NET normalseg5(); #else UCB_NET restorseg5(Bmapsave); #endif UCB_NET }