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