xref: /original-bsd/sys/tahoe/tahoe/trap.c (revision 95ecee29)
1 /*
2  * Copyright (c) 1988 Regents of the University of California.
3  * All rights reserved.  The Berkeley software License Agreement
4  * specifies the terms and conditions for redistribution.
5  *
6  *	@(#)trap.c	7.14 (Berkeley) 09/23/93
7  */
8 
9 #include "sys/param.h"
10 #include "sys/systm.h"
11 #include "sys/user.h"
12 #include "sys/proc.h"
13 #include "sys/seg.h"
14 #include "sys/acct.h"
15 #include "sys/kernel.h"
16 
17 #include "../include/psl.h"
18 #include "../include/reg.h"
19 #include "../include/pte.h"
20 #include "../include/mtpr.h"
21 #ifdef KTRACE
22 #include "sys/ktrace.h"
23 #endif
24 
25 #include "../include/trap.h"
26 
27 #define	USER	040		/* user-mode flag added to type */
28 
29 struct	sysent sysent[];
30 int	nsysent;
31 
32 char	*trap_type[] = {
33 	"Reserved addressing mode",		/* T_RESADFLT */
34 	"Privileged instruction",		/* T_PRIVINFLT */
35 	"Reserved operand",			/* T_RESOPFLT */
36 	"Breakpoint",				/* T_BPTFLT */
37 	0,
38 	"Kernel call",				/* T_SYSCALL */
39 	"Arithmetic trap",			/* T_ARITHTRAP */
40 	"System forced exception",		/* T_ASTFLT */
41 	"Segmentation fault",			/* T_SEGFLT */
42 	"Protection fault",			/* T_PROTFLT */
43 	"Trace trap",				/* T_TRCTRAP */
44 	0,
45 	"Page fault",				/* T_PAGEFLT */
46 	"Page table fault",			/* T_TABLEFLT */
47 	"Alignment fault",			/* T_ALIGNFLT */
48 	"Kernel stack not valid",		/* T_KSPNOTVAL */
49 	"Bus error",				/* T_BUSERR */
50 	"Kernel debugger request",		/* T_KDBTRAP */
51 };
52 int	TRAP_TYPES = sizeof (trap_type) / sizeof (trap_type[0]);
53 
54 /*
55  * Called from the trap handler when a processor trap occurs.
56  */
57 /*ARGSUSED*/
58 trap(sp, type, hfs, accmst, acclst, dbl, code, pc, psl)
59 	unsigned type, code;	/* kdb assumes these are *not* registers */
60 {
61 	int r0, r1;		/* must reserve space */
62 	register int *locr0 = ((int *)&psl)-PS;
63 	register int i;
64 	unsigned ucode = code;
65 	register struct proc *p;
66 	struct timeval syst;
67 
68 #ifdef lint
69 	r0 = 0; r0 = r0; r1 = 0; r1 = r1;
70 #endif
71 	syst = u.u_ru.ru_stime;
72 	if (USERMODE(locr0[PS])) {
73 		type |= USER;
74 		u.u_ar0 = locr0;
75 	}
76 	switch (type) {
77 
78 	default:
79 #ifdef KADB
80 		if (kdb_trap(&psl))
81 			return;
82 #endif
83 		printf("trap type %d, code = %x, pc = %x\n", type, code, pc);
84 		type &= ~USER;
85 		if (type < TRAP_TYPES && trap_type[type])
86 			panic(trap_type[type]);
87 		else
88 			panic("trap");
89 		/*NOTREACHED*/
90 
91 	case T_PROTFLT + USER:		/* protection fault */
92 		i = SIGBUS;
93 		break;
94 
95 	case T_PRIVINFLT + USER:	/* privileged instruction fault */
96 	case T_RESADFLT + USER:		/* reserved addressing fault */
97 	case T_RESOPFLT + USER:		/* resereved operand fault */
98 	case T_ALIGNFLT + USER:		/* unaligned data fault */
99 		ucode = type &~ USER;
100 		i = SIGILL;
101 		break;
102 
103 	case T_ASTFLT + USER:		/* Allow process switch */
104 	case T_ASTFLT:
105 		astoff();
106 		if ((u.u_procp->p_flag & P_OWEUPC) && u.u_prof.pr_scale) {
107 			addupc(pc, &u.u_prof, 1);
108 			u.u_procp->p_flag &= ~P_OWEUPC;
109 		}
110 		goto out;
111 
112 	case T_ARITHTRAP + USER:
113 		i = SIGFPE;
114 		break;
115 
116 	/*
117 	 * If the user SP is above the stack segment,
118 	 * grow the stack automatically.
119 	 */
120 	case T_SEGFLT + USER:
121 		if (grow((unsigned)locr0[SP]) || grow(code))
122 			goto out;
123 		i = SIGSEGV;
124 		break;
125 
126 	case T_TABLEFLT:		/* allow page table faults in kernel */
127 	case T_TABLEFLT + USER:		/* page table fault */
128 		panic("ptable fault");
129 
130 	case T_PAGEFLT:			/* allow page faults in kernel mode */
131 	case T_PAGEFLT + USER:		/* page fault */
132 		pagein(code, 0);
133 		if (type == T_PAGEFLT)
134 			return;
135 		goto out;
136 
137 	case T_BPTFLT + USER:		/* bpt instruction fault */
138 	case T_TRCTRAP + USER:		/* trace trap */
139 		locr0[PS] &= ~PSL_T;
140 		i = SIGTRAP;
141 		break;
142 
143 #ifdef notdef
144 	/* THIS CODE IS BOGUS- delete? (KSP not valid is unrecoverable)
145 	   And what does KSPNOTVAL in user-mode mean? */
146 	/*
147 	 * For T_KSPNOTVAL and T_BUSERR, can not allow spl to
148 	 * drop to 0 as clock could go off and we would end up
149 	 * doing an rei to the interrupt stack at ipl 0 (a
150 	 * reserved operand fault).  Instead, we allow psignal
151 	 * to post an ast, then return to user mode where we
152 	 * will reenter the kernel on the kernel's stack and
153 	 * can then service the signal.
154 	 */
155 	case T_KSPNOTVAL:
156 		if (noproc)
157 			panic("ksp not valid");
158 		/* fall thru... */
159 	case T_KSPNOTVAL + USER:
160 		printf("pid %d: ksp not valid\n", u.u_procp->p_pid);
161 panic("ksp not valid - 2");
162 		/* must insure valid kernel stack pointer? */
163 		psignal(u.u_procp, SIGKILL);
164 		return;
165 #endif
166 
167 	case T_BUSERR + USER:
168 		i = SIGBUS;
169 		break;
170 	}
171 	trapsignal(i, ucode);
172 out:
173 	p = u.u_procp;
174 	if (i = CURSIG(p))
175 		postsig(i);
176 	p->p_priority = p->p_usrpri;
177 	if (runrun) {
178 		/*
179 		 * Since we are u.u_procp, clock will normally just change
180 		 * our priority without moving us from one queue to another
181 		 * (since the running process is not on a queue.)
182 		 * If that happened after we put ourselves on the run queue
183 		 * but before we Xswitch()'ed, we might not be on the queue
184 		 * indicated by our priority.
185 		 */
186 		(void) splclock();
187 		setrunqueue(p);
188 		u.u_ru.ru_nivcsw++;
189 		Xswitch();
190 		if (i = CURSIG(p))
191 			postsig(i);
192 	}
193 	if (u.u_prof.pr_scale) {
194 		int ticks;
195 		struct timeval *tv = &u.u_ru.ru_stime;
196 
197 		ticks = ((tv->tv_sec - syst.tv_sec) * 1000 +
198 			(tv->tv_usec - syst.tv_usec) / 1000) / (tick / 1000);
199 		if (ticks)
200 			addupc(locr0[PC], &u.u_prof, ticks);
201 	}
202 	curpriority = p->p_priority;
203 }
204 
205 /*
206  * Called from locore when a system call occurs
207  */
208 /*ARGSUSED*/
209 syscall(sp, type, hfs, accmst, acclst, dbl, code, pc, psl)
210 	unsigned code;
211 {
212 	int r0, r1;			/* must reserve space */
213 	register int *locr0 = ((int *)&psl)-PS;
214 	register caddr_t params;
215 	register int i;
216 	register struct sysent *callp;
217 	register struct proc *p = u.u_procp;
218 	struct timeval syst;
219 	int error, opc;
220 	struct args {
221 		int i[8];
222 	} args;
223 	int rval[2];
224 
225 #ifdef lint
226 	r0 = 0; r0 = r0; r1 = 0; r1 = r1;
227 #endif
228 	syst = u.u_ru.ru_stime;
229 	if (!USERMODE(locr0[PS]))
230 		panic("syscall");
231 	u.u_ar0 = locr0;
232 	params = (caddr_t)locr0[FP] + NBPW;
233 /* BEGIN GROT */
234 	/*
235 	 * Try to reconstruct pc, assuming code
236 	 * is an immediate constant
237 	 */
238 	opc = pc - 2;		/* short literal */
239 	if (code > 0x3f) {
240 		opc--;				/* byte immediate */
241 		if (code > 0x7f) {
242 			opc--;			/* word immediate */
243 			if (code > 0x7fff)
244 				opc -= 2;	/* long immediate */
245 		}
246 	}
247 /* END GROT */
248 	if (code == 0) {			/* indir */
249 		code = fuword(params);
250 		params += NBPW;
251 	}
252 	if (code >= nsysent)
253 		callp = &sysent[0];		/* indir (illegal) */
254 	else
255 		callp = &sysent[code];
256 	if ((i = callp->sy_narg * sizeof (int)) &&
257 	    (error = copyin(params, (caddr_t)&args, (u_int)i)) != 0) {
258 		locr0[R0] = error;
259 		locr0[PS] |= PSL_C;	/* carry bit */
260 #ifdef KTRACE
261 		if (KTRPOINT(p, KTR_SYSCALL))
262 			ktrsyscall(p->p_tracep, code, callp->sy_narg, args.i);
263 #endif
264 		goto done;
265 	}
266 #ifdef KTRACE
267 	if (KTRPOINT(p, KTR_SYSCALL))
268 		ktrsyscall(p->p_tracep, code, callp->sy_narg, args.i);
269 #endif
270 	rval[0] = 0;
271 	rval[1] = locr0[R1];
272 	error = (*callp->sy_call)(u.u_procp, &args, rval);
273 	if (error == ERESTART)
274 		pc = opc;
275 	else if (error != EJUSTRETURN) {
276 		if (error) {
277 			locr0[R0] = error;
278 			locr0[PS] |= PSL_C;	/* carry bit */
279 		} else {
280 			locr0[PS] &= ~PSL_C;	/* clear carry bit */
281 			locr0[R0] = rval[0];
282 			locr0[R1] = rval[1];
283 		}
284 	}
285 	/* else if (error == EJUSTRETURN) */
286 		/* nothing to do */
287 done:
288 	/*
289 	 * Reinitialize proc pointer `p' as it may be different
290 	 * if this is a child returning from fork syscall.
291 	 */
292 	p = u.u_procp;
293 	if (i = CURSIG(p))
294 		postsig(i);
295 	p->p_priority = p->p_usrpri;
296 	if (runrun) {
297 		/*
298 		 * Since we are u.u_procp, clock will normally just change
299 		 * our priority without moving us from one queue to another
300 		 * (since the running process is not on a queue.)
301 		 * If that happened after we put ourselves on the run queue
302 		 * but before we Xswitch()'ed, we might not be on the queue
303 		 * indicated by our priority.
304 		 */
305 		(void) splclock();
306 		setrunqueue(p);
307 		u.u_ru.ru_nivcsw++;
308 		Xswitch();
309 		if (i = CURSIG(p))
310 			postsig(i);
311 	}
312 	if (u.u_prof.pr_scale) {
313 		int ticks;
314 		struct timeval *tv = &u.u_ru.ru_stime;
315 
316 		ticks = ((tv->tv_sec - syst.tv_sec) * 1000 +
317 			(tv->tv_usec - syst.tv_usec) / 1000) / (tick / 1000);
318 		if (ticks)
319 			addupc(locr0[PC], &u.u_prof, ticks);
320 	}
321 	curpriority = p->p_priority;
322 #ifdef KTRACE
323 	if (KTRPOINT(p, KTR_SYSRET))
324 		ktrsysret(p->p_tracep, code, error, rval[0]);
325 #endif
326 }
327