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