Ultrix-3.1/sys/sys/trap.c
/**********************************************************************
* Copyright (c) Digital Equipment Corporation 1984, 1985, 1986. *
* All Rights Reserved. *
* Reference "/usr/src/COPYRIGHT" for applicable restrictions. *
**********************************************************************/
/*
* SCCSID: @(#)trap.c 3.0 4/21/86
*/
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/dir.h>
#include <sys/user.h>
#include <sys/proc.h>
#include <sys/reg.h>
#include <sys/file.h>
#include <sys/seg.h>
#include <sys/errlog.h>
#include <sys/inline.h>
#define EBIT 1 /* user error bit in PS: C-bit */
#define SETD 0170011 /* SETD instruction */
#define SYS 0104400 /* sys (trap) instruction */
#define USER 020 /* user-mode flag added to dev */
#define MEMORY ((physadr)0177740) /* 11/70 "memory" subsystem */
#define MPCSR ((physadr)0172100) /* memory parity CSR base address */
/*
* Error log buffer for memory parity errors
*/
struct
{
int m_nmsr; /* number of memory system error reg.'s */
int m_mlea; /* low error address */
int m_mhea; /* hi error address */
int m_mser; /* memory system error reg. */
int m_mscr; /* memory system control reg. */
int m_prcw; /* parity CSR configuration word */
int m_pcsr[32]; /* parity CSR contents and error address */
} mp_ebuf = 0;
/*
* Offsets of the user's registers relative to
* the saved r0. See reg.h
*/
char regloc[] =
{
R0, R1, R2, R3, R4, R5, R6, R7, RPS, ROVN
};
int osp;
/*
* Called from l.s 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.
* dev is the kind of trap that occurred.
*/
int tnt = 0; /* trap N trap */
#define CD_SAVE ((physadr)040) /* save crash info */
mapinfo kernelmap; /* saved mapping info on kernel-mode trap */
extern int fpemulation;
/*
* 1/16/86 -- Fred Canter
* If non zero, fd_udno disables (default is enabled) the last
* minute fix for the partial file descriptor allocation bug,
* which occurs when an open() system call that has blocked
* gets interrupted (by an alarm in the test case).
* See Y2.4 field test QAR # 94 (/arch/qar)
* The reference to open() is just so we know its address.
*/
int fd_undo = 0;
extern int open();
trap(dev, sp, r1, ov, nps, r0, pc, ps)
int *pc;
dev_t dev;
{
register i;
register *a;
register struct sysent *callp;
int (*fetch)();
extern int fuword(), fuiword();
time_t syst;
int sz, j;
int *opc; /* save original pc in case we must restart syscall */
struct file *fp;
syst = u.u_stime;
u.u_fpsaved = 0;
if ((ps&(PS_CURMOD|PS_PRVMOD)) == (PS_CURMOD|PS_PRVMOD))
dev |= USER;
else
savemap(kernelmap);
u.u_ar0 = &r0;
switch(minor(dev)) {
/*
* Trap not expected.
* Usually a kernel mode bus error.
* The numbers printed are used to
* find the hardware PS/PC as follows.
* (all numbers in octal 18 bits)
* address_of_saved_ps =
* (ka6*0100) + aps - 0140000;
* address_of_saved_pc =
* address_of_saved_ps - 2;
*/
default:
if(tnt) /* fatal trap - one and only one */
for(;;) ;
tnt++;
printf("\nka6 = %o\n", ka6->r[0]);
CD_SAVE->r[0] = &ps;
CD_SAVE->r[1] = ka6->r[0];
printf("aps = %o\n", &ps);
printf("pc = %o ps = %o\n", pc, ps);
if(_ovno >= 0) /* if overlay kernel print overlay number */
printf("ovno = %d\n", ov);
printf("trap type %o\n", dev);
panic("trap");
case 0+USER: /* bus error */
i = SIGBUS;
break;
/*
* If illegal instructions are not
* being caught and the offending instruction
* is a SETD, the trap is ignored.
* This is because C produces a SETD at
* the beginning of every program which
* will trap on CPUs without 11/45 FPU.
*/
case 1+USER: /* illegal instruction */
if (fpemulation == 1) {
if ((i = fptrap(u.u_ar0, &u.u_fperr.f_fec)) == 0)
goto out; /* instruction was emulated */
if (i == SIGTRAP)
ps &= ~TBIT;
break;
}
if (fuiword((caddr_t)(pc-1)) == SETD && u.u_signal[SIGILL] == 0)
goto out;
i = SIGILL;
break;
case 2+USER: /* bpt or trace */
i = SIGTRAP;
ps &= ~TBIT;
break;
case 3+USER: /* iot */
i = SIGIOT;
break;
case 5+USER: /* emt */
spl0(); /* the emt flag is set, no need for high pri */
if(u.u_ovdata.uo_ovbase != 0 && r0 <= 7 && r0 > 0){
ps &= ~EBIT;
save(u.u_qsav);
u.u_ovdata.uo_curov = r0;
if(estabur(u.u_tsize,u.u_dsize,u.u_ssize,u.u_sep,RO)==0)
{
u.u_ar0[R0] = u.u_ovdata.uo_curov;
u.u_inemt = 0;
goto out;
}
}
u.u_inemt = 0;
i = SIGEMT;
break;
case 6+USER: /* sys call */
u.u_error = 0;
opc = pc - 1; /* opc now points at syscall */
i = fuiword((caddr_t)opc);
callp = &sysent[i&0177];
if (i & 0200) { /* are argument(s) on the stack ? */
a = sp;
fetch = fuword;
} else
{
a = pc;
fetch = fuiword;
pc += callp->sy_narg - callp->sy_nrarg;
}
if (callp == &sysent[SYSINDIR]) { /* indirect */
a = (int *) (*fetch)((caddr_t)(a));
i = fuword((caddr_t)a);
a++;
if (((i & ~0177) != SYS) || ((i &= 0177) > SYSMAX))
i = SYSILLEGAL;
callp = &sysent[i];
fetch = fuword;
} else if (callp == &sysent[BERKINDIR]) { /* Berkely indirect */
a = (int *)(*fetch)((caddr_t)(a));
i = fuword((caddr_t)a);
a++;
if (((i & ~077) != SYS) || ((i &= 077) > BERKMAX))
i = SYSILLEGAL;
else
i += BERKOFFSET;
callp = &sysent[i];
fetch = fuword;
}
if (callp > &sysent[SYSMAX])
callp = &sysent[SYSILLEGAL]; /* illegal */
for (i=0; i<callp->sy_nrarg; i++)
u.u_arg[i] = u.u_ar0[regloc[i]];
for(; i<callp->sy_narg; i++)
u.u_arg[i] = (*fetch)((caddr_t)a++);
u.u_dirp = (caddr_t)u.u_arg[0];
u.u_rval1 = u.u_ar0[R0];
u.u_rval2 = u.u_ar0[R1];
u.u_ap = u.u_arg;
if (save(u.u_qsav)) {
if (u.u_error == 0 && u.u_eosys == JUSTRETURN) {
u.u_error = EINTR;
/* 1/16/86 -- Fred Canter (start of new code) */
/* (see description above, just before of trap()) */
if((fd_undo == 0) && (callp->sy_call == &open)) {
for(j=0; j<NOFILE; j++)
if(u.u_ofile[j] == 0)
break;
j--;
fp = u.u_ofile[j];
if(fp->f_flag&FPENDING) {
fp->f_count--;
fp->f_flag &= ~FPENDING;
u.u_ofile[j] = NULL;
}
}
/* 1/16/86 -- Fred Canter (end of new code) */
}
} else {
u.u_eosys = JUSTRETURN;
(*callp->sy_call)();
}
if (u.u_eosys == RESTARTSYS)
pc = opc; /* backup pc to restart syscall */
else if (u.u_eosys == SIMULATERTI)
dorti(fuiword((caddr_t)opc) & 0200 ?
callp->sy_narg - callp->sy_nrarg : 0);
else
if(u.u_error) {
ps |= EBIT;
u.u_ar0[R0] = u.u_error;
} else {
ps &= ~EBIT;
u.u_ar0[R0] = u.u_rval1;
u.u_ar0[R1] = u.u_rval2;
}
goto out;
#ifdef FP
/*
* Since the floating exception is an
* imprecise trap, a user generated
* trap may actually come from kernel
* mode. In this case, a signal is sent
* to the current process to be picked
* up later.
*/
case 8: /* floating exception */
stst(&u.u_fperr); /* save error code */
psignal(u.u_procp, SIGFPE);
runrun++;
return;
case 8+USER:
i = SIGFPE;
stst(&u.u_fperr);
break;
#endif FP
/*
* If the user SP is below the stack segment,
* grow the stack automatically.
* This relies on the ability of the hardware
* to restart a half executed instruction.
* On the 11/40 this is not the case and
* the routine backup/l40.s may fail.
* The classic example is on the instruction
* cmp -(sp),-(sp)
*/
case 9+USER: /* segmentation exception */
{
osp = sp;
if(backup(u.u_ar0) == 0)
if(grow((unsigned)osp))
goto out;
i = SIGSEGV;
break;
}
/*
* If a memory parity error occurs in user mode
* log it, if one happens in kernel mode
* print the memory system registers and then `panic'.
* The 11/44, 11/60, & 11/70 are the only CPU's which
* have the memory system error registers.
* The other CPU's will have parity CSR's, if they
* have parity or ECC memory.
* The 11/44 & 11/60 have both, makes for nice clean code !
*/
case 10:
case 10+USER:
#ifdef PARITY
mp_ebuf.m_nmsr = nmser;
mp_ebuf.m_prcw = el_prcw;
if(nmser) {
if(nmser == 4) {
mp_ebuf.m_mlea = MEMORY->r[0];
mp_ebuf.m_mhea = MEMORY->r[1];
if((dev & USER) == 0) {
printf("\nMLEA %o", mp_ebuf.m_mlea);
printf("\nMHEA %o", mp_ebuf.m_mhea);
}
}
mp_ebuf.m_mser = MEMORY->r[2];
mp_ebuf.m_mscr = MEMORY->r[3];
MEMORY->r[2] = mp_ebuf.m_mser; /* clear error bits */
if((dev & USER) == 0) {
printf("\nMSER %o", mp_ebuf.m_mser);
printf("\nMSCR %o\n", mp_ebuf.m_mscr);
}
}
j = 0;
for(i=0; i<16; i++)
if(el_prcw & (1 << i)) {
mp_ebuf.m_pcsr[j] = MPCSR->r[i];
MPCSR->r[i] |= 040000; /* get ext. addr if any */
j++;
/* below line replaced to eliminate new c compiler warning message
regarding e_pcsr not being a member of mp_buf struct. OHMS 4/30/85 */
/* mp_ebuf.m_pcsr[j] = (mp_ebuf.e_pcsr[j-1] >> 5) & 0177; */
mp_ebuf.m_pcsr[j] = (mp_ebuf.m_pcsr[j-1] >> 5) & 0177;
mp_ebuf.m_pcsr[j] |= (MPCSR->r[i] << 2) & 03600;
j++;
}
sz = 12 + (j * 2);
if((dev & USER) == 0) {
if(el_prcw)
printf("\nCSR\tDATA\tA21->A11\n");
for(i=0; i<16; i++)
if(el_prcw & (1 << i))
/* below line replaced to eliminate new c compiler warning message
regarding e_pcsr not being a member of mp_buf struct. OHMS 4/30/85 */
/* printf("%d\t%o\t%o\n", i, mp_ebuf.m_pcsr[i*2], mp_ebuf.e_pcsr[(i*2)+1]); */
printf("%d\t%o\t%o\n", i, mp_ebuf.m_pcsr[i*2], mp_ebuf.m_pcsr[(i*2)+1]);
}
/*
* Attempt to log the error even though a panic
* parity could occur before it gets written
* out to the error log file.
* This saves the memory error register contents
* in the kernel error log buffer for later
* crash dump analysis.
*/
logerr(E_MP, &mp_ebuf, sz);
#endif PARITY
if(dev & USER) {
/*
* Send SIGKIL to process instead of
* SIGBUS because SIGBUS causes a core dump
* which will generate another parity
* error, UPE in the disk controller.
*/
i = SIGKILL;
break;
}
panic("parity");
/*
* Allow process switch
*/
case USER+12:
goto out;
/*
* FOLLOWING IS HISTORY -- Fred
* Locations 0-2 specify this style trap, since
* DEC hardware often generates spurious
* traps through location 0. This 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 15:
case 15+USER:
printf("Random interrupt ignored\n");
return;
*/
}
{
long sigmask = 1L << (i - 1);
if (!(u.u_procp->p_ignsig & sigmask) && (u.u_signal[i] != SIG_DFL)
&& !(u.u_procp->p_flag & STRC))
sendsig(u.u_signal[i],i);
else {
psignal(u.u_procp, i);
}
}
out:
if (u.u_inemt==0 && (u.u_procp->p_cursig || ISSIG(u.u_procp)))
psig();
curpri = setpri(u.u_procp);
if (runrun)
qswtch();
if(u.u_prof.pr_scale)
addupc((caddr_t)pc, &u.u_prof, (int)(u.u_stime-syst));
#ifdef FP
if (u.u_fpsaved)
restfp(&u.u_fps);
#endif FP
}
/*
* nonexistent system call-- set fatal error code.
*/
nosys()
{
u.u_error = EINVAL;
}
/*
* Ignored system call
*/
nullsys()
{
}