]> CyberLeo.Net >> Repos - FreeBSD/releng/8.2.git/blob - sys/powerpc/booke/trap.c
Copy stable/8 to releng/8.2 in preparation for FreeBSD-8.2 release.
[FreeBSD/releng/8.2.git] / sys / powerpc / booke / trap.c
1 /*-
2  * Copyright (C) 1995, 1996 Wolfgang Solfrank.
3  * Copyright (C) 1995, 1996 TooLs GmbH.
4  * All rights reserved.
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  * 1. Redistributions of source code must retain the above copyright
10  *    notice, this list of conditions and the following disclaimer.
11  * 2. Redistributions in binary form must reproduce the above copyright
12  *    notice, this list of conditions and the following disclaimer in the
13  *    documentation and/or other materials provided with the distribution.
14  * 3. All advertising materials mentioning features or use of this software
15  *    must display the following acknowledgement:
16  *      This product includes software developed by TooLs GmbH.
17  * 4. The name of TooLs GmbH may not be used to endorse or promote products
18  *    derived from this software without specific prior written permission.
19  *
20  * THIS SOFTWARE IS PROVIDED BY TOOLS GMBH ``AS IS'' AND ANY EXPRESS OR
21  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
22  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
23  * IN NO EVENT SHALL TOOLS GMBH BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
24  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
25  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
26  * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
27  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
28  * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
29  * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30  *
31  * $NetBSD: trap.c,v 1.58 2002/03/04 04:07:35 dbj Exp $
32  */
33
34 #include <sys/cdefs.h>
35 __FBSDID("$FreeBSD$");
36
37 #include "opt_fpu_emu.h"
38 #include "opt_ktrace.h"
39
40 #include <sys/param.h>
41 #include <sys/kdb.h>
42 #include <sys/proc.h>
43 #include <sys/ktr.h>
44 #include <sys/lock.h>
45 #include <sys/mutex.h>
46 #include <sys/pioctl.h>
47 #include <sys/ptrace.h>
48 #include <sys/reboot.h>
49 #include <sys/syscall.h>
50 #include <sys/sysent.h>
51 #include <sys/systm.h>
52 #include <sys/uio.h>
53 #include <sys/signalvar.h>
54 #ifdef KTRACE
55 #include <sys/ktrace.h>
56 #endif
57 #include <sys/vmmeter.h>
58
59 #include <security/audit/audit.h>
60
61 #include <vm/vm.h>
62 #include <vm/pmap.h>
63 #include <vm/vm_extern.h>
64 #include <vm/vm_param.h>
65 #include <vm/vm_kern.h>
66 #include <vm/vm_map.h>
67 #include <vm/vm_page.h>
68
69 #include <machine/cpu.h>
70 #include <machine/db_machdep.h>
71 #include <machine/frame.h>
72 #include <machine/pcb.h>
73 #include <machine/pmap.h>
74 #include <machine/psl.h>
75 #include <machine/trap.h>
76 #include <machine/spr.h>
77
78 #ifdef FPU_EMU
79 #include <powerpc/fpu/fpu_extern.h>
80 #endif
81
82 #define FAULTBUF_LR     0
83 #define FAULTBUF_R1     1
84 #define FAULTBUF_R2     2
85 #define FAULTBUF_CR     3
86 #define FAULTBUF_CTR    4
87 #define FAULTBUF_XER    5
88 #define FAULTBUF_R13    6
89
90 static void     trap_fatal(struct trapframe *frame);
91 static void     printtrap(u_int vector, struct trapframe *frame, int isfatal,
92     int user);
93 static int      trap_pfault(struct trapframe *frame, int user);
94 static int      fix_unaligned(struct thread *td, struct trapframe *frame);
95 static int      handle_onfault(struct trapframe *frame);
96 static void     syscall(struct trapframe *frame);
97
98 int     setfault(faultbuf);             /* defined in locore.S */
99
100 /* Why are these not defined in a header? */
101 int     badaddr(void *, size_t);
102 int     badaddr_read(void *, size_t, int *);
103
104 struct powerpc_exception {
105         u_int   vector;
106         char    *name;
107 };
108
109 static struct powerpc_exception powerpc_exceptions[] = {
110         { EXC_CRIT,     "critical input" },
111         { EXC_MCHK,     "machine check" },
112         { EXC_DSI,      "data storage interrupt" },
113         { EXC_ISI,      "instruction storage interrupt" },
114         { EXC_EXI,      "external interrupt" },
115         { EXC_ALI,      "alignment" },
116         { EXC_PGM,      "program" },
117         { EXC_SC,       "system call" },
118         { EXC_APU,      "auxiliary proc unavailable" },
119         { EXC_DECR,     "decrementer" },
120         { EXC_FIT,      "fixed-interval timer" },
121         { EXC_WDOG,     "watchdog timer" },
122         { EXC_DTMISS,   "data tlb miss" },
123         { EXC_ITMISS,   "instruction tlb miss" },
124         { EXC_DEBUG,    "debug" },
125         { EXC_PERF,     "performance monitoring" },
126         { EXC_LAST,     NULL }
127 };
128
129 static const char *
130 trapname(u_int vector)
131 {
132         struct  powerpc_exception *pe;
133
134         for (pe = powerpc_exceptions; pe->vector != EXC_LAST; pe++) {
135                 if (pe->vector == vector)
136                         return (pe->name);
137         }
138
139         return ("unknown");
140 }
141
142 void
143 trap(struct trapframe *frame)
144 {
145         struct thread   *td;
146         struct proc     *p;
147         int             sig, type, user;
148         ksiginfo_t      ksi;
149
150         PCPU_INC(cnt.v_trap);
151
152         td = PCPU_GET(curthread);
153         p = td->td_proc;
154
155         type = frame->exc;
156         sig = 0;
157         user = (frame->srr1 & PSL_PR) ? 1 : 0;
158
159         CTR3(KTR_TRAP, "trap: %s type=%s (%s)", p->p_comm,
160             trapname(type), user ? "user" : "kernel");
161
162         if (user) {
163                 td->td_frame = frame;
164                 if (td->td_ucred != p->p_ucred)
165                         cred_update_thread(td);
166
167                 /* User Mode Traps */
168                 switch (type) {
169                 case EXC_DSI:
170                 case EXC_ISI:
171                         sig = trap_pfault(frame, 1);
172                         break;
173
174                 case EXC_SC:
175                         syscall(frame);
176                         break;
177
178                 case EXC_ALI:
179                         if (fix_unaligned(td, frame) != 0)
180                                 sig = SIGBUS;
181                         else
182                                 frame->srr0 += 4;
183                         break;
184
185                 case EXC_DEBUG: /* Single stepping */
186                         mtspr(SPR_DBSR, mfspr(SPR_DBSR));
187                         frame->srr1 &= ~PSL_DE;
188                         frame->cpu.booke.dbcr0 &= ~(DBCR0_IDM || DBCR0_IC);
189                         sig = SIGTRAP;
190                         break;
191
192                 case EXC_PGM:   /* Program exception */
193 #ifdef FPU_EMU
194                         sig = fpu_emulate(frame,
195                             (struct fpreg *)&td->td_pcb->pcb_fpu);
196 #else
197                         /* XXX SIGILL for non-trap instructions. */
198                         sig = SIGTRAP;
199 #endif
200                         break;
201
202                 default:
203                         trap_fatal(frame);
204                 }
205         } else {
206                 /* Kernel Mode Traps */
207                 KASSERT(cold || td->td_ucred != NULL,
208                     ("kernel trap doesn't have ucred"));
209
210                 switch (type) {
211                 case EXC_DEBUG:
212                         mtspr(SPR_DBSR, mfspr(SPR_DBSR));
213                         kdb_trap(frame->exc, 0, frame);
214                         return;
215
216                 case EXC_DSI:
217                         if (trap_pfault(frame, 0) == 0)
218                                 return;
219                         break;
220
221                 case EXC_MCHK:
222                         if (handle_onfault(frame))
223                                 return;
224                         break;
225 #ifdef KDB
226                 case EXC_PGM:
227                         if (frame->cpu.booke.esr & ESR_PTR)
228                                 kdb_trap(EXC_PGM, 0, frame);
229                         return;
230 #endif
231                 default:
232                         break;
233                 }
234                 trap_fatal(frame);
235         }
236
237         if (sig != 0) {
238                 if (p->p_sysent->sv_transtrap != NULL)
239                         sig = (p->p_sysent->sv_transtrap)(sig, type);
240                 ksiginfo_init_trap(&ksi);
241                 ksi.ksi_signo = sig;
242                 ksi.ksi_code = type; /* XXX, not POSIX */
243                 /* ksi.ksi_addr = ? */
244                 ksi.ksi_trapno = type;
245                 trapsignal(td, &ksi);
246         }
247
248         userret(td, frame);
249         mtx_assert(&Giant, MA_NOTOWNED);
250 }
251
252 static void
253 trap_fatal(struct trapframe *frame)
254 {
255
256         printtrap(frame->exc, frame, 1, (frame->srr1 & PSL_PR));
257 #ifdef KDB
258         if ((debugger_on_panic || kdb_active) &&
259             kdb_trap(frame->exc, 0, frame))
260                 return;
261 #endif
262         panic("%s trap", trapname(frame->exc));
263 }
264
265 static void
266 printtrap(u_int vector, struct trapframe *frame, int isfatal, int user)
267 {
268         register_t va = 0;
269
270         printf("\n");
271         printf("%s %s trap:\n", isfatal ? "fatal" : "handled",
272             user ? "user" : "kernel");
273         printf("\n");
274         printf("   exception       = 0x%x (%s)\n", vector, trapname(vector));
275         
276         switch (vector) {
277         case EXC_DTMISS:
278         case EXC_DSI:
279                 va = frame->cpu.booke.dear;
280                 break;
281
282         case EXC_ITMISS:
283         case EXC_ISI:
284                 va = frame->srr0;
285                 break;
286         }
287
288         printf("   virtual address = 0x%08x\n", va);
289         printf("   srr0            = 0x%08x\n", frame->srr0);
290         printf("   srr1            = 0x%08x\n", frame->srr1);
291         printf("   curthread       = %p\n", curthread);
292         if (curthread != NULL)
293                 printf("          pid = %d, comm = %s\n",
294                     curthread->td_proc->p_pid, curthread->td_proc->p_comm);
295         printf("\n");
296 }
297
298 /*
299  * Handles a fatal fault when we have onfault state to recover.  Returns
300  * non-zero if there was onfault recovery state available.
301  */
302 static int
303 handle_onfault(struct trapframe *frame)
304 {
305         struct          thread *td;
306         faultbuf        *fb;
307
308         td = curthread;
309         fb = td->td_pcb->pcb_onfault;
310         if (fb != NULL) {
311                 frame->srr0 = (*fb)[FAULTBUF_LR];
312                 frame->fixreg[1] = (*fb)[FAULTBUF_R1];
313                 frame->fixreg[2] = (*fb)[FAULTBUF_R2];
314                 frame->fixreg[3] = 1;
315                 frame->cr = (*fb)[FAULTBUF_CR];
316                 frame->ctr = (*fb)[FAULTBUF_CTR];
317                 frame->xer = (*fb)[FAULTBUF_XER];
318                 bcopy(&(*fb)[FAULTBUF_R13], &frame->fixreg[13],
319                     19 * sizeof(register_t));
320                 return (1);
321         }
322         return (0);
323 }
324
325 int
326 cpu_fetch_syscall_args(struct thread *td, struct syscall_args *sa)
327 {
328         struct proc *p;
329         struct trapframe *frame;
330         caddr_t params;
331         int error, n;
332
333         p = td->td_proc;
334         frame = td->td_frame;
335
336         sa->code = frame->fixreg[0];
337         params = (caddr_t)(frame->fixreg + FIRSTARG);
338         n = NARGREG;
339
340         if (sa->code == SYS_syscall) {
341                 /*
342                  * code is first argument,
343                  * followed by actual args.
344                  */
345                 sa->code = *(u_int *) params;
346                 params += sizeof(register_t);
347                 n -= 1;
348         } else if (sa->code == SYS___syscall) {
349                 /*
350                  * Like syscall, but code is a quad,
351                  * so as to maintain quad alignment
352                  * for the rest of the args.
353                  */
354                 params += sizeof(register_t);
355                 sa->code = *(u_int *) params;
356                 params += sizeof(register_t);
357                 n -= 2;
358         }
359
360         if (p->p_sysent->sv_mask)
361                 sa->code &= p->p_sysent->sv_mask;
362         if (sa->code >= p->p_sysent->sv_size)
363                 sa->callp = &p->p_sysent->sv_table[0];
364         else
365                 sa->callp = &p->p_sysent->sv_table[sa->code];
366         sa->narg = sa->callp->sy_narg;
367
368         bcopy(params, sa->args, n * sizeof(register_t));
369         if (sa->narg > n) {
370                 error = copyin(MOREARGS(frame->fixreg[1]), sa->args + n,
371                     (sa->narg - n) * sizeof(register_t));
372         } else
373                 error = 0;
374
375         if (error == 0) {
376                 td->td_retval[0] = 0;
377                 td->td_retval[1] = frame->fixreg[FIRSTARG + 1];
378         }
379         return (error);
380 }
381
382 void
383 syscall(struct trapframe *frame)
384 {
385         struct thread *td;
386         struct syscall_args sa;
387         int error;
388
389         td = PCPU_GET(curthread);
390         td->td_frame = frame;
391
392         error = syscallenter(td, &sa);
393         syscallret(td, error, &sa);
394 }
395
396 static int
397 trap_pfault(struct trapframe *frame, int user)
398 {
399         vm_offset_t     eva, va;
400         struct          thread *td;
401         struct          proc *p;
402         vm_map_t        map;
403         vm_prot_t       ftype;
404         int             rv;
405
406         td = curthread;
407         p = td->td_proc;
408
409         if (frame->exc == EXC_ISI) {
410                 eva = frame->srr0;
411                 ftype = VM_PROT_READ | VM_PROT_EXECUTE;
412
413         } else {
414                 eva = frame->cpu.booke.dear;
415                 if (frame->cpu.booke.esr & ESR_ST)
416                         ftype = VM_PROT_WRITE;
417                 else
418                         ftype = VM_PROT_READ;
419         }
420
421         if (user) {
422                 KASSERT(p->p_vmspace != NULL, ("trap_pfault: vmspace  NULL"));
423                 map = &p->p_vmspace->vm_map;
424         } else {
425                 if (eva < VM_MAXUSER_ADDRESS) {
426
427                         if (p->p_vmspace == NULL)
428                                 return (SIGSEGV);
429
430                         map = &p->p_vmspace->vm_map;
431
432                 } else {
433                         map = kernel_map;
434                 }
435         }
436         va = trunc_page(eva);
437
438         if (map != kernel_map) {
439                 /*
440                  * Keep swapout from messing with us during this
441                  *      critical time.
442                  */
443                 PROC_LOCK(p);
444                 ++p->p_lock;
445                 PROC_UNLOCK(p);
446
447                 /* Fault in the user page: */
448                 rv = vm_fault(map, va, ftype,
449                     (ftype & VM_PROT_WRITE) ? VM_FAULT_DIRTY : VM_FAULT_NORMAL);
450
451                 PROC_LOCK(p);
452                 --p->p_lock;
453                 PROC_UNLOCK(p);
454         } else {
455                 /*
456                  * Don't have to worry about process locking or stacks in the
457                  * kernel.
458                  */
459                 rv = vm_fault(map, va, ftype, VM_FAULT_NORMAL);
460         }
461
462         if (rv == KERN_SUCCESS)
463                 return (0);
464
465         if (!user && handle_onfault(frame))
466                 return (0);
467
468         return ((rv == KERN_PROTECTION_FAILURE) ? SIGBUS : SIGSEGV);
469 }
470
471 int
472 badaddr(void *addr, size_t size)
473 {
474
475         return (badaddr_read(addr, size, NULL));
476 }
477
478 int
479 badaddr_read(void *addr, size_t size, int *rptr)
480 {
481         struct thread   *td;
482         faultbuf        env;
483         int             x;
484
485         /* Get rid of any stale machine checks that have been waiting.  */
486         __asm __volatile ("sync; isync");
487
488         td = PCPU_GET(curthread);
489
490         if (setfault(env)) {
491                 td->td_pcb->pcb_onfault = 0;
492                 __asm __volatile ("sync");
493                 return (1);
494         }
495
496         __asm __volatile ("sync");
497
498         switch (size) {
499         case 1:
500                 x = *(volatile int8_t *)addr;
501                 break;
502         case 2:
503                 x = *(volatile int16_t *)addr;
504                 break;
505         case 4:
506                 x = *(volatile int32_t *)addr;
507                 break;
508         default:
509                 panic("badaddr: invalid size (%d)", size);
510         }
511
512         /* Make sure we took the machine check, if we caused one. */
513         __asm __volatile ("sync; isync");
514
515         td->td_pcb->pcb_onfault = 0;
516         __asm __volatile ("sync");      /* To be sure. */
517
518         /* Use the value to avoid reorder. */
519         if (rptr)
520                 *rptr = x;
521
522         return (0);
523 }
524
525 /*
526  * For now, this only deals with the particular unaligned access case
527  * that gcc tends to generate.  Eventually it should handle all of the
528  * possibilities that can happen on a 32-bit PowerPC in big-endian mode.
529  */
530
531 static int
532 fix_unaligned(struct thread *td, struct trapframe *frame)
533 {
534 #if 0
535         struct thread   *fputhread;
536         int             indicator, reg;
537         double          *fpr;
538
539         indicator = EXC_ALI_OPCODE_INDICATOR(frame->dsisr);
540
541         switch (indicator) {
542         case EXC_ALI_LFD:
543         case EXC_ALI_STFD:
544                 reg = EXC_ALI_RST(frame->dsisr);
545                 fpr = &td->td_pcb->pcb_fpu.fpr[reg];
546                 fputhread = PCPU_GET(fputhread);
547                 /* Juggle the FPU to ensure that we've initialized
548                  * the FPRs, and that their current state is in
549                  * the PCB.
550                  */
551                 if (fputhread != td) {
552                         if (fputhread)
553                                 save_fpu(fputhread);
554                         enable_fpu(td);
555                 }
556                 save_fpu(td);
557
558                 if (indicator == EXC_ALI_LFD) {
559                         if (copyin((void *)frame->dar, fpr,
560                             sizeof(double)) != 0)
561                                 return -1;
562                         enable_fpu(td);
563                 } else {
564                         if (copyout(fpr, (void *)frame->dar,
565                             sizeof(double)) != 0)
566                                 return -1;
567                 }
568                 return 0;
569                 break;
570         }
571
572 #endif
573         return (-1);
574 }
575
576 #ifdef KDB
577 int db_trap_glue(struct trapframe *);
578 int
579 db_trap_glue(struct trapframe *tf)
580 {
581         if (!(tf->srr1 & PSL_PR))
582                 return (kdb_trap(tf->exc, 0, tf));
583         return (0);
584 }
585 #endif