static char rcsid[] = "$Header: util.c,v 820.1 86/12/04 19:54:51 root Exp $";
static char sccsid[]="%W% %Y% %Q% %G%";

/************************************************************************
*									*
*				Copyright 1984				*
*			VALID LOGIC SYSTEMS INCORPORATED		*
*									*
*	This listing contains confidential proprietary information	*
*	which is not to be disclosed to unauthorized persons without	*
*	written consent of an officer of Valid Logic Systems 		*
*	Incorporated.							*
*									*
*	The copyright notice appearing above is included to provide	*
*	statutory protection in the event of unauthorized or 		*
*	unintentional public disclosure.				*
*									*
************************************************************************/

/*
 * History:
 * ========
 * jht 860317 -- Add code to define and subsequently use register for V_CONTEXT.
 * jht 860321 -- Board-up/document holes regarding getpagemap() returning -1;
 */

#include "../machine/reg.h"
#include "../machine/pte.h"
#include "../machine/psl.h"
#include "../machine/cpu.h"

#include "../h/param.h"
#include "../h/systm.h"
#include "../h/dir.h"
#include "../h/user.h"
#include "../h/kernel.h"
#include "../h/map.h"
#include "../h/vm.h"
#include "../h/vmmac.h"
#include "../h/proc.h"
#include "../h/buf.h"
#include "../h/reboot.h"
#include "../h/conf.h"
#include "../h/cmap.h"
#include "../h/text.h"

#include "../s32/debug.h"
#include "../s32/rpb.h"

label_t *nofault;	/* when nonzero, buserr will longjmp (see trap.c) */

#ifdef	DEBUG
extern	short	verbosity;
#endif	DEBUG

/*
 * Raise the processor to level 5 (i.e. don't spl5() if we're on level 6)
 */
rspl5()
{
	asm("	movw	sr,d0")
	asm("	cmpw	#/2500,d0")	/* at or above level 5 ? */
	asm("	bge	rspl5ok")
	asm("	movw	#/2500,sr")	/* set it to level 5 */
	asm("rspl5ok:")
}

#ifdef NEW_DS
#ifdef WHITE
#include "../white/acia.h"
short use_ds = 1;		/* use display */
#endif WHITE

cnputc (c) 
{
#ifdef WHITE
	char logchar[1];

	if (use_ds) {
		/*
	 	* No beeping because viabell() calls timeout!
	 	*/
		if (c == 7)
			goto nobeep;
		if (c == '\n')
			dsputch('\r');
		dsputch(c);
	} else {
		if (c == '\n')
			cnputc('\r');
		{
			register struct acia_device *addr = 
						(struct acia_device *)0x830F20;
			register int timo;
			int s, cmd;
	
			s = spl7();
			cmd = addr->ac_cmd;
			addr->ac_cmd |= C_DTR;
			timo = 10000;
			while ((addr->ac_stat & S_XEMP) == 0 && timo--)
				;
			addr->ac_data = c;
			addr->ac_cmd = cmd;
			splx(s);
		}
	}
nobeep:
#include "log.h"
#if NLOG > 0
	logchar[0] = c;
	log_data (logchar, 1, 1/*LOGTYPE_KERNEL*/);
#endif NLOG
#else WHITE
     extern struct uartcntl sccntl[];
     char                   logchar[1];
#    ifdef DEBUG
	long i;
#    endif
	int s;

	if (c == '\n')
		cnputc ('\r');

	s = rspl5();      /* prevent xmitter interrupts */

	SUcommand(0) = UENABLE;  /* enable xmitter first */

	while (!(SUstatus(0) & SUtxrdy))  /* wait til ready */
		;

#include "log.h"
#if NLOG > 0
	logchar[0] = c;
	log_data (logchar, 1, 1/*LOGTYPE_KERNEL*/);
#endif NLOG
	SUdata(0) = c;            /* then output */
	while (!(SUstatus(0) & SUtxrdy)) /* wait til done */
		;
	/*
	 * If the console uart is marked busy then it needs to
	 * see an interrupt.
	 */
	if (!sccntl[0].busy) 
	    /* Disable transmitter */
	    SUcommand(0) = UTRADIS;  
	splx (s);

#ifdef notdef
#define DELAY 400	/* 800 may  keep even TI from overrunning */ 
	if (debug)	/* any debugging on? */
		for (i = 0; i < DELAY; i++) 
		  ; /* do nothing but delay,
			until printer can catch up */
#endif
#endif WHITE
}


getchar() {
	int c;

#ifdef WHITE
	if (use_ds)
		c = kbgetchar();
	else {
		register struct acia_device *addr = 
					(struct acia_device *)0x830F20;
		register int timo;
		int s, cmd;

		s = spl7();
		cmd = addr->ac_cmd;
		addr->ac_cmd |= C_DTR;
		while ((addr->ac_stat & S_RRDY) == 0)
			;
		c = addr->ac_data;
		addr->ac_cmd = cmd;
		splx(s);
	}
#else WHITE
	while (!(SUstatus(0) & SUrxrdy));

	c = SUdata(0);
#endif WHITE

	if (c == '\r')
		cnputc ('\n');
	else
		cnputc (c);

	return ((c&0x7F));
}
#endif NEW_DS
/*
 * Check user's access to a virtual area
 * starting at vaddr and count bytes in
 * length.  Return 0 if the user does not
 * have access.
 *
 * SIMULATES VAX VERSION
 */
int useracc(vaddr, count, rwflag)
   long vaddr;
   long count;
   int rwflag;
{
	register struct proc *p = u.u_procp;
	register int page = vaddr / NBPG;
	register int lastpage = (vaddr+count-1) / NBPG;

	/*
	 * User only has read access to his text
	 * segment.
	 */
	if (isatsv(p, page) && isatsv(p, lastpage))
	{
		if (rwflag == B_READ)	/* Text is read only */
			return(1);
	}
	/*
	 * Read and write access is allowed within
	 * the data and stack regions.
	 */
	else if (isadsv(p, page) && isadsv(p, lastpage) ||
	         isassv(p, page) && isassv(p, lastpage))
			return(1);
#ifdef s32	/* MAPUPPER64K */
	/*
	 * The user is allowed to access the high
	 * 64K of memory for both reading and writing.
	 */
	else if ((page >> PAGE_TO_SEG_SHIFT) == nsegs(p)-1 &&
		 (lastpage >> PAGE_TO_SEG_SHIFT) == nsegs(p)-1 &&
		 (lastpage & V_VPAGENO) <= V_VPAGENO - UPAGES)
		return(1);
#endif s32	/* MAPUPPER64K */
	return(0);
}
/*
 * Check the accessability of memory to
 * the kernel.  If the address is in
 * kernel virtual memory we must check all pages
 * starting at vaddr and count bytes in
 * length since there may be holes in
 * the system map.  If it is not in kernel
 * virtual memory then the address must be
 * a valid user address so we call useracc.
 */
int kernacc(vaddr, count, rwflag)
   u_long vaddr;
   u_long count;
   int rwflag;
{
	register u_long page = vaddr / NBPG;
	register u_long lastpage = (vaddr+count-1) / NBPG;
	extern _etext, _end;

	if (lastpage < btop(K_A))
		return(1);
	if (page >= mmu_sizing[u.u_procp->p_mmuIndx].mmu_kvarea)
		return(1);
	if (rwflag == B_WRITE && page < btop(&_etext))
		return(0);
	if (lastpage <= btop((int)&_end - 1))
		return(1);
	if (page <= btop((int)&_end - 1))
		page = btop((int)&_end - 1) + 1;
	if (lastpage < usrbase)
	{
		register struct pte *pte = &Sysmap[page-KVBASE];

		while (page++ <= lastpage)
		{
			if (pte->pg_prot == PG_NOACC ||
			    rwflag == B_WRITE &&
			      pte->pg_prot != PG_KW && pte->pg_prot != PG_URKW)
				return(0);
			++pte;
		}
		return(1);
	}
	if (UPAGENUM <= page && lastpage < UPAGENUM+UPAGES)
		return(1);
	return(useracc(vaddr, count, rwflag));
 }

#if	defined(M68000) && defined(NoLonger)
/* fuword:  Fetch word from user space */

