Coherent4.2.10/i386/trap.c

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

/*
 * $Header: /v/src/rcskrnl/i386/RCS/trap.c,v 420.6 1993/12/02 18:05:11 srcadm Exp srcadm $
 */

/*********************************************************************
 *
 * Coherent, Mark Williams Company
 * RCS Header
 * This file contains proprietary information and is considered
 * a trade secret.  Unauthorized use is prohibited.
 *
 *
 * $Id: trap.c,v 420.6 1993/12/02 18:05:11 srcadm Exp srcadm $
 *
 * $Log: trap.c,v $
 * Revision 420.6  1993/12/02  18:05:11  srcadm
 * Attempt to fix bogus call number in lock imbalance printf.
 *
 * Revision 420.5  1993/12/02  18:02:57  srcadm
 * Initial RCS submission.
 *
 *
 */

#ifdef EMBEDDED_VERSION
/* Embedded Version Constant */
char *MWC_TRAP_C_VERSION = "MWC_TRAP_C_VERSION($Revision: 420.6 $)";
#endif

/*
 * Trap entry for miscellaneous i386 traps and faults.
 * Revision 2.5  93/10/29  00:57:27  nigel
 * R98 (aka 4.2 Beta) prior to removing System Global memory
 * 
 * Revision 2.4  93/09/02  18:12:26  nigel
 * Major edits for new flag system, cleanup of dead variables.
 * 
 * Revision 2.3  93/08/19  03:40:17  nigel
 * Nigel's R83
 */

#include <common/_gregset.h>
#include <sys/errno.h>
#include <signal.h>
#include <stddef.h>

#define	_KERNEL		1

#include <kernel/trace.h>
#include <kernel/systab.h>
#include <kernel/reg.h>
#include <sys/proc.h>
#include <sys/uproc.h>
#include <sys/seg.h>
#include <sys/mmu.h>


/*
 * Tunable parameter for controlling whether signal-generating traps cause
 * output on the system console.
 */

extern	unsigned char	CONSOLE_TRAP_DUMP;
extern	unsigned char	NMI_DUMP;


/* opcodes recognized, and partially emulated, in gp fault handler */
#define READ_CR0	1
#define WRITE_CR0	2
#define READ_CR2	3
#define READ_CR3	4
#define WRITE_CR3	5
#define HALT		6
#define IRET		7
#define READ_DR0	8
#define READ_DR1	9
#define READ_DR2	10
#define READ_DR3	11
#define READ_DR6	12
#define READ_DR7	13
#define WRITE_DR0	14
#define WRITE_DR1	15
#define WRITE_DR2	16
#define WRITE_DR3	17
#define WRITE_DR6	18
#define WRITE_DR7	19

#define ENTER_OP	0xC8	/* Opcode for 'enter' instruction.  */
#define IRET_RETRY_LIM	10

extern unsigned char selkcopy();
extern unsigned int DR0,DR1,DR2,DR3,DR7;
static int trap_op();


/*
 * Global symbols from kernel text.
 */

extern unsigned int	__xtrap_break__;
extern unsigned int	__xtrap_off__;
extern unsigned int	__xtrap_on__;
extern unsigned int	signal_386;
extern unsigned int	syscall_386;

/*
 * iret_flt is set when first bad iret is detected.
 */
static int iret_flt;

/*
 * Trap handler.
 * The arguments are the registers,
 * saved on the stack by machine code. This call
 * is different from most C calls in that the registers
 * get copied back; if you change a "trap" parameter then
 * the machine register will be altered when the trap is
 * dismissed.
 *
 * Argument "trapno" is the return eip for the code calling tsave().
 */

