]> CyberLeo.Net >> Repos - FreeBSD/releng/9.0.git/blob - sys/powerpc/aim/trap.c
Copy stable/9 to releng/9.0 as part of the FreeBSD 9.0-RELEASE release
[FreeBSD/releng/9.0.git] / sys / powerpc / aim / 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 <sys/param.h>
38 #include <sys/kdb.h>
39 #include <sys/proc.h>
40 #include <sys/ktr.h>
41 #include <sys/lock.h>
42 #include <sys/mutex.h>
43 #include <sys/pioctl.h>
44 #include <sys/ptrace.h>
45 #include <sys/reboot.h>
46 #include <sys/syscall.h>
47 #include <sys/sysent.h>
48 #include <sys/systm.h>
49 #include <sys/uio.h>
50 #include <sys/signalvar.h>
51 #include <sys/vmmeter.h>
52
53 #include <security/audit/audit.h>
54
55 #include <vm/vm.h>
56 #include <vm/pmap.h>
57 #include <vm/vm_extern.h>
58 #include <vm/vm_param.h>
59 #include <vm/vm_kern.h>
60 #include <vm/vm_map.h>
61 #include <vm/vm_page.h>
62
63 #include <machine/_inttypes.h>
64 #include <machine/altivec.h>
65 #include <machine/cpu.h>
66 #include <machine/db_machdep.h>
67 #include <machine/fpu.h>
68 #include <machine/frame.h>
69 #include <machine/pcb.h>
70 #include <machine/pmap.h>
71 #include <machine/psl.h>
72 #include <machine/trap.h>
73 #include <machine/spr.h>
74 #include <machine/sr.h>
75
76 static void     trap_fatal(struct trapframe *frame);
77 static void     printtrap(u_int vector, struct trapframe *frame, int isfatal,
78                     int user);
79 static int      trap_pfault(struct trapframe *frame, int user);
80 static int      fix_unaligned(struct thread *td, struct trapframe *frame);
81 static int      ppc_instr_emulate(struct trapframe *frame);
82 static int      handle_onfault(struct trapframe *frame);
83 static void     syscall(struct trapframe *frame);
84
85 #ifdef __powerpc64__
86 static int      handle_slb_spill(pmap_t pm, vm_offset_t addr);
87 #endif
88
89 int     setfault(faultbuf);             /* defined in locore.S */
90
91 /* Why are these not defined in a header? */
92 int     badaddr(void *, size_t);
93 int     badaddr_read(void *, size_t, int *);
94
95 struct powerpc_exception {
96         u_int   vector;
97         char    *name;
98 };
99
100 static struct powerpc_exception powerpc_exceptions[] = {
101         { 0x0100, "system reset" },
102         { 0x0200, "machine check" },
103         { 0x0300, "data storage interrupt" },
104         { 0x0380, "data segment exception" },
105         { 0x0400, "instruction storage interrupt" },
106         { 0x0480, "instruction segment exception" },
107         { 0x0500, "external interrupt" },
108         { 0x0600, "alignment" },
109         { 0x0700, "program" },
110         { 0x0800, "floating-point unavailable" },
111         { 0x0900, "decrementer" },
112         { 0x0c00, "system call" },
113         { 0x0d00, "trace" },
114         { 0x0e00, "floating-point assist" },
115         { 0x0f00, "performance monitoring" },
116         { 0x0f20, "altivec unavailable" },
117         { 0x1000, "instruction tlb miss" },
118         { 0x1100, "data load tlb miss" },
119         { 0x1200, "data store tlb miss" },
120         { 0x1300, "instruction breakpoint" },
121         { 0x1400, "system management" },
122         { 0x1600, "altivec assist" },
123         { 0x1700, "thermal management" },
124         { 0x2000, "run mode/trace" },
125         { 0x3000, NULL }
126 };
127
128 static const char *
129 trapname(u_int vector)
130 {
131         struct  powerpc_exception *pe;
132
133         for (pe = powerpc_exceptions; pe->vector != 0x3000; pe++) {
134                 if (pe->vector == vector)
135                         return (pe->name);
136         }
137
138         return ("unknown");
139 }
140
141 void
142 trap(struct trapframe *frame)
143 {
144         struct thread   *td;
145         struct proc     *p;
146         int             sig, type, user;
147         u_int           ucode;
148         ksiginfo_t      ksi;
149
150         PCPU_INC(cnt.v_trap);
151
152         td = curthread;
153         p = td->td_proc;
154
155         type = ucode = frame->exc;
156         sig = 0;
157         user = frame->srr1 & PSL_PR;
158
159         CTR3(KTR_TRAP, "trap: %s type=%s (%s)", td->td_name,
160             trapname(type), user ? "user" : "kernel");
161
162         if (user) {
163                 td->td_pticks = 0;
164                 td->td_frame = frame;
165                 if (td->td_ucred != p->p_ucred)
166                         cred_update_thread(td);
167
168                 /* User Mode Traps */
169                 switch (type) {
170                 case EXC_RUNMODETRC:
171                 case EXC_TRC:
172                         frame->srr1 &= ~PSL_SE;
173                         sig = SIGTRAP;
174                         break;
175
176 #ifdef __powerpc64__
177                 case EXC_ISE:
178                 case EXC_DSE:
179                         if (handle_slb_spill(&p->p_vmspace->vm_pmap,
180                             (type == EXC_ISE) ? frame->srr0 :
181                             frame->cpu.aim.dar) != 0)
182                                 sig = SIGSEGV;
183                         break;
184 #endif
185                 case EXC_DSI:
186                 case EXC_ISI:
187                         sig = trap_pfault(frame, 1);
188                         break;
189
190                 case EXC_SC:
191                         syscall(frame);
192                         break;
193
194                 case EXC_FPU:
195                         KASSERT((td->td_pcb->pcb_flags & PCB_FPU) != PCB_FPU,
196                             ("FPU already enabled for thread"));
197                         enable_fpu(td);
198                         break;
199
200                 case EXC_VEC:
201                         KASSERT((td->td_pcb->pcb_flags & PCB_VEC) != PCB_VEC,
202                             ("Altivec already enabled for thread"));
203                         enable_vec(td);
204                         break;
205
206                 case EXC_VECAST_G4:
207                 case EXC_VECAST_G5:
208                         /*
209                          * We get a VPU assist exception for IEEE mode
210                          * vector operations on denormalized floats.
211                          * Emulating this is a giant pain, so for now,
212                          * just switch off IEEE mode and treat them as
213                          * zero.
214                          */
215
216                         save_vec(td);
217                         td->td_pcb->pcb_vec.vscr |= ALTIVEC_VSCR_NJ;
218                         enable_vec(td);
219                         break;
220
221                 case EXC_ALI:
222                         if (fix_unaligned(td, frame) != 0)
223                                 sig = SIGBUS;
224                         else
225                                 frame->srr0 += 4;
226                         break;
227
228                 case EXC_PGM:
229                         /* Identify the trap reason */
230                         if (frame->srr1 & EXC_PGM_TRAP)
231                                 sig = SIGTRAP;
232                         else if (ppc_instr_emulate(frame) == 0)
233                                 frame->srr0 += 4;
234                         else
235                                 sig = SIGILL;
236                         break;
237
238                 default:
239                         trap_fatal(frame);
240                 }
241         } else {
242                 /* Kernel Mode Traps */
243
244                 KASSERT(cold || td->td_ucred != NULL,
245                     ("kernel trap doesn't have ucred"));
246                 switch (type) {
247                 case EXC_DSI:
248                         if (trap_pfault(frame, 0) == 0)
249                                 return;
250                         break;
251 #ifdef __powerpc64__
252                 case EXC_DSE:
253                         if ((frame->cpu.aim.dar & SEGMENT_MASK) == USER_ADDR) {
254                                 __asm __volatile ("slbmte %0, %1" ::
255                                      "r"(td->td_pcb->pcb_cpu.aim.usr_vsid),
256                                      "r"(USER_SLB_SLBE));
257                                 return;
258                         }
259
260                         /* FALLTHROUGH */
261                 case EXC_ISE:
262                         if (handle_slb_spill(kernel_pmap,
263                             (type == EXC_ISE) ? frame->srr0 :
264                             frame->cpu.aim.dar) != 0)
265                                 panic("Fault handling kernel SLB miss");
266                         return;
267 #endif
268                 case EXC_MCHK:
269                         if (handle_onfault(frame))
270                                 return;
271                         break;
272                 default:
273                         break;
274                 }
275                 trap_fatal(frame);
276         }
277
278         if (sig != 0) {
279                 if (p->p_sysent->sv_transtrap != NULL)
280                         sig = (p->p_sysent->sv_transtrap)(sig, type);
281                 ksiginfo_init_trap(&ksi);
282                 ksi.ksi_signo = sig;
283                 ksi.ksi_code = (int) ucode; /* XXX, not POSIX */
284                 /* ksi.ksi_addr = ? */
285                 ksi.ksi_trapno = type;
286                 trapsignal(td, &ksi);
287         }
288
289         userret(td, frame);
290         mtx_assert(&Giant, MA_NOTOWNED);
291 }
292
293 static void
294 trap_fatal(struct trapframe *frame)
295 {
296
297         printtrap(frame->exc, frame, 1, (frame->srr1 & PSL_PR));
298 #ifdef KDB
299         if ((debugger_on_panic || kdb_active) &&
300             kdb_trap(frame->exc, 0, frame))
301                 return;
302 #endif
303         panic("%s trap", trapname(frame->exc));
304 }
305
306 static void
307 printtrap(u_int vector, struct trapframe *frame, int isfatal, int user)
308 {
309
310         printf("\n");
311         printf("%s %s trap:\n", isfatal ? "fatal" : "handled",
312             user ? "user" : "kernel");
313         printf("\n");
314         printf("   exception       = 0x%x (%s)\n", vector >> 8,
315             trapname(vector));
316         switch (vector) {
317         case EXC_DSE:
318         case EXC_DSI:
319                 printf("   virtual address = 0x%" PRIxPTR "\n",
320                     frame->cpu.aim.dar);
321                 break;
322         case EXC_ISE:
323         case EXC_ISI:
324                 printf("   virtual address = 0x%" PRIxPTR "\n", frame->srr0);
325                 break;
326         }
327         printf("   srr0            = 0x%" PRIxPTR "\n", frame->srr0);
328         printf("   srr1            = 0x%" PRIxPTR "\n", frame->srr1);
329         printf("   lr              = 0x%" PRIxPTR "\n", frame->lr);
330         printf("   curthread       = %p\n", curthread);
331         if (curthread != NULL)
332                 printf("          pid = %d, comm = %s\n",
333                     curthread->td_proc->p_pid, curthread->td_name);
334         printf("\n");
335 }
336
337 /*
338  * Handles a fatal fault when we have onfault state to recover.  Returns
339  * non-zero if there was onfault recovery state available.
340  */
341 static int
342 handle_onfault(struct trapframe *frame)
343 {
344         struct          thread *td;
345         faultbuf        *fb;
346
347         td = curthread;
348         fb = td->td_pcb->pcb_onfault;
349         if (fb != NULL) {
350                 frame->srr0 = (*fb)[0];
351                 frame->fixreg[1] = (*fb)[1];
352                 frame->fixreg[2] = (*fb)[2];
353                 frame->fixreg[3] = 1;
354                 frame->cr = (*fb)[3];
355                 bcopy(&(*fb)[4], &frame->fixreg[13],
356                     19 * sizeof(register_t));
357                 return (1);
358         }
359         return (0);
360 }
361
362 int
363 cpu_fetch_syscall_args(struct thread *td, struct syscall_args *sa)
364 {
365         struct proc *p;
366         struct trapframe *frame;
367         caddr_t params;
368         size_t argsz;
369         int error, n, i;
370
371         p = td->td_proc;
372         frame = td->td_frame;
373
374         sa->code = frame->fixreg[0];
375         params = (caddr_t)(frame->fixreg + FIRSTARG);
376         n = NARGREG;
377
378         if (sa->code == SYS_syscall) {
379                 /*
380                  * code is first argument,
381                  * followed by actual args.
382                  */
383                 sa->code = *(register_t *) params;
384                 params += sizeof(register_t);
385                 n -= 1;
386         } else if (sa->code == SYS___syscall) {
387                 /*
388                  * Like syscall, but code is a quad,
389                  * so as to maintain quad alignment
390                  * for the rest of the args.
391                  */
392                 if (SV_PROC_FLAG(p, SV_ILP32)) {
393                         params += sizeof(register_t);
394                         sa->code = *(register_t *) params;
395                         params += sizeof(register_t);
396                         n -= 2;
397                 } else {
398                         sa->code = *(register_t *) params;
399                         params += sizeof(register_t);
400                         n -= 1;
401                 }
402         }
403
404         if (p->p_sysent->sv_mask)
405                 sa->code &= p->p_sysent->sv_mask;
406         if (sa->code >= p->p_sysent->sv_size)
407                 sa->callp = &p->p_sysent->sv_table[0];
408         else
409                 sa->callp = &p->p_sysent->sv_table[sa->code];
410
411         sa->narg = sa->callp->sy_narg;
412
413         if (SV_PROC_FLAG(p, SV_ILP32)) {
414                 argsz = sizeof(uint32_t);
415
416                 for (i = 0; i < n; i++)
417                         sa->args[i] = ((u_register_t *)(params))[i] &
418                             0xffffffff;
419         } else {
420                 argsz = sizeof(uint64_t);
421
422                 for (i = 0; i < n; i++)
423                         sa->args[i] = ((u_register_t *)(params))[i];
424         }
425
426         if (sa->narg > n)
427                 error = copyin(MOREARGS(frame->fixreg[1]), sa->args + n,
428                                (sa->narg - n) * argsz);
429         else
430                 error = 0;
431
432 #ifdef __powerpc64__
433         if (SV_PROC_FLAG(p, SV_ILP32) && sa->narg > n) {
434                 /* Expand the size of arguments copied from the stack */
435
436                 for (i = sa->narg; i >= n; i--)
437                         sa->args[i] = ((uint32_t *)(&sa->args[n]))[i-n];
438         }
439 #endif
440
441         if (error == 0) {
442                 td->td_retval[0] = 0;
443                 td->td_retval[1] = frame->fixreg[FIRSTARG + 1];
444         }
445         return (error);
446 }
447
448 #include "../../kern/subr_syscall.c"
449
450 void
451 syscall(struct trapframe *frame)
452 {
453         struct thread *td;
454         struct syscall_args sa;
455         int error;
456
457         td = curthread;
458         td->td_frame = frame;
459
460 #ifdef __powerpc64__
461         /*
462          * Speculatively restore last user SLB segment, which we know is
463          * invalid already, since we are likely to do copyin()/copyout().
464          */
465         __asm __volatile ("slbmte %0, %1; isync" ::
466             "r"(td->td_pcb->pcb_cpu.aim.usr_vsid), "r"(USER_SLB_SLBE));
467 #endif
468
469         error = syscallenter(td, &sa);
470         syscallret(td, error, &sa);
471 }
472
473 #ifdef __powerpc64__
474 static int 
475 handle_slb_spill(pmap_t pm, vm_offset_t addr)
476 {
477         struct slb *user_entry;
478         uint64_t esid;
479         int i;
480
481         esid = (uintptr_t)addr >> ADDR_SR_SHFT;
482
483         if (pm == kernel_pmap) {
484                 slb_insert_kernel((esid << SLBE_ESID_SHIFT) | SLBE_VALID,
485                     kernel_va_to_slbv(addr));
486                 return (0);
487         }
488
489         PMAP_LOCK(pm);
490         user_entry = user_va_to_slb_entry(pm, addr);
491
492         if (user_entry == NULL) {
493                 /* allocate_vsid auto-spills it */
494                 (void)allocate_user_vsid(pm, esid, 0);
495         } else {
496                 /*
497                  * Check that another CPU has not already mapped this.
498                  * XXX: Per-thread SLB caches would be better.
499                  */
500                 for (i = 0; i < pm->pm_slb_len; i++)
501                         if (pm->pm_slb[i] == user_entry)
502                                 break;
503
504                 if (i == pm->pm_slb_len)
505                         slb_insert_user(pm, user_entry);
506         }
507         PMAP_UNLOCK(pm);
508
509         return (0);
510 }
511 #endif
512
513 static int
514 trap_pfault(struct trapframe *frame, int user)
515 {
516         vm_offset_t     eva, va;
517         struct          thread *td;
518         struct          proc *p;
519         vm_map_t        map;
520         vm_prot_t       ftype;
521         int             rv;
522         register_t      user_sr;
523
524         td = curthread;
525         p = td->td_proc;
526         if (frame->exc == EXC_ISI) {
527                 eva = frame->srr0;
528                 ftype = VM_PROT_EXECUTE;
529                 if (frame->srr1 & SRR1_ISI_PFAULT)
530                         ftype |= VM_PROT_READ;
531         } else {
532                 eva = frame->cpu.aim.dar;
533                 if (frame->cpu.aim.dsisr & DSISR_STORE)
534                         ftype = VM_PROT_WRITE;
535                 else
536                         ftype = VM_PROT_READ;
537         }
538
539         if (user) {
540                 map = &p->p_vmspace->vm_map;
541         } else {
542                 if ((eva >> ADDR_SR_SHFT) == (USER_ADDR >> ADDR_SR_SHFT)) {
543                         if (p->p_vmspace == NULL)
544                                 return (SIGSEGV);
545
546                         map = &p->p_vmspace->vm_map;
547
548                         user_sr = td->td_pcb->pcb_cpu.aim.usr_segm;
549                         eva &= ADDR_PIDX | ADDR_POFF;
550                         eva |= user_sr << ADDR_SR_SHFT;
551                 } else {
552                         map = kernel_map;
553                 }
554         }
555         va = trunc_page(eva);
556
557         if (map != kernel_map) {
558                 /*
559                  * Keep swapout from messing with us during this
560                  *      critical time.
561                  */
562                 PROC_LOCK(p);
563                 ++p->p_lock;
564                 PROC_UNLOCK(p);
565
566                 /* Fault in the user page: */
567                 rv = vm_fault(map, va, ftype, VM_FAULT_NORMAL);
568
569                 PROC_LOCK(p);
570                 --p->p_lock;
571                 PROC_UNLOCK(p);
572         } else {
573                 /*
574                  * Don't have to worry about process locking or stacks in the
575                  * kernel.
576                  */
577                 rv = vm_fault(map, va, ftype, VM_FAULT_NORMAL);
578         }
579
580         if (rv == KERN_SUCCESS)
581                 return (0);
582
583         if (!user && handle_onfault(frame))
584                 return (0);
585
586         return (SIGSEGV);
587 }
588
589 int
590 badaddr(void *addr, size_t size)
591 {
592         return (badaddr_read(addr, size, NULL));
593 }
594
595 int
596 badaddr_read(void *addr, size_t size, int *rptr)
597 {
598         struct thread   *td;
599         faultbuf        env;
600         int             x;
601
602         /* Get rid of any stale machine checks that have been waiting.  */
603         __asm __volatile ("sync; isync");
604
605         td = curthread;
606
607         if (setfault(env)) {
608                 td->td_pcb->pcb_onfault = 0;
609                 __asm __volatile ("sync");
610                 return 1;
611         }
612
613         __asm __volatile ("sync");
614
615         switch (size) {
616         case 1:
617                 x = *(volatile int8_t *)addr;
618                 break;
619         case 2:
620                 x = *(volatile int16_t *)addr;
621                 break;
622         case 4:
623                 x = *(volatile int32_t *)addr;
624                 break;
625         default:
626                 panic("badaddr: invalid size (%zd)", size);
627         }
628
629         /* Make sure we took the machine check, if we caused one. */
630         __asm __volatile ("sync; isync");
631
632         td->td_pcb->pcb_onfault = 0;
633         __asm __volatile ("sync");      /* To be sure. */
634
635         /* Use the value to avoid reorder. */
636         if (rptr)
637                 *rptr = x;
638
639         return (0);
640 }
641
642 /*
643  * For now, this only deals with the particular unaligned access case
644  * that gcc tends to generate.  Eventually it should handle all of the
645  * possibilities that can happen on a 32-bit PowerPC in big-endian mode.
646  */
647
648 static int
649 fix_unaligned(struct thread *td, struct trapframe *frame)
650 {
651         struct thread   *fputhread;
652         int             indicator, reg;
653         double          *fpr;
654
655         indicator = EXC_ALI_OPCODE_INDICATOR(frame->cpu.aim.dsisr);
656
657         switch (indicator) {
658         case EXC_ALI_LFD:
659         case EXC_ALI_STFD:
660                 reg = EXC_ALI_RST(frame->cpu.aim.dsisr);
661                 fpr = &td->td_pcb->pcb_fpu.fpr[reg];
662                 fputhread = PCPU_GET(fputhread);
663
664                 /* Juggle the FPU to ensure that we've initialized
665                  * the FPRs, and that their current state is in
666                  * the PCB.
667                  */
668                 if (fputhread != td) {
669                         if (fputhread)
670                                 save_fpu(fputhread);
671                         enable_fpu(td);
672                 }
673                 save_fpu(td);
674
675                 if (indicator == EXC_ALI_LFD) {
676                         if (copyin((void *)frame->cpu.aim.dar, fpr,
677                             sizeof(double)) != 0)
678                                 return -1;
679                         enable_fpu(td);
680                 } else {
681                         if (copyout(fpr, (void *)frame->cpu.aim.dar,
682                             sizeof(double)) != 0)
683                                 return -1;
684                 }
685                 return 0;
686                 break;
687         }
688
689         return -1;
690 }
691
692 static int
693 ppc_instr_emulate(struct trapframe *frame)
694 {
695         uint32_t instr;
696         int reg;
697
698         instr = fuword32((void *)frame->srr0);
699
700         if ((instr & 0xfc1fffff) == 0x7c1f42a6) {       /* mfpvr */
701                 reg = (instr & ~0xfc1fffff) >> 21;
702                 frame->fixreg[reg] = mfpvr();
703                 return (0);
704         }
705
706         return (-1);
707 }
708