#define	HUGHES_BUG	/* 'til ELP or JHT fixes /lib/ccom's bitfield code */
#define	NORTHRUP_BUG

static char rcsid[] = "$Header: trap.c,v 820.1 86/12/04 19:54:25 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.				*
*									*
************************************************************************/

/*	trap.c	4.27	83/01/22	*/

/*
 * Handle system calls, address errors, and bus errors.
 *
 * jht 860201 -- Add code for variable maximum process size: SETTABLE_MMU_SIZE
 * jht 860308 -- Add code for LRU allocation of virtual segments.
 * jht 860312 -- Add code for virtual-smap list management;
 * jht 860316 -- Completed the support for 'p1pages';
 * jht 860318 -- trap() -- break out large cohesive chunks as routines;
 * jht 860321 -- Board-up/document holes regarding getpagemap() returning -1;
 * jht 860323 -- Ifdef-ed the NORTHRUP and HUGHES code, thus disabling same;
 *		 Presumes the use of ELP's new /lib/ccom or RS's /lib/c2;
 *		 Either will prevent 32-bit operations on 16-bit(fields);
 * jht 860609 -- Install M68881 FPU coprocessor support;
 */

#include "../DOT/sky.h"

#include "../machine/psl.h"
#include "../machine/reg.h"
#ifdef	M68881
#include "../s32/fpu68881.h"
#endif	M68881
#include "../machine/pte.h"
#include "../machine/cpu.h"
#include "../machine/mem.h"		/* SKY_BOARDNUM, boardmap[], etc */
#include "../machine/frame.h"		/* Fine structure of exception frames */
#include "../h/cmap.h"
#include "../machine/context.h"

#include "../h/param.h"
#include "../h/vmparam.h"
#include "../h/vmmac.h"
#include "../h/systm.h"
#include "../h/dir.h"
#include "../h/user.h"
#include "../h/proc.h"
#include "../h/seg.h"
#include "../h/text.h"
#include "../h/acct.h"
#include "../h/kernel.h"
#ifdef	s32	/* SYSCALLTRACE */
#include "../sys/syscalls.c"
#endif	s32	/* SYSCALLTRACE */

#include "../s32/trap.h"
#include "../s32/debug.h"
#include "../h/map.h"

#define	USER	0x1000		/* user-mode flag added to type */

#define WYES(x) ((x)?"yes":"no")

/*
 * Processor dependent values
 * from busErr or addrErr exception stack.
 * These are allocated within locore.s
 */
#if	defined(M68000) || defined(M68010) || defined(M68020)
extern	u_short	ctxtReg;	/* Context at time of the bus/addr fault */
extern	u_short	iReg;		/* Instruction which caused fault	 */
extern	u_long	aAddr;		/* (Virt.) Address of the bus/addr fault */
#endif	defined(M68000) || defined(M68010) || defined(M68020)


#ifdef	M68000
extern	u_short	fCode;		/* Access type, function code, etc. */
#endif	M68000


#if	defined(M68010) && !defined(M68020)
extern	u_short	diBuf,		/* Data  input buffer	*/
		doBuf;		/* Data output buffer	*/
#endif	defined(M68010) && !defined(M68020)


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


#ifdef	M68020
extern	u_long	aAddrB,		/* Pipeline: stage B Access Addr */
		aAddrC;		/* Pipeline: stage C Access Addr */

extern	u_long	diBuf,		/* Data  Input buffer	*/
		doBuf;		/* Data Output buffer	*/
/*
 * Multiple bus error firewall queue set
 * in machine/locore.s upon vector-entry
 * to busErr68020 and addrErr68020.
 */
extern	long	errTypeQueue;	/* Byte-wide error-type "stack"	*/
extern	long	eReg32;		/* TOP of 32-bit  error "stack"	*/
extern	long	eReg32_0;	/* ...				*/
extern	long	eReg32_1;
extern	long	eReg32_2;
extern	long	eReg32_3;	/* BOT of 32-bit  error "stack"	*/

#endif	M68020

extern	u_short	getpagemap();/* Can return -1 as h/w entry */

/*
 * System-call entry table.
 */
struct	sysent	sysent[];
int	nsysent;

/*
 * Exception vector table "boiler plate".
 */
#ifdef	M68010
char	*trap_type_68010[] = {
	"reset initial ssp?",
	"reset initial pc?",
	"bus error",
	"address error",
	"illegal instruction",
	"zero divide",
	"chk instruction",
	"trapv instruction",
	"privilege violation",
	"trace",
	"line 1010 emulator",
	"line 1111 emulator",
	"reserved #1",
	"reserved #2",
	"format error",
	"reserved #4",
	"reserved #5",
	"reserved #6",
	"reserved #7",
	"reserved #8",
	"reserved #9",
	"reserved #10",
	"reserved #11",
	"reserved #12",
	"spurious interrupt",
	"level 1 autovector",
	"level 2 autovector",
	"level 3 autovector",
	"level 4 autovector",
	"level 5 autovector",
	"level 6 autovector",
	"level 7 autovector",
	"trap #0",
	"trap #1",
	"trap #2",
	"trap #3",
	"trap #4",
	"trap #5",
	"trap #6",
	"trap #7",
	"trap #8",
	"trap #9",
	"trap #A",
	"trap #B",
	"trap #C",
	"trap #D",
	"trap #E",
	"trap #F",
};
#define	TRAP_TYPES_68010 (sizeof trap_type_68010 / sizeof trap_type_68010[0])
#endif	M68010


/*
 * Exception vector table "boiler plate".
 */
#ifdef	M68020
char	*trap_type_68020[] = {
/* 0*/	"Reset: Initial Interrupt ssp?",
/* 1*/	"Reset: Initial pc?",
/* 2*/	"Bus Error",
/* 3*/	"Address Error",
/* 4*/	"Illegal Instruction",
/* 5*/	"Zero Divide",
/* 6*/	"CHK, CHK2 instruction",
/* 7*/	"cpTRAPcc, TRAPcc, TRAPV instruction",
/* 8*/	"Privilege Violation",
/* 9*/	"Trace",
/*10*/	"Line 1010 Emulator",
/*11*/	"Line 1111 Emulator",
/*12*/	"Reserved #1",
/*13*/	"Coprocessor Protocol Violation",
/*14*/	"Format Error",
/*15*/	"Uninitialized Interrupt",
/*16*/	"reserved #5",
/*17*/	"reserved #6",
/*18*/	"reserved #7",
/*19*/	"reserved #8",
/*20*/	"reserved #9",
/*21*/	"reserved #10",
/*22*/	"reserved #11",
/*23*/	"reserved #12",
/*24*/	"Spurious Interrupt",
/*25*/	"Level 1 Autovector",
/*26*/	"Level 2 Autovector",
/*27*/	"Level 3 Autovector",
/*28*/	"Level 4 Autovector",
/*29*/	"Level 5 Autovector",
/*00*/	"Level 6 Autovector",
/*31*/	"Level 7 Autovector",
/*32*/	"Trap #0",
/*33*/	"Trap #1",
/*34*/	"Trap #2",
/*35*/	"Trap #3",
/*36*/	"Trap #4",
/*37*/	"Trap #5",
/*38*/	"Trap #6",
/*39*/	"Trap #7",
/*40*/	"Trap #8",
/*41*/	"Trap #9",
/*42*/	"Trap #A",
/*43*/	"Trap #B",
/*44*/	"Trap #C",
/*45*/	"Trap #D",
/*46*/	"Trap #E",
/*47*/	"Trap #F",

#ifdef	M68881
/*48*/	"FPU Branch/Set on Unordered",
/*49*/	"FPU Inexact Result",
/*50*/	"FPU Divide by Zero",
/*51*/	"FPU Underflow",
/*52*/	"FPU Operand Error",
/*53*/	"FPU Overflow",
/*54*/	"FPU Signaling 'Not A Number'",
#endif	M68881
};
#define	TRAP_TYPES_68020 (sizeof trap_type_68020 / sizeof trap_type_68020[0])
#endif	M68020


short	inrange;	/* 1 ==> u_aAddr is within proper domain of process */


#ifdef	COMPILERBUG
#ifdef	HUGHES_BUG
u_long	hughesBug = 0;	/* Compiler bit field generation problem touched
			 * when the u page PTE of the highest page table
			 * page is read.  Temporary fix occurs below.
			 */
#endif	HUGHES_BUG

#ifdef	NORTHRUP_BUG
u_long	northrupBug = 0;/* The WRITE-variation on the hughesBug	*/
#endif	NORTHRUP_BUG
#endif	COMPILERBUG


#ifndef	STILL_GETTING__PG_V__PAGEFAULTS
u_long	inv_page_fixup = 0;	/* # of pg_v==1 pagefault fixups */
#endif	STILL_GETTING__PG_V__PAGEFAULTS


#if	NSKY > 0
u_long	skyReadBug  = 0;	/* A truly ugly patch for SKY Cretinism */
u_long	skyWriteBug = 0;	/* A truly ugly patch for SKY Cretinism */
short	skydebug    = 0;	/* 1 ==> enables debugging for trap/sky */
#endif	NSKY > 0

#ifdef	DEBUG
short	movesBlab      = 0; /* 1 ==> printf() 'moves' instruction fault       */
short	userSegBlab    = 0; /* 1 ==> printf() user-mode segment-error blab    */
short	userPagingBlab = 0; /* 1 ==> printf() user-mode  paging-error blab    */
short	virtSmapBlab   = 0; /* 1 ==> printf() status of relevant virt. smap   */
short	coProcBlab     = 1; /* 1 ==> printf() info re FPU Coprocessor	      */

u_long	pmapBerr;	    /* # times V_PMAP_BERR:    page map bus error     */
u_long	smapBerr;	    /* # times V_SMAP_BERR: segment map bus error     */
u_long	badLaddr;	    /* # times V_BAD_LADR_ERR: bad logical addr err   */

#ifdef	s32	/* EXCEPTION_BUT_NO_ERROR */
u_long	lcwSegFaults	= 0;		/* Seg  fault recovery attempts       */
u_long	lcwPageFaults	= 0;		/* Page fault recovery attempts       */
extern	short	 lcwDebug;		/* 1==>enables debugging: s32/locore.s*/
extern	long	 lcwTOCnt;		/* Count of # of TimeOuts	      */

#endif	s32	/* EXCEPTION_BUT_NO_ERROR */
#endif	DEBUG

short	proc0Initd	= 0;	/* 0 ==> proc[0], upage NOT initialized; */
/*
 * Called from the trap handler when a processor trap occurs.
 * The arguments are the words saved on the system stack
 * by the hardware and software during the trap processing.
 * Their order is dictated by the hardware and the details
 * of C's calling sequence. They are peculiar in that
 * this call is not 'by value' and changed user registers
 * get copied back on return.
 * 'type' is the kind of trap that occurred.
 */
/*ARGSUSED*/
#ifdef s32
trap(type, regs)
   int type;
