Ultrix-3.1/sys/sys/machdep.c

Compare this file to the similar file:
Show the results in this format:


/**********************************************************************
 *   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
}