fuword(addr)
int *addr;
{
	int val;
	label_t jb, *saved_jb;

	if( addr < (int *) USRTEXT ) {
		printf("fuword: %s: bad adrs %x\n",u.u_comm,addr);
		return( -1 );
	}
	if ((char *)addr < usrtext || usrstack(u.u_procp) <= (char *)addr)
		return(-1);

	saved_jb = nofault;
	if (!setjmp(&jb))
	{
		nofault = &jb;
		val = *addr;
	}
	else val = -1;
	nofault = saved_jb;
	return(val);
}

/* fubyte:  Fetch byte from user space */

char
fubyte(addr)
char *addr;
{
	char val;
	label_t jb, *saved_jb;

	if( addr < (char *) USRTEXT ) {
		printf("fubyte: %s: bad adrs %x\n",u.u_comm,addr);
		return( -1 );
	}
	if (addr < usrtext || usrstack(u.u_procp) <= addr)
		return(-1);

	saved_jb = nofault;
	if (!setjmp(&jb))
	{
		nofault = &jb;
		val = *addr;
	}
	else val = -1;
	nofault = saved_jb;
	return(val);
}

/* suword:  Store word into user space */

suword(addr, word)
int *addr;
int word;
{
	label_t jb, *saved_jb;
	
	if( addr < (int *) USRTEXT ) {
		printf("suword: %s: bad adrs %x\n",u.u_comm,addr);
		return;
	}
	if ((char *)addr < usrtext || usrstack(u.u_procp) <= (char *)addr)
		return(-1);

	saved_jb = nofault;
	if (!setjmp(&jb))
	{
		nofault = &jb;
		*addr = word;
	}
	nofault = saved_jb;
}

/* subyte:  Store byte into user space */

subyte(addr, byte)
char *addr;
char byte;
{
	label_t jb, *saved_jb;
	
	if( addr < (char *) USRTEXT ) {
		printf("subyte: %s: bad adrs %x\n",u.u_comm,addr);
		return;
	}
	if (addr < usrtext || usrstack(u.u_procp) <= addr)
		return(-1);

	saved_jb = nofault;
	if (!setjmp(&jb))
	{
		nofault = &jb;
		*addr = byte;
	}
	nofault = saved_jb;
}
#endif	defined(M68000) && defined(NoLonger)

/* copy:  Move bytes in and out of user's address space */

copy(from, to, nbytes)
char *from, *to;
int nbytes;
{
	int val;
	label_t jb, *saved_jb;
	
	saved_jb = nofault;
	if (!setjmp(&jb))
	{
		nofault = &jb;
		blt (to, from, nbytes);
		val = 0;
	}
	else val = -1;
	nofault = saved_jb;
	return (val);
}
/*
 * Copy bytes from the user's area to the kernel
 * area.  Return 0 on success and -1 if a fault
 * occurs or the user address is not within the
 * user space.
 */
copyin(from, to, nbytes)
char *from, *to;
int nbytes;
{
	int val;
	label_t jb, *saved_jb;
	
	if (from < usrtext || usrstack(u.u_procp) < from+nbytes)
		return(EFAULT);
	saved_jb = nofault;
	if (!setjmp(&jb))
	{
		nofault = &jb;
		blt (to, from, nbytes);
		val = 0;
	}
	else val = EFAULT;
	nofault = saved_jb;
	return (val);
}
/*
 * Copy bytes to the user's area from the kernel
 * area.  Return 0 on success and -1 if a fault
 * occurs or the user address is not within the
 * user space.
 */
copyout(from, to, nbytes)
char *from, *to;
int nbytes;
{
	int val;
	label_t jb, *saved_jb;
	
	if (to < usrtext || usrstack(u.u_procp) < to+nbytes)
		return(EFAULT);
	saved_jb = nofault;
	if (!setjmp(&jb))
	{
		nofault = &jb;
		blt (to, from, nbytes);
		val = 0;
	}
	else val = EFAULT;
	nofault = saved_jb;
	return (val);
}

/*
 * Copy one page of data from user virtual
 * address to physical page.  This routine is
 * allowed to page fault so Cmap2 must get
 * saved during a context switch.
 */
copyseg(vaddr, ppage)
   register long *vaddr;	/* Must be in A5 */
   int ppage;
{
	register long *paddr = (long *)&caddr2;

	*(int *)&Cmap2 = PG_V | PG_KW | ppage;
	setsysmap(btop(paddr), &Cmap2, 1);
	bcopy(vaddr, paddr, NBPG);
	*(int *)&Cmap2 = 0;  /* Invalidate Cmap2 so resume() doesn't have
				to call setpagemap() on it */
}
/*
 * Clear a physical page of memory to
 * zeros.
 */
clearpage(ppage)
   int ppage;
{
	register long *paddr = (long *)&caddr1;
#ifdef	M68020
	register junk;
#endif	M68020

	*(int *)&Cmap1 = PG_V | PG_KW | ppage;
	setsysmap(btop(paddr), &Cmap1, 1);

#ifdef	M68020
	/*
	 * For M68020 we must do a read-probe
	 * to produce the needed IMMEDIATE bus error.
	 * Normally we could do a write-probe,
	 * as was historically done for the M68000/10.
	 */
	if (chipType == CHIPTYPE_68020)
		junk = *paddr;
#endif	M68020
	/*
	 * If we get this far -- we didn't nofault --
	 * then we can go ahead and WRITE to the memory:
	 * We know that the memory is there.
	 * We always zero memory to initialize it to a known state.
	 */
	bclear(paddr, NBPG);

	/*
	 * See if we can write and read back a
	 * specific value to determine if the
	 * memory is nominally well behaved.
	 */

	*paddr = 0x12345678;

	if (*paddr != 0x12345678)
		return (-1);		/* Failure */

	*paddr = 0;
	return (0);
}

/* copybuf:  copy one buffer's worth of data (512 bytes) */

copybuf (from, to, count)
int from, to, count;
{
	register u_short i,j, temp1, temp2, temp3, temp4;

	/* need 4 scratch segments -- might overlap page boundaries */

	temp1 = setpagemap(i=(SSEG1_VA>>pageshift), j=(to>>pageshift));
	temp2 = setpagemap(i+1, j+1);
	temp3 = setpagemap(i=(SSEG2_VA>>pageshift), j=(from>>pageshift));
	temp4 = setpagemap(i+1, j+1);
	blt (SSEG1_VA | (to&pagemask), SSEG2_VA | (from&pagemask), count);
	setpagemap(i, temp3);
	setpagemap(i+1, temp4);
	setpagemap(i=(SSEG1_VA>>pageshift), temp1);
	setpagemap(i+1, temp2);
}


/*
 * Copy exception information into u area
 */
busaddr()
{
	extern	u_short ssr;		/* System Status Register (ps)	*/
	extern	u_long	aAddr;		/* Actual fault address		*/
	extern	u_short	iReg;		/* Instruction Register 	*/
	extern	u_short	trapType;	/* T_BUSERR, T_ADDRERR, etc.	*/
	extern	u_long	errType;	/* Error Register on cpu board 	*/
#ifdef	M68000
	extern	u_short fCode;
#endif	M68000

#if	defined(M68010) && !defined(M68020)
	extern	u_short diBuf;		/* Data  Input Buffer */
	extern	u_short doBuf;		/* Data Output Buffer */
#endif	defined(M68010) && !defined(M68020)

#if	defined(M68010) || defined(M68020)
	extern	u_short effn;		/* Exception Frame Fmt #	*/
	extern	u_short ssw;		/* Special Status Word		*/
#endif	defined(M68010) || defined(M68020)

#ifdef	M68020
	extern	u_short	 iRegB;		/* Stage B Instruction Pipe	*/
	extern	u_short	 iRegC;		/* Stage C Instruction Pipe	*/
	extern	u_long	 aAddrB;	/* "B" inst-stream Addr error	*/
	extern	u_long	 aAddrC;	/* "C" inst-stream Addr error	*/
	extern	u_long	 diBuf;		/* Data  Input Buffer		*/
	extern	u_long	 doBuf;		/* Data Output Buffer		*/
	extern	u_long	eReg32;		/* Current h/w error reg	*/
#endif	M68020


	/*
	 * Common to all members
	 * of the M68000 family.
	 * The RHS's are set in s32/locore.s
	 * in the addrErr/busErr code.
	 *
	 * BUG: FPU and other exceptions will have
	 * to be handled sometime...
	 */
	u.u_ssr		= ssr;
	u.u_aAddr	= aAddr;
	u.u_iReg	= iReg;

#ifdef	LATER
	u.u_trapType	= trapType;
	u.u_errReg	= eReg32;
#endif	LATER

#ifdef	M68000
	/*
	 * M68000 only
	 */
	u.u_fCode	= fCode;
#endif	M68000

#if	defined(M68010) || defined(M68020)
	/*
	 * Common to both M68010 & M68020
	 */
	u.u_effn	= effn;
	u.u_ssw   	= ssw;
	u.u_diBuf	= diBuf;
	u.u_doBuf	= doBuf;
#endif	defined(M68010) || defined(M68020)

#ifdef	M68020
	/*
	 * Only for the M68020 processor.
	 */
	u.u_iRegB   	= iRegB;
	u.u_iRegC   	= iRegC;
	u.u_aAddrB   	= aAddrB;
	u.u_aAddrC   	= aAddrC;
#endif	M68020
}