#ifndef	M68881
#define code 0
#endif	M68881
{
	int		*locr0 = &regs;	/* Ptr to R0/D0 in the stack frame */
	register exceptionFrame_t *efp = (exceptionFrame_t *)
							((u_long) &locr0[PS]
							/*
							 * Normalize for 'e_ssr'
							 * as either a short or
							 * a long.
							 */
							+ sizeof(long)
							- sizeof(efp->e_ssr));
#ifdef	M68881
	unsigned	code = 0;	/* Fine structure of SIGFPE */
#endif	M68881
#else s32
trap(sp, type, code, pc, psl)
	int sp, type;
	unsigned code;
	int pc, psl;
{
	register int *locr0 = ((int *)&psl)-PS;
#endif s32
	register int		i;
	register struct	proc	*p;
	struct	timeval		syst;
	struct	pte		*pte;
	int			pleaseClean = 0;
	extern	int		grow();		/* Grows the stack	*/
	extern			pagein();	/* Pages in faulted page*/


#if	1 && defined(DEBUG)
	if ((caddr_t)&efp->e_ps != (caddr_t)&locr0[PS]) {
		printf( "efp->e_ps @ 0x%X  --  locr0[PS] @ 0x%X\n",
			&efp->e_ps,	      &locr0[PS]);
		cdebugger("Botched exception frame address!");
	}
#endif	1 && defined(DEBUG)

	syst = u.u_ru.ru_stime;
	if (USERMODE(efp->e_ps)) {
		type |= USER;
		u.u_ar0 = locr0;
	}

	/*
	 * Process the exception.
	 */
	switch (type) {

	default:
		printf("\ntrap type 0x%x,  pc=0x%x,  %s mode,  context=0x%x\n",
			type&~USER,
			efp->e_pc,
			(type&USER) ? "user" : "kernel",
			ctxtReg);
		u.u_ar0 = locr0;
		showregs(u.u_ar0);
		type &= ~USER;
		panic(((unsigned)type < min(TRAP_TYPES_68010,TRAP_TYPES_68020))
			? (chipType==CHIPTYPE_68010)
				? trap_type_68010[type]
				: (chipType==CHIPTYPE_68020)
					? trap_type_68020[type]
					: "trap/E-0:"
			: "trap/E-1:");
		return;

#ifdef	M68020
#ifdef	M68881
	/*
	 * Floating Point exceptions:
	 *	Class I:  Those which map
	 *	into the VAX paradigm.
	 *
	 * NOTE:  Nevertheless, we ignore the VAX mnomenclature
	 *	  and simply pass along the M68881
	 *	  exception vector trap-values.
	 */
	case T_FPU_DIVBY0	|USER:		/* FPU Divide by Zero */
#if 0
	     code = FPE_FLTDIV_FAULT;
	     u.u_code = code; i = SIGFPE; break;
#endif 0

	case T_FPU_UNDERFLOW	|USER:		/* FPU Underflow */
#if 0
	     code = FPE_FLTUND_FAULT;
	     u.u_code = code; i = SIGFPE; break;
#endif 0

	case T_FPU_OVERFLOW	|USER:		/* FPU Overflow */
#if 0
	     code = FPE_FLTOVF_FAULT;
	     u.u_code = code; i = SIGFPE; break;
#endif 0


	/*
	 * Floating Point exceptions:
	 *	Class II:  Those which do NOT map
	 *	into the VAX paradigm.
	 *
	 * NOTE:  These codes are disjoint from the VAX FPE
	 *	  error code, so we just pass them along
	 *	  for anyone's later use.
	 */
	case T_FPU_OPERR	|USER:	/* FPU Operand Error		*/
	case T_FPU_BSUN		|USER:	/* FPU Branch/Set on Unordered	*/
	case T_FPU_INEX		|USER:	/* FPU Inexact Result		*/
	case T_FPU_SIGNAL_NAN	|USER:	/* FPU Signaling "Not A Number"	*/
	     u.u_code = type &~ USER;

asm("	.globl	case_T_FPU");
asm("case_T_FPU:");


	case T_1111|USER:		/* Better this, than a SIGILL	*/
	     u.u_code = type &~ USER;

asm("	.globl	case_T_1111");
asm("case_T_1111:");

	     i = SIGFPE;
	     break;
#endif	M68881


	case T_COPROC_VIOLATION	|USER:
	     /*
#ifdef	M68881
	      * Cope with M68881 related exceptions.
	      * Probably attempting to run M68881 machine code
	      * on a processor with no such coprocessor.
	      *
	      * BUG:  This handler is neither complete no appropriate.
#endif	M68881
	      */
	     if (coProcBlab)
	     {
		printf("\ntrap type 0x%x,  pc=0x%x,  %s mode,  context=0x%x\n",
			type&~USER,
			efp->e_pc,
			(type&USER) ? "user" : "kernel",
			ctxtReg);
		u.u_ar0 = locr0;
		showregs(u.u_ar0);
		type &= ~USER;
		printf("\n%s\n",
		       ((unsigned)type < min(TRAP_TYPES_68010,TRAP_TYPES_68020))
			? (chipType==CHIPTYPE_68010)
				? trap_type_68010[type]
				: (chipType==CHIPTYPE_68020)
					? trap_type_68020[type]
					: "trap/E-2:"
			: "trap/E-3:");
	     }
#endif	M68020

	case T_PRIV|USER:
		/*
		 * SUPROC would be implemented here and this trap
		 * would fall through to illegal instruction below.
		 */
	case T_CHK|USER:
	case T_TRAPV|USER:
	case T_ILL|USER:
	case T_1010|USER:
	case T_TRAP4|USER:
	case T_TRAP5|USER:
	case T_TRAP6|USER:
	case T_TRAP7|USER:
	case T_TRAP8|USER:
	case T_TRAP9|USER:
	case T_TRAP10|USER:
	case T_TRAP11|USER:
	case T_TRAP12|USER:
	case T_TRAP13|USER:
	case T_TRAP14|USER:
	case T_TRAP15|USER:
		u.u_code = type &~ USER;
		i = SIGILL;
		break;

	case T_ZERODIV|USER:
		u.u_code = code;
		i = SIGFPE;
		break;

	case T_ADDRERR|USER: /* user mode address error */
#ifdef	DEBUG
		if (userSegBlab){
			printf("trap/I-4: User-mode Address Error (SIGBUS)\n");
			showbus();
		}
#endif	DEBUG

#if	!defined(M68010) && !defined(M68020)
		/*
		 * Only the M68000/M68008 require fixup.
		 */
		if (backup()) {
#ifdef	DEBUG
			printf("trap/I-5: Unable to backup to fault site\n");
#else	DEBUG
		    0;
#endif	DEBUG
		}
#endif	!defined(M68010) && !defined(M68020)

		pleaseClean = 1;
		i = SIGBUS;
		break;

	case T_BUSERR:		/* allow page faults in kernel mode */
	case T_BUSERR|USER:
	{
#if	defined(M68000) || defined(M68010)
		u_char	error;
#endif	defined(M68000) || defined(M68010)
#ifdef	M68020
		u_long	error32;
		u_long	busErrPhysAddr;
#endif	M68020

#ifdef DEBUG
		extern label_t *nofault;
		u_short	hwPmap	= 0;
		u_long	swPmap	= 0;
#endif DEBUG


#if	defined(M68000) || defined(M68010) && !defined(M68020)
		/*
		 * Only on M68010...
		 */
		error = V_EREG;
#endif	defined(M68000) || defined(M68010) && !defined(M68020)

#if	defined(M68010) && defined(M68020)
		/*
		 * Both M68010 and M68020...
		 */
		if (chipType==CHIPTYPE_68020) {
			/*
			 * Bus error handling for the M68020 must deal
			 * with possibility of DELAYED write timeouts.
			 * This implies that PROBES OF MULTIBUS DATA SPACE,
			 * MIGHT NOT TIMEOUT IMMEDIATELY -- dev drivers beware!
			 *
			 * Previously, the logical address
			 * was always available to the bus-error handler,
			 * but now, FOR DELAYED WRITE TIMEOUTS,
			 * ONLY THE PHYSICAL ADDRESS is available.
			 */
			error32		= eReg32;  /* From top of err "stack" */
			busErrPhysAddr	= error32 >> V_EREG32_PHYSADDR_SHIFT;
		} else
			error = V_EREG;
#endif	defined(M68010) && defined(M68020)


#if	!defined(M68000) && !defined(M68010) && defined(M68020)
		/*
		 * When we have ONLY an M68020...
		 */
		error32		= eReg32;	/* From top of error "stack" */
		busErrPhysAddr	= error32 >> V_EREG32_PHYSADDR_SHIFT;

#endif	!defined(M68000) && !defined(M68010) && defined(M68020)


#ifdef	M68020
#ifdef	s32	/* EXCEPTION_BUT_NO_ERROR */

		/*
		 * Handle case where Bus Err, but no h/w error-bits.
		 */
		if (chipType==CHIPTYPE_68020)
			error32 |= spuriousBusErr(error32);
#endif	s32	/* EXCEPTION_BUT_NO_ERROR

		/*
		 * Determine if we had a "delayed write timeout"
		 * causing this bus error.
		 * If so, then flush the onboard cache, since other
		 * values the cache contains may have depended upon
		 * those write-results that never made it to mbus memory.
		 * Perhaps we are overly cautious...
		 */
		if ( (chipType==CHIPTYPE_68020)
		  && ((error32  &  (V_MBCMDR_MEM_EN|V_MBSEQ_MB_W))
				== (V_MBCMDR_MEM_EN|V_MBSEQ_MB_W))
		  && V_TIMEOUT_BERR(error32)
		   )
		{
		    /*
		     * Only if onboard cache is already enabled.
		     */
		    if (getStatusReg(S1_CACHE_EN_STATUS))
			initCache();	/* Flush/re-initialize onboard cache */
		}
#endif	M68020
		 
#ifdef	DEBUG
		/*
		 * Fault information for detailed event-tracing.
		 */
		if (debug&(D_TRAP|D_VMEM|D_PMEM) && !nofault) {
			register u_long	pageno = u.u_aAddr>>PGSHIFT;
			extern	u_short	getpagemap();/* Can return -1 as h/w entry */

			hwPmap = 	 getpagemap(	   pageno);
			swPmap = (u_long)vtopte(u.u_procp, pageno);

			printf(" trap/I-6: %s-mode bus err %x, pid=%d pc=0x%X ctxt=0x%x ssw=0x%x statReg=0x%x p_mmuIndx=%d (%s) aAddr=0x%x proc=0x%X hwPmap=0x%x swPmap=0x%x *swPmap=0x%X\n",
				(type==T_BUSERR) ? "Kernel" : "User",
#if	defined(M68010) && defined(M68020)
				((chipType==CHIPTYPE_68020)
					? error32
					: error
				),
#else	defined(M68010) && defined(M68020)
				error,
#endif	defined(M68010) && defined(M68020)
				(u.u_procp ? u.u_procp->p_pid : -1),
				efp->e_pc,
				ctxtReg,
				efp->e_ssw_68020,
				getStatusReg(),
				(u.u_procp ? u.u_procp->p_mmuIndx : -1),
				(u.u_procp
					? mmu_sizing[u.u_procp->p_mmuIndx].mmu_name
					: "UNKNOWN ADDR SPACE!"),
				u.u_aAddr,
				u.u_procp,
				hwPmap, swPmap,
				swPmap ? *(u_long *)swPmap : 0xBADBAD
			     );
		}
#endif	DEBUG
		/*
		 * Clear error-bits and all interrupts
		 * that the cpu direct-support hardware has latched up.
		 *
		 * This only affects cpu onboard latches,
		 * and has no impact upon bus-resident peripherials.
		 */
#ifndef	M68020
		V_CLR_ERRS = 0;	/* Reset the error register for next time */
#else	M68020
#ifdef	OnlyBrutalDebugging
		/*
		 * Present some detail if MULTIPLE bus errors...
		 *
		 * Since the errTypeQueue is a SHARED resource,
		 * simultaneous use by various processes can
		 * invalidate any relationships.
		 * Viz., several processes page faulting at about
		 * the same time and going into page-waits...
		 * The notion of "multiple faults" has a whole new meaning.
		 */
		if (errTypeQueue & 0xffffffff) {
			if (errTypeQueue & 0xffffff00) {
				showbus();
				printf("Error Stack:  0:%d/0x%X  1:%d/0x%X  2:%d/0x%X  3:%d/0x%X\n",
					((errTypeQueue>> 0)&255), eReg32_0,
					((errTypeQueue>> 8)&255), eReg32_1,
					((errTypeQueue>>16)&255), eReg32_2,
					((errTypeQueue>>24)&255), eReg32_3
					);
				if (errTypeQueue & 0xffff0000) {
					/*
					 * BUG: more than two???
					 */
					if (errTypeQueue & 0xff000000) {
						cdebugger("Quadruple bus fault!");
					} else {
						cdebugger("Triple bus fault!");
					}
				} else {
					cdebugger("Double bus fault!");
				}
			}
		}
#endif	OnlyBrutalDebugging
		/*
		 * Now we would receive (the first of)
		 * any ADDITIONAL busErr that had latched up
		 * between our entry to busErr and here.
		 * We have saved enough state information
		 * to successfully sort through the entrails.
		 */
		setErrorReg(0);
		flushWriteQueue();	/* Slight delay to insure concurrency */
#endif	M68020

#ifdef WHITE
		/*
		 * Parity errors should never happen
		 * so we print a bunch on the console
		 * then give the process an error it
		 * cannot recover from, else enter the
		 * debugger.
		 */
		if (error & V_PARERR)
		{ 
			printf("Parity error\n");
			showbus();
			if (type == 2+USER) {
				printf("Parity error -- process %d killed\n",
					(u.u_procp ? u.u_procp->p_pid : 0));
				uprintf("Parity error -- process %d killed\n",
					(u.u_procp ? u.u_procp->p_pid : 0));
				i = SIGKILL;
				goto out;
			}
			cdebugger("kernel parity error");
		}
		/*
		 * DMA should never encounter any problems
		 * so we enter the debugger if it does.
		 */
#ifdef notdef
		/*
		 * Ifdef this out since we now longer care about the
		 * V_DMADELAY bit.  This condition signifies that
		 * we have a page fault on the cycle after a DMA transfer.
		 * We assume that we will "never" DMA into a paged out
		 * page.  Probably not a correct assumption, but necessary
		 * for Omninet
		 */
		if (error & (V_DMAERR | V_DMADELAY))
#else notdef
		if (error & (V_DMAERR))
#endif notdef
		{
			printf("DMA error, error reg = 0x%x\n", error);
			cdebugger("DMA error");
		}
#endif WHITE
		/*
		 * Handle the case where the suregp1lr
		 * has not been initialized yet.
		 */
		if (suregp1lr == 0)
			inrange = 0;
		else
			/*
			 * End of special case.
			 * Determine if access is within
			 * the designated bounds of the process.
			 */
			inrange = inRange(u.u_aAddr);

		/*
		 * If the error was due to segment access and the
		 * address was within legal range but not initialized
		 * then change the segment map to allow access.  If
		 * it was a TEXT segment then make sure it is read only.
		 */
#ifndef	M68020
		if (error & (V_SMERR))
#else	M68020
		if (testErrorReg(V_SMAP_BERR))
#endif	M68020
		{
		   smapBerr++;
asm(" .globl smapBerrLabel");		/* Label for breakpoint debugging */
asm("smapBerrLabel:");

		   if (inrange)
		   {
#ifdef	M68020_REV_B
		     if ((U_sMaps[(u_long)u.u_aAddr>>segshift
				].s_fwdIndx & S_INSTANTIATED) == 0)
		     {
			/*
			 * Handle SMAP_BERR with insufficient virtual smap
			 * instantiation.
			 */
			hyperMmu(u.u_aAddr);

			/*
			 * Let the CPU re-run the faulted bus cycle...
			 */
			return;
		     }
#else	M68020_REV_B
		     if (((i = getsegmap(MYCTXT, u.u_aAddr)) & SEG_ACCMODE)== 0)
			/*
			 * Segment has never been touched until now: no ACCMODE.
			 */
		     {
			i &= SEG_PAGE;
			if (isatsv(u.u_procp, u.u_aAddr >> pageshift) &&
			    (*(u_long *)suregp0br & PG_PROT) != PG_UW)
				/*
				 * Text segment -- make readonly
				 * and let the microprocessor rerun it.
				 */
				setsegmap(MYCTXT, u.u_aAddr, i | SEG_AUR);
			else
				/*
				 * Data or stack segment -- make writeable.
				 * and let the microprocessor rerun it.
				 *
				 * If this is the first access to a page
				 * in a new stack segment, then we will
				 * subsequently pagefault at the same addr.
				 */
				setsegmap(MYCTXT, u.u_aAddr, i | SEG_AURW);
#ifdef	s32	/* EXCEPTION_BUT_NO_ERROR */
			if (lcwDebug) {
				debug	      &= ~D_VMEM;/* Turn off the blab */
				userSegBlab    = 0;
				userPagingBlab = 0;
			}
#endif	s32	/* EXCEPTION_BUT_NO_ERROR */
			return;
		     }
#endif	M68020_REV_B

		     /*
		      * Otherwise fall through into the PMAP_BERR code,
		      * which will treat the problem as a pagemap err.
		      *
		      * NOTE:  Both SMAP_BERR and PMAP_BERR bits are asserted
		      * by the h/w in this instance.
		      */

		   } else {
		     /*
		      * Segment error: "out of range" reference.
		      */
#ifdef	DEBUG
		     if (userSegBlab) {
			printf("trap/I-12: %s-mode SEGMENT Err: inrange=%d  pid %d pc=0x%X cmd='%s' ctxt=0x%x\n",
				(type==T_BUSERR) ? "kernel" : "user",
				inrange,
				(u.u_procp ? u.u_procp->p_pid : 0),
				efp->e_pc, &u.u_comm[0], ctxtReg, u.u_ssw);
			showbus();
		     }
#endif	DEBUG
		   }
		}

		/*
		 * If the error was due to page map error,
		 * and the address was within range,
		 * and the page was invalid,
		 * then assume that it was a page fault
		 * and attempt to page it in.
		 */
#ifndef	M68020
		if (error & (V_PMERR))
#else	M68020
		if (testErrorReg(V_PMAP_BERR))
#endif	M68020
		{
		   pmapBerr++;

asm(" .globl pmapBerrLabel");		/* Label for breakpoint debugging */
asm("pmapBerrLabel:");

		   if (inrange)
		   {
		     register struct pte *pte;
		     extern   struct pte *vtopte();

		     pte = vtopte(u.u_procp, u.u_aAddr>>pageshift);

		     /*
		      * If the pte (ptr) is bogus (-1),
		      * then the page has not been tallied yet
		      * by the virtual memory s/w and
		      * we simply want to fall through
		      * into the grow() code below.
		      * From grow(), the virtual memory support
		      * can the bring the new page into its bosom.
		      */
		     if (pte && ((int)pte != -1)) /* Ptr is probably ok */
		     {

		      if (! (pte->pg_v))  /* Page is not marked valid */
		      {	int j = 0;

			/*
			 * Faulting page is "in range" but NOT valid;
			 * Therefore page it in.
			 */
			i = u.u_error;
			pagein(u.u_aAddr, 0);
			if (i)		/* Always manifest earliest */
				u.u_error = i;

#ifdef	s32	/* EXCEPTION_BUT_NO_ERROR */
			if (lcwDebug) {
				debug	      &= ~D_VMEM;/* Turn off the blab */
				userSegBlab    = 0;
				userPagingBlab = 0;
			}
#endif	s32	/* EXCEPTION_BUT_NO_ERROR */

			if (type == T_BUSERR)  /* kernel mode page fault */
				return;

			/*
			 * On 68010/68020, we must return to the faulted code
			 * and NOT check for signals.
			 */
			return;

		     } else {	/* pg_v asserted! */
#ifndef	STILL_GETTING__PG_V__PAGEFAULTS

				/*
				 * Pte ok, AND the page is marked 'valid'.
				 * BUG:  We are still getting pg_v==1 pagefaults
				 * For now, just patch things up
				 * and rerun the faulted instruction.
				 *
				 * NOTE:  The segment could be 'gapped',
				 * which of course this KLUDGE will not fix.
				 */
				setsysmap(btop(u.u_aAddr), pte, 1);
				inv_page_fixup++;
				return;

#else	STILL_GETTING__PG_V__PAGEFAULTS

				/*
				 * Pte ok, AND marked valid.
				 * Fall through for latter 'error'.
				 */
				showbus();
				cdebugger("trap/E-14: pagefault with pte->p_v==1.");
#endif	STILL_GETTING__PG_V__PAGEFAULTS
		      }

		     }


#ifdef	s32	/* EXCEPTION_BUT_NO_ERROR */
		     if (lcwDebug) {
			debug	      &= ~D_VMEM;	/* Turn off the blab */
			userSegBlab    = 0;
			userPagingBlab = 0;
		     }
#endif	s32	/* EXCEPTION_BUT_NO_ERROR */
		   } else {
			/*
			 * An "out of range" page fault has occurred,
			 * probably in USER mode, which is OK.
			 */
#ifdef	DEBUG
			if (!(type|USER))	/* Firedoor */
			  cdebugger("trap/E-15: KERNEL pagefault: not inrange");
#endif	DEBUG
		   }
		}

		/*
		 * If it was a kernel mode bus error but it
		 * was not a page fault then something is
		 * dreadfully wrong and we must panic.
		 *
		 * The only exception will be during configure()
		 * when we are using the 'nofault' mechanism
		 * during device probing..
		 */
		if (type == T_BUSERR)	/* ==> kernel mode */
			goto buserr;

		/*
		 * Here we deal with USER mode segment error.
		 * If the user SP is above the stack segment,
		 * grow the stack automatically.
		 * This relies on the ability of the hardware
		 * to restart a half executed instruction.
		 */
#ifndef	M68020
		if (error & (V_PMERR|V_SMERR) &&
#else	M68020
		if (testErrorReg(V_PMAP_BERR|V_SMAP_BERR) &&
#endif	M68020
		    /*
		     * USUALLY inrange==1.
		     *
		     * A barely sufficient test
		     * for grow()-ing the stack is
		     * that the candidate reference is between
		     * the TOP of data and the TOP of the stack.
		     */
	   	    u.u_aAddr > USRTEXT+(u_long)ptob(suregp0lr) /* TOP'o data */
		 && u.u_aAddr < (u_long)usrstack(u.u_procp))	/* Top'o stack*/
		{
			if (grow(u.u_aAddr))
				return;
		}

		/*
		 * If the user's address was out of range or
		 * he faulted due to segment or page protection
		 * then convert the exception frame so that a
		 * normal return may be made from the user's
		 * signal handler.
		 */
#ifdef WHITE
		if (!inrange || (error & (V_PMERR|V_SMERR)))
#else WHITE
#ifndef	M68020
		if (!inrange || (error & (V_PMERR|V_SMERR|V_BOUNDS)))
#else	M68020
		if (!inrange
		 || (testErrorReg(V_PMAP_BERR|V_SMAP_BERR|V_BAD_LADR_ERR)))
#endif	M68020
#endif	WHITE
		{
#if	!defined(M68000) && !defined(M68020)
			/*
			 * Only the M68000/M68008 require fixup.
			 */
			if (backup()) {
#ifdef	DEBUG
			    printf("trap/I-16: backup to fault site failed\n");
#else	DEBUG
			    ;
#endif	DEBUG
			}
#endif	!defined(M68000) && !defined(M68020)

			if (userSegBlab) {
				printf("trap/I-17: inrange=%d;  User-mode SEGMENT err (SIGSEGV)\n", inrange);
				showbus();
			}
			i = SIGSEGV;
			pleaseClean = 1; /* We may pagefault during core() */
			break;
		}
		/*
		 * If the user's address was valid and he
		 * did not trap due to page or segment mode
		 * violation or bounds violation then it must
		 * have been a timeout or some hardware failure.
		 * NOTE: this cannot happen without a kernel
		 * problem or hardware problem.
		 */
		printf("trap/I-18: user mode bus error (SIGBUS)\n");
		showbus();
		i = SIGBUS;
		break;
	}

	case T_ADDRERR:

buserr:		/* Kernel-mode bus error which was NOT a page or segment fault*/
	{
		extern label_t *nofault;

		if (nofault) {
			/*
			 * We will not be going back through the 'fault' code
			 * in machine/locore.s, where we normaly unwind this.
			 * Hence we must cleanup various odds and ends:
			 */
			errTypeQueue >>= NBBY;	/* 'Pop' the error stacks */
			eReg32_0 = eReg32_1;
			eReg32_1 = eReg32_2;
			eReg32_2 = eReg32_3;
			eReg32_3 = 0;

			longjmp(nofault);	/* Warp out of here forever */
		}
		spl7();

		/*
		 * If the fault was due to a 'moves' instruction,
		 * then pretend that it succeeded by setting the
		 * software re-run bit, but stuff -1 into register D0.
		 *
		 * This procedure (using 'moves' in-line and the
		 * following code) is equivalent to setting
		 * 'nofault' inside the [fs]u{byte,word} functions
		 * and returning -1 on a bus or address error.
		 *
		 * We detect that the fault was due to a 'moves'
		 * instruction by the processor running in
		 * supervisor mode, but the fault occuring in
		 * user data space.
		 */
#ifdef	M68010
		if (chipType == CHIPTYPE_68010) {
		 if ((efp->e_ssr	& SR_SUPER)
		  && (efp->e_ssw_68010	& SSW_FCODE) == SSW_FCODE_USERDATA) {
			/*
			 * We always say that the s/w already
			 * reran any broken instructions.
			 */
			efp->e_ssw_68010 |= SSW_SOFTRERUN_68010;
			locr0[R0] = -1;
#if	0 && defined(DEBUG)
			if (movesBlab)
			   printf("M68010/I: %su%s: %s: bad address 0x%X\n",
				(efp->e_ssw_68010 & SSW_READ_68010) ? "f" : "s",
				(efp->e_ssw_68010 & SSW_BYTE_68010) ? "byte" : "word",
				&u.u_comm[0], e_dataFaultAddr);
#endif	0 && defined(DEBUG)
			return;
		 }
		}
#else	M68010
		if (0) ;	/* Syntactic sugar... */
#endif	M68010

#ifdef	M68020
		else if (chipType == CHIPTYPE_68020) {
		 if ((efp->e_ps		& SR_SUPER)
		  && (efp->e_ssw_68020	& SSW_FCODE) == SSW_FCODE_USERDATA) {
			/*
			 * The 68020 sets BOTH of the RC/RB flags if EITHER
			 * stage of the INSTRUCTION pipe faulted.
			 * Thereby the default would be to have
			 * the microprocessor rerun any faulted stages,
			 * which is NOT what we want.
			 * Therefore, we RESET the RC/RB bits.
			 * (We always say that the s/w already
			 * reran any broken instructions.)
			 * The DATA FAULT flag (DF) is also accordingly reset.
			 */
			efp->e_ssw_68020 &= ~(SSW_RC_68020
					     |SSW_RB_68020
					     |SSW_DF_68020);
			locr0[R0] = -1;

#if	0 && defined(DEBUG)
			if (movesBlab)
			 printf("M68020/I: %su%s: %s: bad address 0x%x\n",
			  (efp->e_ssw_68020 & SSW_RW_68020)
					? "f"
					: "s",
			  ( ((efp->e_ssw_68020 & SSW_SIZ_68020)==0x10) ?"byte"
			   :((efp->e_ssw_68020 & SSW_SIZ_68020)==0x20) ?"word"
			   :((efp->e_ssw_68020 & SSW_SIZ_68020)==0x30) ?"3-byte"
			   :((efp->e_ssw_68020 & SSW_SIZ_68020)==0x00) ?"long"
			   :					       "UnKnown"
			  ),
			  &u.u_comm[0],
			  u.u_aAddr);	/* Several contingencies, herein */
#endif	0 && defined(DEBUG)
			return;
		 }
		}
#else	M68020
		;
#endif	M68020



#ifdef	COMPILERBUG
#if	defined(HUGHES_BUG) || defined(NORTHRUP_BUG)
		/*
		 * The kernel may have inapprorpiately accessed
		 * off the end of its high-memory virtual area due
		 * to a compiler bug in generating bit field code.
		 * We return 0 on reads of this location
		 * assuming that this bug was the cause.
		 *
		 * UPDATE: The same problem(s) can occur with regard
		 *	   to the last pte for the process's upage.
		 */
#ifdef	M68010
		if (chipType == CHIPTYPE_68010) {
		 if ( (efp->e_ssr & SR_SUPER)
		  /*
		   * Last word in page of pte-s:  0xFF0000 for s32
		   */
		  && ((efp->e_faultAddr == (caddr_t)((mmu_sizing[normalMmuIndx].mmu_nsegs-1)<<segshift))
		   || (efp->e_faultAddr == (caddr_t)((u_long)(&u.u_procp->p_addr[UPAGES-1])+sizeof(struct pte))))
		  && ((efp->e_ssw_68010 &  SSW_FCODE) == SSW_FCODE_SUPERDATA)
		  && (
			((efp->e_ssw_68010   &	(SSW_READ_68010
						|SSW_DATA_68010
						|SSW_INST_68010
						|SSW_BYTE_68010
						|SSW_RMW_68010)) ==

						(SSW_READ_68010	/* Read     */
						|SSW_DATA_68010)/* Data-get */
			)

		    ||	((efp->e_ssw_68010   &	(SSW_READ_68010
						|SSW_DATA_68010
						|SSW_INST_68010
						|SSW_BYTE_68010
						|SSW_RMW_68010)) ==
						
							0	/* Write */
			)
		     )
		    )
		 {
			/*
			 * Say we did the rerun ourselves.
			 */
			efp->e_ssw_68010	|= SSW_SOFTRERUN_68010;

			if ((efp->e_ssw_68010   &	(SSW_READ_68010
							|SSW_DATA_68010
							|SSW_INST_68010
							|SSW_BYTE_68010
							|SSW_RMW_68010)) == 0) {

#ifdef	NORTHRUP_BUG
				++northrupBug;		/* Write-fault	     */
#else	NORTHRUP_BUG
				;
#endif	NORTHRUP_BUG
			} else {
				efp->e_DIB_68010 = 0;	/* Clear data buffer */
#ifdef	HUGHES_BUG
				++hughesBug;		/* Read-data-fault   */
#else	HUGHES_BUG
				;
#endif	HUGHES_BUG
			}
			return;
		 }
		}
#else	M68010
		if (0) ;
#endif	M68010

#ifdef	M68020
		else if (chipType == CHIPTYPE_68020) {
		 if ( (efp->e_ssr & SR_SUPER)
		  /*
		   * Last word in page of pte-s:  0xFF0000 for s32
		   *
		   * UPDATE: The same problem(s) can occur with regard
		   *	   to the last pte for the process's upage.
		   */
		  && ((u.u_aAddr == (u_long)((mmu_sizing[normalMmuIndx].mmu_nsegs-1)<<segshift))
		   || (u.u_aAddr == (u_long)((u_long)(&u.u_procp->p_addr[UPAGES-1])+sizeof(struct pte))))
		  && ((u.u_ssw & SSW_FCODE) == SSW_FCODE_SUPERDATA)
		  && ((u.u_ssw & SSW_SIZ_68020) == 0x20)/* 2==> 16-bit word   */

		  && ((u.u_ssw    &	(SSW_RW_68020	/* 1==> Read	      */
					|SSW_DF_68020	/* 1==> Data Cycle    */
					|SSW_RM_68020))	/* 1==>Read/Mod/Write */
			    ==
					(SSW_RW_68020	/* 1==> Read	      */
					|SSW_DF_68020)	/* 1==> Data Cycle    */
		     )
		  || ((u.u_ssw    &	(SSW_RW_68020	/* 1==> Read	      */
					|SSW_DF_68020	/* 1==> Data Cycle    */
					|SSW_RM_68020))	/* 1==>Read/Mod/Write */
			    ==
					(0		/* 0==> Write	      */
					|SSW_DF_68020)	/* 1==> Data Cycle    */
		     )
		    ) {
			if ((u.u_ssw  &	(SSW_RW_68020	/* 1==> Read	      */
					|SSW_DF_68020	/* 1==> Data Cycle    */
					|SSW_RM_68020))	/* 1==>Read/Mod/Write */
			    ==
					(0		/* 0==> Write	      */
					|SSW_DF_68020)	/* 1==> Data Cycle    */
			   ) {
				/*
				 * No need to clear the DOB,
				 * since it isn't used.
				 */
				++northrupBug;		/* Write-fault	      */
			} else {
				++hughesBug;		/* Read-data-fault    */

				/*
				 * Clear data buffer
				 */
				if (e_effn(efp)==11)
					efp->e_DIB_68020_f11 = 0;
			        else cdebugger("PANIC: trap/E-19: effn not 10 or 11");
			}
			/*
			 * Say we did the DATACYCLE rerun ourselves.
			 * We let the microprocessor rerun any B/C stages
			 * of the INSTRUCTION pipeline,
			 * since those are problems orthogonal
			 * to the recent datafault, (and we didn't fix them.)
			 */
			efp->e_ssw_68020 &= ~SSW_DF_68020;
			return;
		 }
		}
#else	M68020
		;
#endif	M68020
#endif	defined(HUGHES_BUG) || defined(NORTHRUP_BUG)
#endif COMPILERBUG

#if	0
		/*
		 * BUG: WHY were we moving this data back?!
		 */
#ifdef	M68000
		fCode = u.u_fCode;
#endif	M68000
		aAddr = u.u_aAddr;
		iReg = 0xFFFF;
#endif 0
		printf("trap/I-20: Kernel mode %s error\n",
			(type == T_BUSERR) ? "Bus" : "Address");
		u.u_ar0 = locr0;
		showbus();
		panic("kernel bus/address error");
		return;
	}

	case T_TRACE|USER:
	case T_TRAP1|USER:	/* bpt */
		efp->e_ssr &= ~PSL_T;
		i = SIGTRAP;
		break;

	case T_TRAP3|USER:	/* emt */
		i = SIGEMT;
		break;

	case T_TRACE:
		/* Trace out of kernel mode -
		 * This is assumed to happen when a 'trap' instruction is
		 * executed with the trace bit set.
		 */
		efp->e_ssr &= ~PSL_T;
		return;

	case T_TRAP2|USER:	/* iot */
		i = SIGIOT;
		break;

	/*
	 * Unused trap vectors generate this trap type.
	 * Receipt of this trap is a
	 * symptom of hardware problems and may
	 * represent a real interrupt that got
	 * sent to the wrong place.  Watch out
	 * for hangs on disk completion if this message appears.
	 */
	case T_VEC0:
	case T_VEC0|USER:
		printf("\ntrap: spurious interrupt ignored\n");
		return;

	case T_AST|USER:
		astoff();
		if ((u.u_procp->p_flag & SOWEUPC) && u.u_prof.pr_scale) {
			addupc(efp->e_pc, &u.u_prof, 1);
			u.u_procp->p_flag &= ~SOWEUPC;
		}
		goto out;
	}

	/*
	 * Send the specified signal
	 * to the specified process.
	 */
	psignal(u.u_procp, i);

out:
	/*
	 * Carry out any pending signals for the process.
	 */
	p = u.u_procp;
	if (p->p_cursig || ISSIG(p))
		psig();
	p->p_pri = p->p_usrpri;
	if (runrun) {
		/*
		 * Since we are u.u_procp, clock will normally just change
		 * our priority without moving us from one queue to another
		 * (since the running process is not on a queue.)
		 * If that happened after we setrq ourselves but before we
		 * swtch()'ed, we might not be on the queue indicated by
		 * our priority.
		 */
		(void) spl6();
		setrq(p);
		u.u_ru.ru_nivcsw++;
		swtch();
	}
	if (u.u_prof.pr_scale) {
		int ticks;
		register struct timeval *tv = &u.u_ru.ru_stime;

		ticks = ((tv->tv_sec -  syst.tv_sec)  * 1000 +
			 (tv->tv_usec - syst.tv_usec) / 1000) / (tick / 1000);
		if (ticks)
			addupc(efp->e_pc, &u.u_prof, ticks);
	}

	curpri = p->p_pri;

	/*
	 * If the code above requested that a bus error
	 * format exception frame be converted into a
	 * normal exception frame then, oblige by
	 * telling cleanberr() to do the work.
	 *
	 * Note that we will likely end up in core(),
	 * which may provoke subsequent page faults,
	 * as the process image is writen to the bit locker.
	 * I.e., SIGBUS usually is coincident with 'pleaseClean'.
	 */
	if (pleaseClean)
		cleanberr(locr0);
}

/*
 * Called from the trap handler when a system call occurs
 */
/*ARGSUSED*/
#ifdef s32
syscall(regs)
{
	register int *locr0 = &regs;	/* Ptr to R0/D0 in the stack frame */
	register exceptionFrame_t *efp = (exceptionFrame_t *)
							((u_long) &locr0[PS]
							/*
							 * Normalize for 'e_ssr'
							 * as either a short or
							 * a long.
							 */
							+ sizeof(long)
							- sizeof(efp->e_ssr));
#else s32
syscall(sp, type, code, pc, psl)
	unsigned code;
{
	register int *locr0 = ((int *)&psl)-PS;
#endif s32
	register caddr_t	params;		/* Known to be r10 below */
	register int		i;		/* Known to be  r9 below */
	register struct sysent	*callp;
	register struct proc	*p;
	int	 		opc;
	struct	 timeval	syst;

	syst = u.u_ru.ru_stime;
	if (!USERMODE(efp->e_ps))
		panic("syscall");
	u.u_ar0 = locr0;

	/*
	 * Undocumented 139-flavored magic!
	 * A user's signal catcher terminates by issuing:
	 *
	 *	mov.l &8b,%d0	| Specify system-call #139
	 *	trap &40	| Transfer control back to kernel to cleanup sig
	 */
	if (locr0[R0] == 139) {			/* XXX */
		sigcleanup();			/* XXX */
		goto done;			/* XXX */
	}
#ifdef s32
	/*
	 * Locate the user's arguments via HER (usp) stackpointer,
	 * rather than the system's stackpointer.
	 * Then bump past the return address left on the stack
	 * by the 'jsr' to the libc.a interface routine.
	 */
	params = ((caddr_t)locr0[SP]) + NBPW;
#else s32
	params = (caddr_t)locr0[AP] + NBPW;
#endif s32
	u.u_error = 0;
	opc = efp->e_pc - 2;	/* jam - 2 is the length of a trap instr */
#ifndef s32
	if (locr0[R0] > 63)
		opc -= 2;	/* jam - 2 is the length of an extra word */
#endif s32
	callp = (locr0[R0] >= nsysent) ? &sysent[63] : &sysent[locr0[R0]];
	if (callp == sysent) {
		i = fuword(params);
		params += NBPW;
		callp = (locr0[R0] >= nsysent) ? &sysent[63] : &sysent[locr0[R0]];
	}
#ifdef s32
	/*
	 * Copy what the user pushed onto his stack,
	 * into our u-page holding area.
	 */
	for (i=0; i < callp->sy_narg; ++i) {
		u.u_arg[i] = fuword((caddr_t)params);
		params += NBPW;
	}
#else s32
	if (i = callp->sy_narg * sizeof (int)) {
#ifndef lint
		asm("prober $3,r9,(r10)");		/* GROT */
		asm("bnequ ok");			/* GROT */
		u.u_error = EFAULT;			/* GROT */
		goto bad;				/* GROT */
asm("ok:");						/* GROT */
		asm("movc3 r9,(r10),_u+U_ARG");		/* GROT */
#else
		bcopy(params, (caddr_t)u.u_arg, (u_int)i);
#endif
	}
#endif s32
	u.u_ap		= u.u_arg;
	u.u_dirp	= (caddr_t)u.u_arg[0];	/* Always the FIRST argument!!*/
	u.u_r.r_val1	= 0;
	u.u_r.r_val2	= locr0[R1];

	if (setjmp(&u.u_qsave)) {
		if (u.u_error == 0 && u.u_eosys == JUSTRETURN)
			u.u_error = EINTR;
	} else {
		u.u_eosys = JUSTRETURN;
#ifdef	s32	/* SYSCALLTRACE */
#ifdef DEBUG
		if (debug&D_TRAP) {
			register int i;
			char *cp, *ap;

#ifdef	SYSCALLARGS
			if (locr0[R0] == 3  /*read*/ || 
			    locr0[R0] == 4  /*write*/ || 
			    locr0[R0] == 19 /*lseek*/)
				;
			else
#endif	SYSCALLARGS
			if (locr0[R0] >= nsysent)
				printf("0x%x", locr0[R0]);
			else
				printf("%s", syscallnames[locr0[R0]]);
			cp = "(";
#ifdef	SYSCALLARGS
			if (locr0[R0] > 0 && locr0[R0] < nsysent &&
			    locr0[R0] != 3 /*read*/ && locr0[R0] != 4 /*write*/
			    && locr0[R0] != 19 /*lseek*/ &&
			    (ap = syscallargs [locr0[R0]]))
			 {
				for (i= 0; i < callp->sy_narg; i++)
				 {
				    printf ("%s", cp);
				    switch (*ap++)
				     {
					case 's':
					    printf ("\"%s\"", u.u_arg[i]);
					    break;
					case 0:
						ap--;
					case 'x':
					default:
						printf ("%x",u.u_arg[i]);
						break;
				     }
				    cp = ", ";
				 }
			 }
			else if (locr0[R0] != 3 /*read*/ && 
				 locr0[R0] != 4 /*write*/ && 
				 locr0[R0] != 19 /*lseek*/)
#endif	SYSCALLARGS
			for (i= 0; i < callp->sy_narg; i++) {
				printf("%s%x", cp, u.u_arg[i]);
				cp = ", ";
			}
			if (i)
				putchar(')', 0);
			(*(callp->sy_call))();
#ifdef	SYSCALLARGS
			if (locr0[R0] == 3 /*read*/ || 
			    locr0[R0] == 4 /*write*/ || 
			    locr0[R0] == 19 /*lseek*/)
				;
			else
#endif	SYSCALLARGS
			if (u.u_error)
#ifdef	SYSCALLARGS
				printf(" error %d ", u.u_error);
			else
				printf(" = %d (0x%x) ",
					u.u_r.r_val1, u.u_r.r_val1);
#else	SYSCALLARGS
				printf(" error %d\n", u.u_error);
			else
				printf(" = %d (0x%x)\n",
					u.u_r.r_val1, u.u_r.r_val1);
#endif	SYSCALLARGS
		}
		else
#endif DEBUG
#endif	s32	/* SYSCALLTRACE */
		(*(callp->sy_call))();
	}
	efp->e_ps &= ~PSL_C;
	if (u.u_eosys == RESTARTSYS)
		efp->e_pc = opc;
#ifdef	INTERMEDSIG
	else if (u.u_eosys == SIMULATERTI)
		dorti();
#endif	INTERMEDSIG
	else if (u.u_error) {
#ifndef lint
bad:
#endif
		locr0[R0]  = u.u_error;
		efp->e_ps |= PSL_C;	/* carry bit */
	} else {
		locr0[R0] = u.u_r.r_val1;
		locr0[R1] = u.u_r.r_val2;
	}
done:
	p = u.u_procp;
#ifdef s32
	if(efp->e_ps & PSL_T) {
		/* The trap instruction was executed with the
		   trace bit set (the trace trap was already ignored)
		   now set the trace signal to avoid missing the trace
		   on the trap instruction
		 */
		u.u_ar0[PS] &= ~PSL_T;
		psignal(p, SIGTRAP);
	}
#endif s32
	if (p->p_cursig || ISSIG(p))
		psig();
	p->p_pri = p->p_usrpri;
	if (runrun) {
		/*
		 * Since we are u.u_procp, clock will normally just change
		 * our priority without moving us from one queue to another
		 * (since the running process is not on a queue.)
		 * If that happened after we setrq ourselves but before we
		 * swtch()'ed, we might not be on the queue indicated by
		 * our priority.
		 */
		(void) spl6();
		setrq(p);
		u.u_ru.ru_nivcsw++;
		swtch();
	}
	if (u.u_prof.pr_scale) {
		int			ticks;
		register struct timeval *tv = &u.u_ru.ru_stime;

		ticks = ((tv->tv_sec -  syst.tv_sec)  * 1000 +
			 (tv->tv_usec - syst.tv_usec) / 1000) / (tick / 1000);
		if (ticks)
			addupc(efp->e_pc, &u.u_prof, ticks);
	}
	curpri = p->p_pri;
}

/*
 * nonexistent system call-- signal process (may want to handle it)
 * flag error if process won't see signal immediately
 * Q: should we do that all the time ??
 */
nosys()
{
	if (u.u_signal[SIGSYS] == SIG_IGN || u.u_signal[SIGSYS] == SIG_HOLD)
		u.u_error = EINVAL;
	psignal(u.u_procp, SIGSYS);
}

/*
 * Show Process Registers
 */
showregs(regs)
	register u_long	regs[16];	/* Aledged register values */
{
	register int	i;
	extern	 char	*showoffset();
	register char	*c;

	printf("pid=%d   pc=0x%X-->",
		(u.u_procp
			? u.u_procp->p_pid
			: 0),
		regs[PC]);

	showoffset(regs[PC]);		/* PRINT the symbol:  860331 jht */

	printf(";  sr=0x%X  sp=0x%X\n",
		regs[PS] & 0xFFFF,
		regs[SP]);

	for (i = 0; i < 16; i++) {
		printf("%s%d=0x%X ",
			(i<8)? "d":"a", (i<8)? i:i-8, regs[i]);
		if (i == 7 || i == 15)
			printf("\n");
	}
}

/*
 * showbus -	Print out status on mmgt error
 */
char opmap[][10] = {
	"bit manip", "move byte", "move long", "move word", "misc",
	"addq", "bcc", "moveq", "or", "sub", "1010", "cmp", "and",
	"add", "shift", "1111"
};

char *fmap[] = {
	"Undefined/Reserved", "user data", "user program", "Undefined/Reserved",
	"Undefined/Reserved", "supervisor data", "supervisor program", "cpu"
};

char	virtual = 1;	/* 1==>virtual addr; 0==>physical addr: c.f., u_aAddr */

/*
 * Display information from the exception stack.
 */
showbus()
{
	register struct	proc	*p = u.u_procp;
	extern	 u_short getpagemap();		/* Can return -1 as h/w entry */
	register u_short entry	= getpagemap(u.u_aAddr >> pageshift);

	/*
	 * Define a set of LOCAL buckets for processor information.
	 * These local buckets are filled with information
	 * from the upage of the CURRENT context.
	 */
#ifdef	M68000
	register u_short ssr	= u.u_fCode;
#endif	M68000

#if	defined(M68010)  && !defined(M68020)
	register u_short diBuf	= u.u_diBuf;	/* Data  Input Buffer */
	register u_short doBuf	= u.u_doBuf;	/* Data Output Buffer */
#endif	defined(M68010)  && !defined(M68020)

#if	defined(M68010) || defined(M68020)
	register u_short effn	= u.u_effn;	/* Exception Frame Fmt # */
	register u_short ssr	= u.u_ssr;
	register u_short ssw	= u.u_ssw;
#endif	defined(M68010) || defined(M68020)

#ifdef	M68020
	register u_short iregB	= u.u_iRegB;	/* Stage B Instruction Pipe   */
	register u_short iregC	= u.u_iRegC;	/* Stage C Instruction Pipe   */
	register u_long	 aAddrB	= u.u_aAddrB;	/* "B" inst-stream Addr error */
	register u_long	 diBuf	= u.u_diBuf;	/* Data  Input Buffer	      */
	register u_long	 doBuf	= u.u_doBuf;	/* Data Output Buffer	      */
#endif	M68020

	/*
	 * Print human-readable time-of-event.
	 */
	printf("\nTime=");
	ddhhProcTime(&time);			/* Does its own printf() */
	printf("  uid=%d  pid=%d  cmd='%s'\n",
		u.u_ruid,
		(p ? p->p_pid : 0),
		(p ? p->p_pid : 0)
			? &u.u_comm[0]
			: "swapper");	/* For p_pid==0 */

	printf("   Access address: 0x%X %s in (%s) context 0x%x on an %s\n   ",
		u.u_aAddr,
		virtual ? "virtual" : "PHYSICAL",
		(u.u_procp
			? mmu_sizing[u.u_procp->p_mmuIndx].mmu_name
			: "UNKNOWN ADDR SPACE!"),
		ctxtReg,
		( (chipType==CHIPTYPE_68000)	? "M68000"
		 :(chipType==CHIPTYPE_68010)	? "M68010"
		 :(chipType==CHIPTYPE_68020)	? "M68020"
		 :				  "Unknown Processor!"));
	if ((entry & V_MISSING) == V_MISSING)
		printf("   Missing page ");
	else
#ifdef WHITE
		printf("physical page 0x%x of memory", entry & V_PAGEMASK);
#else WHITE
		printf("physical page 0x%x of %s",
			entry & V_PAGEMASK,
			(entry & V_MBIO) ? "multibus I/O" : "multibus memory");
#endif WHITE
	printf("  (map entry = 0x%x)\n", entry);

#ifdef	M68010
	/*
	 * Special Status Word
	 */
	if (chipType==CHIPTYPE_68010) {
	   printf("   SSW=0x%x:  %s re-run, %s %s %s%s\n",
		 ssw,
		(ssw & SSW_SOFTRERUN_68010) ? "software" : "processor",
		(ssw & SSW_BYTE_68010)
			? ((ssw & SSW_HIGHBYTE_68010)
				? "high byte"
				: "low byte")
			: "word",
		(ssw & SSW_DATA_68010) ? "data" : "instruction",
		(ssw & SSW_READ_68010) ? "read" : "write",
		(ssw & SSW_RMW_68010) ? " (read-modify-write)" : "");
	   printf("   address space = %d = %s\n",
		ssw & SSW_FCODE, fmap[ssw & SSW_FCODE]);
	}
#endif	M68010


#if	defined(M68020)
	/*
	 * Special Status Word
	 */
	if (chipType==CHIPTYPE_68020)
	   printf("   u_ssw=0x%x: ==> <%s%s%s%s%s%s%s>, SIZ=%d=%s, FCn=%d\n",
		u.u_ssw,

		/*
		 * Fault on stage C/B of the instruction pipe
		 */
		(u.u_ssw & 0x8000)	? "FC,"			: "",
		(u.u_ssw & 0x4000)	? "FB,"			: "",

		/*
		 * Rerun flag for stage C/B of the Instruction Pipe.
		 */
		(u.u_ssw & 0x2000)	? "RC:reRunI/A,"	: "",
		(u.u_ssw & 0x1000)	? "RB:reRunI/A,"	: "",

		/*
		 * Data Fault iff set, which then MUST be rerun.
		 */
		(u.u_ssw & 0x0100)	? "DF:reRunD/A,"	: "",

		/*
		 * Read-Modify-Write on Data cycle
		 */
		(u.u_ssw & 0x0080)	? "RM:onDataCycle,"	: "",

		/*
		 * 1 ==> Read;	0 ==> Write for Data cycle
		 */
		(u.u_ssw & 0x0040)	? "RW:dataRead,"	: "RW:dataWrite,",

		((u.u_ssw & SSW_SIZ_68020)>>4),			/* SIZ */

		( 	((u.u_ssw & SSW_SIZ_68020)==0x10) ? "byte"
		  :	((u.u_ssw & SSW_SIZ_68020)==0x20) ? "short-word"
		  :	((u.u_ssw & SSW_SIZ_68020)==0x30) ? "3-byte"
		  :	((u.u_ssw & SSW_SIZ_68020)==0x00) ? "long-word"
		  :					    "UNKNOWN size!"),

		(u.u_ssw & SSW_FCODE_68020),			/* FCn */
		fmap[(u.u_ssw & SSW_FCODE_68020)]
	   );
#endif	defined(M68020)

#if	defined(M68010) || defined(M68020)
	/*
	 * Exception Fault Frame #
	 */
	printf("   u_effn=0x%x: ==> %s stack frame.\n",
		u.u_effn,
		(
		  (u.u_effn==0)	? "Normal 4-word"
		: (u.u_effn==1)	? "Throwaway 4-word"
		: (u.u_effn==2)	? "Normal 6-word"
		: (u.u_effn==8)	? "68010 Bus/Addr Error Exception (29-word)"
		: (u.u_effn==9)	? "CoProcessor Mid-Instruction (10-word)"
		: (u.u_effn==10)? "Short Bus-Cycle-Fault (16-word)"
		: (u.u_effn==11)? "Long Bus-Cycle-Fault (44-word)"
		:		  "UNKNOWN FORMAT"
		));
#endif	defined(M68010) || defined(M68020)

#ifdef	M68020
	if (chipType==CHIPTYPE_68020) {
	   printf("   aAddr=0x%X  aAddrB=0x%X  aAddrC=0x%X\n",
		u.u_aAddr, u.u_aAddrB, u.u_aAddrC);
	   printf("   iReg=0x%X  iRegB=0x%x iRegC=0x%x  doBuf=0x%X",
		u.u_iReg, u.u_iRegB, u.u_iRegC, u.u_doBuf);

	   /*
	    * Long Bus-Cycle-Fault stack frame
	    */
	   if (u.u_effn==11)
		printf("  diBuf=0x%X\n", u.u_diBuf);
	   else	printf("\n");
	}
#endif	M68020

#ifdef	VALID_RPC
	printf("   u_procp=0x%X  p_rpcresults=0x%x  p_rpcflags=0x%x  p_rpcerror=0x%x\n",
		p,
		p->p_rpcresults,	/* Results from RPC call */
		p->p_rpcflags,		/* Flags used with RPC	*/
		p->p_rpcerror);		/* Error from RPC call	*/
#endif	VALID_RPC

	showregs();
}

/*
 * Display the cpu time
 * in 'dd+hh:mm:ss' format.
 */
ddhhProcTime(tp)
	register struct timeval *tp;
{
	register int	dd, hh, mm, ss;

	/*
	 * This is WRONG, but for now it'll do.
	 * Need to subtract the time since the epoch
	 * to the beginning of today.
	 */
	mm  = tp->tv_sec / 60;
	ss  = tp->tv_sec % 60;

	hh  = mm / 60;
	mm %= 60;

	dd  = hh / 24;
	hh %= 24;

#if 1
	/*
	 * For our purposes here,
	 * we may dispense with the date.
	 */
	printf("%2ld:%02ld:%02ld",	     hh, mm, ss);
#else
	/*
	 * The origional, as stolen from /bin/ps
	 */
	if (dd)
		printf(" %2ld+%02ld:%02ld:%02ld", dd, hh, mm, ss);
	else if (hh)
		printf("    %2ld:%02ld:%02ld",	     hh, mm, ss);
	else
		printf("       %2ld:%02ld",		 mm, ss);
#endif 1
}

/*
 * inRange -- Determine if 'vAddr' is within the proper range
 *	      of CURRENT process.
 */
inRange(vAddr)	/* Returns 1 iff vAddr within domain of current process */
	register u_long	vAddr;
{

  if (! (u.u_aAddr >= USRTEXT))		/* Never not applicable */
	return 0;	/* Out of range */

  if (	 /*
	  * Within the p0 partition, a'la VAX:  TEXT+DATA.
	  *
	  * Recall that the VAX p0 partition grows upward
	  * from the low end of the process and includes
	  * BOTH the text and data areas,
	  * but does not include the process stackarea (p1 partition)
	  *
	  * ...and within text XOR data portion of p0, exclusive of the GAP.
	  * Note that p_tsize is rounded up to a whole # of segments,
	  * and x_size isn't rounded up.
	  * Hence the '=' in the relation.
	  *
	  * Recall that the VAX p0 partition grows upward
	  * from the low end of the process and includes
	  * BOTH the text and data areas.
	  * p0 excludes the process stackarea, which is the p1 partition.
	  */
	   ( u.u_aAddr <  USRTEXT+(u_long)ptob(suregp0lr)    /* < TOP of data */

	   && ( u.u_procp->p_textp==NULL   /* ...and NO extant text (or data) */
		/*
		 * ...or strictly in the (extant) TEXT portion...
		 */
	      || u.u_aAddr <  USRTEXT + (u_long)ptob(u.u_procp->p_textp->x_size)
		/*
		 * ...or strictly in the (extant) DATA portion...
		 * E.g., NOT in the GAP between text and data.
		 */
	      || u.u_aAddr >= USRTEXT + (u_long)ptob(u.u_procp->p_tsize)
	      )
	   )
	||  u.u_aAddr >= ( (u_long) ptob(usrtop(u.u_procp)+HIGHPAGES)
		 	 - (u_long) ptob(proc0Initd	/* Safe now...*/
						? p1pages(u.u_procp)
						: p1Pages
					)
			 + (u_long) ptob(suregp1lr)
			 )
	    /*
	     * ...and simply in (below) the high end of the user stack...
	     */
	&& u.u_aAddr < (u_long)usrstack(u.u_procp)
     )
  {
	return 1;	/* Within ONE of text, data, stack, or highpages area */
  }

#if 0
	printf("u.u_aAddr=(0x%x)<(USRTEXT+(u_long)ptob(suregp0lr))=(0x%x)\n",
		u.u_aAddr, USRTEXT+(u_long)ptob(suregp0lr));
	printf("&& (!(u.u_procp->p_textp=(0x%x))\n", u.u_procp->p_textp);
	printf("   || u.u_aAddr < (USRTEXT + (u_long)ptob(u.u_procp->p_textp->x_size)) = (0x%x)\n",
		USRTEXT+(u_long)ptob(u.u_procp->p_textp->x_size));
	printf("   || u.u_aAddr >= (USRTEXT + (u_long)ptob(u.u_procp->p_tsize))=(0x%x)\n)\n",
		(USRTEXT + (u_long)ptob(u.u_procp->p_tsize)));

	printf("||  u.u_aAddr >= ( (u_long) ptob(usrtop(u.u_procp)+HIGHPAGES)=(0x%x)\n",
		(u_long) ptob(usrtop(u.u_procp)+HIGHPAGES));
	printf("\t- (u_long) ptob(proc0Initd(%d) ? p1pages(u.u_procp)=(0x%x) : p1Pages(0x%x))=(0x%x)\n",
		proc0Initd, p1pages(u.u_procp), p1Pages,
		(u_long) ptob(proc0Initd ? p1pages(u.u_procp) : p1Pages));
	printf("\t+ (u_long) ptob(suregp1lr=(0x%x))=(0x%x)\n)\n",
		suregp1lr, (u_long) ptob(suregp1lr));
	printf("&& u.u_aAddr < (u_long)usrstack(u.u_procp)=(0x%x)\n",	
		usrstack(u.u_procp));
	/*
	 * Squawk -- out of range reference!
	 */
	cdebugger("inRange == 0");
#endif 0

	return 0;
}

#ifdef	M68020
#ifdef	s32	/* EXCEPTION_BUT_NO_ERROR */
/*
 * spuriousBusErr -- Handle case where Bus Err, but no h/w error-bits.
 *
 * This is a "feature" of the 68020:
 *
 *	One can get a fault on a pre-fetch,
 *	the fault being spurious because the cpu
 *	never "really" needed the results of the pre-fetch.
 *
 * However, since we spent this much work finding
 * out that there's nothing to do, rather than RTE immediately,
 * we might as well see if there is SOMETHING useful
 * that can come of all of this...
 */
spuriousBusErr(error32)
	register u_long	error32;
{
	register int		i;
	register struct	pte	*pte;

	/*
	 * Hunt for the elusive logical inconsistency...
	 * ...an exception, but no error signified by the h/w.
	 */
	if ( (chipType==CHIPTYPE_68020)
	  && ((error32 & (V_SUM_BERR_BAR/* Summation of several ERRs */
			 |V_BAD_LADR_ERR/* BAD.LADR.ERR		     */
			 |V_SMAP_BERR	/* Segment map error	     */
			 |V_PMAP_BERR))	/* Page map error	     */

				== V_SUM_BERR_BAR	/* I.e., no error... */
	     )
	   )
	{
		u_short	entry;

		/*
		 * Gosh, folks we had an execption, but NO ERROR!!
		 *
		 * Probably a spurious prefetch done by the 68020,
		 * which was later discarded by the microprocessor
		 * as unneeded.
		 *
		 * Theoretically, we should be able to simply return,
		 * thus effecting an 'RTE' instruction
		 * with no harm done.
		 *
		 * However, since we are here, let's see if we can
		 * do some useful work...
		 */
		if (lcwDebug) {
			debug	      |= D_VMEM; /* Produce some blab */
			userSegBlab    = 1;
			userPagingBlab = 1;
		}

		/*
		 * Attempt to find and fixup a segment fault;
		 * Otherwise attempt pagefault fixup.
		 */
		if (((i=getsegmap(MYCTXT,u.u_aAddr)) & SEG_ACCMODE)==0)
		{
			/*
			 * Segment has never been touched before
			 */
			return V_SMAP_BERR;	/* Lie outrageously */

		} else {

		   entry = getpagemap(u.u_aAddr >> pageshift);

		   /*
		    * Validate the h/w entry.
		    */
		   if (entry != (u_short) -1)	/* Seems ok... */
		   {
			if ((entry & V_MISSING) == V_MISSING)
			{
				/*
				 * BINGO...this is the most likely cause...
				 */
				return V_PMAP_BERR;	/* Lie outrageously */
			}
		   } else {
			cdebugger("trap/E-22: getpagemap() returned -1 for u.u_aAddr");
			return 0;	/* Spurious error; but bad pte? */
		   }
		}

		/*
		 * At this point, our only choice is a spurious
		 * V_BAD_LADR_ERR which was disregarded by the prefetch.
		 */
		badLaddr++;

		/*
		 * Now we would receive (the first of)
		 * any ADDITIONAL busErr that had latched up
		 * between our entry to busErr and here.
		 * We have saved enough state information
		 * to successfully sort through the entrails.
		 */
		setErrorReg(0);
		flushWriteQueue(); /* Delay for concurrency */
		return 0;
	}
	return 0;
}
#endif	s32	/* EXCEPTION_BUT_NO_ERROR */

#ifdef	M68020_REV_B
/*
 * hyperMmu -- Handle segment fault for process requiring
 *		more than maxVSmaps worth of physical segment maps.
 *
 * Algorithm:
 * ==========
 *	Do the right thing:  "LRU" in an smap so she can continue
 *	running the process.
 */
hyperMmu(vAddr)
/*D7*/	register u_long	vAddr;
{
/*A5*/	register struct	pte	*pte;
/*A4*/	register struct	proc	*p = u.u_procp;
/*D6*/	register int		i;
/*D5*/	register u_long		vSegAddr = vAddr & ~segmask;
/*D4*/	register		s = spl7();	/* Protect posterior */
	int	 		oldD_VMEM = debug & D_VMEM;

	/*
	 * Virtual segment is NOT mapped.
	 *
	 *	1) Delete the virtual segment from the front
	 *	of the LRU linear list in the upage;
	 *
	 *	2) Add the non-instantianted virtual segment
	 *	to the front of the MRU-list;
	 *
	 *	3) Update the segment mmu hardware to reflect
	 *	both the deleted-LRU and the added-MRU
	 *	virtual segment entries.
	 *
	 *	4) pagein() the u_aAddr-referenced page
	 *	contained in the newly added segment.
	 *	Two things can then happen:
	 *
	 *		i) The page is reclaimed and an immediate
	 *		direct return is made back here.
	 *
	 *			==> No consequences; nothing to do.  A-OK!
	 *
	 *		ii) We sleep() in pagein(), presumably invoking 
	 *		ctxt_invalidate() indirectly and probably scrambling
	 *		the smaps[] ordering as (an)other process(es) run.
	 *
	 *			==> Maybe the faulted segment is again
	 *			    not mapped, thus faulting again.
	 *			    Dire straits if we fall into fibrilation!
	 *
	 *	Therefore, we MUST insure that our faulted segment is mapped
	 *	the first time.  This in turn implies that sureg() should
	 *	probably reload the segment maps in the MRU ordering designated
	 *	by the list in the upage.
	 */

	/*
	 * 1) Make room for the faulted segment
	 * by purging one we haven't referenced for awhile.
	 *
	 * We only do this if we have no more PHYSICAL segments
	 * to allocate for this process in our virtual space.
	 */
#define	maxPSmaps	mmu_sizing[MMU_16MB].mmu_maxVSmaps /* BUG: aka KLUDGE */

	if (u.u_vSmapsInUse >= maxPSmaps) {
	   register struct	cmap	*c;
	   register unsigned		sno;
	   register unsigned		j	= 0;
	   unsigned			pf	= btop(vAddr);
	   int				stillLooking = -1;

	   if (virtSmapBlab) {
#if 1
		cdebugger("hyperMmu/I-s3a4: virtual segment map entry to be deleted");
#endif 1
		debug |= D_VMEM;	/* Blab... */
	   }
#ifdef	JHT
	   /*
	    * We also need to FREE
	    * both the h/w & s/w segment maps
	    * and  the h/w & s/w page maps
	    * corresponding to the deleted VIRTUAL smap.
	    *
	    * Scan the candidate deletion segments for any
	    * locked pages.  Delete() and re-add() the segment,
	    * if any interior page is currently locked.
	    * This effectively moves it from the back
	    * of the list up to the front of the list.
	    */
	   while (HEAD != NOSMAP
	       && stillLooking
	       && (j++ < maxVSmaps(u.u_procp)))	/* Firedoor */
	   {
	     /*
	      * Process each candidate segment in turn.
	      */
	     sno = HEAD;
	     pf	 = sno >> PTOSSHIFT;

	     /*
	      * Scan the pages for user-locks.
	      * We begin with the 1st page
	      * of the candidate segment.
	      */
	     for (i = 0; i < SEGSIZE/NBPG; i++) {
		c  = &cmap[pgtocm(pf)];
		if (c->c_lock) {

			/*
			 * Page locked; move this segment
			 * to the other end of our list.
			 * And try the next segment in our list.
			 *
			 * BUG: No range checking is done
			 * for delAtHead()/addAtTail().
			 */
			delAtHead();	 /* HEAD is updated   */
			addAtTail(sno++);/* Try next smap, too */
			break;		/* ...the for-loop    */

		} else {
		  /*
		   * BINGO!  None of this segment's pages
		   * have been locked.
		   */
		  if (i >= ((SEGSIZE/NBPG)-1)) {
			register struct	dmap	*dmp;
			u_long			vaddr = pf<<pageshift;

			p = (struct proc *)u.u_procp;

			/*
			 * NOTE:  Is there a better way to to this: (?!)
			 *
			 * Swap a segment of virtual memory
			 * to disk, by locating the contiguous
			 * dirty pte's and calling vschunk()
			 * with each chunk.
			 *
			 * BUG: we could block on vsswap()
			 */
			if (c->c_type == CTEXT) {

				pte = tptopte(p, vaddr);
				/*
				 * We can just abandon TEXT.
				 * ('dmp' is never used if TEXT)
				 */
				dmp = (struct dmap *)0;

			} else if (c->c_type == CDATA) {
				pte = dptopte(p, vaddr);
				dmp = &u.u_dmap;

			} else if (c->c_type == CSTACK) {
				pte = sptopte(p, vaddr);
				dmp = &u.u_smap;

			} else cdebugger("hyperMmu/E-s3a9: c_type");

			vaddr = sno << segshift;
			vsswap(	p,

				/*
				 * vtopte() could return -1 or 0;
				 * BUG: for now, let it fault.
				 */
				vtopte(p, vaddr),

				c->c_type,
				0,		/* vsbase  */
				SEGSIZE/NBPG,	/* vscount */
				dmp
			      );
		
			stillLooking = 0;
			break;
		   }
		}
		pf++;	/* Try the next page */
	     }
	   }
#endif	JHT
	   if (j >= maxPSmaps) {	/* Firedoor */
		cdebugger("hyperMmu/I-s3a5: Out of VSmaps");
	   }
	} else {	/* Steal one from the free list or another context */
		register want = 1;
		register loop_count = 0;
#ifdef	USE_CTXT
		extern u_short	ctxt_dequeue_debug;
		extern u_long	dequeue_fixup_count;
#endif	USE_CTXT

		/*
		 * Take our process off any lists so that
		 * we will not take smaps from ourselves
		 * in case we start stealing them from
		 * processes.
		 */
#ifdef	USE_CTXT
		dequeue(&p->p_lru);
#endif	USE_CTXT
			/************************/
			/*	Free list	*/
			/************************/

		if (( i = smap_free) != NOSMAP) {
			smap_free = smaps[i];
			want = 0;
#ifdef	USE_CTXT
			CTXT_ADDSTAT(freetaken, 1);
			p->p_needmap--;
			smaps[i] = p->p_smaps;
			p->p_smaps = i;
#endif	USE_CTXT
		}


#ifdef	USE_CTXT
			/********************************/
			/*	"No-Contexts"		*/
			/********************************/

		/*
		 * If there are any processes with segment
		 * maps, but no context, then start stealing
		 * segment maps from them.
		 */
		while (want && ctxt_noctxt.lru != &ctxt_noctxt) {
/*A2*/			register struct proc *oldproc = P(ctxt_noctxt.lru);

			if ((i = oldproc->p_smaps) != NOSMAP) {
				oldproc->p_smaps = smaps[i];
				oldproc->p_needmap ++;
				want = 0;
				p->p_needmap--;
				smaps[i] = p->p_smaps;
				p->p_smaps = i;
			}
			/*
			 * If the process has no segment maps
			 * left then take it off all lists.
			 */
			if (oldproc->p_smaps == NOSMAP)
			{
				dequeue(&oldproc->p_lru);
				emptyList(&oldproc->p_lru);
			}
		}

			/********************************/
			/*	"Have-Contexts"		*/
			/********************************/

		/*
		 * Finally, we must steal segment maps
		 * from processes that have contexts.
		 */
ctxt_loopback:
		while (want && ctxt_havectxt.lru != &ctxt_havectxt) {
/*A2*/			register struct proc *oldproc = P(ctxt_havectxt.lru);

			if ((i = oldproc->p_smaps) != NOSMAP) {
				oldproc->p_smaps = smaps[i];
				oldproc->p_needmap ++;
				want = 0;
				p->p_needmap--;
				smaps[i] = p->p_smaps;
				p->p_smaps = i;
			}
			/*
			 * If the process has no segment maps
			 * left then take it off all lists and
			 * make it give up its context since
			 * it no longer contains any valid
			 * data.
			 */
			if (oldproc->p_smaps == NOSMAP)
			{
				dequeue(&oldproc->p_lru);
				emptyList(&oldproc->p_lru);
				if (oldproc->p_ctxt == NOCTXT)
					panic("sureg: ctxt_havectxt list is bad");
				oldproc->p_ctxt->procp = NULL;
				dequeue(oldproc->p_ctxt);
				addlru(&ctxt_list, oldproc->p_ctxt);
				oldproc->p_ctxt = NOCTXT;
			}
		}
		/*
		 * If we still need smaps we are really hurting now.  It
		 * seems that there are processes which have contexts (and
		 * smaps) which are possibly not on the "havectxt" list.
		 * No clue (yet) as to how they get there, but we can use 
		 * brute force to seek them out and put them back on the
		 * "havectxt" list then jump back and try to get more
		 * smaps.  This is ineffecient and kludgy; but when the
		 * alternative is panic-ing, you can get creative.
		 *
		 * ELP - 3/6/86
		 */

		if (want && (loop_count < 10)) {
			register ctxt_t		*ctxt;

			ctxt = (ctxt_t *) ctxt_list.lru;
			while (ctxt != (ctxt_t *) &ctxt_list) {
				if (ctxt->procp && p != ctxt->procp &&
				    ctxt->procp->p_smaps != NOSMAP) {
					if (ctxt_dequeue_debug) {
						cdebugger ("About to reclaim dequeued context");
					}
					loop_count ++;	
					dequeue_fixup_count ++;	
					DODEBUG(D_CTXT,
						(" dequeued context pid %d",
						ctxt->procp->p_pid));
					dequeue (&ctxt->procp->p_lru);
					addlru (&ctxt_havectxt, &ctxt->procp->p_lru);
					goto ctxt_loopback;
				}
				ctxt = ctxt->lru;
			}
		}
#endif	USE_CTXT
		if (want && HEAD != NOSMAP) {
			/*
			 * If we get here we couldn't beg, borrow, or steal
			 * an smap so we consume frometh our own flesh.
			 */
			/* Get the vtop mapping */
			i = getsegmap (MYCTXT, stob(HEAD & M_));
			/* Invalidate oldest one */
			setsegmap(MYCTXT, stob(HEAD & M_), DUMMYSMAP); 
			delAtHead ();	/* Remove it from the list */
			want = 0;
		}
		if (want) panic ("hyperMmu: virtual segment botch");
#ifdef	USE_CTXT
		addmru(&ctxt_havectxt, &p->p_lru);
#endif	USE_CTXT
	}

	splx (s);	/* Bring us back down */
	/*
	 * 2) Add the faulted segment to the
	 * virtual smap's instantiation list.
	 *
	 * NOTE: setsegmap() does the addAtHead() invocation. Not any more - ELP
	 */
	if (virtSmapBlab) {
#if 1
	  cdebugger("hyperMmu/I-s3a8: virtual segment map altered");
#endif 1
	  debug |= D_VMEM;	/* Blab... */
	}
	i &= SEG_PAGE;
	addAtTail (btos(vSegAddr));
	if (isatsv(u.u_procp, vAddr >> pageshift) &&
	 (*(u_long *)suregp0br & PG_PROT) != PG_UW) {
		/*
		 * Text segment -- make readonly
		 * and let the microprocessor rerun it.
		 */
		setsegmap(MYCTXT, vAddr, i | SEG_AUR);
		pte = (struct pte *) &suregp0br [btop(vSegAddr)-LOWPAGES];
	} else {
		/*
		 * Data or stack segment -- make it user-writeable,
		 * and let the microprocessor rerun the faulted instruction.
		 *
		 * If this is the first access to a page
		 * in a new stack segment, then we will, in addition,
		 * subsequently pagefault at the same address,
		 * which is the cleanest way to handle it,
		 * the exception being benchmarks that willfully exacerbate
		 * THAT specific degeneracy!  To wit, one could avoid ensuing
		 * the pagefault overhead if one selectively zero pre-filled 
		 * such a (fod) stack page.  Oh, well...
		 */
		setsegmap(MYCTXT, vAddr, i | SEG_AURW);
		if (isatsv(u.u_procp, vAddr >> pageshift) ||
		    isadsv(u.u_procp, vAddr >> pageshift))
			pte = (struct pte *)&suregp0br[btop(vSegAddr)-LOWPAGES];		else if ((vAddr & ~segmask) == ((nSegs - 1) << segshift))
			pte = (struct pte *)
			    &suregp0br[(u.u_procp->p_szpt*NPTEPG)-PPS];
		else	/* Stack */
			pte = (struct pte *)&suregp1br[btop(vSegAddr)];
	}
	setsysmap (btop(vSegAddr), pte, PPS);
	pte = &pte [btop(vAddr - vSegAddr)];
	if (!pte->pg_v) {
		register struct fpte *fpte = (struct fpte *) pte;

		/*
		 * This stuff is taken care of by the setsysmap and will 
		 * cause a panic if we let pagein handle it.
		 */
		if (fpte->pg_fod == 0 || fpte->pg_fileno != PG_FPHYS)
			pagein (vAddr, 0);
	}
	debug &=   ~D_VMEM;	/* Turn off blab */
	debug |= oldD_VMEM;
}
#endif	M68020_REV_B
