xref: /original-bsd/sys/i386/i386/trap.c (revision c2d8c538)
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.5 (Berkeley) 11/25/90
11  */
12 
13 /*
14  * Copyright (c) 1989, 1990 William F. Jolitz
15  */
16 
17 /*
18  * 386 Trap and System call handleing
19  */
20 
21 #include "../i386/psl.h"
22 #include "../i386/reg.h"
23 #include "../i386/pte.h"
24 #include "../i386/segments.h"
25 #include "../i386/frame.h"
26 
27 #include "param.h"
28 #include "systm.h"
29 #include "dir.h"
30 #include "user.h"
31 #include "proc.h"
32 #include "seg.h"
33 #include "acct.h"
34 #include "kernel.h"
35 #include "vm.h"
36 #include "cmap.h"
37 
38 #include "../i386/trap.h"
39 
40 #define	USER	0x100		/* user-mode flag added to type */
41 
42 struct	sysent sysent[];
43 int	nsysent;
44 /*
45  * Called from the trap handler when a processor trap occurs.
46  */
47 unsigned *rcr2(), Sysbase;
48 extern short cpl;
49 /*ARGSUSED*/
50 trap(frame)
51 	struct trapframe frame;
52 #define type frame.tf_trapno
53 #define code frame.tf_err
54 #define pc frame.tf_eip
55 {
56 	register int *locr0 = ((int *)&frame);
57 	register int i;
58 	register struct proc *p;
59 	struct timeval syst;
60 	extern int nofault;
61 
62 
63 	locr0[tEFLAGS] &= ~PSL_NT;	/* clear nested trap XXX */
64 	if(nofault && frame.tf_trapno != 0xc) {
65 		locr0[tEIP] = nofault; return;
66 	}
67 
68 	syst = u.u_ru.ru_stime;
69 	if (ISPL(locr0[tCS]) == SEL_UPL) {
70 		type |= USER;
71 		u.u_ar0 = locr0;
72 	}
73 	switch (type) {
74 
75 	default:
76 bit_sucker:
77 #ifdef KDB
78 		if (kdb_trap(&psl))
79 			return;
80 #endif
81 		printf("trap type %d code %x pc %x cs %x eflags %x\n",
82 			type, code, pc, frame.tf_cs, frame.tf_eflags);
83 		type &= ~USER;
84 		panic("trap");
85 		/*NOTREACHED*/
86 
87 	case T_SEGNPFLT + USER:
88 	case T_PROTFLT + USER:		/* protection fault */
89 		u.u_code = code + BUS_SEGM_FAULT ;
90 		i = SIGBUS;
91 		break;
92 
93 	case T_PRIVINFLT + USER:	/* privileged instruction fault */
94 	case T_RESADFLT + USER:		/* reserved addressing fault */
95 	case T_RESOPFLT + USER:		/* reserved operand fault */
96 	case T_FPOPFLT + USER:		/* coprocessor operand fault */
97 		u.u_code = type &~ USER;
98 		i = SIGILL;
99 		break;
100 
101 	case T_ASTFLT + USER:		/* Allow process switch */
102 	case T_ASTFLT:
103 		astoff();
104 		if ((u.u_procp->p_flag & SOWEUPC) && u.u_prof.pr_scale) {
105 			addupc(pc, &u.u_prof, 1);
106 			u.u_procp->p_flag &= ~SOWEUPC;
107 		}
108 		goto out;
109 
110 	case T_DNA + USER:
111 		u.u_code = FPE_FPU_NP_TRAP;
112 		i = SIGFPE;
113 		break;
114 
115 	case T_BOUND + USER:
116 		u.u_code = FPE_SUBRNG_TRAP;
117 		i = SIGFPE;
118 		break;
119 
120 	case T_OFLOW + USER:
121 		u.u_code = FPE_INTOVF_TRAP;
122 		i = SIGFPE;
123 		break;
124 
125 	case T_DIVIDE + USER:
126 		u.u_code = FPE_INTDIV_TRAP;
127 		i = SIGFPE;
128 		break;
129 
130 	case T_ARITHTRAP + USER:
131 		u.u_code = code;
132 		i = SIGFPE;
133 		break;
134 #ifdef notdef
135 	/*
136 	 * If the user SP is above the stack segment,
137 	 * grow the stack automatically.
138 	 */
139 	case T_STKFLT + USER:
140 	case T_SEGFLT + USER:
141 		if (grow((unsigned)locr0[tESP]))
142 			goto out;
143 		u.u_code = code;
144 		i = SIGSEGV;
145 		break;
146 
147 	case T_TABLEFLT:		/* allow page table faults in kernel */
148 	case T_TABLEFLT + USER:		/* page table fault */
149 		panic("ptable fault");
150 #endif
151 
152 	case T_PAGEFLT:			/* allow page faults in kernel mode */
153 		if (code & PGEX_P) goto bit_sucker;
154 		/* fall into */
155 	case T_PAGEFLT + USER:		/* page fault */
156 		{	register u_int vp;
157 			u_int ea;
158 
159 			ea = (u_int)rcr2();
160 
161 			/* out of bounds reference */
162 			if (ea >= &Sysbase || code & PGEX_P) {
163 				u.u_code = code + BUS_PAGE_FAULT;
164 				i = SIGBUS;
165 				break;
166 			}
167 
168 			/* stack reference to the running process? */
169 			vp = btop(ea);
170 			if (vp >= dptov(u.u_procp, u.u_procp->p_dsize)
171 			&& vp < sptov(u.u_procp, u.u_procp->p_ssize-1)){
172 				/* attempt to grow stack */
173 				if (grow((unsigned)locr0[tESP]) || grow(ea)) {
174 					if (type == T_PAGEFLT) return;
175 					goto out;
176 				} else	if (nofault) {
177 					locr0[tEIP] = nofault;
178 					return;
179 				}
180 				i = SIGSEGV;
181 				break;
182 			}
183 
184 			i = u.u_error;
185 			pagein(ea, 0);
186 			u.u_error = i;
187 			if (type == T_PAGEFLT) return;
188 			goto out;
189 		}
190 
191 	case T_TRCTRAP:	 /* trace trap -- someone single stepping lcall's */
192 		locr0[tEFLAGS] &= ~PSL_T;
193 			/* Q: how do we turn it on again? */
194 		return;
195 
196 	case T_BPTFLT + USER:		/* bpt instruction fault */
197 	case T_TRCTRAP + USER:		/* trace trap */
198 		locr0[tEFLAGS] &= ~PSL_T;
199 		i = SIGTRAP;
200 		break;
201 
202 #ifdef notdef
203 	/*
204 	 * For T_KSPNOTVAL and T_BUSERR, can not allow spl to
205 	 * drop to 0 as clock could go off and we would end up
206 	 * doing an rei to the interrupt stack at ipl 0 (a
207 	 * reserved operand fault).  Instead, we allow psignal
208 	 * to post an ast, then return to user mode where we
209 	 * will reenter the kernel on the kernel's stack and
210 	 * can then service the signal.
211 	 */
212 	case T_KSPNOTVAL:
213 		if (noproc)
214 			panic("ksp not valid");
215 		/* fall thru... */
216 	case T_KSPNOTVAL + USER:
217 		printf("pid %d: ksp not valid\n", u.u_procp->p_pid);
218 		/* must insure valid kernel stack pointer? */
219 		psignal(u.u_procp, SIGKILL);
220 		return;
221 
222 	case T_BUSERR + USER:
223 		u.u_code = code;
224 		psignal(u.u_procp, SIGBUS);
225 		return;
226 #endif
227 
228 #include "isa.h"
229 #if	NISA > 0
230 	case T_NMI:
231 	case T_NMI + USER:
232 		if(isa_nmi(code) == 0) return;
233 		else goto bit_sucker;
234 #endif
235 	}
236 	psignal(u.u_procp, i);
237 out:
238 	p = u.u_procp;
239 
240 	if (p->p_cursig || ISSIG(p))
241 		psig(1);
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 		(void)spl0();
257 	}
258 	if (u.u_prof.pr_scale) {
259 		int ticks;
260 		struct timeval *tv = &u.u_ru.ru_stime;
261 
262 		ticks = ((tv->tv_sec - syst.tv_sec) * 1000 +
263 			(tv->tv_usec - syst.tv_usec) / 1000) / (tick / 1000);
264 		if (ticks)
265 			addupc(pc, &u.u_prof, ticks);
266 	}
267 	curpri = p->p_pri;
268 #undef type
269 #undef code
270 #undef pc
271 }
272 
273 /*
274  * Called from locore when a system call occurs
275  */
276 /*ARGSUSED*/
277 syscall(frame)
278 	struct syscframe frame;
279 #define code frame.sf_eax	/* note: written over! */
280 #define pc frame.sf_eip
281 {
282 	register int *locr0 = ((int *)&frame);
283 	register caddr_t params;
284 	register int i;
285 	register struct sysent *callp;
286 	register struct proc *p;
287 	struct timeval syst;
288 	int opc;
289 
290 #ifdef lint
291 	r0 = 0; r0 = r0; r1 = 0; r1 = r1;
292 #endif
293 	syst = u.u_ru.ru_stime;
294 	if (ISPL(locr0[sCS]) != SEL_UPL)
295 		panic("syscall");
296 	u.u_ar0 = locr0;
297 	params = (caddr_t)locr0[sESP] + NBPW ;
298 	u.u_error = 0;
299 	/*
300 	 * Reconstruct pc, assuming lcall $X,y is 7 bytes, as it is always.
301 	 */
302 	opc = pc - 7;
303 	callp = (code >= nsysent) ? &sysent[63] : &sysent[code];
304 	if (callp == sysent) {
305 		i = fuword(params);
306 		params += NBPW;
307 		callp = (code >= nsysent) ? &sysent[63] : &sysent[code];
308 	}
309 	if ((i = callp->sy_narg * sizeof (int)) &&
310 	    (u.u_error = copyin(params, (caddr_t)u.u_arg, (u_int)i)) != 0) {
311 		locr0[sEAX] = u.u_error;
312 		locr0[sEFLAGS] |= PSL_C;	/* carry bit */
313 		goto done;
314 	}
315 	u.u_r.r_val1 = 0;
316 	u.u_r.r_val2 = locr0[sEDX];
317 	if (setjmp(&u.u_qsave)) {
318 		if (u.u_error == 0 && u.u_eosys != RESTARTSYS)
319 			u.u_error = EINTR;
320 	} else {
321 		u.u_eosys = NORMALRETURN;
322 		(*callp->sy_call)();
323 	}
324 	if (u.u_eosys == NORMALRETURN) {
325 		if (u.u_error) {
326 			locr0[sEAX] = u.u_error;
327 			locr0[sEFLAGS] |= PSL_C;	/* carry bit */
328 		} else {
329 			locr0[sEFLAGS] &= ~PSL_C;	/* clear carry bit */
330 			locr0[sEAX] = u.u_r.r_val1;
331 			locr0[sEDX] = u.u_r.r_val2;
332 		}
333 	} else if (u.u_eosys == RESTARTSYS)
334 		pc = opc;
335 	/* else if (u.u_eosys == JUSTRETURN) */
336 		/* nothing to do */
337 done:
338 	p = u.u_procp;
339 	if (p->p_cursig || ISSIG(p))
340 		psig(0);
341 	p->p_pri = p->p_usrpri;
342 	if (runrun) {
343 		/*
344 		 * Since we are u.u_procp, clock will normally just change
345 		 * our priority without moving us from one queue to another
346 		 * (since the running process is not on a queue.)
347 		 * If that happened after we setrq ourselves but before we
348 		 * swtch()'ed, we might not be on the queue indicated by
349 		 * our priority.
350 		 */
351 		(void) splclock();
352 		setrq(p);
353 		u.u_ru.ru_nivcsw++;
354 		swtch();
355 		(void)spl0();
356 	}
357 	if (u.u_prof.pr_scale) {
358 		int ticks;
359 		struct timeval *tv = &u.u_ru.ru_stime;
360 
361 		ticks = ((tv->tv_sec - syst.tv_sec) * 1000 +
362 			(tv->tv_usec - syst.tv_usec) / 1000) / (tick / 1000);
363 		if (ticks)
364 			addupc(opc, &u.u_prof, ticks);
365 	}
366 	curpri = p->p_pri;
367 }
368 
369 /*
370  * nonexistent system call-- signal process (may want to handle it)
371  * flag error if process won't see signal immediately
372  * Q: should we do that all the time ??
373  */
374 nosys()
375 {
376 
377 	if (u.u_signal[SIGSYS] == SIG_IGN || u.u_signal[SIGSYS] == SIG_HOLD)
378 		u.u_error = EINVAL;
379 	psignal(u.u_procp, SIGSYS);
380 }
381 
382 /*
383  * Ignored system call
384  */
385 nullsys()
386 {
387 }
388