/*
 *  The C compiler has been modified to generate a "tstl" instruction, 
 *  (the Silicon Valley Software Pascal compiler a "tstb" instruction)
 *  in the procedure prolog that touches the last location in the stack the
 *  procedure will reference.  If a fault occurs the stack needs to grow.
 *  backup() looks for this instruction and resets the pc (which would
 *  otherwise be indeterminate).
 *
 *  This routine is only applicable for the M68000/M68008.
 *  It is not used (is not necessary) on M68010 or M68020.
 */

backup()
{
	register int c;
	register unsigned short *upc = (unsigned short *)u.u_ar0[PC];

	for (c=5; --c>=0; ) if (*--upc==u.u_iReg) {
		u.u_ar0[PC]=(long)upc;
		if (030==(*upc&070) || 040==(*upc&070)) return(-1);
			/* addressing side effects unpredictable */
		return(0);
	}
	return(-1);
}

#ifdef s32
/*
 * This system call is hidden from the
 * normal user, but is used by programs to
 * set the generic signal handler address.
 */
setsighandler()
{
	struct a {
		caddr_t	handler;
	} *uap = (struct a *)u.u_ap;

	u.u_r.r_val1 = (int)u.u_sighandler;
	u.u_sighandler = uap->handler;
}
#endif s32

#ifdef INTERMEDSIG
oldsendsig(p, signo)
caddr_t p;
{
	int ps;
	register unsigned long n;

	n = u.u_ar0[SP] - 6;
	if (grow(n)) {
		ps = u.u_ar0[PS];
		subyte((caddr_t)n, (ps >> 8) & 0377);	/* high order byte of ps */
		subyte((caddr_t)n+1, ps & 0377);	/* low order byte of ps */
		suword((caddr_t)n+2, u.u_ar0[PC]);
		u.u_ar0[SP] = n;
		u.u_ar0[PS] &= ~PSL_T;
		u.u_ar0[PC] = (long)p;
		return(1);
	}
	return(0);
}

/*
 * Send an interrupt to a process.
 */
intermedsendsig(p, sig, sigmask)
	int (*p)(), sig, sigmask;
{
	register int *usp, *regs;

#ifndef s32NOSIGCOMPAT
	/*
	 * Maintain compatability with old signal
	 * stack format for now until we flush all
	 * old programs.
	 * (NOTE: 0x4EB9 is the opcode of a JSR instruction.)
	 */
	if ((fuword(p) & 0xFFFF0000) == 0x4EB90000)
		return(oldsendsig(p, sig));
#endif s32NOSIGCOMPAT
	regs = u.u_ar0;
	usp = (int *)regs[SP];
	usp -= 7;
	if ((int)usp <= (unsigned)usrstack(u.u_procp) - ctob(u.u_ssize))
		(void) grow((unsigned)usp);
	;			/* Avoid asm() label botch */
	if (!useracc((caddr_t)usp, 7*4, 1))
		goto bad;
	suword(usp++, -1);  /* Place holder for return from signal catcher */
	suword(usp++, sig);
	if (sig == SIGILL || sig == SIGFPE) {
		suword(usp++, u.u_code);
		u.u_code = 0;
	}
	else
		suword(usp++, 0);
	suword(usp++, (int)p);
	suword(usp++, regs[PC]);
	suword(usp++, regs[PS]);
	suword(usp++, regs[R0]);
	regs[SP] = (int)(usp - 7);
	regs[PS] &= ~PSL_T;
	regs[PC] = (long)p;
	/*
	 * We will now return to the user process signal
	 * handler as if it were called as follows:
	 *
	 *	(*p)(signum, code, p, pc, ps);
	 *
	 * although the return address is -1 so that the
	 * program will crash if the handler just tries
	 * an rts.
	 */
	return;

bad:
	/*
	 * Process has trashed its stack; give it an illegal
	 * instruction to halt it in its tracks.
	 */
	u.u_signal[SIGILL] = SIG_DFL;
#define mask(s)	(1<<((s)-1))
	sig = mask(SIGILL);
#undef mask(s)
	u.u_procp->p_sigignore &= ~sig;
	u.u_procp->p_sigcatch &= ~sig;
	u.u_procp->p_sigmask &= ~sig;
	psignal(u.u_procp, SIGILL);
}
#endif INTERMEDSIG
/*
 * Send an interrupt to a process.
 *
 * Stack is set up to allow sigcode stored
 * in u. to call routine, followed by chmk
 * to sigcleanup() routine below.  After sigcleanup()
 * resets the signal mask and the stack, it
 * returns to user who then unwinds with the
 * rei at the bottom of sigcode.
 */
#if	1 && defined(DEBUG) && defined(U_SIGHANDLER)
short	sigHandlerBlab = 0;	/* 1==> enable u_sighandler fixup blab */
#endif	1 && defined(DEBUG) && defined(U_SIGHANDLER)