void
trap (regset)
gregset_t	regset;
{
	int		sigcode;

	/*
	 * Expect this to never happen!
	 */

	if (SELF->p_flags & PFKERN) {
		panic ("pid%d: kernel process trap: err=%x, ip=%x ax=%d",
			SELF->p_pid, regset._i386._err, __PC_REG (& regset),
			regset._i386._eax);
	}

	T_HAL (0x4000, printf ("T%d ", regset._i386._err));
	sigcode = 0;

	switch (regset._i386._err) {
	case SIOSYS:
		/*
		 * 286 System call.
		 */
		sigcode = oldsys (& regset);
		break;

	case SISYS: {
		struct systab *	stp;
		long		args [MSACOUNT];
		unsigned	callnum;
		struct __menv	sigenv;

		/*
		 * 386 System call.
		 */

		set_user_error (0);
		callnum = regset._i386._eax;

		if (callnum < NMICALL)
			stp = sysitab + callnum;
		else if (callnum == COHCALL)
			stp = & cohcall;
		else if ((callnum & 0xFF) == 0x28 &&
			 (callnum >> 8) <= H28CALL)
			stp = h28itab + (callnum >> 8) - 1;
		else {
			sigcode = SIGSYS;
			goto trapend;
		}

		T_ERRNO (2, cmn_err (CE_CONT, "{%s", stp->s_name));
		stp->s_stat ++;

		ukcopy (regset._i386._uesp + sizeof (long), args,
			stp->s_nargs * sizeof (long));

		if (get_user_error ()) {
			sigcode = SIGSYS;
			goto trapend;
		}

		if (envsave (u.u_sigenvp = & sigenv)) {
			set_user_error (EINTR);
		} else {
			regset._i386._eax = __DOSYSCALL (stp->s_nargs,
							 stp->s_func, args,
							 & regset);
			regset._i386._edx = u.u_rval2;
		}

		/*
		 * LOUIS:
		 * This is after the system call, so we can't be
		 * assured that _eax is the same even though the
		 * environment is recovered.  Well, it's not at
		 * any rate.  So, we just use callnum to place
		 * the system call since this is always good because
		 * it is saved in the stack frame.
		 */

		if (u.u_lock_cnt != 0) {
			cmn_err (CE_WARN,
				 "Lock count imbalance (%d) after syscall %d",
				 u.u_lock_cnt, callnum);
		}

		if (get_user_error ()) {
			regset._i386._eax = get_user_error ();

			__FLAG_REG (& regset) =
				__FLAG_SET_FLAG (__FLAG_REG (& regset),
						 __CARRY);
			T_ERRNO (2, cmn_err (CE_CONT, "-err"));
#ifdef FORJRD
		printf("Call: %d   Errno: %d\n", callnum, get_user_error());
#endif
		} else		/* clear carry flag in return efl */
			__FLAG_REG (& regset) =
				__FLAG_CLEAR_FLAG (__FLAG_REG (& regset),
						   __CARRY);
		LOCK_DISPATCH ();
		u.u_sigenvp = 0;

		T_ERRNO (2, cmn_err (CE_CONT, "=%x}", regset._i386._eax));
		break;
	    } /* end block */

		/*
		 * Trap.
		 */
	case SIDIV:
		if (! __IS_USER_REGS (& regset)) {

			curr_register_dump (& regset, _PRIVILEGE_RING_1);
			panic ("Integer divide by zero");
		}
#if	TRACER
		printf ("Integer divide by zero");
		curr_register_dump (& regset, _PRIVILEGE_RING_1);
#endif
		sigcode = SIGFPE;
		break;

	case SISST:
		sigcode = SIGTRAP;
		break;

	case SIBPT:
		sigcode = SIGTRAP;
		break;

	case SIOVF:
		sigcode = SIGEMT;
		break;

	case SIBND:
		/*
		 * Bound
		 */
		sigcode = SIGIOT;
		break;

	case SIOP: {
		int	      *	ip = (int *) __PC_REG (& regset);

		printf ("(eip)=%x %x %x  ", ip [0], ip [1], ip [2]);

		/*
		 * Invalid opcode
		 */

		if (! __IS_USER_REGS (& regset)) {

			curr_register_dump (& regset, _PRIVILEGE_RING_1);
			panic ("Invalid Opcode");
		}
		
		sigcode = SIGILL;
		break;
	}
#if 0
	case SIXNP:
		/*
		 * Processor extension not available
		 */
		if (int11() & 2)	/* NDP present */
			ndpNewOwner();
		else
			sigcode = SIGFPE;
		break;
#endif

	case SIDBL:
		/*
		 * Double exception
		 */
		panic ("double exception: cs=%x ip=%x", regset._i386._cs,
		       __PC_REG (& regset));
		sigcode = SIGSEGV;
		break;

	case SIXS:
		/*
		 * Processor extension segment overrun
		 */
		sigcode = SIGSEGV;
		break;

	case SITS:
		/*
		 * Invalid task state segment
		 */
		panic ("invalid tss: cs=%x ip=%x", regset._i386._cs,
		       __PC_REG (& regset));
		sigcode = SIGSEGV;
		break;

	case SINP:
		/*
		 * Segment not present
		 */
		sigcode = SIGSEGV;
		break;

	case SISS:
		/*
		 * Stack segment overrun/not present
		 */
		sigcode = SIGKILL;
		break;

	case SINMI:
#define	__SYSCON_B	0x61		/* System control port B */
#define	__PARITY_FAULT	0x80		/* Parity fault flag */
		if ((inb (__SYSCON_B) & __PARITY_FAULT) != 0) {
			printf ("Parity error\n");
			curr_register_dump (& regset, _PRIVILEGE_RING_1);
#if	0
			panic("...");
#endif
		} else if (NMI_DUMP)
			printf ("Unexpected NMI\n");
		return;

	default:
		curr_register_dump (& regset, _PRIVILEGE_RING_1);
		panic("Fatal Trap");
	}

trapend:
	/*
	 * Send user a signal.
	 * If not a breakpoint, do console register dump.
	 */
	if (sigcode) {
		if (sigcode != SIGTRAP && CONSOLE_TRAP_DUMP) {
			curr_register_dump (& regset, _PRIVILEGE_RING_1);
			cmn_err (CE_CONT, "sigcode=#%d  User Trap\n", sigcode);
			user_bt (& regset);
		}
		sendsig (sigcode, SELF);
	}
}


