The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/powerpc/aim/trap.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

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

Cache object: b68c1e7468f15bb699b05463516aa8ee


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.