sendsig(p, sig, sigmask)
	int (*p)(), sig, sigmask;
{
	register struct sigcontext *scp;	/* know to be r11 */
	register int *regs;
	register struct sigframe {
		int	sf_signum;
		int	sf_code;
		struct	sigcontext *sf_scp;
		int	(*sf_handler)();
		struct	sigcontext *sf_scpcopy;
	} *fp;
	int oonstack;

#ifdef INTERMEDSIG
	if (u.u_procp->p_flag & SOUSIG) {
		intermedsendsig(p, sig, sigmask);
		return;
	}
#endif INTERMEDSIG
	regs = u.u_ar0;
	oonstack = u.u_onstack;

	/*
	 * Denote space for the sigframe on the user's stack.
	 */
	scp = (struct sigcontext *)regs[SP] - 1;
#define	mask(s)	(1<<((s)-1))
	if (!u.u_onstack && (u.u_sigonstack & mask(sig))) {
		fp = (struct sigframe *)u.u_sigsp - 1;
		u.u_onstack = 1;
	} else
		fp = (struct sigframe *)scp - 1;
	/*
	 * Must build signal handler context on stack to be returned to
	 * so that rei instruction in sigcode will pop ps and pc
	 * off correct stack.  The remainder of the signal state
	 * used in calling the handler must be placed on the stack
	 * on which the handler is to operate so that the calls
	 * in sigcode will save the registers and such correctly.
	 */
	if (!oonstack && (int)fp <= (int)usrstack(u.u_procp) - (int)ctob(u.u_ssize)) 
		grow((unsigned)fp);
	;
	if (!useracc((caddr_t)fp, sizeof (struct sigframe), 1))
		goto bad;
	if (!u.u_onstack && (int)scp <= (int)usrstack(u.u_procp) - (int)ctob(u.u_ssize))
		grow((unsigned)scp);
	;			/* Avoid asm() label botch */
	if (!useracc((caddr_t)scp, sizeof (struct sigcontext), 1))
		goto bad;
	suword((caddr_t)&fp->sf_signum, sig);
	if (sig == SIGILL || sig == SIGFPE) {
		suword((caddr_t)&fp->sf_code, u.u_code);
		u.u_code = 0;
	} else
		suword((caddr_t)&fp->sf_code, 0);
	suword((caddr_t)&fp->sf_scp, scp);
	suword((caddr_t)&fp->sf_handler, p);
	/*
	 * Duplicate the pointer to the sigcontext structure.
	 * This one doesn't get popped by the ret, and is used 
	 * by sigcleanup to reset the signal state on inward return.
	 */
	suword((caddr_t)&fp->sf_scpcopy, scp);
	/* sigcontext goes on previous stack */
	suword((caddr_t)&scp->sc_onstack, oonstack);
	suword((caddr_t)&scp->sc_mask, sigmask);
	/* setup rei */
	suword((caddr_t)&scp->sc_sp, (int)&scp->sc_pc);
	suword((caddr_t)&scp->sc_pc, regs[PC]);
	suword((caddr_t)&scp->sc_ps, regs[PS]);
#ifdef s32
	regs[SP] = (int)fp;
	regs[PS] &= ~PSL_T;		/* BUG this may not be right */

#ifdef	U_SIGHANDLER	/* jht 851104 */
	/*
	 * u_sighandler!=0 most of the time.
	 * Perhaps this is really a libc.a problem?
	 */
	regs[PC] = (int)	u.u_sighandler
			? (int) u.u_sighandler
			/*
			 * If the (int *p)() handler is bogus,
			 * we'll just let the user take his lumps.
			 */
#if	0 && defined(DEBUG)
			: sigHandlerBlab
				? printf("u_sighandler==0 Subsituted 0x%X\n",p),
				  (int) p
				: (int) p
					? (int) p
					: (u.u_error=EINVAL), (int) p;
#else	0 && defined(DEBUG)
			: (int) p
				? (int) p
				: (u.u_error=EINVAL), (int) p;
#endif	0 && defined(DEBUG)
#else	U_SIGHANDLER	/* jht 851104 */

	/*
	 * This breaks with Valid's LED application:
	 *	C^ && u_sighandler==0
	 *
	 *	when 4.1c/libc object programs are run
	 *	with 4.2/kernel with INTERMEDSIG turned off.
	 *
	 * The symptoms are a little bizarre:
	 * Since both the 68010 and 68020 prefetch instructions,
	 * the PC @ the time of fault is of the RTE+2
	 * which reloaded the nano-state of the 680xx.
	 *
	 * However the exception frame reloaded via the RTE
	 * "contains" a PC==0, which causes a read fetch
	 * from 0 as the "real" access-address error (aAddr).
	 *
	 * We intercept PC==0 here (and set u_error=EINVAL) rather
	 * than confuse the issue by letting it bash
	 * into the interrupt vector table.
	 */
	regs[PC] = (int)u.u_sighandler;
#endif	U_SIGHANDLER	/* jht 851104 */
#else s32
	regs[SP] = (int)fp;
	regs[PS] &= ~PSL_T;
	regs[PC] = (int)u.u_pcb.pcb_sigc;
#endif s32
	return;

asm("bad:");
bad:
	/*
	 * Process has trashed its stack; give it an illegal
	 * instruction to halt it in its tracks.
	 */
	u.u_signal[SIGILL] = SIG_DFL;
	sig = mask(SIGILL);
	u.u_procp->p_sigignore &= ~sig;
	u.u_procp->p_sigcatch &= ~sig;
	u.u_procp->p_sigmask &= ~sig;
	psignal(u.u_procp, SIGILL);
}
/*
 * Routine to cleanup state after a signal
 * has been taken.  Reset signal mask and
 * stack state from context left by sendsig (above).
 * Pop these values in preparation for rei which
 * follows return from this routine.
 */
sigcleanup()
{
	register struct sigcontext *scp;

#ifdef s32
	/*
	 * Get the return value from the 'fault' handler
	 * in /usr/src/libc/s32/sys/sigvec.c
	 */
	u.u_ar0[R0] = fuword((caddr_t)(int)u.u_ar0[SP]);
	u.u_ar0[SP] += sizeof(int);	/* Pop the D0 from the user's stack */
#endif s32
	scp = (struct sigcontext *)fuword((caddr_t)u.u_ar0[SP]);
	if ((int)scp == -1)
		return;
	if (!useracc((caddr_t)scp, sizeof (*scp), 0))
		return;
	u.u_onstack = scp->sc_onstack & 01;
	u.u_procp->p_sigmask =
	    scp->sc_mask &~ (mask(SIGKILL)|mask(SIGCONT)|mask(SIGSTOP));
#ifdef s32
	u.u_ar0[SP] = scp->sc_sp + sizeof(scp->sc_pc) + sizeof(scp->sc_ps);
	u.u_ar0[PC] = scp->sc_pc;
	u.u_ar0[PS] = scp->sc_ps & ~PSL_USERCLR;
#else s32
	u.u_ar0[SP] = scp->sc_sp;
#endif s32
}
#undef mask

#ifdef INTERMEDSIG
/*
 * Simulate a return from interrupt by popping
 * off all of the junk that sendsig() put on
 * the stack:
 *
 *	SP  ->  (low)  xx, xx, xx, -1, signum, code, xx, PC, PS, D0  (high)
 *
 * Note that all registers but D0 must be intact
 * at this point.
 */
dorti()
{
	register int *regs = u.u_ar0;
	register int *usp = (int *)regs[SP];

	usp += 7;
	regs[PC] = fuword(usp++);
	regs[PS] = fuword(usp++) & ~0x2700;	/* Make sure he doesn't try
						   to be tricky */
	regs[R0] = fuword(usp++);
	regs[SP] = (int)usp;
}
#endif INTERMEDSIG

/*ksendsig(p,khand)
/*register struct proc *p;
/*register int (*khand)();
/*{
/*#define KSP 11
/*#define KPC 12
/*	register struct user *up;
/*	register caddr_t *ksp;
/*	if (p==u.u_procp) panic("ksendsig");
/*	mSSEG1(p->p_addr); up=(struct user *)SSEG1_VA; ksp=up->u_rsav[KSP];
/*	*--ksp=up->u_rsav[KPC];
/*	up->u_rsav[KPC]=khand;
/*	up->u_rsav[KSP]=ksp;
/*	setrq(u.u_procp);
/*	resume(p->p_addr);
/*}
*/
#ifdef SUPROC
/*
 * Return the "index register" value for the indexed addressing modes.
 */
long
idxval( xwrd )
register short xwrd;
{
	register long *xbase, xdisp;
	register xreg;
	register char xc;
	register short xs;

	if( xwrd & 0x8000 )
		xbase = &((long) u.u_ar0[AR0]);	/* address, */
	else
		xbase = &((long) u.u_ar0[R0]);	/*  or data register? */

	xreg = (xwrd & 0x7000) >> 12;		/* get register no. */
	xc = xwrd;				/* to sign extend */

	if( xwrd & 0x0800 )			/* "long" index ? */
		xdisp = xbase[xreg];
	else {
		xs = xbase[xreg];
		xdisp = xs;
	}
	return( xdisp + xc );
}

/*
 * De-reference the effective address in an instruction.
 *  (asuming the instruction is of the form op|ae where ea is the 6 bit
 *  mode | register.
 */
#define	DREGD		0x0
#define AREGD		0x1
#define AREGI		0x2
#define AREGI_INC	0x3
#define AREGI_DEC	0x4
#define AREGI_D		0x5
#define AREGI_I		0x6
#define SPEC		0x7

#define ABS_W		0x0
#define ABS_L		0x1
#define PC_D		0x2
#define PC_I		0x3
#define IMMED		0x4

