xref: /original-bsd/sys/tahoe/tahoe/trap.c (revision c0f053f7)
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.4 (Berkeley) 07/04/89
7  */
8 
9 #include "param.h"
10 #include "systm.h"
11 #include "user.h"
12 #include "proc.h"
13 #include "seg.h"
14 #include "acct.h"
15 #include "kernel.h"
16 
17 #include "psl.h"
18 #include "reg.h"
19 #include "pte.h"
20 #include "mtpr.h"
21 #ifdef KTRACE
22 #include "ktrace.h"
23 #endif
24 
25 #include "../tahoe/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 trap",			/* 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;
60 {
61 	int r0, r1;		/* must reserve space */
62 	register int *locr0 = ((int *)&psl)-PS;
63 	register int i;
64 	register struct proc *p;
65 	struct timeval syst;
66 
67 #ifdef lint
68 	r0 = 0; r0 = r0; r1 = 0; r1 = r1;
69 #endif
70 	syst = u.u_ru.ru_stime;
71 	if (USERMODE(locr0[PS])) {
72 		type |= USER;
73 		u.u_ar0 = locr0;
74 	}
75 	switch (type) {
76 
77 	default:
78 #ifdef KADB
79 		if (kdb_trap(&psl))
80 			return;
81 #endif
82 		printf("trap type %d, code = %x, pc = %x\n", type, code, pc);
83 		type &= ~USER;
84 		if (type < TRAP_TYPES && trap_type[type])
85 			panic(trap_type[type]);
86 		else
87 			panic("trap");
88 		/*NOTREACHED*/
89 
90 	case T_PROTFLT + USER:		/* protection fault */
91 		i = SIGBUS;
92 		break;
93 
94 	case T_PRIVINFLT + USER:	/* privileged instruction fault */
95 	case T_RESADFLT + USER:		/* reserved addressing fault */
96 	case T_RESOPFLT + USER:		/* resereved operand fault */
97 	case T_ALIGNFLT + USER:		/* unaligned data fault */
98 		u.u_code = type &~ USER;
99 		i = SIGILL;
100 		break;
101 
102 	case T_ASTFLT + USER:		/* Allow process switch */
103 	case T_ASTFLT:
104 		astoff();
105 		if ((u.u_procp->p_flag & SOWEUPC) && u.u_prof.pr_scale) {
106 			addupc(pc, &u.u_prof, 1);
107 			u.u_procp->p_flag &= ~SOWEUPC;
108 		}
109 		goto out;
110 
111 	case T_ARITHTRAP + USER:
112 		u.u_code = code;
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 		i = u.u_error;
133 		pagein(code, 0);
134 		u.u_error = i;
135 		if (type == T_PAGEFLT)
136 			return;
137 		goto out;
138 
139 	case T_BPTFLT + USER:		/* bpt instruction fault */
140 	case T_TRCTRAP + USER:		/* trace trap */
141 		locr0[PS] &= ~PSL_T;
142 		i = SIGTRAP;
143 		break;
144 
145 	/*
146 	 * For T_KSPNOTVAL and T_BUSERR, can not allow spl to
147 	 * drop to 0 as clock could go off and we would end up
148 	 * doing an rei to the interrupt stack at ipl 0 (a
149 	 * reserved operand fault).  Instead, we allow psignal
150 	 * to post an ast, then return to user mode where we
151 	 * will reenter the kernel on the kernel's stack and
152 	 * can then service the signal.
153 	 */
154 	case T_KSPNOTVAL:
155 		if (noproc)
156 			panic("ksp not valid");
157 		/* fall thru... */
158 	case T_KSPNOTVAL + USER:
159 		printf("pid %d: ksp not valid\n", u.u_procp->p_pid);
160 		/* must insure valid kernel stack pointer? */
161 		psignal(u.u_procp, SIGKILL);
162 		return;
163 
164 	case T_BUSERR + USER:
165 		u.u_code = code;
166 		psignal(u.u_procp, SIGBUS);
167 		return;
168 	}
169 	psignal(u.u_procp, i);
170 out:
171 	p = u.u_procp;
172 	if (p->p_cursig || ISSIG(p))
173 		psig();
174 	p->p_pri = p->p_usrpri;
175 	if (runrun) {
176 		/*
177 		 * Since we are u.u_procp, clock will normally just change
178 		 * our priority without moving us from one queue to another
179 		 * (since the running process is not on a queue.)
180 		 * If that happened after we setrq ourselves but before we
181 		 * swtch()'ed, we might not be on the queue indicated by
182 		 * our priority.
183 		 */
184 		(void) splclock();
185 		setrq(p);
186 		u.u_ru.ru_nivcsw++;
187 		swtch();
188 	}
189 	if (u.u_prof.pr_scale) {
190 		int ticks;
191 		struct timeval *tv = &u.u_ru.ru_stime;
192 
193 		ticks = ((tv->tv_sec - syst.tv_sec) * 1000 +
194 			(tv->tv_usec - syst.tv_usec) / 1000) / (tick / 1000);
195 		if (ticks)
196 			addupc(locr0[PC], &u.u_prof, ticks);
197 	}
198 	curpri = p->p_pri;
199 }
200 
201 #ifdef SYSCALLTRACE
202 int	syscalltrace = 0;
203 #endif
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 opc;
220 
221 #ifdef lint
222 	r0 = 0; r0 = r0; r1 = 0; r1 = r1;
223 #endif
224 	syst = u.u_ru.ru_stime;
225 	if (!USERMODE(locr0[PS]))
226 		panic("syscall");
227 	u.u_ar0 = locr0;
228 	params = (caddr_t)locr0[FP] + NBPW;
229 	u.u_error = 0;
230 /* BEGIN GROT */
231 	/*
232 	 * Try to reconstruct pc, assuming code
233 	 * is an immediate constant
234 	 */
235 	opc = pc - 2;		/* short literal */
236 	if (code > 0x3f) {
237 		opc--;				/* byte immediate */
238 		if (code > 0x7f) {
239 			opc--;			/* word immediate */
240 			if (code > 0x7fff)
241 				opc -= 2;	/* long immediate */
242 		}
243 	}
244 /* END GROT */
245 	callp = (code >= nsysent) ? &sysent[63] : &sysent[code];
246 	if (callp == sysent) {
247 		i = fuword(params);
248 		params += NBPW;
249 		callp = (code >= nsysent) ? &sysent[63] : &sysent[code];
250 	}
251 	if ((i = callp->sy_narg * sizeof (int)) &&
252 	    (u.u_error = copyin(params, (caddr_t)u.u_arg, (u_int)i)) != 0) {
253 		locr0[R0] = u.u_error;
254 		locr0[PS] |= PSL_C;	/* carry bit */
255 		goto done;
256 	}
257 	u.u_r.r_val1 = 0;
258 	u.u_r.r_val2 = locr0[R1];
259 	if (setjmp(&u.u_qsave)) {
260 		if (u.u_error == 0 && u.u_eosys != RESTARTSYS)
261 			u.u_error = EINTR;
262 	} else {
263 		u.u_eosys = NORMALRETURN;
264 #ifdef KTRACE
265 		if (KTRPOINT(p, KTR_SYSCALL))
266 			ktrsyscall(p->p_tracep, code, callp->sy_narg);
267 #endif
268 		(*callp->sy_call)(&u);
269 	}
270 	if (u.u_eosys == NORMALRETURN) {
271 		if (u.u_error) {
272 			locr0[R0] = u.u_error;
273 			locr0[PS] |= PSL_C;	/* carry bit */
274 		} else {
275 			locr0[PS] &= ~PSL_C;	/* clear carry bit */
276 			locr0[R0] = u.u_r.r_val1;
277 			locr0[R1] = u.u_r.r_val2;
278 		}
279 	} else if (u.u_eosys == RESTARTSYS)
280 		pc = opc;
281 	/* else if (u.u_eosys == JUSTRETURN) */
282 		/* nothing to do */
283 #ifdef KTRACE
284 	if (KTRPOINT(p, KTR_SYSRET))
285 		ktrsysret(p->p_tracep, code);
286 #endif
287 done:
288 	p = u.u_procp;
289 	if (p->p_cursig || ISSIG(p))
290 		psig();
291 	p->p_pri = p->p_usrpri;
292 	if (runrun) {
293 		/*
294 		 * Since we are u.u_procp, clock will normally just change
295 		 * our priority without moving us from one queue to another
296 		 * (since the running process is not on a queue.)
297 		 * If that happened after we setrq ourselves but before we
298 		 * swtch()'ed, we might not be on the queue indicated by
299 		 * our priority.
300 		 */
301 		(void) splclock();
302 		setrq(p);
303 		u.u_ru.ru_nivcsw++;
304 		swtch();
305 	}
306 	if (u.u_prof.pr_scale) {
307 		int ticks;
308 		struct timeval *tv = &u.u_ru.ru_stime;
309 
310 		ticks = ((tv->tv_sec - syst.tv_sec) * 1000 +
311 			(tv->tv_usec - syst.tv_usec) / 1000) / (tick / 1000);
312 		if (ticks)
313 			addupc(locr0[PC], &u.u_prof, ticks);
314 	}
315 	curpri = p->p_pri;
316 }
317 
318 /*
319  * nonexistent system call-- signal process (may want to handle it)
320  * flag error if process won't see signal immediately
321  * Q: should we do that all the time ??
322  */
323 nosys()
324 {
325 
326 	if (u.u_signal[SIGSYS] == SIG_IGN || u.u_signal[SIGSYS] == SIG_HOLD)
327 		u.u_error = EINVAL;
328 	psignal(u.u_procp, SIGSYS);
329 }
330 
331 #ifdef notdef
332 /*
333  * Ignored system call
334  */
335 nullsys()
336 {
337 
338 }
339 #endif
340