xref: /csrg-svn/sys/tahoe/tahoe/trap.c (revision 34408)
1*34408Skarels /*
2*34408Skarels  * Copyright (c) 1988 Regents of the University of California.
3*34408Skarels  * All rights reserved.  The Berkeley software License Agreement
4*34408Skarels  * specifies the terms and conditions for redistribution.
5*34408Skarels  *
6*34408Skarels  *	@(#)trap.c	7.1 (Berkeley) 05/21/88
7*34408Skarels  */
824012Ssam 
925678Ssam #include "param.h"
1025678Ssam #include "systm.h"
1125678Ssam #include "dir.h"
1225678Ssam #include "user.h"
1325678Ssam #include "proc.h"
1425678Ssam #include "seg.h"
1525678Ssam #include "acct.h"
1625678Ssam #include "kernel.h"
17*34408Skarels 
18*34408Skarels #include "psl.h"
19*34408Skarels #include "reg.h"
20*34408Skarels #include "pte.h"
21*34408Skarels #include "mtpr.h"
22*34408Skarels 
2325678Ssam #define	SYSCALLTRACE
2424012Ssam #ifdef SYSCALLTRACE
2524012Ssam #include "../sys/syscalls.c"
2624012Ssam #endif
2724012Ssam 
2825678Ssam #include "../tahoe/trap.h"
2925678Ssam 
3024012Ssam #define	USER	040		/* user-mode flag added to type */
3124012Ssam 
3225678Ssam struct	sysent sysent[];
3325678Ssam int	nsysent;
3424012Ssam 
3525678Ssam char	*trap_type[] = {
3625678Ssam 	"Reserved addressing mode",		/* T_RESADFLT */
3725678Ssam 	"Privileged instruction",		/* T_PRIVINFLT */
3825678Ssam 	"Reserved operand",			/* T_RESOPFLT */
3925678Ssam 	"Breakpoint",				/* T_BPTFLT */
4025678Ssam 	0,
4125678Ssam 	"Kernel call",				/* T_SYSCALL */
4225678Ssam 	"Arithmetic trap",			/* T_ARITHTRAP */
4325678Ssam 	"System forced exception",		/* T_ASTFLT */
4425678Ssam 	"Segmentation fault",			/* T_SEGFLT */
4525678Ssam 	"Protection fault",			/* T_PROTFLT */
4625678Ssam 	"Trace trap",				/* T_TRCTRAP */
4725678Ssam 	0,
4825678Ssam 	"Page fault",				/* T_PAGEFLT */
4925678Ssam 	"Page table fault",			/* T_TABLEFLT */
5025678Ssam 	"Alignment fault",			/* T_ALIGNFLT */
5125678Ssam 	"Kernel stack not valid",		/* T_KSPNOTVAL */
5225678Ssam 	"Bus error",				/* T_BUSERR */
5330176Ssam 	"Kernel debugger trap",			/* T_KDBTRAP */
5425678Ssam };
5530176Ssam int	TRAP_TYPES = sizeof (trap_type) / sizeof (trap_type[0]);
5625678Ssam 
5724012Ssam /*
5824012Ssam  * Called from the trap handler when a processor trap occurs.
5924012Ssam  */
6025678Ssam /*ARGSUSED*/
6124012Ssam trap(sp, type, hfs, accmst, acclst, dbl, code, pc, psl)
6225678Ssam 	unsigned type, code;
6324012Ssam {
6425678Ssam 	int r0, r1;		/* must reserve space */
6524012Ssam 	register int *locr0 = ((int *)&psl)-PS;
6624012Ssam 	register int i;
6724012Ssam 	register struct proc *p;
6824012Ssam 	struct timeval syst;
6924012Ssam 
7025678Ssam #ifdef lint
7125678Ssam 	r0 = 0; r0 = r0; r1 = 0; r1 = r1;
7225678Ssam #endif
7324012Ssam 	syst = u.u_ru.ru_stime;
7424012Ssam 	if (USERMODE(locr0[PS])) {
7524012Ssam 		type |= USER;
7624012Ssam 		u.u_ar0 = locr0;
7724012Ssam 	}
7824012Ssam 	switch (type) {
7924012Ssam 
8025678Ssam 	default:
8134402Skarels #ifdef KADB
8230176Ssam 		if (kdb_trap(&psl))
8330176Ssam 			return;
8430176Ssam #endif
8525678Ssam 		printf("trap type %d, code = %x, pc = %x\n", type, code, pc);
8625678Ssam 		type &= ~USER;
8725678Ssam 		if (type < TRAP_TYPES && trap_type[type])
8825678Ssam 			panic(trap_type[type]);
8925678Ssam 		else
9025678Ssam 			panic("trap");
9125678Ssam 		/*NOTREACHED*/
9224012Ssam 
9325678Ssam 	case T_PROTFLT + USER:		/* protection fault */
9424012Ssam 		i = SIGBUS;
9524012Ssam 		break;
9624012Ssam 
9724012Ssam 	case T_PRIVINFLT + USER:	/* privileged instruction fault */
9825678Ssam 	case T_RESADFLT + USER:		/* reserved addressing fault */
9925678Ssam 	case T_RESOPFLT + USER:		/* resereved operand fault */
10025678Ssam 	case T_ALIGNFLT + USER:		/* unaligned data fault */
10124012Ssam 		u.u_code = type &~ USER;
10224012Ssam 		i = SIGILL;
10324012Ssam 		break;
10424012Ssam 
10525678Ssam 	case T_ASTFLT + USER:		/* Allow process switch */
10624012Ssam 	case T_ASTFLT:
10724012Ssam 		astoff();
10824012Ssam 		if ((u.u_procp->p_flag & SOWEUPC) && u.u_prof.pr_scale) {
10924012Ssam 			addupc(pc, &u.u_prof, 1);
11024012Ssam 			u.u_procp->p_flag &= ~SOWEUPC;
11124012Ssam 		}
11224012Ssam 		goto out;
11324012Ssam 
11424012Ssam 	case T_ARITHTRAP + USER:
11524012Ssam 		u.u_code = code;
11624012Ssam 		i = SIGFPE;
11724012Ssam 		break;
11824012Ssam 
11924012Ssam 	/*
12024012Ssam 	 * If the user SP is above the stack segment,
12124012Ssam 	 * grow the stack automatically.
12224012Ssam 	 */
12324012Ssam 	case T_SEGFLT + USER:
12424012Ssam 		if (grow((unsigned)locr0[SP]) || grow(code))
12524012Ssam 			goto out;
12624012Ssam 		i = SIGSEGV;
12724012Ssam 		break;
12824012Ssam 
12925678Ssam 	case T_TABLEFLT:		/* allow page table faults in kernel */
13025678Ssam 	case T_TABLEFLT + USER:		/* page table fault */
13124012Ssam 		panic("ptable fault");
13224012Ssam 
13325678Ssam 	case T_PAGEFLT:			/* allow page faults in kernel mode */
13425678Ssam 	case T_PAGEFLT + USER:		/* page fault */
13524012Ssam 		i = u.u_error;
13625678Ssam 		pagein(code, 0);
13724012Ssam 		u.u_error = i;
13824012Ssam 		if (type == T_PAGEFLT)
13924012Ssam 			return;
14024012Ssam 		goto out;
14124012Ssam 
14225678Ssam 	case T_BPTFLT + USER:		/* bpt instruction fault */
14325678Ssam 	case T_TRCTRAP + USER:		/* trace trap */
14424012Ssam 		locr0[PS] &= ~PSL_T;
14524012Ssam 		i = SIGTRAP;
14624012Ssam 		break;
14725678Ssam 
14825746Ssam 	/*
14925746Ssam 	 * For T_KSPNOTVAL and T_BUSERR, can not allow spl to
15025746Ssam 	 * drop to 0 as clock could go off and we would end up
15125746Ssam 	 * doing an rei to the interrupt stack at ipl 0 (a
15225746Ssam 	 * reserved operand fault).  Instead, we allow psignal
15325746Ssam 	 * to post an ast, then return to user mode where we
15425746Ssam 	 * will reenter the kernel on the kernel's stack and
15525746Ssam 	 * can then service the signal.
15625746Ssam 	 */
15724012Ssam 	case T_KSPNOTVAL:
15825746Ssam 		if (noproc)
15925746Ssam 			panic("ksp not valid");
16025746Ssam 		/* fall thru... */
16124012Ssam 	case T_KSPNOTVAL + USER:
16225772Ssam 		printf("pid %d: ksp not valid\n", u.u_procp->p_pid);
16325746Ssam 		/* must insure valid kernel stack pointer? */
16425746Ssam 		psignal(u.u_procp, SIGKILL);
16525746Ssam 		return;
16624012Ssam 
16725678Ssam 	case T_BUSERR + USER:
16825678Ssam 		u.u_code = code;
16925746Ssam 		psignal(u.u_procp, SIGBUS);
17025746Ssam 		return;
17124012Ssam 	}
17224012Ssam 	psignal(u.u_procp, i);
17324012Ssam out:
17424012Ssam 	p = u.u_procp;
17524012Ssam 	if (p->p_cursig || ISSIG(p))
17624012Ssam 		psig();
17724012Ssam 	p->p_pri = p->p_usrpri;
17824012Ssam 	if (runrun) {
17924012Ssam 		/*
18024012Ssam 		 * Since we are u.u_procp, clock will normally just change
18124012Ssam 		 * our priority without moving us from one queue to another
18224012Ssam 		 * (since the running process is not on a queue.)
18324012Ssam 		 * If that happened after we setrq ourselves but before we
18424012Ssam 		 * swtch()'ed, we might not be on the queue indicated by
18524012Ssam 		 * our priority.
18624012Ssam 		 */
18729561Ssam 		(void) splclock();
18824012Ssam 		setrq(p);
18924012Ssam 		u.u_ru.ru_nivcsw++;
19024012Ssam 		swtch();
19124012Ssam 	}
19224012Ssam 	if (u.u_prof.pr_scale) {
19324012Ssam 		int ticks;
19424012Ssam 		struct timeval *tv = &u.u_ru.ru_stime;
19524012Ssam 
19624012Ssam 		ticks = ((tv->tv_sec - syst.tv_sec) * 1000 +
19724012Ssam 			(tv->tv_usec - syst.tv_usec) / 1000) / (tick / 1000);
19824012Ssam 		if (ticks)
19924012Ssam 			addupc(locr0[PC], &u.u_prof, ticks);
20024012Ssam 	}
20124012Ssam 	curpri = p->p_pri;
20224012Ssam }
20324012Ssam 
20424012Ssam #ifdef SYSCALLTRACE
20525678Ssam int	syscalltrace = 0;
20624012Ssam #endif
20724012Ssam 
20824012Ssam /*
20925678Ssam  * Called from locore when a system call occurs
21024012Ssam  */
21125678Ssam /*ARGSUSED*/
21224012Ssam syscall(sp, type, hfs, accmst, acclst, dbl, code, pc, psl)
21325678Ssam 	unsigned code;
21424012Ssam {
21525678Ssam 	int r0, r1;			/* must reserve space */
21624012Ssam 	register int *locr0 = ((int *)&psl)-PS;
21725678Ssam 	register caddr_t params;
21825678Ssam 	register int i;
21924012Ssam 	register struct sysent *callp;
22024012Ssam 	register struct proc *p;
22125678Ssam 	struct timeval syst;
22224012Ssam 	int opc;
22324012Ssam 
22425678Ssam #ifdef lint
22525678Ssam 	r0 = 0; r0 = r0; r1 = 0; r1 = r1;
22625678Ssam #endif
22724012Ssam 	syst = u.u_ru.ru_stime;
22824012Ssam 	if (!USERMODE(locr0[PS]))
22924012Ssam 		panic("syscall");
23024012Ssam 	u.u_ar0 = locr0;
23125678Ssam 	if (code == 139) {			/* 4.2 COMPATIBILTY XXX */
23225678Ssam 		osigcleanup();			/* 4.2 COMPATIBILTY XXX */
23325678Ssam 		goto done;			/* 4.2 COMPATIBILTY XXX */
23424012Ssam 	}
23524012Ssam 	params = (caddr_t)locr0[FP] + NBPW;
23624012Ssam 	u.u_error = 0;
23725678Ssam /* BEGIN GROT */
23825678Ssam 	/*
23925678Ssam 	 * Try to reconstruct pc, assuming code
24025678Ssam 	 * is an immediate constant
24125678Ssam 	 */
24224012Ssam 	opc = pc - 2;		/* short literal */
24324012Ssam 	if (code > 0x3f) {
24425678Ssam 		opc--;				/* byte immediate */
24524012Ssam 		if (code > 0x7f) {
24625678Ssam 			opc--;			/* word immediate */
24724012Ssam 			if (code > 0x7fff)
24824012Ssam 				opc -= 2;	/* long immediate */
24924012Ssam 		}
25024012Ssam 	}
25125678Ssam /* END GROT */
25224012Ssam 	callp = (code >= nsysent) ? &sysent[63] : &sysent[code];
25324012Ssam 	if (callp == sysent) {
25424012Ssam 		i = fuword(params);
25524012Ssam 		params += NBPW;
25625678Ssam 		callp = (code >= nsysent) ? &sysent[63] : &sysent[code];
25724012Ssam 	}
25825678Ssam 	if ((i = callp->sy_narg * sizeof (int)) &&
25925678Ssam 	    (u.u_error = copyin(params, (caddr_t)u.u_arg, (u_int)i)) != 0) {
26025678Ssam 		locr0[R0] = u.u_error;
26125678Ssam 		locr0[PS] |= PSL_C;	/* carry bit */
26225678Ssam 		goto done;
26324012Ssam 	}
26424012Ssam 	u.u_r.r_val1 = 0;
26525678Ssam 	u.u_r.r_val2 = locr0[R1];
26624012Ssam 	if (setjmp(&u.u_qsave)) {
26725678Ssam 		if (u.u_error == 0 && u.u_eosys != RESTARTSYS)
26824012Ssam 			u.u_error = EINTR;
26924012Ssam 	} else {
27025678Ssam 		u.u_eosys = NORMALRETURN;
27124012Ssam #ifdef SYSCALLTRACE
27224012Ssam 		if (syscalltrace) {
27330297Ssam 			register int a;
27424012Ssam 			char *cp;
27524012Ssam 
27624012Ssam 			if (code >= nsysent)
27724012Ssam 				printf("0x%x", code);
27824012Ssam 			else
27924012Ssam 				printf("%s", syscallnames[code]);
28024012Ssam 			cp = "(";
28130297Ssam 			for (a = 0; a < callp->sy_narg; a++) {
28230297Ssam 				printf("%s%x", cp, u.u_arg[a]);
28324012Ssam 				cp = ", ";
28424012Ssam 			}
28530297Ssam 			if (a)
28630297Ssam 				printf(")");
28730297Ssam 			printf("\n");
28824012Ssam 		}
28924012Ssam #endif
29025678Ssam 		(*callp->sy_call)();
29124012Ssam 	}
29225678Ssam 	if (u.u_eosys == NORMALRETURN) {
29325678Ssam 		if (u.u_error) {
29425678Ssam 			locr0[R0] = u.u_error;
29525678Ssam 			locr0[PS] |= PSL_C;	/* carry bit */
29625678Ssam 		} else {
29725678Ssam 			locr0[PS] &= ~PSL_C;	/* clear carry bit */
29825678Ssam 			locr0[R0] = u.u_r.r_val1;
29925678Ssam 			locr0[R1] = u.u_r.r_val2;
30025678Ssam 		}
30125678Ssam 	} else if (u.u_eosys == RESTARTSYS)
30224012Ssam 		pc = opc;
30325678Ssam 	/* else if (u.u_eosys == JUSTRETURN) */
30425678Ssam 		/* nothing to do */
30524012Ssam done:
30624012Ssam 	p = u.u_procp;
30724012Ssam 	if (p->p_cursig || ISSIG(p))
30824012Ssam 		psig();
30924012Ssam 	p->p_pri = p->p_usrpri;
31024012Ssam 	if (runrun) {
31124012Ssam 		/*
31224012Ssam 		 * Since we are u.u_procp, clock will normally just change
31324012Ssam 		 * our priority without moving us from one queue to another
31424012Ssam 		 * (since the running process is not on a queue.)
31524012Ssam 		 * If that happened after we setrq ourselves but before we
31624012Ssam 		 * swtch()'ed, we might not be on the queue indicated by
31724012Ssam 		 * our priority.
31824012Ssam 		 */
31929561Ssam 		(void) splclock();
32024012Ssam 		setrq(p);
32124012Ssam 		u.u_ru.ru_nivcsw++;
32224012Ssam 		swtch();
32324012Ssam 	}
32424012Ssam 	if (u.u_prof.pr_scale) {
32524012Ssam 		int ticks;
32624012Ssam 		struct timeval *tv = &u.u_ru.ru_stime;
32724012Ssam 
32824012Ssam 		ticks = ((tv->tv_sec - syst.tv_sec) * 1000 +
32924012Ssam 			(tv->tv_usec - syst.tv_usec) / 1000) / (tick / 1000);
33024012Ssam 		if (ticks)
33124012Ssam 			addupc(locr0[PC], &u.u_prof, ticks);
33224012Ssam 	}
33324012Ssam 	curpri = p->p_pri;
33424012Ssam }
33524012Ssam 
33624012Ssam /*
33724012Ssam  * nonexistent system call-- signal process (may want to handle it)
33824012Ssam  * flag error if process won't see signal immediately
33924012Ssam  * Q: should we do that all the time ??
34024012Ssam  */
34124012Ssam nosys()
34224012Ssam {
34325678Ssam 
34424012Ssam 	if (u.u_signal[SIGSYS] == SIG_IGN || u.u_signal[SIGSYS] == SIG_HOLD)
34524012Ssam 		u.u_error = EINVAL;
34624012Ssam 	psignal(u.u_procp, SIGSYS);
34724012Ssam }
34824012Ssam 
34925678Ssam #ifdef notdef
35024012Ssam /*
35124012Ssam  * Ignored system call
35224012Ssam  */
35324012Ssam nullsys()
35424012Ssam {
35524012Ssam 
35624012Ssam }
35725678Ssam #endif
358