/*
 * trap_op()
 *
 * Look at the trapped instruction.
 * If it's one of a select few, recognize and return the type.
 * Otherwise, return 0.
 *
 * This could be fancier, but all we want to look for is:
 * (for CRx and DRx, second operand is limited to %eax).
 *	0F 20 C0	READ_CR0
 *	0F 22 C0	WRITE_CR0
 *	0F 20 D0	READ_CR2
 *	0F 20 D8	READ_CR3
 *	0F 22 D8	WRITE_CR3
 *	CF		IRET
 *	F4		HALT
 *	0F 23 C0	WRITE_DR0
 *	0F 23 C8	WRITE_DR1
 *	0F 23 D0	WRITE_DR2
 *	0F 23 D8	WRITE_DR3
 *	0F 23 F0	WRITE_DR6
 *	0F 23 F8	WRITE_DR7
 *	0F 21 C0	READ_DR0
 *	0F 21 C8	READ_DR1
 *	0F 21 D0	READ_DR2
 *	0F 21 D8	READ_DR3
 *	0F 21 F0	READ_DR6
 *	0F 21 F8	READ_DR7
 */

static int
trap_op(cs,eip)
unsigned int cs, eip;
{
	int		ret = 0;

	switch (ffbyte (eip, cs)) {

	case 0x0F:
		switch (ffbyte (eip + 1, cs)) {

		case 0x20:
			switch (ffbyte (eip + 2, cs)) {
			case 0xC0:
				ret = READ_CR0;
				break;

			case 0xD0:
				ret = READ_CR2;
				break;

			case 0xD8:
				ret = READ_CR3;
				break;
			}
			break;

		case 0x21:
			switch (ffbyte (eip + 2, cs)) {

			case 0xC0:
				ret = READ_DR0;
				break;

			case 0xC8:
				ret = READ_DR1;
				break;

			case 0xD0:
				ret = READ_DR2;
				break;

			case 0xD8:
				ret = READ_DR3;
				break;

			case 0xF0:
				ret = READ_DR6;
				break;

			case 0xF8:
				ret = READ_DR7;
				break;
			}
			break;

		case 0x22:
			switch (ffbyte (eip + 2, cs)) {

			case 0xC0:
				ret = WRITE_CR0;
				break;

			case 0xD8:
				ret = WRITE_CR3;
				break;
			}
			break;

		case 0x23:
			switch (ffbyte (eip + 2, cs)) {

			case 0xC0:
				ret = WRITE_DR0;
				break;

			case 0xC8:
				ret = WRITE_DR1;
				break;

			case 0xD0:
				ret = WRITE_DR2;
				break;

			case 0xD8:
				ret = WRITE_DR3;
				break;

			case 0xF0:
				ret = WRITE_DR6;
				break;

			case 0xF8:
				ret = WRITE_DR7;
				break;
			}
			break;
		}
		break;

	case 0xF4:
		ret = HALT;
		break;

	case 0xCF:
		ret = IRET;
		break;
	}
	return ret;
}


