xref: /netbsd/sys/arch/i386/i386/trap.c (revision bf9ec67e)
1 /*	$NetBSD: trap.c,v 1.165 2002/02/18 15:58:02 simonb Exp $	*/
2 
3 /*-
4  * Copyright (c) 1998, 2000 The NetBSD Foundation, Inc.
5  * All rights reserved.
6  *
7  * This code is derived from software contributed to The NetBSD Foundation
8  * by Charles M. Hannum.
9  *
10  * Redistribution and use in source and binary forms, with or without
11  * modification, are permitted provided that the following conditions
12  * are met:
13  * 1. Redistributions of source code must retain the above copyright
14  *    notice, this list of conditions and the following disclaimer.
15  * 2. Redistributions in binary form must reproduce the above copyright
16  *    notice, this list of conditions and the following disclaimer in the
17  *    documentation and/or other materials provided with the distribution.
18  * 3. All advertising materials mentioning features or use of this software
19  *    must display the following acknowledgement:
20  *        This product includes software developed by the NetBSD
21  *        Foundation, Inc. and its contributors.
22  * 4. Neither the name of The NetBSD Foundation nor the names of its
23  *    contributors may be used to endorse or promote products derived
24  *    from this software without specific prior written permission.
25  *
26  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
27  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
28  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
29  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
30  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
31  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
32  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
33  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
34  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
35  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
36  * POSSIBILITY OF SUCH DAMAGE.
37  */
38 
39 /*-
40  * Copyright (c) 1990 The Regents of the University of California.
41  * All rights reserved.
42  *
43  * This code is derived from software contributed to Berkeley by
44  * the University of Utah, and William Jolitz.
45  *
46  * Redistribution and use in source and binary forms, with or without
47  * modification, are permitted provided that the following conditions
48  * are met:
49  * 1. Redistributions of source code must retain the above copyright
50  *    notice, this list of conditions and the following disclaimer.
51  * 2. Redistributions in binary form must reproduce the above copyright
52  *    notice, this list of conditions and the following disclaimer in the
53  *    documentation and/or other materials provided with the distribution.
54  * 3. All advertising materials mentioning features or use of this software
55  *    must display the following acknowledgement:
56  *	This product includes software developed by the University of
57  *	California, Berkeley and its contributors.
58  * 4. Neither the name of the University nor the names of its contributors
59  *    may be used to endorse or promote products derived from this software
60  *    without specific prior written permission.
61  *
62  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
63  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
64  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
65  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
66  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
67  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
68  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
69  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
70  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
71  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
72  * SUCH DAMAGE.
73  *
74  *	@(#)trap.c	7.4 (Berkeley) 5/13/91
75  */
76 
77 /*
78  * 386 Trap and System call handling
79  */
80 
81 #include <sys/cdefs.h>
82 __KERNEL_RCSID(0, "$NetBSD: trap.c,v 1.165 2002/02/18 15:58:02 simonb Exp $");
83 
84 #include "opt_ddb.h"
85 #include "opt_kgdb.h"
86 #include "opt_math_emulate.h"
87 #include "opt_vm86.h"
88 #include "opt_cputype.h"
89 
90 #include <sys/param.h>
91 #include <sys/systm.h>
92 #include <sys/proc.h>
93 #include <sys/user.h>
94 #include <sys/acct.h>
95 #include <sys/kernel.h>
96 #include <sys/signal.h>
97 #include <sys/syscall.h>
98 
99 #include <uvm/uvm_extern.h>
100 
101 #include <machine/cpu.h>
102 #include <machine/cpufunc.h>
103 #include <machine/psl.h>
104 #include <machine/reg.h>
105 #include <machine/trap.h>
106 #include <machine/userret.h>
107 #ifdef DDB
108 #include <machine/db_machdep.h>
109 #endif
110 
111 #include "mca.h"
112 #if NMCA > 0
113 #include <machine/mca_machdep.h>
114 #endif
115 
116 #include "isa.h"
117 
118 #ifdef KGDB
119 #include <sys/kgdb.h>
120 #endif
121 
122 #include "npx.h"
123 
124 void trap __P((struct trapframe));
125 #if defined(I386_CPU)
126 int trapwrite __P((unsigned));
127 #endif
128 
129 const char *trap_type[] = {
130 	"privileged instruction fault",		/*  0 T_PRIVINFLT */
131 	"breakpoint trap",			/*  1 T_BPTFLT */
132 	"arithmetic trap",			/*  2 T_ARITHTRAP */
133 	"asynchronous system trap",		/*  3 T_ASTFLT */
134 	"protection fault",			/*  4 T_PROTFLT */
135 	"trace trap",				/*  5 T_TRCTRAP */
136 	"page fault",				/*  6 T_PAGEFLT */
137 	"alignment fault",			/*  7 T_ALIGNFLT */
138 	"integer divide fault",			/*  8 T_DIVIDE */
139 	"non-maskable interrupt",		/*  9 T_NMI */
140 	"overflow trap",			/* 10 T_OFLOW */
141 	"bounds check fault",			/* 11 T_BOUND */
142 	"FPU not available fault",		/* 12 T_DNA */
143 	"double fault",				/* 13 T_DOUBLEFLT */
144 	"FPU operand fetch fault",		/* 14 T_FPOPFLT */
145 	"invalid TSS fault",			/* 15 T_TSSFLT */
146 	"segment not present fault",		/* 16 T_SEGNPFLT */
147 	"stack fault",				/* 17 T_STKFLT */
148 	"reserved trap",			/* 18 T_RESERVED */
149 };
150 int	trap_types = sizeof trap_type / sizeof trap_type[0];
151 
152 #ifdef DEBUG
153 int	trapdebug = 0;
154 #endif
155 
156 #define	IDTVEC(name)	__CONCAT(X, name)
157 
158 /*
159  * trap(frame):
160  *	Exception, fault, and trap interface to BSD kernel. This
161  * common code is called from assembly language IDT gate entry
162  * routines that prepare a suitable stack frame, and restore this
163  * frame after the exception has been processed. Note that the
164  * effect is as if the arguments were passed call by reference.
165  */
166 /*ARGSUSED*/
167 void
168 trap(frame)
169 	struct trapframe frame;
170 {
171 	register struct proc *p = curproc;
172 	int type = frame.tf_trapno;
173 	struct pcb *pcb;
174 	extern char fusubail[],
175 		    resume_iret[], resume_pop_ds[], resume_pop_es[],
176 		    resume_pop_fs[], resume_pop_gs[],
177 		    IDTVEC(osyscall)[];
178 	struct trapframe *vframe;
179 	int resume;
180 	caddr_t onfault;
181 	int error;
182 
183 	uvmexp.traps++;
184 
185 	pcb = (p != NULL) ? &p->p_addr->u_pcb : NULL;
186 #ifdef DEBUG
187 	if (trapdebug) {
188 		printf("trap %d code %x eip %x cs %x eflags %x cr2 %x cpl %x\n",
189 		    frame.tf_trapno, frame.tf_err, frame.tf_eip, frame.tf_cs,
190 		    frame.tf_eflags, rcr2(), cpl);
191 		printf("curproc %p\n", curproc);
192 	}
193 #endif
194 
195 	if (!KERNELMODE(frame.tf_cs, frame.tf_eflags)) {
196 		type |= T_USER;
197 		p->p_md.md_regs = &frame;
198 		pcb->pcb_cr2 = 0;
199 	}
200 
201 	switch (type) {
202 
203 	default:
204 	we_re_toast:
205 #ifdef KGDB
206 		if (kgdb_trap(type, &frame))
207 			return;
208 		else {
209 			/*
210 			 * If this is a breakpoint, don't panic
211 			 * if we're not connected.
212 			 */
213 			if (type == T_BPTFLT) {
214 				printf("kgdb: ignored %s\n", trap_type[type]);
215 				return;
216 			}
217 		}
218 #endif
219 #ifdef DDB
220 		if (kdb_trap(type, 0, &frame))
221 			return;
222 #endif
223 		if (frame.tf_trapno < trap_types)
224 			printf("fatal %s", trap_type[frame.tf_trapno]);
225 		else
226 			printf("unknown trap %d", frame.tf_trapno);
227 		printf(" in %s mode\n", (type & T_USER) ? "user" : "supervisor");
228 		printf("trap type %d code %x eip %x cs %x eflags %x cr2 %x cpl %x\n",
229 		    type, frame.tf_err, frame.tf_eip, frame.tf_cs, frame.tf_eflags, rcr2(), cpl);
230 
231 		panic("trap");
232 		/*NOTREACHED*/
233 
234 	case T_PROTFLT:
235 	case T_SEGNPFLT:
236 	case T_ALIGNFLT:
237 	case T_TSSFLT:
238 		/* Check for copyin/copyout fault. */
239 		if (pcb->pcb_onfault != 0) {
240 copyefault:
241 			error = EFAULT;
242 copyfault:
243 			frame.tf_eip = (int)pcb->pcb_onfault;
244 			frame.tf_eax = error;
245 			return;
246 		}
247 
248 		/*
249 		 * Check for failure during return to user mode.
250 		 *
251 		 * We do this by looking at the instruction we faulted on.  The
252 		 * specific instructions we recognize only happen when
253 		 * returning from a trap, syscall, or interrupt.
254 		 *
255 		 * At this point, there are (at least) two trap frames on
256 		 * the kernel stack; we presume here that we faulted while
257 		 * loading our registers out of the outer one.
258 		 *
259 		 * The inner frame does not involve a ring crossing, so it
260 		 * ends right before &frame.tf_esp.  The outer frame has
261 		 * been partially consumed by the INTRFASTEXIT; exactly
262 		 * how much depends which register we were popping when we
263 		 * faulted, so we compute the outer frame address based on
264 		 * register-dependant offsets computed from &frame.tf_esp
265 		 * below.  To decide whether this was a kernel-mode or
266 		 * user-mode error, we look at this outer frame's tf_cs
267 		 * and tf_eflags, which are (fortunately) not consumed until
268 		 * the final instruction of INTRFASTEXIT.
269 		 *
270 		 * XXX
271 		 * The heuristic used here will currently fail for the case of
272 		 * one of the 2 pop instructions faulting when returning from a
273 		 * a fast interrupt.  This should not be possible.  It can be
274 		 * fixed by rearranging the trap frame so that the stack format
275 		 * at this point is the same as on exit from a `slow'
276 		 * interrupt.
277 		 */
278 		switch (*(u_char *)frame.tf_eip) {
279 		case 0xcf:	/* iret */
280 			vframe = (void *)((int)&frame.tf_esp -
281 			    offsetof(struct trapframe, tf_eip));
282 			resume = (int)resume_iret;
283 			break;
284 		case 0x1f:	/* popl %ds */
285 			vframe = (void *)((int)&frame.tf_esp -
286 			    offsetof(struct trapframe, tf_ds));
287 			resume = (int)resume_pop_ds;
288 			break;
289 		case 0x07:	/* popl %es */
290 			vframe = (void *)((int)&frame.tf_esp -
291 			    offsetof(struct trapframe, tf_es));
292 			resume = (int)resume_pop_es;
293 			break;
294 		case 0x0f:	/* 0x0f prefix */
295 			switch (*(u_char *)(frame.tf_eip+1)) {
296 			case 0xa1:		/* popl %fs */
297 				vframe = (void *)((int)&frame.tf_esp -
298 				    offsetof(struct trapframe, tf_fs));
299 				resume = (int)resume_pop_fs;
300 				break;
301 			case 0xa9:		/* popl %gs */
302 				vframe = (void *)((int)&frame.tf_esp -
303 				    offsetof(struct trapframe, tf_gs));
304 				resume = (int)resume_pop_gs;
305 				break;
306 			}
307 			break;
308 		default:
309 			goto we_re_toast;
310 		}
311 		if (KERNELMODE(vframe->tf_cs, vframe->tf_eflags))
312 			goto we_re_toast;
313 
314 		frame.tf_eip = resume;
315 		return;
316 
317 	case T_PROTFLT|T_USER:		/* protection fault */
318 #ifdef VM86
319 		if (frame.tf_eflags & PSL_VM) {
320 			vm86_gpfault(p, type & ~T_USER);
321 			goto out;
322 		}
323 #endif
324 	case T_TSSFLT|T_USER:
325 	case T_SEGNPFLT|T_USER:
326 	case T_STKFLT|T_USER:
327 	case T_ALIGNFLT|T_USER:
328 	case T_NMI|T_USER:
329 		(*p->p_emul->e_trapsignal)(p, SIGBUS, type & ~T_USER);
330 		goto out;
331 
332 	case T_PRIVINFLT|T_USER:	/* privileged instruction fault */
333 	case T_FPOPFLT|T_USER:		/* coprocessor operand fault */
334 		(*p->p_emul->e_trapsignal)(p, SIGILL, type & ~T_USER);
335 		goto out;
336 
337 	case T_ASTFLT|T_USER:		/* Allow process switch */
338 		uvmexp.softs++;
339 		if (p->p_flag & P_OWEUPC) {
340 			p->p_flag &= ~P_OWEUPC;
341 			ADDUPROF(p);
342 		}
343 		/* Allow a forced task switch. */
344 		if (want_resched)
345 			preempt(NULL);
346 		goto out;
347 
348 	case T_DNA|T_USER: {
349 #ifdef MATH_EMULATE
350 		int rv;
351 		if ((rv = math_emulate(&frame)) == 0) {
352 			if (frame.tf_eflags & PSL_T)
353 				goto trace;
354 			return;
355 		}
356 		(*p->p_emul->e_trapsignal)(p, rv, type & ~T_USER);
357 		goto out;
358 #else
359 		printf("pid %d killed due to lack of floating point\n",
360 		    p->p_pid);
361 		(*p->p_emul->e_trapsignal)(p, SIGKILL, type & ~T_USER);
362 		goto out;
363 #endif
364 	}
365 
366 	case T_BOUND|T_USER:
367 	case T_OFLOW|T_USER:
368 	case T_DIVIDE|T_USER:
369 		(*p->p_emul->e_trapsignal)(p, SIGFPE, type & ~T_USER);
370 		goto out;
371 
372 	case T_ARITHTRAP|T_USER:
373 		(*p->p_emul->e_trapsignal)(p, SIGFPE, frame.tf_err);
374 		goto out;
375 
376 	case T_PAGEFLT:			/* allow page faults in kernel mode */
377 		if (p == 0)
378 			goto we_re_toast;
379 		/*
380 		 * fusubail is used by [fs]uswintr() to prevent page faulting
381 		 * from inside the profiling interrupt.
382 		 */
383 		if (pcb->pcb_onfault == fusubail)
384 			goto copyefault;
385 #if 0
386 		/* XXX - check only applies to 386's and 486's with WP off */
387 		if (frame.tf_err & PGEX_P)
388 			goto we_re_toast;
389 #endif
390 		/* FALLTHROUGH */
391 
392 	case T_PAGEFLT|T_USER: {	/* page fault */
393 		register vaddr_t va;
394 		register struct vmspace *vm = p->p_vmspace;
395 		register struct vm_map *map;
396 		vm_prot_t ftype;
397 		extern struct vm_map *kernel_map;
398 		unsigned nss;
399 
400 		if (vm == NULL)
401 			goto we_re_toast;
402 		pcb->pcb_cr2 = rcr2();
403 		va = trunc_page((vaddr_t)pcb->pcb_cr2);
404 		/*
405 		 * It is only a kernel address space fault iff:
406 		 *	1. (type & T_USER) == 0  and
407 		 *	2. pcb_onfault not set or
408 		 *	3. pcb_onfault set but supervisor space fault
409 		 * The last can occur during an exec() copyin where the
410 		 * argument space is lazy-allocated.
411 		 */
412 		if (type == T_PAGEFLT && va >= KERNBASE)
413 			map = kernel_map;
414 		else
415 			map = &vm->vm_map;
416 		if (frame.tf_err & PGEX_W)
417 			ftype = VM_PROT_WRITE;
418 		else
419 			ftype = VM_PROT_READ;
420 
421 #ifdef DIAGNOSTIC
422 		if (map == kernel_map && va == 0) {
423 			printf("trap: bad kernel access at %lx\n", va);
424 			goto we_re_toast;
425 		}
426 #endif
427 
428 		nss = 0;
429 		if ((caddr_t)va >= vm->vm_maxsaddr
430 		    && (caddr_t)va < (caddr_t)VM_MAXUSER_ADDRESS
431 		    && map != kernel_map) {
432 			nss = btoc(USRSTACK-(unsigned)va);
433 			if (nss > btoc(p->p_rlimit[RLIMIT_STACK].rlim_cur)) {
434 				/*
435 				 * We used to fail here. However, it may
436 				 * just have been an mmap()ed page low
437 				 * in the stack, which is legal. If it
438 				 * wasn't, uvm_fault() will fail below.
439 				 *
440 				 * Set nss to 0, since this case is not
441 				 * a "stack extension".
442 				 */
443 				nss = 0;
444 			}
445 		}
446 
447 		/* Fault the original page in. */
448 		onfault = pcb->pcb_onfault;
449 		pcb->pcb_onfault = NULL;
450 		error = uvm_fault(map, va, 0, ftype);
451 		pcb->pcb_onfault = onfault;
452 		if (error == 0) {
453 			if (nss > vm->vm_ssize)
454 				vm->vm_ssize = nss;
455 
456 			if (type == T_PAGEFLT)
457 				return;
458 			goto out;
459 		}
460 		if (error == EACCES) {
461 			error = EFAULT;
462 		}
463 
464 		if (type == T_PAGEFLT) {
465 			if (pcb->pcb_onfault != 0)
466 				goto copyfault;
467 			printf("uvm_fault(%p, 0x%lx, 0, %d) -> %x\n",
468 			    map, va, ftype, error);
469 			goto we_re_toast;
470 		}
471 		if (error == ENOMEM) {
472 			printf("UVM: pid %d (%s), uid %d killed: out of swap\n",
473 			       p->p_pid, p->p_comm,
474 			       p->p_cred && p->p_ucred ?
475 			       p->p_ucred->cr_uid : -1);
476 			(*p->p_emul->e_trapsignal)(p, SIGKILL, T_PAGEFLT);
477 		} else {
478 			(*p->p_emul->e_trapsignal)(p, SIGSEGV, T_PAGEFLT);
479 		}
480 		break;
481 	}
482 
483 	case T_TRCTRAP:
484 		/* Check whether they single-stepped into a lcall. */
485 		if (frame.tf_eip == (int)IDTVEC(osyscall))
486 			return;
487 		if (frame.tf_eip == (int)IDTVEC(osyscall) + 1) {
488 			frame.tf_eflags &= ~PSL_T;
489 			return;
490 		}
491 		goto we_re_toast;
492 
493 	case T_BPTFLT|T_USER:		/* bpt instruction fault */
494 	case T_TRCTRAP|T_USER:		/* trace trap */
495 #ifdef MATH_EMULATE
496 	trace:
497 #endif
498 		(*p->p_emul->e_trapsignal)(p, SIGTRAP, type & ~T_USER);
499 		break;
500 
501 #if	NISA > 0 || NMCA > 0
502 	case T_NMI:
503 #if defined(KGDB) || defined(DDB)
504 		/* NMI can be hooked up to a pushbutton for debugging */
505 		printf ("NMI ... going to debugger\n");
506 #ifdef KGDB
507 
508 		if (kgdb_trap(type, &frame))
509 			return;
510 #endif
511 #ifdef DDB
512 		if (kdb_trap(type, 0, &frame))
513 			return;
514 #endif
515 #endif /* KGDB || DDB */
516 		/* machine/parity/power fail/"kitchen sink" faults */
517 
518 #if NMCA > 0
519 		/* mca_nmi() takes care to call isa_nmi() if appropriate */
520 		if (mca_nmi() != 0)
521 			goto we_re_toast;
522 		else
523 			return;
524 #else /* NISA > 0 */
525 		if (isa_nmi() != 0)
526 			goto we_re_toast;
527 		else
528 			return;
529 #endif /* NMCA > 0 */
530 #endif /* NISA > 0 || NMCA > 0 */
531 	}
532 
533 	if ((type & T_USER) == 0)
534 		return;
535 out:
536 	userret(p);
537 }
538 
539 #if defined(I386_CPU)
540 /*
541  * Compensate for 386 brain damage (missing URKR)
542  */
543 int
544 trapwrite(addr)
545 	unsigned addr;
546 {
547 	vaddr_t va;
548 	unsigned nss;
549 	struct proc *p;
550 	struct vmspace *vm;
551 
552 	va = trunc_page((vaddr_t)addr);
553 	if (va >= VM_MAXUSER_ADDRESS)
554 		return 1;
555 
556 	nss = 0;
557 	p = curproc;
558 	vm = p->p_vmspace;
559 	if ((caddr_t)va >= vm->vm_maxsaddr) {
560 		nss = btoc(USRSTACK-(unsigned)va);
561 		if (nss > btoc(p->p_rlimit[RLIMIT_STACK].rlim_cur))
562 			nss = 0;
563 	}
564 
565 	if (uvm_fault(&vm->vm_map, va, 0, VM_PROT_WRITE) != 0)
566 		return 1;
567 
568 	if (nss > vm->vm_ssize)
569 		vm->vm_ssize = nss;
570 
571 	return 0;
572 }
573 #endif /* I386_CPU */
574