long
deref( pcp, size )
short **pcp;
{
	register short *ip = *pcp;
	short mode, ea;
	register long *obase, opadrs;

	mode = (*ip >> 3) & 0x07;
	ea = *ip & 0x07;
	ip++;

	/*
	 * Get the "base" address for the operand.
	 */
	switch( mode ) {
	case DREGD:
		obase = &((long)u.u_ar0[R0]);
		break;

	case AREGD:
	case AREGI:
	case AREGI_INC:
	case AREGI_DEC:
	case AREGI_D:
	case AREGI_I:
		obase = &((long)u.u_ar0[AR0]);
		break;

	case SPEC:
		obase = (long *)ip;
		break;

	}

	/*
	 *
	 */

	switch( mode ) {
	case DREGD:
	case AREGD:
		opadrs = (long) &obase[ea];
		opadrs += 4 - size;
		break;

	case AREGI_DEC:
		obase[ea] -= size;
	case AREGI:
		opadrs = obase[ea];
		break;

	case AREGI_INC:
		opadrs = obase[ea];
		obase[ea] += size;
		break;

	case AREGI_D:
		opadrs = obase[ea] + *ip++;
		break;

	case AREGI_I:
		opadrs = obase[ea] + idxval( *ip++ );
		break;

	case SPEC:
		switch( ea ) {
		case ABS_W:
			opadrs = *ip++;
			break;

		case ABS_L:
			opadrs = *obase;
			ip += 2;
			break;

		case PC_D:
			opadrs = (long)ip + *ip++;
			break;

		case PC_I:
			opadrs = (long)ip + idxval( *ip++ );
			break;

		case IMMED:
			opadrs = (long) ip++;
			if( size == 4 )
				ip++;
			break;
		}
		break;
	}

	*pcp = ip;
	return( opadrs );
}
#endif		/* of ifdef SUPROC */

#ifdef DEBUG
/*
 * Print a portion of the supervisor stack from beg to end.
 */	

printstack()
{
	register char *i;
	long * stkMark;
	register long j;

	/*
	 * Determine WHICH stack we are using.
	 * Look for our local &stkMark less than the first
	 * stack frame that might be in use.
	 * NOTE:  We presume TMPSTACK < DUMMYU_PA < U_PAGE
	 */
	if ((long *) &stkMark < (long *) TMPSTACK)/* Used for context switches*/
	    stkMark = (long *) TMPSTACK;	/* Initial stack */

	else if ((long *) &stkMark < (long *) DUMMYU_PA)	
	    stkMark = (long *) DUMMYU_PA;	/* Stack in dummy upage */

	else if ((long *) &stkMark < (long *) U_PAGE)	
	    stkMark = (long *) U_PAGE;		/* Stack in the nominal upage */

	for (i = (char *) ((int) &stkMark & 0xFFFFFFF0); i < (char *) stkMark; )
	{
	    /*
	     * Print one line of the hex-dump
	     */
	    printf("\n%-06x: ",i);
	    for (j = 0; j < 32; j++,i++)
	    {
		if (j && j%4 == 0)
		    printf(" ");
		if (((int) *i & 0xFF) < 0x10 )
		    printf("0%x",(int) *i  & 0xFF);	/* 0-fill the nibble */
		else
		    printf("%x", (int) *i  & 0xFF);
            }
	    if ((((u_long) i) % 0x100) == 0)
		printf("\n");
	}
	printf("\n");
}
#endif

/*
 * Put a process on the head of the run queue.
 * The queue is doubly linked with the first
 * entry pointing backward at runq itself and
 * the last entry pointing forward at NULL.
 *
 * NOTE: must be called at spl6() with p->p_stat == SRUN
 */
setrq(p)
   register struct proc *p;
{
	if (p->p_rlink != NULL)
		panic("setrq");		/* Firewall */
	if (runq != NULL)
		runq->p_rlink = p;
	p->p_link = runq;
	p->p_rlink = (struct proc *)&runq;
	runq = p;
}
/*
 * Remove a process from the run queue.
 *
 * NOTE: must be called at spl6().
 */
remrq(p)
   register struct proc *p;
{
	if (p->p_rlink == NULL)
		panic("remrq");
	if (p->p_rlink == (struct proc *)&runq)
		runq = p->p_link;
	else
		p->p_rlink->p_link = p->p_link;
	if (p->p_link != NULL)
		p->p_link->p_rlink = p->p_rlink;
	p->p_rlink = 0;		/* Firewall */
}

int noproc;
/*
 * This routine is called to reschedule the CPU.
 * if the calling process is not in RUN state,
 * arrangements for it to restart must have
 * been made elsewhere, usually by calling via sleep.
 * There is a race here. A process may become
 * ready after it has been examined.
 * In this case, idle() will be called and
 * will return in at most 1HZ time.
 * i.e. it's not worth putting an spl() in.
 */
swtch()
{
	register n;
	register struct proc *p, *pp;
	int s = rpl();		/* save current priority level for resumesr() */

	noproc=1;
loop:
	spl6();
	runrun = 0;
	/*
	 * Search for highest-priority runnable process
	 */
	pp = NULL;
	n = 128;
	for(p=runq; p!=NULL; p=p->p_link)
		if (p->p_pri < n && p->p_stat != SZOMB) {
			pp = p;
			n = p->p_pri;
		}
	/*
	 * If no process is runnable, idle.
	 */
	if ((p=pp)==NULL) {
		idle();
		goto loop;
	}
	remrq(p);
	noproc = 0;
	if (p->p_wchan || p->p_stat != SRUN)	/* Firewall */
		panic("swtch");
	++cnt.v_swtch;
	DODEBUG(D_RUN,("r%d ", p->p_pid));
#ifdef s32
	if (p == u.u_procp) {
		splx(s);
		return;		/* It is easy to resume ourselves */
	}
#endif s32
	resumesr(p->p_addr, s);
}

int	waittime = -1;

boot(paniced, arghowto)
	int paniced, arghowto;
{
	register int howto;		/* r11 == how to boot */
	register int devtype;		/* r10 == major of root dev */

#ifdef lint
	howto = 0; devtype = 0;
	printf("howto %d, devtype %d\n", arghowto, devtype);
#endif
	(void) spl1();
	howto = arghowto;
	if ((howto&RB_NOSYNC)==0 && waittime < 0 && bfreelist[0].b_forw) {
		waittime = 0;
		update();
		printf("syncing disks... ");
#ifdef notdef
		{ register struct buf *bp;
		  int iter, nbusy;

		  for (iter = 0; iter < 10; iter++) {
			nbusy = 0;
			for (bp = &buf[nbuf]; --bp >= buf; )
				if (bp->b_flags & B_BUSY)
					nbusy++;
			if (nbusy == 0)
				break;
			printf("%d ", nbusy);
		  }
		}
#else
		DELAY(10000000);
#endif
		printf("done\n");
	}
	spl7();				/* as high as we can go */
	devtype = major(rootdev);
	if (howto&RB_HALT) {
		DELAY(1000000);
		reset(1);
	} else {
		if (paniced == RB_PANIC) {
			printf("Doing a dump...\n");
			doadump();	/* boots itself */
			/*NOTREACHED*/
		}
		printf("Can't do boots yet ... ");
		DELAY(1000000);
		reset(0);
	}
	printf("Halting ... ");
	DELAY(1000000);
	reset(0);
}

int	dumpmag = 0x8fca0101;	/* magic number for savecore */
int	dumpsize = 0;		/* also for savecore */
/*
 * Doadump comes here after turning off memory management and
 * getting on the dump stack, either when called above, or by
 * the auto-restart code.
 */
dumpsys()
{

	rpb.rp_flag = 1;
	if ((minor(dumpdev)&07) != 1)
		return;
	dumpsize = physmem;
	printf("\ndumping to dev %x, offset %d\n", dumpdev, dumplo);
	printf("dump ");
	switch ((*bdevsw[major(dumpdev)].d_dump)(dumpdev)) {

	case ENXIO:
		printf("device bad\n");
		break;

	case EFAULT:
		printf("device not ready\n");
		break;

	case EINVAL:
		printf("area improper\n");
		break;

	case EIO:
		printf("i/o error");
		break;

	default:
		printf("succeeded");
		break;
	}
}

#ifdef notdef
microtime(tvp)
	struct timeval *tvp;
{
	int s = spl7();

	tvp->tv_sec = time.tv_sec;
	tvp->tv_usec = (lbolt+1)*16667 + mfpr(ICR);
	while (tvp->tv_usec > 1000000) {
		tvp->tv_sec++;
		tvp->tv_usec -= 1000000;
	}
	splx(s);
}
#endif