/*
 * General protection fault handler.
 * Entered via a ring 0 gate.
 */

void
gpfault (regset)
gregset_t	regset;
{
	/*
	 * Switch on CPL of code that trapped.
	 */

	switch (__SELECTOR_PRIVILEGE (regset._i386._cs)) {

	case _PRIVILEGE_RING_0:
		/*
		 * Ring 0 should not gp fault.
		 */
		curr_register_dump (& regset, _PRIVILEGE_RING_0);
		panic ("System GP Fault from Ring 0");
		break;

	case _PRIVILEGE_RING_1:
		/*
		 * If ring 1 faulted on a valid request, emulate the
		 * request while running in ring 0.
		 */
		switch (trap_op (regset._i386._cs, __PC_REG (& regset))) {
		case READ_CR0:
			regset._i386._eax = read_cr0 ();
			__PC_REG (& regset) += 3;
			break;

		case WRITE_CR0:
			write_cr0(regset._i386._eax);
			__PC_REG(& regset) += 3;
			break;

		case READ_CR2:
			regset._i386._eax = read_cr2 ();
			__PC_REG (& regset) += 3;
			break;

		case READ_CR3:
			regset._i386._eax = read_cr3 ();
			__PC_REG (& regset) += 3;
			break;
#if 0
		case WRITE_CR3:
			mmuupdnR0 ();
			__PC_REG (& regset) += 3;
			break;
#endif
		case IRET:
			/*
			 * Some CPU's wrongly generate GP faults on IRET
			 * from inner ring to ring 3.
			 * Fix is to retry the instruction a few times.
			 */
			if (! iret_flt) {
				iret_flt = 1;
				printf ("CPU Bug:  "
				  "Spurious GP Fault on Iret to Ring 3.\n");
			}
			break;

		case READ_DR0:
			regset._i386._eax = read_dr0 ();
			__PC_REG (& regset) += 3;
			break;

		case READ_DR1:
			regset._i386._eax = read_dr1 ();
			__PC_REG (& regset) += 3;
			break;

		case READ_DR2:
			regset._i386._eax = read_dr2 ();
			__PC_REG (& regset) += 3;
			break;

		case READ_DR3:
			regset._i386._eax = read_dr3 ();
			__PC_REG (& regset) += 3;
			break;

		case READ_DR6:
			regset._i386._eax = read_dr6 ();
			__PC_REG (& regset) += 3;
			break;

		case READ_DR7:
			regset._i386._eax = read_dr7 ();
			__PC_REG (& regset) += 3;
			break;

		case WRITE_DR0:
			write_dr0 (regset._i386._eax);
			__PC_REG (& regset) += 3;
			break;

		case WRITE_DR1:
			write_dr1 (regset._i386._eax);
			__PC_REG (& regset) += 3;
			break;

		case WRITE_DR2:
			write_dr2 (regset._i386._eax);
			__PC_REG (& regset) += 3;
			break;

		case WRITE_DR3:
			write_dr3 (regset._i386._eax);
			__PC_REG (& regset) += 3;
			break;

		case WRITE_DR6:
			write_dr6 (regset._i386._eax);
			__PC_REG (& regset) += 3;
			break;

		case WRITE_DR7:
			write_dr7 (regset._i386._eax);
			__PC_REG (& regset) += 3;
			break;

		case HALT:
			halt ();
			break;
#if 0
		case WRITE_DR7:
			/*
			 * Expect breakpoint info in globals DR0-3,DR7.
			 */
printf("Setting DR0=%x  DR1=%x  DR2=%x  DR3=%x  DR7=%x\n",
  DR0, DR1, DR2, DR3, DR7);
			write_dr0 (DR0);
			write_dr1 (DR1);
			write_dr2 (DR2);
			write_dr3 (DR3);
			write_dr7 (DR7);
			__PC_REG (& regset) += 3;
			break;
#endif
		default:
			if (__PC_REG (& regset) >= (__ulong_t) & __xtrap_on__ &&
			    __PC_REG (& regset) < (__ulong_t) & __xtrap_off__) {
#if	TRACER
				curr_register_dump (& regset,
						    _PRIVILEGE_RING_0);
				printf ("copy fault called from %x\n",
					* (int *) regset._i386._edx);
#endif
				SET_U_ERROR (EFAULT, "copy gp");
				__PC_REG (& regset) = (__ulong_t) & __xtrap_break__;
			} else {
				curr_register_dump (& regset,
						    _PRIVILEGE_RING_0);
				panic ("System GP Fault from Ring 1");
			}
		}
		break;

	case _PRIVILEGE_RING_2:
		/*
		 * Nothing should be running in Ring 2.
		 */

	case _PRIVILEGE_RING_3:
		/*
		 * Ring 3 gp fault means errant user process.
		 */
		curr_register_dump (& regset, _PRIVILEGE_RING_0);
		cmn_err (CE_CONT, "User GP Violation\n");
		user_bt (& regset);
		sendsig (SIGSEGV, SELF);
		break;
	}
}


