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