physstrat(bp, strat, prio)
	struct buf *bp;
	int (*strat)(), prio;
{
	int s;

	physiomap(bp, strat);
	/* pageout daemon doesn't wait for pushed pages */
	if (bp->b_flags & B_DIRTY)
		return;
	s = spl6();
	while ((bp->b_flags & B_DONE) == 0)
		sleep((caddr_t)bp, prio);
	splx(s);
}

/*
 * Here to break up a single virtual request
 * into several physical requests.
 *
 * Called only from physstrat(), should probably be part of it.
 */
physiomap(bp, strat)
   register struct buf *bp;
   int (*strat)();
{
	register u_long a = (long)bp->b_adrs;
	register u_long bleft = bp->b_bcount;
	register u_long bno = bp->b_blkno;
	register struct buf *pbp;
	register u_long c;
	struct proc *p;
	extern caddr_t pvtop();

	p = bp->b_flags&B_DIRTY ? &proc[2] : bp->b_proc;

	/*
	 * If B_PARTIAL, iodone() counts # of partials in bp->b_error.
	 * When the count of partials goes to zero, the whole operation
	 * is complete.  We issue partial requests as we discover
	 * contiguous pieces, so we must insure that the count goes
	 * to zero only when all partials have been issued.  Thus
	 * we inflate b_error at the beginning and deflate it as we go,
	 * insuring that it can never get to zero until after we have
	 * issued the last partial request.
	 */
	/*
	 * We translate the transfer into sub-transfer(s) which
	 * have the B_PARTIAL bit set and which also have the
	 * following attributes:
	 *	they span only physically contiguous memory,
	 *	they do not cross megabyte boundaries,
	 *	they are not more than MAXPHYS bytes in length.
	 *
	 * We use bp->b_error in the original buffer header to
	 * keep the count of the number of partial buffer headers
	 * being used for sub-transfers; biodone() decrements
	 * bp->b_error until it reaches zero, implying that the
	 * last sub-transfer is complete.
	 *
	 * U page and page table transfers must be done one
	 * page at a time so we initially set the count to
	 * the number of bytes left in the current page for
	 * those transfers.
	 */

	/* If B_UAREA, then b_adrs is a relative address in the u
	 * structure.  In that case, we turn it back into an absolute
	 * virtual address within the u structure and let vtop map it.
	 */

	if (bp->b_flags&B_UAREA)
		a += (u_long)&u;

	/*
	 * If it is a U area or page table swap, then do it
	 * one page at a time; the first time, swapping from
	 * the starting address to the next page boundary.
	 */
	if (bp->b_flags&(B_UAREA|B_PAGET))
		c = NBPG - (a & pagemask);
	else
		c = lenpcont(a, bleft, p);

	bp->b_resid = 0;
	bp->b_error = 1;
	while (bleft > 0) {
		extern struct buf *getphdr();

		if (c > bleft)
			c = bleft;
		pbp = getphdr(0);
		pbp->av_forw = NULL;
		pbp->av_back = bp; /* iodone() knows which b_bcount */
		pbp->b_flags = (bp->b_flags|(B_PHYS|B_PARTIAL)) &~
					     (B_DIRTY|B_UAREA|B_PAGET);
		pbp->b_proc = bp->b_proc;
		pbp->b_dev = bp->b_dev;
		pbp->b_resid = 0;
		pbp->b_bcount = c;
		pbp->b_blkno = bno;
		if (bp->b_flags&B_PAGET) {
			struct pte *pte = &Usrptmap[btokmx((struct pte *)a)];

			if (pte->pg_v == 0)
				panic("physiomap: PAGET");
			pbp->b_adrs = (caddr_t)
					((pte->pg_pfnum << pageshift) +
					(a & pagemask));
		} else
			pbp->b_adrs = pvtop(p, a);
		if (pbp->b_adrs == (caddr_t)-1)
			panic("iomap: vtop");
		a += c;
		/* BUG should that be (c+DEV_BMASK) instead of c? */
		bno += c >> DEV_BSHIFT;
		if ((bleft -= c) > 0) {
			++bp->b_error;
			if (bp->b_flags & (B_UAREA|B_PAGET))
				c = NBPG;
			else
				c = lenpcont(a, bleft, p);
		}
		(*strat)(pbp);
	}
}

/*
 * NOTE: pvtop() returns (-1) as an error indicator -- callers beware!
 */
caddr_t
pvtop(p,virt)	/* virtual to physical address translation */
struct proc *p;
long virt;
{
	register u_int ppage, page = virt >> pageshift;
#ifdef	BSDBUGFIX
	register struct pte	*pte;;
#endif	BSDBUGFIX

	/*
	 * Within user txt, data and stack
	 */
	if (usrbase <= page && page < usrtop(p))
#ifndef	BSDBUGFIX
		ppage = vtopte(p,page)->pg_pfnum;
#else	BSDBUGFIX
		ppage = (((int)(pte=vtopte(p,page)) > NULL)
			   ? pte
			   : (struct pte *) panic("pvtop/E-0: vtopte invalid")
			) ->pg_pfnum;
#endif	BSDBUGFIX
	/*
	 * Within upages
	 */
	else if (btop(&u) <= page && page < btop(&u) + UPAGES)
		if (p == NULL)
			ppage = getpagemap(page) & V_PAGEMASK; /*Can retun -1 */
		else {
#ifdef	COMPILERBUG
			struct pte upage_pte[UPAGES];

			bcopy (p->p_addr, upage_pte,UPAGES * sizeof *p->p_addr);	
			ppage = upage_pte[page - btop(&u)].pg_pfnum;
#else	COMPILERBUG
			ppage = p->p_addr[page - btop(&u)].pg_pfnum;
#endif	COMPILERBUG
		}
	/*
	 * "Outside" the userbase...usrtop range
	 */
	else if (page < usrbase || usrtop(p) <= page)
		ppage = getpagemap(page) & V_PAGEMASK;
#ifdef s32	/* MAPUPPER64K */
	/*
	 * In the topmost segment
	 * of the address space
	 */
	else if ((page >> PAGE_TO_SEG_SHIFT) == nsegs(p)-1)
		ppage = vtopte(p, page)->pg_pfnum;
#endif s32	/* MAPUPPER64K */
	else
		return((caddr_t)-1);

	return((caddr_t)((ppage << pageshift) | (virt & pagemask)));
}

caddr_t
vtop(virt)	/* virtual to physical address translation */
long virt;
{
	return(pvtop(u.u_procp, virt));
}

#ifdef	s32	/* INIT_CACHE */
#ifdef	M68020

extern	short	disMbCmds;			/* Disable multibus commands */

long		cacheSize = CACHE_SIZE_BYTES;	/* Onboard cache	      */
u_long		cacheClearCount;		/* initCache() invocation cnt */
extern	short	enableOnBoardCache;		/* 1==>enable; 0==> disable   */

#ifdef	DEBUG
extern	short	verbosity;
#endif	DEBUG

/*
 * initCache  --  Initialize the onboard cache
 *		  for Valid's dual-card Multibus 68020 cpu boardset.
 *
 * Returns:
 *	 0 ==>	OK, all is well and initialized;
 *	 1 ==>	No initialization:
 *			Not a M68020 cpu;
 *			Or not 'enableOnBoardCache';
 *	-1 ==>	Severe problem.
 *
 * panic:
 *	Iff scratch-segments are insufficient
 *	to provide a simultaneous cover of the cache.
 *
 * NOTE:  A complication to the task is that the instructions
 *	  that we will fetch to do the work MUST also not come
 *	  from the being-initialized cache.
 *
 *	  This is an M68020-ONLY routine!
 */