/*
 * Kernel debugger.
 *
 * Runs in ring 0.
 */

void
__debug_ker__ (regset)
gregset_t	regset;
{
	unsigned int	dr6 = read_dr6 ();
	int		do_rdump = 1;

	if (dr6 & 0xf) {	/* report breakpoint exception(s) */
		printf("Breakpoint  ");
		if (dr6 & 1)
			printf("DR0=%x  ", DR0);
		if (dr6 & 2)
			printf("DR1=%x  ", DR1);
		if (dr6 & 4)
			printf("DR2=%x  ", DR2);
		if (dr6 & 8)
			printf("DR3=%x  ", DR3);
		printf("DR7=%x\n", DR7);
	}

	if (dr6 & 0xf000) {	/* report other debug exception(s) */
		if (dr6 & 0x8000)
			printf("Switch to debugged task\n");

		if (dr6 & 0x4000) {
			/* Single Step */
			switch (__SELECTOR_PRIVILEGE (regset._i386._cs)) {

			/*
			 * If user code trapped, send signal
			 * and suppress console register dump.
			 */

			case _PRIVILEGE_RING_1:
				/*
				 * Turn off single-stepping when entering
				 * Ring 1.
				 */
				if (__PC_REG (& regset) == (__ulong_t) & syscall_386 ||
				    __PC_REG (& regset) == (__ulong_t) & signal_386) {
					do_rdump = 0;
				} else {
printf("\nefl=%x  No single stepping the kernel.\n",
	(__flag_arith_t) __FLAG_REG (& regset));
				}
				__FLAG_REG (& regset) = 
					__FLAG_CLEAR_FLAG (__FLAG_REG (& regset),
							   __TRAP);
				break;

			case _USER_PRIVILEGE:
				do_rdump = 0;
T_HAL(0x20000, printf ("Kernel SSTEP eip=%x efl=%x  ", __PC_REG (& regset),
			(__flag_arith_t) __FLAG_REG (& regset)));
				sendsig (SIGTRAP, SELF);
				break;
			}
		}
		if (dr6 & 0x2000) {
			printf("ICE in use\n");
			__PC_REG (& regset) += 3;
		}
	}

	if (do_rdump)
		curr_register_dump (& regset, _PRIVILEGE_RING_0);

	write_dr6 (0);

	__FLAG_REG (& regset) =
		__FLAG_SET_FLAG (__FLAG_REG (& regset), __RESUME);
}


/*
 * User debugger.
 *
 * Runs in ring 1.
 */

