Coherent4.2.10/i386/trap.c
/*
* $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);
}
}