initCache()	/* Invalidate the entire onboard cache: sweep into bit bucket */
{
/*A5*/	register caddr_t	lp;			/* Ptr to a long  */
/*A4*/	register u_short      * R_V_STATUS1 = (u_short *)STATUS1_HW_ADDR;
/*A3*/	register short        * disMbCmdsV = (short *)disMbCmds; /* LIE!! */
/*D7*/	register int		pageShift = pageshift;	/* Reg. copy	*/
/*D6*/	register int		pno;			/* Page #	*/
/*D5*/	register int		cacheEndPno;		/* Reg. copy	*/
/*D4*/	register int		ssegEndPno;		/* Reg. copy	*/
/*D3*/	register u_short	oldHwPte;		/* Prior entry	*/
	int			pageNo;
	int			i;
	int			count;
	extern	short		enableOnBoardCache;
	int			oldMaxPage = maxpage;


	if (chipType!=CHIPTYPE_68020 || !enableOnBoardCache)
		return 1;		/* Say we did not init the cache */

	cacheClearCount++;		/* Statistics */

	/*
	 * Scratch "segments" MUST span the onboard cache.
	 * These are NOT 64k-byte segments associated
	 * with the mmu architecture.
	 */
	if (cacheSize > ((SSEG2_VA-SSEG1_VA) << 1)) {
		panic("initCache/E-0: Scratch swatches too small to span onboard cache");
	}

	/*
	 * Upper boundaries for the initialization.
	 */
	cacheEndPno	= (SSEG1_VA  >> pageshift)
			+ (cacheSize >> pageshift);

	ssegEndPno	= (SSEG2_VA + (SSEG2_VA-SSEG1_VA)) >> pageshift;

	/*
	 * To guarantee the correct execution
	 * of this function, we map these pages
	 * of kernal instructions as non-cached.
	 *
	 * That way, there is no chance
	 * of the instructions being inadvertantly fetched
	 * from the cache
	 * when we enable it.
	 *
	 * NOTE: There is no collision between the addresses
	 * of this routine and the range of virtual addresses
	 * being used to sweep the cache.
	 *
	 * NOTE: The only exceptions could be references to TMPSTACK
	 * made in some of the debugging code -- e.g., printf()
	 * or any use made of the cdebugger!
	 *
	 * Flag the pages as noncached.
	 */
	count	= 3;				/* Insure bracketing	    */
	pageNo	= btoc(initCache) - 1;		/* Page prior to origin	    */
	maxpage	= pageNo + count;		/* KLUDGE: For setpagemap() */

	for (i=1; i<= count; i++, pageNo++) {
		/*
		 * NOTE:  Since we are doing this
		 * so damn early during bringup, 
		 * the s/w page map entry is not filled in!
		 */
		setpagemap(pageNo, V_NONCACHED | pageNo);
	}

	if (verbosity >= 9)
		printf("initCache/I-0: getStatusReg = 0x%x\n", getStatusReg(0));

	/*
	 * Ascend up through the pages spanning
	 * the onboard cache...
	 *
	 * Remain within cache AND the scratch segments.
	 * We presume two equal sized, contigous scratch segment,
	 * the cumulative span of which is sufficient to span the cache.
	 * BUG: when the cachSize > 16k, we will have to rewrite this!
	 */
	for (pno = (SSEG1_VA >> pageShift);
	     pno <  ssegEndPno &&	/* Scratch segments' addressibility. */
	     pno < cacheEndPno;		/* Where the onboard cache ends	     */
	     pno++)
	{

		/*
		 * Map in a scratch hunk of real memory,
		 * GUARANTEED not to collide with any part of the kernel.
		 *
		 * As long as we write before we read,
		 * we can fetch things from multibus memory,
		 * namely the stack.  Everything else is
		 * retained in the processor's registers.
		 */
		if (verbosity >= 9)
			printf("initCache/I-2: setpagemap(0x%x, 0x%x) = ",
				pno, V_MBMEM | pno);

		oldHwPte = setpagemap(pno, V_MBMEM | pno);

		if (verbosity >= 9)
			printf("0x%x\n", oldHwPte);

		/*
		 * Enable the onboard cache hardware
		 */

		*R_V_STATUS1 |= (u_short)(S1_CACHE_EN_STATUS);/* Same as above*/

#if 0
		/*
		 * NOTE:  This swatch of debugging code violates
		 * the non-cached constraints for this routine.
		 * It also depends upon chipType being properly set.
		 */
		if (verbosity >= 9)
			printf("initCache/I-1: getStatusReg = 0x%x\n",
				getStatusReg(0));
#endif 0
		/*
		 * Punch out the current page,
		 * starting from the TOP of each page.
		 *
		 * NOTE:  'lp' MUST be register A5!
		 */
		for (	   lp = (caddr_t) ((pno+1) << pageShift); /* Page top */
		     (int) lp > (int)      (pno    << pageShift); /* Page bot */
		    /*
		     * NOTE:  'lp' is self decrementing in the asm() code
		     */
		    )
		{		/* 16 regs' worth, 16 whacks at a time */

			if (disMbCmdsV)	/* LIE: Value masquerading as a ptr! */
			   /*
			    * NOTE: There is no reason to actually write
			    * the bytes through the cache, out
			    * to the multibus memory.
			    * Simply writing them into the cache is sufficient.
			    */

			   *R_V_STATUS1 |= S1_DIS_MB_CMDS; /* Swing free */
#ifdef	COMPILERBUG
			else	1;	/* Dummy else-clause to fixup branch */
#endif	COMPILERBUG

			/*
			 * Write all the registers (through the cache)
			 * to a page of multibus memory.
			 *
			 * However, since we have turned off the Multibus,
			 * this effectively write-sweeps the cache
			 * into a bitbucket.
			 *
			 * NOTE:  For efficiency, we push 16 sets of 16 regs.
			 */
			asm("	moveml	#0xFFFF,a5@-	| 0: Push 16 regs");
			asm("	moveml	#0xFFFF,a5@-	| 1:		 ");
			asm("	moveml	#0xFFFF,a5@-	| 2:		 ");
			asm("	moveml	#0xFFFF,a5@-	| 3:		 ");

			asm("	moveml	#0xFFFF,a5@-	| 4:		 ");
			asm("	moveml	#0xFFFF,a5@-	| 5:		 ");
			asm("	moveml	#0xFFFF,a5@-	| 6:		 ");
			asm("	moveml	#0xFFFF,a5@-	| 7:		 ");


			asm("	moveml	#0xFFFF,a5@-	| 8:		 ");
			asm("	moveml	#0xFFFF,a5@-	| 9:		 ");
			asm("	moveml	#0xFFFF,a5@-	| A:		 ");
			asm("	moveml	#0xFFFF,a5@-	| B:		 ");

			asm("	moveml	#0xFFFF,a5@-	| C:		 ");
			asm("	moveml	#0xFFFF,a5@-	| D:		 ");
			asm("	moveml	#0xFFFF,a5@-	| E:		 ");
			asm("	moveml	#0xFFFF,a5@-	| F:		 ");

			/*
			 * Re-enable multibus access!
			 */
			if (disMbCmdsV)	/* LIE: Value masquerading as a ptr! */
			   *R_V_STATUS1 &= (u_short) ~S1_DIS_MB_CMDS;
		}

		/*
		 * Disable the onboard cache hardware.
		 * 
		 * NOTE: The only problem that we could have here
		 * would be that we change something in Multibus memory
		 * which is also still (erroneously "valid") in the cache.
		 *
		 * Since the scratch-segs are DISJOINT from alles anderes,
		 * we should be safe, although the blast door has
		 * some thin spots.
		 */

		*R_V_STATUS1 &= (u_short)(~S1_CACHE_EN_STATUS);/*Same as above*/

		if (verbosity >= 9)
			printf("initCache/I-1: getStatusReg = 0x%x\n",
				getStatusReg(0));

		if (verbosity >= 9)
			printf("initCache/I-3: setpagemap(0x%x, 0x%x)\n",
				pno, oldHwPte);
		(void)setpagemap(pno, oldHwPte); /* Restore prior map entry */
	}

	/*
	 * Re-enable the onboard cache hardware
	 */

	*R_V_STATUS1 |= (u_short)(S1_CACHE_EN_STATUS);

	/*
	 * Re-map these pages of kernal instructions
	 * as cacheable multibus memory.
	 */
	pageNo	= btoc(initCache) - 1;		/* Page prior to origin	      */

	for (i=1; i<= count; i++, pageNo++) {
		setpagemap(pageNo, V_MBMEM | pageNo);
	}

	maxpage = oldMaxPage;
	return 0;		/* Say all is well */
}

 caddr_t