void
__debug_usr__ (regset)
gregset_t	regset;
{
	unsigned int	dr6 = read_dr6();
	int		do_rdump = 1;

	if (dr6 & 0xf) {	/* report breakpoint exception(s) */
		printf("Breakpoint  ");
		if (dr6 & 1)
			printf("DR0=%x  ", DR0);
		if (dr6 & 2)
			printf("DR1=%x  ", DR1);
		if (dr6 & 4)
			printf("DR2=%x  ", DR2);
		if (dr6 & 8)
			printf("DR3=%x  ", DR3);
		printf("DR7=%x\n", DR7);
	}

	if (dr6 &  0xf000) {	/* report other debug exception(s) */
		if (dr6 & 0x8000)
			printf("Switch to debugged task\n");

		if (dr6 & 0x4000) {
			/* Single Step */

			switch (__SELECTOR_PRIVILEGE (regset._i386._cs)) {
			/*
			 * If user code trapped, send signal
			 * and suppress console register dump.
			 */

			case _PRIVILEGE_RING_1:
				/*
				 * Turn off single-stepping when entering
				 * Ring 1.
				 */
				if (__PC_REG (& regset) == (__ulong_t) & syscall_386 ||
				    __PC_REG (& regset) == (__ulong_t) & signal_386) {
					do_rdump = 0;
				} else {
printf("/nefl=%x  No single stepping the kernel.\n",
	(__flag_arith_t) __FLAG_REG (& regset));
				}
				__FLAG_REG (& regset) =
					__FLAG_CLEAR_FLAG (__FLAG_REG (& regset),
							   __TRAP);
				break;

			case _USER_PRIVILEGE:
				do_rdump = 0;
T_HAL(0x20000, printf ("User SSTEP eip=%x efl=%x  ", __PC_REG (& regset),
			__FLAG_REG (& regset)));
				sendsig (SIGTRAP, SELF);
				break;
			}
		}
		if (dr6 & 0x2000) {
			printf("ICE in use\n");
			__PC_REG (& regset) += 3;
		}
	}

	if (do_rdump)
		curr_register_dump (& regset, _PRIVILEGE_RING_1);

	write_dr6 (0);


	__FLAG_REG (& regset) =
		__FLAG_SET_FLAG (__FLAG_REG (& regset), __RESUME);
}


/*
 * Ring 0 stack fault handler; this runs at ring 0 so that we can catch kernel
 * stack overflows (or underruns, whatever you want to call them). Note that
 * user code can also cause these.
 */

void
stackfault (regset)
gregset_t	regset;
{
	printf ("Stack fault");
	curr_register_dump (& regset, _PRIVILEGE_RING_0);

	switch (__SELECTOR_PRIVILEGE (regset._i386._cs)) {

	case _USER_PRIVILEGE:
		if (CONSOLE_TRAP_DUMP) {
			curr_register_dump (& regset, _PRIVILEGE_RING_1);
			cmn_err (CE_CONT, "sigcode=#%d  User Stack Fault\n",
				 SIGTRAP);
			user_bt (& regset);
		}
		sendsig (SIGTRAP, SELF);
		break;

	default:
		panic ("The kernel stack has overflowed: we cannot proceed\n");
		break;
	}
}


