trap.c revision 1.9.2.1 1 /* $NetBSD: trap.c,v 1.9.2.1 2002/12/18 01:05:34 gmcgarry Exp $ */
2
3 /*
4 * Copyright 2001 Wasabi Systems, Inc.
5 * All rights reserved.
6 *
7 * Written by Eduardo Horvath and Simon Burge for Wasabi Systems, Inc.
8 *
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
11 * are met:
12 * 1. Redistributions of source code must retain the above copyright
13 * notice, this list of conditions and the following disclaimer.
14 * 2. Redistributions in binary form must reproduce the above copyright
15 * notice, this list of conditions and the following disclaimer in the
16 * documentation and/or other materials provided with the distribution.
17 * 3. All advertising materials mentioning features or use of this software
18 * must display the following acknowledgement:
19 * This product includes software developed for the NetBSD Project by
20 * Wasabi Systems, Inc.
21 * 4. The name of Wasabi Systems, Inc. may not be used to endorse
22 * or promote products derived from this software without specific prior
23 * written permission.
24 *
25 * THIS SOFTWARE IS PROVIDED BY WASABI SYSTEMS, INC. ``AS IS'' AND
26 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
27 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
28 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL WASABI SYSTEMS, INC
29 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
30 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
31 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
32 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
33 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
34 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
35 * POSSIBILITY OF SUCH DAMAGE.
36 */
37
38 /*
39 * Copyright (C) 1995, 1996 Wolfgang Solfrank.
40 * Copyright (C) 1995, 1996 TooLs GmbH.
41 * All rights reserved.
42 *
43 * Redistribution and use in source and binary forms, with or without
44 * modification, are permitted provided that the following conditions
45 * are met:
46 * 1. Redistributions of source code must retain the above copyright
47 * notice, this list of conditions and the following disclaimer.
48 * 2. Redistributions in binary form must reproduce the above copyright
49 * notice, this list of conditions and the following disclaimer in the
50 * documentation and/or other materials provided with the distribution.
51 * 3. All advertising materials mentioning features or use of this software
52 * must display the following acknowledgement:
53 * This product includes software developed by TooLs GmbH.
54 * 4. The name of TooLs GmbH may not be used to endorse or promote products
55 * derived from this software without specific prior written permission.
56 *
57 * THIS SOFTWARE IS PROVIDED BY TOOLS GMBH ``AS IS'' AND ANY EXPRESS OR
58 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
59 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
60 * IN NO EVENT SHALL TOOLS GMBH BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
61 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
62 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
63 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
64 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
65 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
66 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
67 */
68
69 #include "opt_altivec.h"
70 #include "opt_ddb.h"
71 #include "opt_ktrace.h"
72 #include "opt_systrace.h"
73 #include "opt_syscall_debug.h"
74
75 #include <sys/param.h>
76 #include <sys/proc.h>
77 #include <sys/reboot.h>
78 #include <sys/syscall.h>
79 #include <sys/systm.h>
80 #include <sys/user.h>
81 #ifdef KTRACE
82 #include <sys/ktrace.h>
83 #endif
84 #ifdef SYSTRACE
85 #include <sys/systrace.h>
86 #endif
87
88 #include <uvm/uvm_extern.h>
89
90 #include <dev/cons.h>
91
92 #include <machine/cpu.h>
93 #include <machine/db_machdep.h>
94 #include <machine/fpu.h>
95 #include <machine/frame.h>
96 #include <machine/pcb.h>
97 #include <machine/psl.h>
98 #include <machine/trap.h>
99
100 #include <powerpc/spr.h>
101 #include <powerpc/ibm4xx/pmap.h>
102 #include <powerpc/ibm4xx/tlb.h>
103 #include <powerpc/fpu/fpu_extern.h>
104
105 /* These definitions should probably be somewhere else XXX */
106 #define FIRSTARG 3 /* first argument is in reg 3 */
107 #define NARGREG 8 /* 8 args are in registers */
108 #define MOREARGS(sp) ((caddr_t)((int)(sp) + 8)) /* more args go here */
109
110 #ifndef MULTIPROCESSOR
111 volatile int astpending;
112 volatile int want_resched;
113 #endif
114
115 static int fix_unaligned __P((struct proc *p, struct trapframe *frame));
116
117 void trap __P((struct trapframe *)); /* Called from locore / trap_subr */
118 int setfault __P((faultbuf)); /* defined in locore.S */
119 /* Why are these not defined in a header? */
120 int badaddr __P((void *, size_t));
121 int badaddr_read __P((void *, size_t, int *));
122 int ctx_setup __P((int, int));
123
124 #ifdef DEBUG
125 #define TDB_ALL 0x1
126 int trapdebug = /* TDB_ALL */ 0;
127 #define DBPRINTF(x, y) if (trapdebug & (x)) printf y
128 #else
129 #define DBPRINTF(x, y)
130 #endif
131
132 void
133 trap(struct trapframe *frame)
134 {
135 struct proc *p = curproc;
136 int type = frame->exc;
137 int ftype, rv;
138
139 KASSERT(p == 0 || (p->p_stat == SONPROC));
140
141 if (frame->srr1 & PSL_PR)
142 type |= EXC_USER;
143
144 ftype = VM_PROT_READ;
145
146 DBPRINTF(TDB_ALL, ("trap(%x) at %x from frame %p &frame %p\n",
147 type, frame->srr0, frame, &frame));
148
149 switch (type) {
150 case EXC_DEBUG|EXC_USER:
151 {
152 int srr2, srr3;
153 __asm __volatile("mfspr %0,0x3f0" : "=r" (rv), "=r" (srr2), "=r" (srr3) :);
154 printf("debug reg is %x srr2 %x srr3 %x\n", rv, srr2, srr3);
155 }
156 /*
157 * DEBUG intr -- probably single-step.
158 */
159 case EXC_TRC|EXC_USER:
160 KERNEL_PROC_LOCK(p);
161 frame->srr1 &= ~PSL_SE;
162 trapsignal(p, SIGTRAP, EXC_TRC);
163 KERNEL_PROC_UNLOCK(p);
164 break;
165
166 /* If we could not find and install appropriate TLB entry, fall through */
167
168 case EXC_DSI:
169 /* FALLTHROUGH */
170 case EXC_DTMISS:
171 {
172 struct vm_map *map;
173 vaddr_t va;
174 faultbuf *fb = NULL;
175
176 KERNEL_LOCK(LK_CANRECURSE|LK_EXCLUSIVE);
177 va = frame->dear;
178 if (frame->pid == KERNEL_PID) {
179 map = kernel_map;
180 } else {
181 map = &p->p_vmspace->vm_map;
182 }
183
184 if (frame->esr & (ESR_DST|ESR_DIZ))
185 ftype = VM_PROT_WRITE;
186
187 DBPRINTF(TDB_ALL, ("trap(EXC_DSI) at %x %s fault on %p esr %x\n",
188 frame->srr0, (ftype&VM_PROT_WRITE) ? "write" : "read", (void *)va, frame->esr));
189 rv = uvm_fault(map, trunc_page(va), 0, ftype);
190 KERNEL_UNLOCK();
191 if (rv == 0)
192 goto done;
193 if ((fb = p->p_addr->u_pcb.pcb_onfault) != NULL) {
194 frame->pid = KERNEL_PID;
195 frame->srr0 = (*fb)[0];
196 frame->srr1 |= PSL_IR; /* Re-enable IMMU */
197 frame->fixreg[1] = (*fb)[1];
198 frame->fixreg[2] = (*fb)[2];
199 frame->fixreg[3] = 1; /* Return TRUE */
200 frame->cr = (*fb)[3];
201 memcpy(&frame->fixreg[13], &(*fb)[4],
202 19 * sizeof(register_t));
203 goto done;
204 }
205 }
206 goto brain_damage;
207
208 case EXC_DSI|EXC_USER:
209 /* FALLTHROUGH */
210 case EXC_DTMISS|EXC_USER:
211 KERNEL_PROC_LOCK(p);
212
213 if (frame->esr & (ESR_DST|ESR_DIZ))
214 ftype = VM_PROT_WRITE;
215
216 DBPRINTF(TDB_ALL, ("trap(EXC_DSI|EXC_USER) at %x %s fault on %x %x\n",
217 frame->srr0, (ftype&VM_PROT_WRITE) ? "write" : "read", frame->dear, frame->esr));
218 KASSERT(p == curproc && (p->p_stat == SONPROC));
219 rv = uvm_fault(&p->p_vmspace->vm_map,
220 trunc_page(frame->dear), 0, ftype);
221 if (rv == 0) {
222 KERNEL_PROC_UNLOCK(p);
223 break;
224 }
225 if (rv == ENOMEM) {
226 printf("UVM: pid %d (%s), uid %d killed: "
227 "out of swap\n",
228 p->p_pid, p->p_comm,
229 p->p_ucred ? p->p_ucred->cr_uid : -1);
230 trapsignal(p, SIGKILL, EXC_DSI);
231 } else {
232 trapsignal(p, SIGSEGV, EXC_DSI);
233 }
234 KERNEL_PROC_UNLOCK(p);
235 break;
236 case EXC_ITMISS|EXC_USER:
237 case EXC_ISI|EXC_USER:
238 KERNEL_PROC_LOCK(p);
239 ftype = VM_PROT_READ | VM_PROT_EXECUTE;
240 DBPRINTF(TDB_ALL, ("trap(EXC_ISI|EXC_USER) at %x %s fault on %x tf %p\n",
241 frame->srr0, (ftype&VM_PROT_WRITE) ? "write" : "read", frame->srr0, frame));
242 rv = uvm_fault(&p->p_vmspace->vm_map, trunc_page(frame->srr0), 0, ftype);
243 if (rv == 0) {
244 KERNEL_PROC_UNLOCK(p);
245 break;
246 }
247 trapsignal(p, SIGSEGV, EXC_ISI);
248 KERNEL_PROC_UNLOCK(p);
249 break;
250
251 case EXC_AST|EXC_USER:
252 astpending = 0; /* we are about to do it */
253 KERNEL_PROC_LOCK(p);
254 uvmexp.softs++;
255 if (p->p_flag & P_OWEUPC) {
256 p->p_flag &= ~P_OWEUPC;
257 ADDUPROF(p);
258 }
259 /* Check whether we are being preempted. */
260 if (want_resched)
261 preempt(NULL);
262 KERNEL_PROC_UNLOCK(p);
263 break;
264
265
266 case EXC_ALI|EXC_USER:
267 KERNEL_PROC_LOCK(p);
268 if (fix_unaligned(p, frame) != 0)
269 trapsignal(p, SIGBUS, EXC_ALI);
270 else
271 frame->srr0 += 4;
272 KERNEL_PROC_UNLOCK(p);
273 break;
274
275 case EXC_PGM|EXC_USER:
276 /*
277 * Illegal insn:
278 *
279 * let's try to see if it's FPU and can be emulated.
280 */
281 uvmexp.traps ++;
282 if (!(p->p_addr->u_pcb.pcb_flags & PCB_FPU)) {
283 memset(&p->p_addr->u_pcb.pcb_fpu, 0,
284 sizeof p->p_addr->u_pcb.pcb_fpu);
285 p->p_addr->u_pcb.pcb_flags |= PCB_FPU;
286 }
287
288 if ((rv = fpu_emulate(frame,
289 (struct fpreg *)&p->p_addr->u_pcb.pcb_fpu))) {
290 KERNEL_PROC_LOCK(p);
291 trapsignal(p, rv, EXC_PGM);
292 KERNEL_PROC_UNLOCK(p);
293 }
294 break;
295
296 case EXC_MCHK:
297 {
298 faultbuf *fb;
299
300 if ((fb = p->p_addr->u_pcb.pcb_onfault) != NULL) {
301 frame->pid = KERNEL_PID;
302 frame->srr0 = (*fb)[0];
303 frame->srr1 |= PSL_IR; /* Re-enable IMMU */
304 frame->fixreg[1] = (*fb)[1];
305 frame->fixreg[2] = (*fb)[2];
306 frame->fixreg[3] = 1; /* Return TRUE */
307 frame->cr = (*fb)[3];
308 memcpy(&frame->fixreg[13], &(*fb)[4],
309 19 * sizeof(register_t));
310 goto done;
311 }
312 }
313 goto brain_damage;
314 default:
315 brain_damage:
316 printf("trap type 0x%x at 0x%x\n", type, frame->srr0);
317 #ifdef DDB
318 if (kdb_trap(type, frame))
319 goto done;
320 #endif
321 #ifdef TRAP_PANICWAIT
322 printf("Press a key to panic.\n");
323 cngetc();
324 #endif
325 panic("trap");
326 }
327
328 /* Take pending signals. */
329 {
330 int sig;
331
332 while ((sig = CURSIG(p)) != 0)
333 postsig(sig);
334 }
335
336 curcpu()->ci_schedstate.spc_curpriority = p->p_priority = p->p_usrpri;
337 done:
338 return;
339 }
340
341 int
342 ctx_setup(int ctx, int srr1)
343 {
344 volatile struct pmap *pm;
345
346 /* Update PID if we're returning to user mode. */
347 if (srr1 & PSL_PR) {
348 pm = curproc->p_vmspace->vm_map.pmap;
349 if (!pm->pm_ctx) {
350 ctx_alloc((struct pmap *)pm);
351 }
352 ctx = pm->pm_ctx;
353 if (srr1 & PSL_SE) {
354 int dbreg, mask = 0x48000000;
355 /*
356 * Set the Internal Debug and
357 * Instruction Completion bits of
358 * the DBCR0 register.
359 *
360 * XXX this is also used by jtag debuggers...
361 */
362 __asm __volatile("mfspr %0,0x3f2;"
363 "or %0,%0,%1;"
364 "mtspr 0x3f2,%0;" :
365 "=&r" (dbreg) : "r" (mask));
366 }
367 }
368 else if (!ctx) {
369 ctx = KERNEL_PID;
370 }
371 return (ctx);
372 }
373
374 /*
375 * Used by copyin()/copyout()
376 */
377 extern vaddr_t vmaprange __P((struct proc *, vaddr_t, vsize_t, int));
378 extern void vunmaprange __P((vaddr_t, vsize_t));
379 static int bigcopyin __P((const void *, void *, size_t ));
380 static int bigcopyout __P((const void *, void *, size_t ));
381
382 int
383 copyin(const void *udaddr, void *kaddr, size_t len)
384 {
385 struct pmap *pm = curproc->p_vmspace->vm_map.pmap;
386 int msr, pid, tmp, ctx;
387 faultbuf env;
388
389 /* For bigger buffers use the faster copy */
390 if (len > 256) return (bigcopyin(udaddr, kaddr, len));
391
392 if (setfault(env)) {
393 curpcb->pcb_onfault = 0;
394 return EFAULT;
395 }
396
397 if (!(ctx = pm->pm_ctx)) {
398 /* No context -- assign it one */
399 ctx_alloc(pm);
400 ctx = pm->pm_ctx;
401 }
402
403 asm volatile("addi %6,%6,1; mtctr %6;" /* Set up counter */
404 "mfmsr %0;" /* Save MSR */
405 "li %1,0x20; "
406 "andc %1,%0,%1; mtmsr %1;" /* Disable IMMU */
407 "mfpid %1;" /* Save old PID */
408 "sync; isync;"
409
410 "1: bdz 2f;" /* while len */
411 "mtpid %3; sync;" /* Load user ctx */
412 "lbz %2,0(%4); addi %4,%4,1;" /* Load byte */
413 "sync; isync;"
414 "mtpid %1;sync;"
415 "stb %2,0(%5); dcbf 0,%5; addi %5,%5,1;" /* Store kernel byte */
416 "sync; isync;"
417 "b 1b;" /* repeat */
418
419 "2: mtpid %1; mtmsr %0;" /* Restore PID and MSR */
420 "sync; isync;"
421 : "=&r" (msr), "=&r" (pid), "=&r" (tmp)
422 : "r" (ctx), "r" (udaddr), "r" (kaddr), "r" (len));
423
424 curpcb->pcb_onfault = 0;
425 return 0;
426 }
427
428 static int
429 bigcopyin(const void *udaddr, void *kaddr, size_t len)
430 {
431 const char *up;
432 char *kp = kaddr;
433 struct proc *p = curproc;
434 int error;
435
436 if (!p) {
437 return EFAULT;
438 }
439
440 /*
441 * Stolen from physio():
442 */
443 PHOLD(p);
444 error = uvm_vslock(p, (caddr_t)udaddr, len, VM_PROT_READ);
445 if (error) {
446 PRELE(p);
447 return EFAULT;
448 }
449 up = (char *)vmaprange(p, (vaddr_t)udaddr, len, VM_PROT_READ);
450
451 memcpy(kp, up, len);
452 vunmaprange((vaddr_t)up, len);
453 uvm_vsunlock(p, (caddr_t)udaddr, len);
454 PRELE(p);
455
456 return 0;
457 }
458
459 int
460 copyout(const void *kaddr, void *udaddr, size_t len)
461 {
462 struct pmap *pm = curproc->p_vmspace->vm_map.pmap;
463 int msr, pid, tmp, ctx;
464 faultbuf env;
465
466 /* For big copies use more efficient routine */
467 if (len > 256) return (bigcopyout(kaddr, udaddr, len));
468
469 if (setfault(env)) {
470 curpcb->pcb_onfault = 0;
471 return EFAULT;
472 }
473
474 if (!(ctx = pm->pm_ctx)) {
475 /* No context -- assign it one */
476 ctx_alloc(pm);
477 ctx = pm->pm_ctx;
478 }
479
480 asm volatile("addi %6,%6,1; mtctr %6;" /* Set up counter */
481 "mfmsr %0;" /* Save MSR */
482 "li %1,0x20; "
483 "andc %1,%0,%1; mtmsr %1;" /* Disable IMMU */
484 "mfpid %1;" /* Save old PID */
485 "sync; isync;"
486
487 "1: bdz 2f;" /* while len */
488 "mtpid %1;sync;"
489 "lbz %2,0(%5); addi %5,%5,1;" /* Load kernel byte */
490 "sync; isync;"
491 "mtpid %3; sync;" /* Load user ctx */
492 "stb %2,0(%4); dcbf 0,%4; addi %4,%4,1;" /* Store user byte */
493 "sync; isync;"
494 "b 1b;" /* repeat */
495
496 "2: mtpid %1; mtmsr %0;" /* Restore PID and MSR */
497 "sync; isync;"
498 : "=&r" (msr), "=&r" (pid), "=&r" (tmp)
499 : "r" (ctx), "r" (udaddr), "r" (kaddr), "r" (len));
500
501 curpcb->pcb_onfault = 0;
502 return 0;
503 }
504
505 static int
506 bigcopyout(const void *kaddr, void *udaddr, size_t len)
507 {
508 char *up;
509 const char *kp = (char *)kaddr;
510 struct proc *p = curproc;
511 int error;
512
513 if (!p) {
514 return EFAULT;
515 }
516
517 /*
518 * Stolen from physio():
519 */
520 PHOLD(p);
521 error = uvm_vslock(p, udaddr, len, VM_PROT_WRITE);
522 if (error) {
523 PRELE(p);
524 return EFAULT;
525 }
526 up = (char *)vmaprange(p, (vaddr_t)udaddr, len,
527 VM_PROT_READ|VM_PROT_WRITE);
528
529 memcpy(up, kp, len);
530 vunmaprange((vaddr_t)up, len);
531 uvm_vsunlock(p, udaddr, len);
532 PRELE(p);
533
534 return 0;
535 }
536
537 /*
538 * kcopy(const void *src, void *dst, size_t len);
539 *
540 * Copy len bytes from src to dst, aborting if we encounter a fatal
541 * page fault.
542 *
543 * kcopy() _must_ save and restore the old fault handler since it is
544 * called by uiomove(), which may be in the path of servicing a non-fatal
545 * page fault.
546 */
547 int
548 kcopy(const void *src, void *dst, size_t len)
549 {
550 faultbuf env, *oldfault;
551
552 oldfault = curpcb->pcb_onfault;
553 if (setfault(env)) {
554 curpcb->pcb_onfault = oldfault;
555 return EFAULT;
556 }
557
558 memcpy(dst, src, len);
559
560 curpcb->pcb_onfault = oldfault;
561 return 0;
562 }
563
564 int
565 badaddr(void *addr, size_t size)
566 {
567
568 return badaddr_read(addr, size, NULL);
569 }
570
571 int
572 badaddr_read(void *addr, size_t size, int *rptr)
573 {
574 faultbuf env;
575 int x;
576
577 /* Get rid of any stale machine checks that have been waiting. */
578 __asm __volatile ("sync; isync");
579
580 if (setfault(env)) {
581 curpcb->pcb_onfault = 0;
582 __asm __volatile ("sync");
583 return 1;
584 }
585
586 __asm __volatile ("sync");
587
588 switch (size) {
589 case 1:
590 x = *(volatile int8_t *)addr;
591 break;
592 case 2:
593 x = *(volatile int16_t *)addr;
594 break;
595 case 4:
596 x = *(volatile int32_t *)addr;
597 break;
598 default:
599 panic("badaddr: invalid size (%d)", size);
600 }
601
602 /* Make sure we took the machine check, if we caused one. */
603 __asm __volatile ("sync; isync");
604
605 curpcb->pcb_onfault = 0;
606 __asm __volatile ("sync"); /* To be sure. */
607
608 /* Use the value to avoid reorder. */
609 if (rptr)
610 *rptr = x;
611
612 return 0;
613 }
614
615 /*
616 * For now, this only deals with the particular unaligned access case
617 * that gcc tends to generate. Eventually it should handle all of the
618 * possibilities that can happen on a 32-bit PowerPC in big-endian mode.
619 */
620
621 static int
622 fix_unaligned(struct proc *p, struct trapframe *frame)
623 {
624
625 return -1;
626 }
627