ptov(p, phys)	/* Physical to virtual address translation */
	struct proc *p;
	long phys;
{
#if 0
	return(pvtop(u.u_procp, virt));
#endif
}
#endif	M68020
#endif	s32	/* INIT_CACHE */

/*
 * return length of physically contiguous memory starting at addr.
 * Note that we consider crossing MAXPHYS boundary as not contiguous.
 */
lenpcont(addr,nbyte,p)
	unsigned long addr;
	long nbyte;
	struct proc *p;
{
	register u_int p0;
	register struct pte *pte;
	register int i,run;
	register int page = addr >> pageshift;

	/*
	 * Kernel virtual address
	 */
	if (page < usrbase || usrtop(p) <= page)
	{
		p0 = getpagemap(page) & V_PAGEMASK; /* Can retun (u_short) -1 */
		i = addr&pagemask; run = -i;
		for (i = (i+nbyte-1)>>pageshift; run += pagesize, --i>=0; )
			if (++p0 != (getpagemap(++page) & V_PAGEMASK) ||
			   (p0 & btoc(MAXPHYS)-1) == 0)
				break;
	}
	/*
	 * User virtual address or UPAGE virtual address
	 */
	else
	{
		if (btop(&u) <= page && page < btop(&u) + UPAGES)
			pte = &p->p_addr[page - btop(&u)];
		else
			pte = vtopte(p,addr >> pageshift);
		p0 = pte->pg_pfnum;
		i = addr&pagemask; run = -i;
		for (i = (i+nbyte-1)>>pageshift; run += pagesize, --i>=0; )
			if (++p0 != (++pte)->pg_pfnum ||
			   (p0 & btoc(MAXPHYS)-1) == 0)
				break;
	}
	return(run);
}

/*
 * Make nbyte bytes at virtual address addr physically contiguous
 * Also lock the pages involved.
 */
makpcont(addr,nbyte)
	register u_long addr;
	register long nbyte;
{
	register struct proc *p = u.u_procp;
	register int pages = btop(addr+nbyte-1) - btop(addr) + 1;
	register struct pte *newpte;
	struct buf *bp;
	int type = vtotype(p, btop(addr)/CLSIZE);
	int s;

	for (;;) {
		p->p_flag |= SPHYSIO;
		vslock(addr, nbyte);
		if (nbyte <= lenpcont(addr, nbyte, p)) return(0);
#ifdef s32 /* LOCKPAGES */
		/*
		 * Make sure that we are not trying to move
		 * any pages that the user has locked in
		 * virtual memory.  Return -1 to the caller
		 * indicating an error condition if at
		 * least one page in the range is locked.
		 */
		{
			register int count = pages;
			register struct pte *upte = vtopte(p, btop(addr));

			while (count--) {
				if (upte->pg_v && upte->pg_ulock) {
					vsunlock(addr, nbyte, B_WRITE);
					p->p_flag &= ~SPHYSIO;
					return(-1);
				}
				++upte;
			}
		}
#endif s32 /* LOCKPAGES */
		bp = geteblk(pages * sizeof(struct pte));
		newpte = (struct pte *)bp->b_adrs;
		if (pcmalloc(1, newpte, pages, p, type, 1)) {
			struct pte *userpte = vtopte(p, btop(addr));
			register u_long vaddr = addr & ~pagemask;
			register struct pte *npte = newpte;
			register struct pte *upte = userpte;
			register count = pages;

			for (; count--; vaddr += NBPG)
				copyseg(vaddr, (npte++)->pg_pfnum);
			vsunlock(addr, nbyte, B_WRITE); /* unlock the old to
							   make memfree happy */
							/* We don't lock the new
							   pages since pcmalloc
							   did that for us */
			memfree(userpte, pages/CLSIZE, 1 /* detach */);
			npte = newpte;
			for (count=pages; count; --count,++upte)
			{
				*(int *)upte = *(int *)npte++ |
					       (*(int *)upte & PG_PROT);
				/*
				 * Fix c_page for each click since it
				 * were computed incorrectly by clickall
				 * due to the fact that we passed a buffer
				 * area to pcmalloc above.
				 */
				switch (type)
				{
				case CTEXT:
					cmap[pgtocm(upte->pg_pfnum)].c_page =
						vtotp(p, ptetov(p, upte));
					break;
				case CDATA:
					cmap[pgtocm(upte->pg_pfnum)].c_page =
						vtodp(p, ptetov(p, upte));
					break;
				case CSTACK:
					cmap[pgtocm(upte->pg_pfnum)].c_page =
						vtosp(p, ptetov(p, upte));
					break;
				}
			}
			brelse(bp);
			newptes(newpte, btop(addr), pages);
			/* we could "return(0);" here
			/* EXCEPT: the new pages might cross a 1MByte boundary.
			/* so go around again to check.
			*/
			vsunlock(addr,nbyte,B_WRITE);
			continue;
		}
		/* Could not get enough physically contiguous memory.
		 * Sleep until there is a reasonable amount of physically
		 * contiguous memory available and then loop again to see
		 * if it is enough for us.
		 */
		brelse(bp);
		vsunlock(addr, nbyte, B_WRITE);

		/* allow swapping during sleep */
		p->p_flag &= ~SPHYSIO;
		s=splimp();
		if (wantpcmem == 0 || pages < wantpcmem) wantpcmem = pages;
		sleep((caddr_t)&wantpcmem, PZERO);
		splx(s);
	}
}

/*
 * Check that transfer is either entirely in the data or the
 * stack.  That is, either the end is in the data or the start
 * is in the stack (remember, wraparound was already checked.)
 */
chkurang(base,count,rw)
register unsigned long base;
int count, rw;
{
    int retval, ts, dbeg, ds, page;
    register int nb, limit;

    retval=0;

    if (count) {
	/*
	 * Check for address wraparound
	 */

	if (base>=base+count)

	{
		PRINTF(("chkurang: address wraparound error\n"));
		retval=EFAULT;
	} else {
		ts = u.u_tsize+usrbase;

		if (u.u_procp->p_textp != NULL)
			dbeg = btoc(srnd(ctob(ts))), ds = dbeg + u.u_dsize;
		else
			dbeg = ts, ds = ts + u.u_dsize;

		nb = base >> pageshift;
		limit = btoc(base + count);

		/*
		* Check that transfer is either entirely in the data or the
		* stack.  That is, either the end is in the data or the start
		* is in the stack (remember, wraparound was already checked.)
		*/

		if ( !( rw==0 && usrbase <= nb && limit <= ts ||
			dbeg <= nb && limit <= ds ||
		        usrtop(u.u_procp) - u.u_ssize <= nb && limit <= usrtop(u.u_procp)
		      )
		   ) {
				PRINTF(("chkurang: base is out of bounds\n"));
				PRINTF(("   ts=%x, ds=%x, nb=%x, limit=%x\n",
					ts,ds,nb,limit));
	PRINTF(("usrTop=%x, usrbase=%x, ssize=%x, dsize=%x, tsize=%x\n",
			usrtop(u.u_procp),usrbase,u.u_ssize,u.u_dsize,u.u_tsize));
				retval = EFAULT;
		};
	};
    };
    return(retval);
}
/*
 * Emulate the old segacc.  This is only here
 * so that we can check to see that virtual space
 * is not used up.
 */
segacc( ctxt, vpno, npages, mode )
unsigned short ctxt, vpno, mode;
int npages;
{
	/*
	 * Do not decrement systop since that will
	 * be done by the caller.
	 */
}

/*
 * ins_strcmp --
 *	Case insensitive string compare.
 */
#define upper(c)	(((c) >= 'a' && (c) <= 'z') ? ((c)-'a'+'A'))
ins_strcmp(s1, s2)
	register char *s1;
	register char *s2;
{
	register char t;
	register char u;

	for (;;) {
		if (*s1 >= 'a' && *s1 <= 'z')
			t = *s1 - 'a' + 'A';
		else
			t = *s1;
		if (*s2 >= 'a' && *s2 <= 'z')
			u = *s2 - 'a' + 'A';
		else
			u = *s2;
		if (t != u)
			return (t - u);
		if (t=='\0')
			return(0);
		else
			s1++, s2++;
	}
}
