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