xref: /original-bsd/sys/i386/i386/trap.c (revision 767d859e)
1 /*-
2  * Copyright (c) 1990 The Regents of the University of California.
3  * All rights reserved.
4  *
5  * This code is derived from software contributed to Berkeley by
6  * the University of Utah, and William Jolitz.
7  *
8  * %sccs.include.386.c%
9  *
10  *	@(#)trap.c	5.7 (Berkeley) 01/19/91
11  */
12 
13 
14 /*
15  * 386 Trap and System call handleing
16  */
17 
18 #include "machine/psl.h"
19 #include "machine/reg.h"
20 #include "machine/pte.h"
21 #include "machine/segments.h"
22 #include "machine/frame.h"
23 
24 #include "param.h"
25 #include "systm.h"
26 #include "user.h"
27 #include "proc.h"
28 #include "seg.h"
29 #include "acct.h"
30 #include "kernel.h"
31 #include "vm.h"
32 #include "cmap.h"
33 #ifdef KTRACE
34 #include "ktrace.h"
35 #endif
36 
37 #include "machine/trap.h"
38 
39 #define	USER	0x40		/* user-mode flag added to type */
40 #define	FRMTRAP	0x100		/* distinguish trap from syscall */
41 
42 struct	sysent sysent[];
43 int	nsysent;
44 #include "dbg.h"
45 /*
46  * Called from the trap handler when a processor trap occurs.
47  */
48 unsigned rcr2(), Sysbase;
49 extern short cpl;
50 /*ARGSUSED*/
51 trap(frame)
52 	struct trapframe frame;
53 #define type frame.tf_trapno
54 #define code frame.tf_err
55 #define pc frame.tf_eip
56 {
57 	register int *locr0 = ((int *)&frame);
58 	register int i;
59 	register struct proc *p;
60 	struct timeval syst;
61 	extern int nofault;
62 	int ucode;
63 	int oar0;
64 
65 #ifdef DEBUG
66 dprintf(DALLTRAPS, "\n%d. trap",u.u_procp->p_pid);
67 dprintf(DALLTRAPS, " pc:%x cs:%x ds:%x eflags:%x isp %x\n",
68 		frame.tf_eip, frame.tf_cs, frame.tf_ds, frame.tf_eflags,
69 		frame.tf_isp);
70 dprintf(DALLTRAPS, "edi %x esi %x ebp %x ebx %x esp %x\n",
71 		frame.tf_edi, frame.tf_esi, frame.tf_ebp,
72 		frame.tf_ebx, frame.tf_esp);
73 dprintf(DALLTRAPS, "edx %x ecx %x eax %x\n",
74 		frame.tf_edx, frame.tf_ecx, frame.tf_eax);
75 p=u.u_procp;
76 dprintf(DALLTRAPS, "sig %x %x %x \n",
77 		p->p_sigignore, p->p_sigcatch, p->p_sigmask);
78 dprintf(DALLTRAPS, " ec %x type %x cpl %x ",
79 		frame.tf_err&0xffff, frame.tf_trapno, cpl);
80 #endif
81 
82 	locr0[tEFLAGS] &= ~PSL_NT;	/* clear nested trap XXX */
83 if(nofault && frame.tf_trapno != 0xc)
84 	{ locr0[tEIP] = nofault; return;}
85 
86 	syst = u.u_ru.ru_stime;
87 oar0= u.u_ar0;
88 	if (ISPL(locr0[tCS]) == SEL_UPL) {
89 		type |= USER;
90 		u.u_ar0 = locr0;
91 	}
92 	ucode=0;
93 	switch (type) {
94 
95 	default:
96 bit_sucker:
97 #ifdef KDB
98 		if (kdb_trap(&psl))
99 			return;
100 #endif
101 
102 splhigh();
103 printf("cr2 %x cpl %x ", rcr2(), cpl);
104 		printf("trap type %d, code = %x, pc = %x cs = %x, eflags = %x\n", type, code, pc, frame.tf_cs, frame.tf_eflags);
105 		type &= ~USER;
106 pg("panic");
107 		panic("trap");
108 		/*NOTREACHED*/
109 
110 	case T_SEGNPFLT + USER:
111 	case T_PROTFLT + USER:		/* protection fault */
112 		ucode = code + BUS_SEGM_FAULT ;
113 		i = SIGBUS;
114 		break;
115 
116 	case T_PRIVINFLT + USER:	/* privileged instruction fault */
117 	case T_RESADFLT + USER:		/* reserved addressing fault */
118 	case T_RESOPFLT + USER:		/* reserved operand fault */
119 	case T_FPOPFLT + USER:		/* coprocessor operand fault */
120 		ucode = type &~ USER;
121 		i = SIGILL;
122 		break;
123 
124 	case T_ASTFLT + USER:		/* Allow process switch */
125 	case T_ASTFLT:
126 		astoff();
127 		if ((u.u_procp->p_flag & SOWEUPC) && u.u_prof.pr_scale) {
128 			addupc(pc, &u.u_prof, 1);
129 			u.u_procp->p_flag &= ~SOWEUPC;
130 		}
131 		goto out;
132 
133 	case T_DNA + USER:
134 #ifdef	NPX
135 		if (npxdna()) return;
136 #endif
137 		ucode = FPE_FPU_NP_TRAP;
138 		i = SIGFPE;
139 		break;
140 
141 	case T_BOUND + USER:
142 		ucode = FPE_SUBRNG_TRAP;
143 		i = SIGFPE;
144 		break;
145 
146 	case T_OFLOW + USER:
147 		ucode = FPE_INTOVF_TRAP;
148 		i = SIGFPE;
149 		break;
150 
151 	case T_DIVIDE + USER:
152 		ucode = FPE_INTDIV_TRAP;
153 		i = SIGFPE;
154 		break;
155 
156 	case T_ARITHTRAP + USER:
157 		ucode = code;
158 		i = SIGFPE;
159 		break;
160 
161 #ifdef notdef
162 	/*
163 	 * If the user SP is above the stack segment,
164 	 * grow the stack automatically.
165 	 */
166 	case T_STKFLT + USER:
167 	case T_SEGFLT + USER:
168 		if (grow((unsigned)locr0[tESP]) /*|| grow(code)*/)
169 			goto out;
170 		ucode = code;
171 		i = SIGSEGV;
172 		break;
173 
174 	case T_TABLEFLT:		/* allow page table faults in kernel */
175 	case T_TABLEFLT + USER:		/* page table fault */
176 		panic("ptable fault");
177 #endif
178 
179 	case T_PAGEFLT:			/* allow page faults in kernel mode */
180 		if (code & PGEX_P) goto bit_sucker;
181 		/* fall into */
182 	case T_PAGEFLT + USER:		/* page fault */
183 		{	register u_int vp;
184 			u_int ea;
185 
186 #ifdef DEBUG
187 dprintf(DPAGIN|DALLTRAPS, "pf code %x pc %x usp %x cr2 %x |",
188 		code, frame.tf_eip, frame.tf_esp, rcr2());
189 #endif
190 			ea = (u_int)rcr2();
191 
192 			/* out of bounds reference */
193 			if (ea >= (u_int)&Sysbase || code & PGEX_P) {
194 				ucode = code + BUS_PAGE_FAULT;
195 				i = SIGBUS;
196 				break;
197 			}
198 
199 			/* stack reference to the running process? */
200 			vp = btop(ea);
201 			if (vp >= dptov(u.u_procp, u.u_procp->p_dsize)
202 			&& vp < sptov(u.u_procp, u.u_procp->p_ssize-1)){
203 				/* attempt to grow stack */
204 				if (grow((unsigned)locr0[tESP]) || grow(ea)) {
205 					if (type == T_PAGEFLT)
206 {
207 u.u_ar0 = oar0;
208 return;
209 }
210 					goto out;
211 				} else	if (nofault) {
212 u.u_ar0 = oar0;
213 					locr0[tEIP] = nofault;
214 					return;
215 				}
216 				i = SIGSEGV;
217 				ucode = code + BUS_PAGE_FAULT;
218 				break;
219 			}
220 
221 			pagein(ea, 0, code);
222 			if (type == T_PAGEFLT) return;
223 			goto out;
224 		}
225 
226 	case T_TRCTRAP:	 /* trace trap -- someone single stepping lcall's */
227 		locr0[tEFLAGS] &= ~PSL_T;
228 			/* Q: how do we turn it on again? */
229 u.u_ar0 = oar0;
230 		return;
231 
232 	case T_BPTFLT + USER:		/* bpt instruction fault */
233 	case T_TRCTRAP + USER:		/* trace trap */
234 		locr0[tEFLAGS] &= ~PSL_T;
235 		i = SIGTRAP;
236 		break;
237 
238 #ifdef notdef
239 	/*
240 	 * For T_KSPNOTVAL and T_BUSERR, can not allow spl to
241 	 * drop to 0 as clock could go off and we would end up
242 	 * doing an rei to the interrupt stack at ipl 0 (a
243 	 * reserved operand fault).  Instead, we allow psignal
244 	 * to post an ast, then return to user mode where we
245 	 * will reenter the kernel on the kernel's stack and
246 	 * can then service the signal.
247 	 */
248 	case T_KSPNOTVAL:
249 		if (noproc)
250 			panic("ksp not valid");
251 		/* fall thru... */
252 	case T_KSPNOTVAL + USER:
253 		printf("pid %d: ksp not valid\n", u.u_procp->p_pid);
254 		/* must insure valid kernel stack pointer? */
255 		trapsignal(SIGKILL,0|FRMTRAP);
256 u.u_ar0 = oar0;
257 		return;
258 
259 	case T_BUSERR + USER:
260 		trapsignal(SIGBUS, code|FRMTRAP);
261 u.u_ar0 = oar0;
262 		return;
263 #endif
264 
265 #include "isa.h"
266 #if	NISA > 0
267 	case T_NMI:
268 	case T_NMI + USER:
269 		if(isa_nmi(code) == 0) return;
270 		else goto bit_sucker;
271 #endif
272 	}
273 	trapsignal(i, ucode|FRMTRAP);
274 	if ((type & USER) == 0)
275 {
276 u.u_ar0 = oar0;
277 		return;
278 }
279 out:
280 	p = u.u_procp;
281 	if (i = CURSIG(p))
282 		psig(i,FRMTRAP);
283 	p->p_pri = p->p_usrpri;
284 	if (runrun) {
285 		/*
286 		 * Since we are u.u_procp, clock will normally just change
287 		 * our priority without moving us from one queue to another
288 		 * (since the running process is not on a queue.)
289 		 * If that happened after we setrq ourselves but before we
290 		 * swtch()'ed, we might not be on the queue indicated by
291 		 * our priority.
292 		 */
293 		(void) splclock();
294 		setrq(p);
295 		u.u_ru.ru_nivcsw++;
296 		swtch();
297 		if (i = CURSIG(p))
298 			psig(i,FRMTRAP);
299 	}
300 	if (u.u_prof.pr_scale) {
301 		int ticks;
302 		struct timeval *tv = &u.u_ru.ru_stime;
303 
304 		ticks = ((tv->tv_sec - syst.tv_sec) * 1000 +
305 			(tv->tv_usec - syst.tv_usec) / 1000) / (tick / 1000);
306 		if (ticks)
307 			addupc(pc, &u.u_prof, ticks);
308 	}
309 	curpri = p->p_pri;
310 u.u_ar0 = oar0;
311 #undef type
312 #undef code
313 #undef pc
314 }
315 
316 /*
317  * Called from locore when a system call occurs
318  */
319 /*ARGSUSED*/
320 syscall(frame)
321 	struct syscframe frame;
322 #define code frame.sf_eax	/* note: written over! */
323 #define pc frame.sf_eip
324 {
325 	register int *locr0 = ((int *)&frame)/*-PS*/;
326 	register caddr_t params;
327 	register int i;
328 	register struct sysent *callp;
329 	register struct proc *p;
330 	struct timeval syst;
331 	int error, opc;
332 	int args[8], rval[2];
333 
334 #ifdef lint
335 	r0 = 0; r0 = r0; r1 = 0; r1 = r1;
336 #endif
337 	syst = u.u_ru.ru_stime;
338 	p = u.u_procp;
339 	if (ISPL(locr0[sCS]) != SEL_UPL)
340 {
341 printf("\npc:%x cs:%x eflags:%x\n",
342 		frame.sf_eip, frame.sf_cs, frame.sf_eflags);
343 printf("edi %x esi %x ebp %x ebx %x esp %x\n",
344 		frame.sf_edi, frame.sf_esi, frame.sf_ebp,
345 		frame.sf_ebx, frame.sf_esp);
346 printf("edx %x ecx %x eax %x\n", frame.sf_edx, frame.sf_ecx, frame.sf_eax);
347 printf("cr0 %x cr2 %x cpl %x \n", rcr0(), rcr2(), cpl);
348 		panic("syscall");
349 }
350 	u.u_ar0 = locr0;
351 	params = (caddr_t)locr0[sESP] + NBPW ;
352 
353 	/*
354 	 * Reconstruct pc, assuming lcall $X,y is 7 bytes, as it is always.
355 	 */
356 	opc = pc - 7;
357 	callp = (code >= nsysent) ? &sysent[63] : &sysent[code];
358 	if (callp == sysent) {
359 		i = fuword(params);
360 		params += NBPW;
361 		callp = (code >= nsysent) ? &sysent[63] : &sysent[code];
362 	}
363 /*dprintf(DALLSYSC,"%d. call %d ", p->p_pid, code);*/
364 	if ((i = callp->sy_narg * sizeof (int)) &&
365 	    (error = copyin(params, (caddr_t)args, (u_int)i))) {
366 		locr0[sEAX] = (u_char) error;
367 		locr0[sEFLAGS] |= PSL_C;	/* carry bit */
368 #ifdef KTRACE
369 		if (KTRPOINT(p, KTR_SYSCALL))
370 			ktrsyscall(p->p_tracep, code, callp->sy_narg, &args);
371 #endif
372 		goto done;
373 	}
374 #ifdef KTRACE
375 	if (KTRPOINT(p, KTR_SYSCALL))
376 		ktrsyscall(p->p_tracep, code, callp->sy_narg, &args);
377 #endif
378 	rval[0] = 0;
379 	rval[1] = locr0[sEDX];
380 	error = (*callp->sy_call)(p, args, rval);
381 	if (error == ERESTART)
382 		pc = opc;
383 	else if (error != EJUSTRETURN) {
384 		if (error) {
385 			locr0[sEAX] = (u_char) error;
386 			locr0[sEFLAGS] |= PSL_C;	/* carry bit */
387 		} else {
388 			locr0[sEAX] = rval[0];
389 			locr0[sEDX] = rval[1];
390 			locr0[sEFLAGS] &= ~PSL_C;	/* carry bit */
391 		}
392 	}
393 	/* else if (error == EJUSTRETURN) */
394 		/* nothing to do */
395 done:
396 	/*
397 	 * Reinitialize proc pointer `p' as it may be different
398 	 * if this is a child returning from fork syscall.
399 	 */
400 	p = u.u_procp;
401 	/*
402 	 * XXX the check for sigreturn ensures that we don't
403 	 * attempt to set up a call to a signal handler (sendsig) before
404 	 * we have cleaned up the stack from the last call (sigreturn).
405 	 * Allowing this seems to lock up the machine in certain scenarios.
406 	 * What should really be done is to clean up the signal handling
407 	 * so that this is not a problem.
408 	 */
409 #include "syscall.h"
410 	if (code != SYS_sigreturn && (i = CURSIG(p)))
411 		psig(i,0);
412 	p->p_pri = p->p_usrpri;
413 	if (runrun) {
414 		/*
415 		 * Since we are u.u_procp, clock will normally just change
416 		 * our priority without moving us from one queue to another
417 		 * (since the running process is not on a queue.)
418 		 * If that happened after we setrq ourselves but before we
419 		 * swtch()'ed, we might not be on the queue indicated by
420 		 * our priority.
421 		 */
422 		(void) splclock();
423 		setrq(p);
424 		u.u_ru.ru_nivcsw++;
425 		swtch();
426 		if (code != SYS_sigreturn && (i = CURSIG(p)))
427 			psig(i,0);
428 	}
429 	if (u.u_prof.pr_scale) {
430 		int ticks;
431 		struct timeval *tv = &u.u_ru.ru_stime;
432 
433 		ticks = ((tv->tv_sec - syst.tv_sec) * 1000 +
434 			(tv->tv_usec - syst.tv_usec) / 1000) / (tick / 1000);
435 		if (ticks) {
436 #ifdef PROFTIMER
437 			extern int profscale;
438 			addupc(pc, &u.u_prof, ticks * profscale);
439 #else
440 			addupc(pc, &u.u_prof, ticks);
441 #endif
442 		}
443 	}
444 	curpri = p->p_pri;
445 #ifdef KTRACE
446 	if (KTRPOINT(p, KTR_SYSRET))
447 		ktrsysret(p->p_tracep, code, error, rval[0]);
448 #endif
449 }
450 
451 #ifdef notdef
452 /*
453  * nonexistent system call-- signal process (may want to handle it)
454  * flag error if process won't see signal immediately
455  * Q: should we do that all the time ??
456  */
457 nosys()
458 {
459 
460 	if (u.u_signal[SIGSYS] == SIG_IGN || u.u_signal[SIGSYS] == SIG_HOLD)
461 		u.u_error = EINVAL;
462 	psignal(u.u_procp, SIGSYS);
463 }
464 #endif
465 
466 /*
467  * Ignored system call
468  */
469 nullsys()
470 {
471 
472 }
473