xref: /csrg-svn/sys/tahoe/tahoe/trap.c (revision 43643)
134408Skarels /*
234408Skarels  * Copyright (c) 1988 Regents of the University of California.
334408Skarels  * All rights reserved.  The Berkeley software License Agreement
434408Skarels  * specifies the terms and conditions for redistribution.
534408Skarels  *
6*43643Skarels  *	@(#)trap.c	7.9 (Berkeley) 06/24/90
734408Skarels  */
824012Ssam 
925678Ssam #include "param.h"
1025678Ssam #include "systm.h"
1125678Ssam #include "user.h"
1225678Ssam #include "proc.h"
1325678Ssam #include "seg.h"
1425678Ssam #include "acct.h"
1525678Ssam #include "kernel.h"
1634408Skarels 
1734408Skarels #include "psl.h"
1834408Skarels #include "reg.h"
1934408Skarels #include "pte.h"
2034408Skarels #include "mtpr.h"
2138404Smarc #ifdef KTRACE
2238404Smarc #include "ktrace.h"
2324012Ssam #endif
2424012Ssam 
2525678Ssam #include "../tahoe/trap.h"
2625678Ssam 
2724012Ssam #define	USER	040		/* user-mode flag added to type */
2824012Ssam 
2925678Ssam struct	sysent sysent[];
3025678Ssam int	nsysent;
3124012Ssam 
3225678Ssam char	*trap_type[] = {
3325678Ssam 	"Reserved addressing mode",		/* T_RESADFLT */
3425678Ssam 	"Privileged instruction",		/* T_PRIVINFLT */
3525678Ssam 	"Reserved operand",			/* T_RESOPFLT */
3625678Ssam 	"Breakpoint",				/* T_BPTFLT */
3725678Ssam 	0,
3825678Ssam 	"Kernel call",				/* T_SYSCALL */
3925678Ssam 	"Arithmetic trap",			/* T_ARITHTRAP */
4025678Ssam 	"System forced exception",		/* T_ASTFLT */
4125678Ssam 	"Segmentation fault",			/* T_SEGFLT */
4225678Ssam 	"Protection fault",			/* T_PROTFLT */
4325678Ssam 	"Trace trap",				/* T_TRCTRAP */
4425678Ssam 	0,
4525678Ssam 	"Page fault",				/* T_PAGEFLT */
4625678Ssam 	"Page table fault",			/* T_TABLEFLT */
4725678Ssam 	"Alignment fault",			/* T_ALIGNFLT */
4825678Ssam 	"Kernel stack not valid",		/* T_KSPNOTVAL */
4925678Ssam 	"Bus error",				/* T_BUSERR */
5038935Skarels 	"Kernel debugger request",		/* T_KDBTRAP */
5125678Ssam };
5230176Ssam int	TRAP_TYPES = sizeof (trap_type) / sizeof (trap_type[0]);
5325678Ssam 
5424012Ssam /*
5524012Ssam  * Called from the trap handler when a processor trap occurs.
5624012Ssam  */
5725678Ssam /*ARGSUSED*/
5824012Ssam trap(sp, type, hfs, accmst, acclst, dbl, code, pc, psl)
5938935Skarels 	unsigned type, code;	/* kdb assumes these are *not* registers */
6024012Ssam {
6125678Ssam 	int r0, r1;		/* must reserve space */
6224012Ssam 	register int *locr0 = ((int *)&psl)-PS;
6324012Ssam 	register int i;
6438935Skarels 	unsigned ucode = code;
6524012Ssam 	register struct proc *p;
6624012Ssam 	struct timeval syst;
6724012Ssam 
6825678Ssam #ifdef lint
6925678Ssam 	r0 = 0; r0 = r0; r1 = 0; r1 = r1;
7025678Ssam #endif
7124012Ssam 	syst = u.u_ru.ru_stime;
7224012Ssam 	if (USERMODE(locr0[PS])) {
7324012Ssam 		type |= USER;
7424012Ssam 		u.u_ar0 = locr0;
7524012Ssam 	}
7624012Ssam 	switch (type) {
7724012Ssam 
7825678Ssam 	default:
7934402Skarels #ifdef KADB
8030176Ssam 		if (kdb_trap(&psl))
8130176Ssam 			return;
8230176Ssam #endif
8325678Ssam 		printf("trap type %d, code = %x, pc = %x\n", type, code, pc);
8425678Ssam 		type &= ~USER;
8525678Ssam 		if (type < TRAP_TYPES && trap_type[type])
8625678Ssam 			panic(trap_type[type]);
8725678Ssam 		else
8825678Ssam 			panic("trap");
8925678Ssam 		/*NOTREACHED*/
9024012Ssam 
9125678Ssam 	case T_PROTFLT + USER:		/* protection fault */
9224012Ssam 		i = SIGBUS;
9324012Ssam 		break;
9424012Ssam 
9524012Ssam 	case T_PRIVINFLT + USER:	/* privileged instruction fault */
9625678Ssam 	case T_RESADFLT + USER:		/* reserved addressing fault */
9725678Ssam 	case T_RESOPFLT + USER:		/* resereved operand fault */
9825678Ssam 	case T_ALIGNFLT + USER:		/* unaligned data fault */
9938935Skarels 		ucode = type &~ USER;
10024012Ssam 		i = SIGILL;
10124012Ssam 		break;
10224012Ssam 
10325678Ssam 	case T_ASTFLT + USER:		/* Allow process switch */
10424012Ssam 	case T_ASTFLT:
10524012Ssam 		astoff();
10624012Ssam 		if ((u.u_procp->p_flag & SOWEUPC) && u.u_prof.pr_scale) {
10724012Ssam 			addupc(pc, &u.u_prof, 1);
10824012Ssam 			u.u_procp->p_flag &= ~SOWEUPC;
10924012Ssam 		}
11024012Ssam 		goto out;
11124012Ssam 
11224012Ssam 	case T_ARITHTRAP + USER:
11324012Ssam 		i = SIGFPE;
11424012Ssam 		break;
11524012Ssam 
11624012Ssam 	/*
11724012Ssam 	 * If the user SP is above the stack segment,
11824012Ssam 	 * grow the stack automatically.
11924012Ssam 	 */
12024012Ssam 	case T_SEGFLT + USER:
12124012Ssam 		if (grow((unsigned)locr0[SP]) || grow(code))
12224012Ssam 			goto out;
12324012Ssam 		i = SIGSEGV;
12424012Ssam 		break;
12524012Ssam 
12625678Ssam 	case T_TABLEFLT:		/* allow page table faults in kernel */
12725678Ssam 	case T_TABLEFLT + USER:		/* page table fault */
12824012Ssam 		panic("ptable fault");
12924012Ssam 
13025678Ssam 	case T_PAGEFLT:			/* allow page faults in kernel mode */
13125678Ssam 	case T_PAGEFLT + USER:		/* page fault */
13225678Ssam 		pagein(code, 0);
13324012Ssam 		if (type == T_PAGEFLT)
13424012Ssam 			return;
13524012Ssam 		goto out;
13624012Ssam 
13725678Ssam 	case T_BPTFLT + USER:		/* bpt instruction fault */
13825678Ssam 	case T_TRCTRAP + USER:		/* trace trap */
13924012Ssam 		locr0[PS] &= ~PSL_T;
14024012Ssam 		i = SIGTRAP;
14124012Ssam 		break;
14225678Ssam 
14338935Skarels #ifdef notdef
14438935Skarels 	/* THIS CODE IS BOGUS- delete? (KSP not valid is unrecoverable)
14538935Skarels 	   And what does KSPNOTVAL in user-mode mean? */
14625746Ssam 	/*
14725746Ssam 	 * For T_KSPNOTVAL and T_BUSERR, can not allow spl to
14825746Ssam 	 * drop to 0 as clock could go off and we would end up
14925746Ssam 	 * doing an rei to the interrupt stack at ipl 0 (a
15025746Ssam 	 * reserved operand fault).  Instead, we allow psignal
15125746Ssam 	 * to post an ast, then return to user mode where we
15225746Ssam 	 * will reenter the kernel on the kernel's stack and
15325746Ssam 	 * can then service the signal.
15425746Ssam 	 */
15524012Ssam 	case T_KSPNOTVAL:
15625746Ssam 		if (noproc)
15725746Ssam 			panic("ksp not valid");
15825746Ssam 		/* fall thru... */
15924012Ssam 	case T_KSPNOTVAL + USER:
16025772Ssam 		printf("pid %d: ksp not valid\n", u.u_procp->p_pid);
16138935Skarels panic("ksp not valid - 2");
16225746Ssam 		/* must insure valid kernel stack pointer? */
16325746Ssam 		psignal(u.u_procp, SIGKILL);
16425746Ssam 		return;
16538935Skarels #endif
16624012Ssam 
16725678Ssam 	case T_BUSERR + USER:
16838935Skarels 		i = SIGBUS;
16938935Skarels 		break;
17024012Ssam 	}
17138935Skarels 	trapsignal(i, ucode);
17224012Ssam out:
17324012Ssam 	p = u.u_procp;
17440716Skarels 	if (i = CURSIG(p))
17540716Skarels 		psig(i);
17624012Ssam 	p->p_pri = p->p_usrpri;
17724012Ssam 	if (runrun) {
17824012Ssam 		/*
17924012Ssam 		 * Since we are u.u_procp, clock will normally just change
18024012Ssam 		 * our priority without moving us from one queue to another
18124012Ssam 		 * (since the running process is not on a queue.)
18224012Ssam 		 * If that happened after we setrq ourselves but before we
18324012Ssam 		 * swtch()'ed, we might not be on the queue indicated by
18424012Ssam 		 * our priority.
18524012Ssam 		 */
18629561Ssam 		(void) splclock();
18724012Ssam 		setrq(p);
18824012Ssam 		u.u_ru.ru_nivcsw++;
18924012Ssam 		swtch();
19040716Skarels 		if (i = CURSIG(p))
19140716Skarels 			psig(i);
19224012Ssam 	}
19324012Ssam 	if (u.u_prof.pr_scale) {
19424012Ssam 		int ticks;
19524012Ssam 		struct timeval *tv = &u.u_ru.ru_stime;
19624012Ssam 
19724012Ssam 		ticks = ((tv->tv_sec - syst.tv_sec) * 1000 +
19824012Ssam 			(tv->tv_usec - syst.tv_usec) / 1000) / (tick / 1000);
19924012Ssam 		if (ticks)
20024012Ssam 			addupc(locr0[PC], &u.u_prof, ticks);
20124012Ssam 	}
20224012Ssam 	curpri = p->p_pri;
20324012Ssam }
20424012Ssam 
20524012Ssam /*
20625678Ssam  * Called from locore when a system call occurs
20724012Ssam  */
20825678Ssam /*ARGSUSED*/
20924012Ssam syscall(sp, type, hfs, accmst, acclst, dbl, code, pc, psl)
21025678Ssam 	unsigned code;
21124012Ssam {
21225678Ssam 	int r0, r1;			/* must reserve space */
21324012Ssam 	register int *locr0 = ((int *)&psl)-PS;
21425678Ssam 	register caddr_t params;
21525678Ssam 	register int i;
21624012Ssam 	register struct sysent *callp;
21738404Smarc 	register struct proc *p = u.u_procp;
21825678Ssam 	struct timeval syst;
21940716Skarels 	int error, opc;
220*43643Skarels 	int args[8], rval[2];
22124012Ssam 
22225678Ssam #ifdef lint
22325678Ssam 	r0 = 0; r0 = r0; r1 = 0; r1 = r1;
22425678Ssam #endif
22524012Ssam 	syst = u.u_ru.ru_stime;
22624012Ssam 	if (!USERMODE(locr0[PS]))
22724012Ssam 		panic("syscall");
22824012Ssam 	u.u_ar0 = locr0;
22924012Ssam 	params = (caddr_t)locr0[FP] + NBPW;
23025678Ssam /* BEGIN GROT */
23125678Ssam 	/*
23225678Ssam 	 * Try to reconstruct pc, assuming code
23325678Ssam 	 * is an immediate constant
23425678Ssam 	 */
23524012Ssam 	opc = pc - 2;		/* short literal */
23624012Ssam 	if (code > 0x3f) {
23725678Ssam 		opc--;				/* byte immediate */
23824012Ssam 		if (code > 0x7f) {
23925678Ssam 			opc--;			/* word immediate */
24024012Ssam 			if (code > 0x7fff)
24124012Ssam 				opc -= 2;	/* long immediate */
24224012Ssam 		}
24324012Ssam 	}
24425678Ssam /* END GROT */
245*43643Skarels 	if (code == 0) {			/* indir */
246*43643Skarels 		code = fuword(params);
24724012Ssam 		params += NBPW;
24824012Ssam 	}
249*43643Skarels 	if (code >= nsysent)
250*43643Skarels 		callp = &sysent[0];		/* indir (illegal) */
251*43643Skarels 	else
252*43643Skarels 		callp = &sysent[code];
25325678Ssam 	if ((i = callp->sy_narg * sizeof (int)) &&
254*43643Skarels 	    (error = copyin(params, (caddr_t)args, (u_int)i)) != 0) {
25540716Skarels 		locr0[R0] = error;
25625678Ssam 		locr0[PS] |= PSL_C;	/* carry bit */
25740669Smarc #ifdef KTRACE
25840669Smarc 		if (KTRPOINT(p, KTR_SYSCALL))
259*43643Skarels 			ktrsyscall(p->p_tracep, code, callp->sy_narg, args);
26040669Smarc #endif
26125678Ssam 		goto done;
26224012Ssam 	}
26340669Smarc #ifdef KTRACE
26440669Smarc 	if (KTRPOINT(p, KTR_SYSCALL))
265*43643Skarels 		ktrsyscall(p->p_tracep, code, callp->sy_narg, args);
26640669Smarc #endif
267*43643Skarels 	rval[0] = 0;
268*43643Skarels 	rval[1] = locr0[R1];
269*43643Skarels 	error = (*callp->sy_call)(u.u_procp, args, rval);
27040716Skarels 	if (error == ERESTART)
27140716Skarels 		pc = opc;
27240716Skarels 	else if (error != EJUSTRETURN) {
27340716Skarels 		if (error) {
27440716Skarels 			locr0[R0] = error;
27525678Ssam 			locr0[PS] |= PSL_C;	/* carry bit */
27625678Ssam 		} else {
27725678Ssam 			locr0[PS] &= ~PSL_C;	/* clear carry bit */
278*43643Skarels 			locr0[R0] = rval[0];
279*43643Skarels 			locr0[R1] = rval[1];
28025678Ssam 		}
28140716Skarels 	}
28240716Skarels 	/* else if (error == EJUSTRETURN) */
28325678Ssam 		/* nothing to do */
28424012Ssam done:
28540669Smarc 	/*
28640669Smarc 	 * Reinitialize proc pointer `p' as it may be different
28740669Smarc 	 * if this is a child returning from fork syscall.
28840669Smarc 	 */
28924012Ssam 	p = u.u_procp;
29040716Skarels 	if (i = CURSIG(p))
29140716Skarels 		psig(i);
29224012Ssam 	p->p_pri = p->p_usrpri;
29324012Ssam 	if (runrun) {
29424012Ssam 		/*
29524012Ssam 		 * Since we are u.u_procp, clock will normally just change
29624012Ssam 		 * our priority without moving us from one queue to another
29724012Ssam 		 * (since the running process is not on a queue.)
29824012Ssam 		 * If that happened after we setrq ourselves but before we
29924012Ssam 		 * swtch()'ed, we might not be on the queue indicated by
30024012Ssam 		 * our priority.
30124012Ssam 		 */
30229561Ssam 		(void) splclock();
30324012Ssam 		setrq(p);
30424012Ssam 		u.u_ru.ru_nivcsw++;
30524012Ssam 		swtch();
30640716Skarels 		if (i = CURSIG(p))
30740716Skarels 			psig(i);
30824012Ssam 	}
30924012Ssam 	if (u.u_prof.pr_scale) {
31024012Ssam 		int ticks;
31124012Ssam 		struct timeval *tv = &u.u_ru.ru_stime;
31224012Ssam 
31324012Ssam 		ticks = ((tv->tv_sec - syst.tv_sec) * 1000 +
31424012Ssam 			(tv->tv_usec - syst.tv_usec) / 1000) / (tick / 1000);
31524012Ssam 		if (ticks)
31624012Ssam 			addupc(locr0[PC], &u.u_prof, ticks);
31724012Ssam 	}
31824012Ssam 	curpri = p->p_pri;
31940669Smarc #ifdef KTRACE
32040669Smarc 	if (KTRPOINT(p, KTR_SYSRET))
321*43643Skarels 		ktrsysret(p->p_tracep, code, error, rval[0]);
32240669Smarc #endif
32324012Ssam }
324