]> CyberLeo.Net >> Repos - FreeBSD/stable/8.git/blob - sys/powerpc/booke/trap.c
MFC r362623:
[FreeBSD/stable/8.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 #include "../../kern/subr_syscall.c"
383
384 void
385 syscall(struct trapframe *frame)
386 {
387         struct thread *td;
388         struct syscall_args sa;
389         int error;
390
391         td = PCPU_GET(curthread);
392         td->td_frame = frame;
393
394         error = syscallenter(td, &sa);
395         syscallret(td, error, &sa);
396 }
397
398 static int
399 trap_pfault(struct trapframe *frame, int user)
400 {
401         vm_offset_t     eva, va;
402         struct          thread *td;
403         struct          proc *p;
404         vm_map_t        map;
405         vm_prot_t       ftype;
406         int             rv;
407
408         td = curthread;
409         p = td->td_proc;
410
411         if (frame->exc == EXC_ISI) {
412                 eva = frame->srr0;
413                 ftype = VM_PROT_READ | VM_PROT_EXECUTE;
414
415         } else {
416                 eva = frame->cpu.booke.dear;
417                 if (frame->cpu.booke.esr & ESR_ST)
418                         ftype = VM_PROT_WRITE;
419                 else
420                         ftype = VM_PROT_READ;
421         }
422
423         if (user) {
424                 KASSERT(p->p_vmspace != NULL, ("trap_pfault: vmspace  NULL"));
425                 map = &p->p_vmspace->vm_map;
426         } else {
427                 if (eva < VM_MAXUSER_ADDRESS) {
428
429                         if (p->p_vmspace == NULL)
430                                 return (SIGSEGV);
431
432                         map = &p->p_vmspace->vm_map;
433
434                 } else {
435                         map = kernel_map;
436                 }
437         }
438         va = trunc_page(eva);
439
440         if (map != kernel_map) {
441                 /*
442                  * Keep swapout from messing with us during this
443                  *      critical time.
444                  */
445                 PROC_LOCK(p);
446                 ++p->p_lock;
447                 PROC_UNLOCK(p);
448
449                 /* Fault in the user page: */
450                 rv = vm_fault(map, va, ftype,
451                     (ftype & VM_PROT_WRITE) ? VM_FAULT_DIRTY : VM_FAULT_NORMAL);
452
453                 PROC_LOCK(p);
454                 --p->p_lock;
455                 PROC_UNLOCK(p);
456         } else {
457                 /*
458                  * Don't have to worry about process locking or stacks in the
459                  * kernel.
460                  */
461                 rv = vm_fault(map, va, ftype, VM_FAULT_NORMAL);
462         }
463
464         if (rv == KERN_SUCCESS)
465                 return (0);
466
467         if (!user && handle_onfault(frame))
468                 return (0);
469
470         return ((rv == KERN_PROTECTION_FAILURE) ? SIGBUS : SIGSEGV);
471 }
472
473 int
474 badaddr(void *addr, size_t size)
475 {
476
477         return (badaddr_read(addr, size, NULL));
478 }
479
480 int
481 badaddr_read(void *addr, size_t size, int *rptr)
482 {
483         struct thread   *td;
484         faultbuf        env;
485         int             x;
486
487         /* Get rid of any stale machine checks that have been waiting.  */
488         __asm __volatile ("sync; isync");
489
490         td = PCPU_GET(curthread);
491
492         if (setfault(env)) {
493                 td->td_pcb->pcb_onfault = 0;
494                 __asm __volatile ("sync");
495                 return (1);
496         }
497
498         __asm __volatile ("sync");
499
500         switch (size) {
501         case 1:
502                 x = *(volatile int8_t *)addr;
503                 break;
504         case 2:
505                 x = *(volatile int16_t *)addr;
506                 break;
507         case 4:
508                 x = *(volatile int32_t *)addr;
509                 break;
510         default:
511                 panic("badaddr: invalid size (%d)", size);
512         }
513
514         /* Make sure we took the machine check, if we caused one. */
515         __asm __volatile ("sync; isync");
516
517         td->td_pcb->pcb_onfault = 0;
518         __asm __volatile ("sync");      /* To be sure. */
519
520         /* Use the value to avoid reorder. */
521         if (rptr)
522                 *rptr = x;
523
524         return (0);
525 }
526
527 /*
528  * For now, this only deals with the particular unaligned access case
529  * that gcc tends to generate.  Eventually it should handle all of the
530  * possibilities that can happen on a 32-bit PowerPC in big-endian mode.
531  */
532
533 static int
534 fix_unaligned(struct thread *td, struct trapframe *frame)
535 {
536 #if 0
537         struct thread   *fputhread;
538         int             indicator, reg;
539         double          *fpr;
540
541         indicator = EXC_ALI_OPCODE_INDICATOR(frame->dsisr);
542
543         switch (indicator) {
544         case EXC_ALI_LFD:
545         case EXC_ALI_STFD:
546                 reg = EXC_ALI_RST(frame->dsisr);
547                 fpr = &td->td_pcb->pcb_fpu.fpr[reg];
548                 fputhread = PCPU_GET(fputhread);
549                 /* Juggle the FPU to ensure that we've initialized
550                  * the FPRs, and that their current state is in
551                  * the PCB.
552                  */
553                 if (fputhread != td) {
554                         if (fputhread)
555                                 save_fpu(fputhread);
556                         enable_fpu(td);
557                 }
558                 save_fpu(td);
559
560                 if (indicator == EXC_ALI_LFD) {
561                         if (copyin((void *)frame->dar, fpr,
562                             sizeof(double)) != 0)
563                                 return -1;
564                         enable_fpu(td);
565                 } else {
566                         if (copyout(fpr, (void *)frame->dar,
567                             sizeof(double)) != 0)
568                                 return -1;
569                 }
570                 return 0;
571                 break;
572         }
573
574 #endif
575         return (-1);
576 }
577
578 #ifdef KDB
579 int db_trap_glue(struct trapframe *);
580 int
581 db_trap_glue(struct trapframe *tf)
582 {
583         if (!(tf->srr1 & PSL_PR))
584                 return (kdb_trap(tf->exc, 0, tf));
585         return (0);
586 }
587 #endif