void
pagefault (regset)
gregset_t	regset;
{
	register int	sigcode;
	register SEG *segp;
	int	splo, datahi;
	unsigned int	txtlo, txthi;
	unsigned long newsp;	/* Anticipated value for stack pointer.  */
	unsigned int cr2 = 0;

	/*
	 * Expect this to never happen!
	 */

	if (SELF->p_flags & PFKERN) {
		panic ("pid%d: kernel process trap: err=%x, ip=%x ax=%d",
			SELF->p_pid, regset._i386._err, __PC_REG (& regset),
			regset._i386._eax);
	}

	T_HAL (0x4000, printf("T%d ", regset._i386._err));
	sigcode = 0;


	/*
	 * Page fault
	 */

	cr2 = read_cr2 ();

	if (! __IS_USER_REGS (& regset)) {
		/*
		 * If page fault during Ring 1 copy service routine,
		 * such as kucopy or ukcopy, set u_error and abort
		 * the copy, but don't send signal to the user.
		 */

		if (__PC_REG (& regset) >= (__ulong_t) & __xtrap_on__ &&
		    __PC_REG (& regset) < (__ulong_t) & __xtrap_off__) {

			T_HAL (0x1000, printf ("copy trapped "));
#if	TRACER
			curr_register_dump (& regset, _PRIVILEGE_RING_1);
			printf ("copy fault called from %x\n",
				* (int *) regset._i386._edx);
#endif
			SET_U_ERROR (EFAULT, "copy service");
			__PC_REG (& regset) = (__ulong_t) & __xtrap_break__;
			goto pf_end;
		} else {
			printf ("cr2=%x", cr2);
			curr_register_dump (& regset, _PRIVILEGE_RING_1);
			panic ("Kernel Page Fault");
		}
	}

	/* Check for stack underflow. */

	/*
	 * I think 'splo' is being calculated in a bass-ackwards way,
	 * and that 'datahi' is just wrong, but I'm not certain,
	 * so the fixes are #if 0'd out. -piggy
	 *
	 * I'll take out the 0 some day and test these changes.
	 */
	segp = SELF->p_segl [SISTACK].sr_segp;
#if 0
	splo = SELF->p_segl [SISTACK].sr_base - segp->s_size;
	datahi = SELF->p_segl [SIPDATA].sr_base + SELF->p_segl [SIPDATA].sr_size;
#else
	splo = __xmode_286 (& regset) ? ISP_286 : ISP_386;
	splo -= segp->s_size;
	datahi = SELF->p_segl [SIPDATA].sr_size;
#endif /* 0 */

	/*
	 * Catch bad function pointer here - don't want to restart
	 * the user instruction and get runaway segv's.
	 *
	 * For 286 executables, eip starts at 0, but cs points to
	 * descriptor SEL_286_UII which adds 0x400000 (UII_BASE).
	 */

	txtlo = (unsigned long) SELF->p_segl [SISTEXT].sr_base;
	if (__xmode_286 (& regset))
		txtlo -= UII_BASE;

	txthi = txtlo + SELF->p_segl [SISTEXT].sr_size;
	if (__PC_REG (& regset) < txtlo ||
	    __PC_REG (& regset) > txthi) {
		T_HAL (0x1000, printf ("Bad eip, txtlo=%x txthi=%x\n",
				       txtlo, txthi));
		goto bad_pf;
	}

	/*
	 * If we trapped on an 'enter' instruction, the stack
	 * pointer (uesp) has not yet been decremented.  In
	 * order to correctly process such a stack overflow,
	 * we must look at the _expected_ value for uesp.
	 * NB: We COPY uesp, because that arg gets loaded back
	 * into the real esp--when we return from the trap the
	 * enter instruction will decrement the esp.
	 */

	newsp = __xmode_286 (& regset) ? regset._i286._usp :
					 regset._i386._uesp;

	if (ffbyte (__PC_REG (& regset), regset._i386._cs) == ENTER_OP) {
		/*
		 * Adjust the sp by the argument of the ENTER
		 * instruction.
		 */

		newsp -= ffword (__PC_REG (& regset) + 1, regset._i386._cs);
	}

	if (cr2 <= splo && newsp <= splo && newsp > datahi &&
	    btocru (datahi) < btocrd (splo)) {
		cseg_t	     *	pp;

		if ((pp = c_extend (segp->s_vmem,
				    btocru (segp->s_size))) == NULL) {
			T_HAL (0x1000, printf ("c_extend(%x,%x)=0 ",
					       segp->s_vmem,
					       btocru (segp->s_size)));
			goto bad_pf;
		}

		segp->s_vmem = pp;
		segp->s_size += NBPC;

		if (sproto (0) == 0) {
			T_HAL(0x1000, printf("sproto(0)=0 "));
			goto bad_pf;
		}

		segload ();
		goto pf_end;
	}

	/*
	 * Catch bad data pointer here - don't want to restart
	 * the user instruction and get runaway segv's.
	 */

	{
		T_HAL(0x1000, printf ("Bad data, splo=%x datahi=%x\n",
				      splo, datahi));
	}

bad_pf:
	/*
	 * User generated unacceptable page fault.
	 */

	sigcode = SIGSEGV;
	printf("\ncr2=%x  ", cr2);

pf_end:
	/*
	 * Send user a signal.
	 * If not segload ();
	 * If not a breakpoint, do console register dump.
	 */

	if (sigcode) {
		if (CONSOLE_TRAP_DUMP) {
			curr_register_dump (& regset, _PRIVILEGE_RING_1);
			cmn_err (CE_CONT, "sigcode=#%d  User Page Fault\n",
				 sigcode);
			user_bt (& regset);
		}
		sendsig (sigcode, SELF);
	}
}