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/powerpc/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: releng/11.0/sys/powerpc/powerpc/trap.c 298560 2016-04-25 03:01:57Z jhibbits $");
   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/kernel.h>
   50 #include <sys/uio.h>
   51 #include <sys/signalvar.h>
   52 #include <sys/vmmeter.h>
   53 
   54 #include <security/audit/audit.h>
   55 
   56 #include <vm/vm.h>
   57 #include <vm/pmap.h>
   58 #include <vm/vm_extern.h>
   59 #include <vm/vm_param.h>
   60 #include <vm/vm_kern.h>
   61 #include <vm/vm_map.h>
   62 #include <vm/vm_page.h>
   63 
   64 #include <machine/_inttypes.h>
   65 #include <machine/altivec.h>
   66 #include <machine/cpu.h>
   67 #include <machine/db_machdep.h>
   68 #include <machine/fpu.h>
   69 #include <machine/frame.h>
   70 #include <machine/pcb.h>
   71 #include <machine/psl.h>
   72 #include <machine/trap.h>
   73 #include <machine/spr.h>
   74 #include <machine/sr.h>
   75 
   76 /* Below matches setjmp.S */
   77 #define FAULTBUF_LR     21
   78 #define FAULTBUF_R1     1
   79 #define FAULTBUF_R2     2
   80 #define FAULTBUF_CR     22
   81 #define FAULTBUF_R14    3
   82 
   83 static void     trap_fatal(struct trapframe *frame);
   84 static void     printtrap(u_int vector, struct trapframe *frame, int isfatal,
   85                     int user);
   86 static int      trap_pfault(struct trapframe *frame, int user);
   87 static int      fix_unaligned(struct thread *td, 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 struct powerpc_exception {
   98         u_int   vector;
   99         char    *name;
  100 };
  101 
  102 #ifdef KDTRACE_HOOKS
  103 #include <sys/dtrace_bsd.h>
  104 
  105 int (*dtrace_invop_jump_addr)(struct trapframe *);
  106 #endif
  107 
  108 static struct powerpc_exception powerpc_exceptions[] = {
  109         { EXC_CRIT,     "critical input" },
  110         { EXC_RST,      "system reset" },
  111         { EXC_MCHK,     "machine check" },
  112         { EXC_DSI,      "data storage interrupt" },
  113         { EXC_DSE,      "data segment exception" },
  114         { EXC_ISI,      "instruction storage interrupt" },
  115         { EXC_ISE,      "instruction segment exception" },
  116         { EXC_EXI,      "external interrupt" },
  117         { EXC_ALI,      "alignment" },
  118         { EXC_PGM,      "program" },
  119         { EXC_FPU,      "floating-point unavailable" },
  120         { EXC_APU,      "auxiliary proc unavailable" },
  121         { EXC_DECR,     "decrementer" },
  122         { EXC_FIT,      "fixed-interval timer" },
  123         { EXC_WDOG,     "watchdog timer" },
  124         { EXC_SC,       "system call" },
  125         { EXC_TRC,      "trace" },
  126         { EXC_FPA,      "floating-point assist" },
  127         { EXC_DEBUG,    "debug" },
  128         { EXC_PERF,     "performance monitoring" },
  129         { EXC_VEC,      "altivec unavailable" },
  130         { EXC_VSX,      "vsx unavailable" },
  131         { EXC_ITMISS,   "instruction tlb miss" },
  132         { EXC_DLMISS,   "data load tlb miss" },
  133         { EXC_DSMISS,   "data store tlb miss" },
  134         { EXC_BPT,      "instruction breakpoint" },
  135         { EXC_SMI,      "system management" },
  136         { EXC_VECAST_G4,        "altivec assist" },
  137         { EXC_THRM,     "thermal management" },
  138         { EXC_RUNMODETRC,       "run mode/trace" },
  139         { EXC_LAST,     NULL }
  140 };
  141 
  142 static const char *
  143 trapname(u_int vector)
  144 {
  145         struct  powerpc_exception *pe;
  146 
  147         for (pe = powerpc_exceptions; pe->vector != EXC_LAST; pe++) {
  148                 if (pe->vector == vector)
  149                         return (pe->name);
  150         }
  151 
  152         return ("unknown");
  153 }
  154 
  155 void
  156 trap(struct trapframe *frame)
  157 {
  158         struct thread   *td;
  159         struct proc     *p;
  160 #ifdef KDTRACE_HOOKS
  161         uint32_t inst;
  162 #endif
  163         int             sig, type, user;
  164         u_int           ucode;
  165         ksiginfo_t      ksi;
  166 
  167         PCPU_INC(cnt.v_trap);
  168 
  169         td = curthread;
  170         p = td->td_proc;
  171 
  172         type = ucode = frame->exc;
  173         sig = 0;
  174         user = frame->srr1 & PSL_PR;
  175 
  176         CTR3(KTR_TRAP, "trap: %s type=%s (%s)", td->td_name,
  177             trapname(type), user ? "user" : "kernel");
  178 
  179 #ifdef KDTRACE_HOOKS
  180         /*
  181          * A trap can occur while DTrace executes a probe. Before
  182          * executing the probe, DTrace blocks re-scheduling and sets
  183          * a flag in its per-cpu flags to indicate that it doesn't
  184          * want to fault. On returning from the probe, the no-fault
  185          * flag is cleared and finally re-scheduling is enabled.
  186          *
  187          * If the DTrace kernel module has registered a trap handler,
  188          * call it and if it returns non-zero, assume that it has
  189          * handled the trap and modified the trap frame so that this
  190          * function can return normally.
  191          */
  192         if (dtrace_trap_func != NULL && (*dtrace_trap_func)(frame, type) != 0)
  193                 return;
  194 #endif
  195 
  196         if (user) {
  197                 td->td_pticks = 0;
  198                 td->td_frame = frame;
  199                 if (td->td_cowgen != p->p_cowgen)
  200                         thread_cow_update(td);
  201 
  202                 /* User Mode Traps */
  203                 switch (type) {
  204                 case EXC_RUNMODETRC:
  205                 case EXC_TRC:
  206                         frame->srr1 &= ~PSL_SE;
  207                         sig = SIGTRAP;
  208                         ucode = TRAP_TRACE;
  209                         break;
  210 
  211 #ifdef __powerpc64__
  212                 case EXC_ISE:
  213                 case EXC_DSE:
  214                         if (handle_user_slb_spill(&p->p_vmspace->vm_pmap,
  215                             (type == EXC_ISE) ? frame->srr0 : frame->dar) != 0){
  216                                 sig = SIGSEGV;
  217                                 ucode = SEGV_MAPERR;
  218                         }
  219                         break;
  220 #endif
  221                 case EXC_DSI:
  222                 case EXC_ISI:
  223                         sig = trap_pfault(frame, 1);
  224                         if (sig == SIGSEGV)
  225                                 ucode = SEGV_MAPERR;
  226                         break;
  227 
  228                 case EXC_SC:
  229                         syscall(frame);
  230                         break;
  231 
  232                 case EXC_FPU:
  233                         KASSERT((td->td_pcb->pcb_flags & PCB_FPU) != PCB_FPU,
  234                             ("FPU already enabled for thread"));
  235                         enable_fpu(td);
  236                         break;
  237 
  238                 case EXC_VEC:
  239                         KASSERT((td->td_pcb->pcb_flags & PCB_VEC) != PCB_VEC,
  240                             ("Altivec already enabled for thread"));
  241                         enable_vec(td);
  242                         break;
  243 
  244                 case EXC_VSX:
  245                         KASSERT((td->td_pcb->pcb_flags & PCB_VSX) != PCB_VSX,
  246                             ("VSX already enabled for thread"));
  247                         if (!(td->td_pcb->pcb_flags & PCB_VEC))
  248                                 enable_vec(td);
  249                         if (!(td->td_pcb->pcb_flags & PCB_FPU))
  250                                 save_fpu(td);
  251                         td->td_pcb->pcb_flags |= PCB_VSX;
  252                         enable_fpu(td);
  253                         break;
  254 
  255                 case EXC_VECAST_E:
  256                 case EXC_VECAST_G4:
  257                 case EXC_VECAST_G5:
  258                         /*
  259                          * We get a VPU assist exception for IEEE mode
  260                          * vector operations on denormalized floats.
  261                          * Emulating this is a giant pain, so for now,
  262                          * just switch off IEEE mode and treat them as
  263                          * zero.
  264                          */
  265 
  266                         save_vec(td);
  267                         td->td_pcb->pcb_vec.vscr |= ALTIVEC_VSCR_NJ;
  268                         enable_vec(td);
  269                         break;
  270 
  271                 case EXC_ALI:
  272                         if (fix_unaligned(td, frame) != 0) {
  273                                 sig = SIGBUS;
  274                                 ucode = BUS_ADRALN;
  275                         }
  276                         else
  277                                 frame->srr0 += 4;
  278                         break;
  279 
  280                 case EXC_DEBUG: /* Single stepping */
  281                         mtspr(SPR_DBSR, mfspr(SPR_DBSR));
  282                         frame->srr1 &= ~PSL_DE;
  283                         frame->cpu.booke.dbcr0 &= ~(DBCR0_IDM || DBCR0_IC);
  284                         sig = SIGTRAP;
  285                         ucode = TRAP_TRACE;
  286                         break;
  287 
  288                 case EXC_PGM:
  289                         /* Identify the trap reason */
  290 #ifdef AIM
  291                         if (frame->srr1 & EXC_PGM_TRAP) {
  292 #else
  293                         if (frame->cpu.booke.esr & ESR_PTR) {
  294 #endif
  295 #ifdef KDTRACE_HOOKS
  296                                 inst = fuword32((const void *)frame->srr0);
  297                                 if (inst == 0x0FFFDDDD &&
  298                                     dtrace_pid_probe_ptr != NULL) {
  299                                         struct reg regs;
  300                                         fill_regs(td, &regs);
  301                                         (*dtrace_pid_probe_ptr)(&regs);
  302                                         break;
  303                                 }
  304 #endif
  305                                 sig = SIGTRAP;
  306                                 ucode = TRAP_BRKPT;
  307                         } else {
  308                                 sig = ppc_instr_emulate(frame, td->td_pcb);
  309                                 if (sig == SIGILL) {
  310                                         if (frame->srr1 & EXC_PGM_PRIV)
  311                                                 ucode = ILL_PRVOPC;
  312                                         else if (frame->srr1 & EXC_PGM_ILLEGAL)
  313                                                 ucode = ILL_ILLOPC;
  314                                 } else if (sig == SIGFPE)
  315                                         ucode = FPE_FLTINV;     /* Punt for now, invalid operation. */
  316                         }
  317                         break;
  318 
  319                 case EXC_MCHK:
  320                         /*
  321                          * Note that this may not be recoverable for the user
  322                          * process, depending on the type of machine check,
  323                          * but it at least prevents the kernel from dying.
  324                          */
  325                         sig = SIGBUS;
  326                         ucode = BUS_OBJERR;
  327                         break;
  328 
  329                 default:
  330                         trap_fatal(frame);
  331                 }
  332         } else {
  333                 /* Kernel Mode Traps */
  334 
  335                 KASSERT(cold || td->td_ucred != NULL,
  336                     ("kernel trap doesn't have ucred"));
  337                 switch (type) {
  338 #ifdef KDTRACE_HOOKS
  339                 case EXC_PGM:
  340                         if (frame->srr1 & EXC_PGM_TRAP) {
  341                                 if (*(uint32_t *)frame->srr0 == EXC_DTRACE) {
  342                                         if (dtrace_invop_jump_addr != NULL) {
  343                                                 dtrace_invop_jump_addr(frame);
  344                                                 return;
  345                                         }
  346                                 }
  347                         }
  348                         break;
  349 #endif
  350 #ifdef __powerpc64__
  351                 case EXC_DSE:
  352                         if ((frame->dar & SEGMENT_MASK) == USER_ADDR) {
  353                                 __asm __volatile ("slbmte %0, %1" ::
  354                                         "r"(td->td_pcb->pcb_cpu.aim.usr_vsid),
  355                                         "r"(USER_SLB_SLBE));
  356                                 return;
  357                         }
  358                         break;
  359 #endif
  360                 case EXC_DSI:
  361                         if (trap_pfault(frame, 0) == 0)
  362                                 return;
  363                         break;
  364                 case EXC_MCHK:
  365                         if (handle_onfault(frame))
  366                                 return;
  367                         break;
  368                 default:
  369                         break;
  370                 }
  371                 trap_fatal(frame);
  372         }
  373 
  374         if (sig != 0) {
  375                 if (p->p_sysent->sv_transtrap != NULL)
  376                         sig = (p->p_sysent->sv_transtrap)(sig, type);
  377                 ksiginfo_init_trap(&ksi);
  378                 ksi.ksi_signo = sig;
  379                 ksi.ksi_code = (int) ucode; /* XXX, not POSIX */
  380                 /* ksi.ksi_addr = ? */
  381                 ksi.ksi_trapno = type;
  382                 trapsignal(td, &ksi);
  383         }
  384 
  385         userret(td, frame);
  386 }
  387 
  388 static void
  389 trap_fatal(struct trapframe *frame)
  390 {
  391 
  392         printtrap(frame->exc, frame, 1, (frame->srr1 & PSL_PR));
  393 #ifdef KDB
  394         if ((debugger_on_panic || kdb_active) &&
  395             kdb_trap(frame->exc, 0, frame))
  396                 return;
  397 #endif
  398         panic("%s trap", trapname(frame->exc));
  399 }
  400 
  401 static void
  402 printtrap(u_int vector, struct trapframe *frame, int isfatal, int user)
  403 {
  404         uint16_t ver;
  405 #ifdef BOOKE
  406         vm_paddr_t pa;
  407 #endif
  408 
  409         printf("\n");
  410         printf("%s %s trap:\n", isfatal ? "fatal" : "handled",
  411             user ? "user" : "kernel");
  412         printf("\n");
  413         printf("   exception       = 0x%x (%s)\n", vector, trapname(vector));
  414         switch (vector) {
  415         case EXC_DSE:
  416         case EXC_DSI:
  417         case EXC_DTMISS:
  418                 printf("   virtual address = 0x%" PRIxPTR "\n", frame->dar);
  419 #ifdef AIM
  420                 printf("   dsisr           = 0x%lx\n",
  421                     (u_long)frame->cpu.aim.dsisr);
  422 #endif
  423                 break;
  424         case EXC_ISE:
  425         case EXC_ISI:
  426         case EXC_ITMISS:
  427                 printf("   virtual address = 0x%" PRIxPTR "\n", frame->srr0);
  428                 break;
  429         case EXC_MCHK:
  430                 ver = mfpvr() >> 16;
  431 #if defined(AIM)
  432                 if (MPC745X_P(ver))
  433                         printf("    msssr0         = 0x%lx\n",
  434                             (u_long)mfspr(SPR_MSSSR0));
  435 #elif defined(BOOKE)
  436                 pa = mfspr(SPR_MCARU);
  437                 pa = (pa << 32) | (u_register_t)mfspr(SPR_MCAR);
  438                 printf("   mcsr            = 0x%lx\n", (u_long)mfspr(SPR_MCSR));
  439                 printf("   mcar            = 0x%jx\n", (uintmax_t)pa);
  440 #endif
  441                 break;
  442         }
  443 #ifdef BOOKE
  444         printf("   esr             = 0x%" PRIxPTR "\n",
  445             frame->cpu.booke.esr);
  446 #endif
  447         printf("   srr0            = 0x%" PRIxPTR "\n", frame->srr0);
  448         printf("   srr1            = 0x%lx\n", (u_long)frame->srr1);
  449         printf("   lr              = 0x%" PRIxPTR "\n", frame->lr);
  450         printf("   curthread       = %p\n", curthread);
  451         if (curthread != NULL)
  452                 printf("          pid = %d, comm = %s\n",
  453                     curthread->td_proc->p_pid, curthread->td_name);
  454         printf("\n");
  455 }
  456 
  457 /*
  458  * Handles a fatal fault when we have onfault state to recover.  Returns
  459  * non-zero if there was onfault recovery state available.
  460  */
  461 static int
  462 handle_onfault(struct trapframe *frame)
  463 {
  464         struct          thread *td;
  465         jmp_buf         *fb;
  466 
  467         td = curthread;
  468         fb = td->td_pcb->pcb_onfault;
  469         if (fb != NULL) {
  470                 frame->srr0 = (*fb)->_jb[FAULTBUF_LR];
  471                 frame->fixreg[1] = (*fb)->_jb[FAULTBUF_R1];
  472                 frame->fixreg[2] = (*fb)->_jb[FAULTBUF_R2];
  473                 frame->fixreg[3] = 1;
  474                 frame->cr = (*fb)->_jb[FAULTBUF_CR];
  475                 bcopy(&(*fb)->_jb[FAULTBUF_R14], &frame->fixreg[14],
  476                     18 * sizeof(register_t));
  477                 td->td_pcb->pcb_onfault = NULL; /* Returns twice, not thrice */
  478                 return (1);
  479         }
  480         return (0);
  481 }
  482 
  483 int
  484 cpu_fetch_syscall_args(struct thread *td, struct syscall_args *sa)
  485 {
  486         struct proc *p;
  487         struct trapframe *frame;
  488         caddr_t params;
  489         size_t argsz;
  490         int error, n, i;
  491 
  492         p = td->td_proc;
  493         frame = td->td_frame;
  494 
  495         sa->code = frame->fixreg[0];
  496         params = (caddr_t)(frame->fixreg + FIRSTARG);
  497         n = NARGREG;
  498 
  499         if (sa->code == SYS_syscall) {
  500                 /*
  501                  * code is first argument,
  502                  * followed by actual args.
  503                  */
  504                 sa->code = *(register_t *) params;
  505                 params += sizeof(register_t);
  506                 n -= 1;
  507         } else if (sa->code == SYS___syscall) {
  508                 /*
  509                  * Like syscall, but code is a quad,
  510                  * so as to maintain quad alignment
  511                  * for the rest of the args.
  512                  */
  513                 if (SV_PROC_FLAG(p, SV_ILP32)) {
  514                         params += sizeof(register_t);
  515                         sa->code = *(register_t *) params;
  516                         params += sizeof(register_t);
  517                         n -= 2;
  518                 } else {
  519                         sa->code = *(register_t *) params;
  520                         params += sizeof(register_t);
  521                         n -= 1;
  522                 }
  523         }
  524 
  525         if (p->p_sysent->sv_mask)
  526                 sa->code &= p->p_sysent->sv_mask;
  527         if (sa->code >= p->p_sysent->sv_size)
  528                 sa->callp = &p->p_sysent->sv_table[0];
  529         else
  530                 sa->callp = &p->p_sysent->sv_table[sa->code];
  531 
  532         sa->narg = sa->callp->sy_narg;
  533 
  534         if (SV_PROC_FLAG(p, SV_ILP32)) {
  535                 argsz = sizeof(uint32_t);
  536 
  537                 for (i = 0; i < n; i++)
  538                         sa->args[i] = ((u_register_t *)(params))[i] &
  539                             0xffffffff;
  540         } else {
  541                 argsz = sizeof(uint64_t);
  542 
  543                 for (i = 0; i < n; i++)
  544                         sa->args[i] = ((u_register_t *)(params))[i];
  545         }
  546 
  547         if (sa->narg > n)
  548                 error = copyin(MOREARGS(frame->fixreg[1]), sa->args + n,
  549                                (sa->narg - n) * argsz);
  550         else
  551                 error = 0;
  552 
  553 #ifdef __powerpc64__
  554         if (SV_PROC_FLAG(p, SV_ILP32) && sa->narg > n) {
  555                 /* Expand the size of arguments copied from the stack */
  556 
  557                 for (i = sa->narg; i >= n; i--)
  558                         sa->args[i] = ((uint32_t *)(&sa->args[n]))[i-n];
  559         }
  560 #endif
  561 
  562         if (error == 0) {
  563                 td->td_retval[0] = 0;
  564                 td->td_retval[1] = frame->fixreg[FIRSTARG + 1];
  565         }
  566         return (error);
  567 }
  568 
  569 #include "../../kern/subr_syscall.c"
  570 
  571 void
  572 syscall(struct trapframe *frame)
  573 {
  574         struct thread *td;
  575         struct syscall_args sa;
  576         int error;
  577 
  578         td = curthread;
  579         td->td_frame = frame;
  580 
  581 #ifdef __powerpc64__
  582         /*
  583          * Speculatively restore last user SLB segment, which we know is
  584          * invalid already, since we are likely to do copyin()/copyout().
  585          */
  586         __asm __volatile ("slbmte %0, %1; isync" ::
  587             "r"(td->td_pcb->pcb_cpu.aim.usr_vsid), "r"(USER_SLB_SLBE));
  588 #endif
  589 
  590         error = syscallenter(td, &sa);
  591         syscallret(td, error, &sa);
  592 }
  593 
  594 #ifdef __powerpc64__
  595 /* Handle kernel SLB faults -- runs in real mode, all seat belts off */
  596 void
  597 handle_kernel_slb_spill(int type, register_t dar, register_t srr0)
  598 {
  599         struct slb *slbcache;
  600         uint64_t slbe, slbv;
  601         uint64_t esid, addr;
  602         int i;
  603 
  604         addr = (type == EXC_ISE) ? srr0 : dar;
  605         slbcache = PCPU_GET(slb);
  606         esid = (uintptr_t)addr >> ADDR_SR_SHFT;
  607         slbe = (esid << SLBE_ESID_SHIFT) | SLBE_VALID;
  608         
  609         /* See if the hardware flushed this somehow (can happen in LPARs) */
  610         for (i = 0; i < n_slbs; i++)
  611                 if (slbcache[i].slbe == (slbe | (uint64_t)i))
  612                         return;
  613 
  614         /* Not in the map, needs to actually be added */
  615         slbv = kernel_va_to_slbv(addr);
  616         if (slbcache[USER_SLB_SLOT].slbe == 0) {
  617                 for (i = 0; i < n_slbs; i++) {
  618                         if (i == USER_SLB_SLOT)
  619                                 continue;
  620                         if (!(slbcache[i].slbe & SLBE_VALID))
  621                                 goto fillkernslb;
  622                 }
  623 
  624                 if (i == n_slbs)
  625                         slbcache[USER_SLB_SLOT].slbe = 1;
  626         }
  627 
  628         /* Sacrifice a random SLB entry that is not the user entry */
  629         i = mftb() % n_slbs;
  630         if (i == USER_SLB_SLOT)
  631                 i = (i+1) % n_slbs;
  632 
  633 fillkernslb:
  634         /* Write new entry */
  635         slbcache[i].slbv = slbv;
  636         slbcache[i].slbe = slbe | (uint64_t)i;
  637 
  638         /* Trap handler will restore from cache on exit */
  639 }
  640 
  641 static int 
  642 handle_user_slb_spill(pmap_t pm, vm_offset_t addr)
  643 {
  644         struct slb *user_entry;
  645         uint64_t esid;
  646         int i;
  647 
  648         esid = (uintptr_t)addr >> ADDR_SR_SHFT;
  649 
  650         PMAP_LOCK(pm);
  651         user_entry = user_va_to_slb_entry(pm, addr);
  652 
  653         if (user_entry == NULL) {
  654                 /* allocate_vsid auto-spills it */
  655                 (void)allocate_user_vsid(pm, esid, 0);
  656         } else {
  657                 /*
  658                  * Check that another CPU has not already mapped this.
  659                  * XXX: Per-thread SLB caches would be better.
  660                  */
  661                 for (i = 0; i < pm->pm_slb_len; i++)
  662                         if (pm->pm_slb[i] == user_entry)
  663                                 break;
  664 
  665                 if (i == pm->pm_slb_len)
  666                         slb_insert_user(pm, user_entry);
  667         }
  668         PMAP_UNLOCK(pm);
  669 
  670         return (0);
  671 }
  672 #endif
  673 
  674 static int
  675 trap_pfault(struct trapframe *frame, int user)
  676 {
  677         vm_offset_t     eva, va;
  678         struct          thread *td;
  679         struct          proc *p;
  680         vm_map_t        map;
  681         vm_prot_t       ftype;
  682         int             rv;
  683 #ifdef AIM
  684         register_t      user_sr;
  685 #endif
  686 
  687         td = curthread;
  688         p = td->td_proc;
  689         if (frame->exc == EXC_ISI) {
  690                 eva = frame->srr0;
  691                 ftype = VM_PROT_EXECUTE;
  692                 if (frame->srr1 & SRR1_ISI_PFAULT)
  693                         ftype |= VM_PROT_READ;
  694         } else {
  695                 eva = frame->dar;
  696 #ifdef BOOKE
  697                 if (frame->cpu.booke.esr & ESR_ST)
  698 #else
  699                 if (frame->cpu.aim.dsisr & DSISR_STORE)
  700 #endif
  701                         ftype = VM_PROT_WRITE;
  702                 else
  703                         ftype = VM_PROT_READ;
  704         }
  705 
  706         if (user) {
  707                 KASSERT(p->p_vmspace != NULL, ("trap_pfault: vmspace  NULL"));
  708                 map = &p->p_vmspace->vm_map;
  709         } else {
  710 #ifdef BOOKE
  711                 if (eva < VM_MAXUSER_ADDRESS) {
  712 #else
  713                 if ((eva >> ADDR_SR_SHFT) == (USER_ADDR >> ADDR_SR_SHFT)) {
  714 #endif
  715                         map = &p->p_vmspace->vm_map;
  716 
  717 #ifdef AIM
  718                         user_sr = td->td_pcb->pcb_cpu.aim.usr_segm;
  719                         eva &= ADDR_PIDX | ADDR_POFF;
  720                         eva |= user_sr << ADDR_SR_SHFT;
  721 #endif
  722                 } else {
  723                         map = kernel_map;
  724                 }
  725         }
  726         va = trunc_page(eva);
  727 
  728         /* Fault in the page. */
  729         rv = vm_fault(map, va, ftype, VM_FAULT_NORMAL);
  730         /*
  731          * XXXDTRACE: add dtrace_doubletrap_func here?
  732          */
  733 
  734         if (rv == KERN_SUCCESS)
  735                 return (0);
  736 
  737         if (!user && handle_onfault(frame))
  738                 return (0);
  739 
  740         return (SIGSEGV);
  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].fpr;
  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->dar, fpr,
  778                             sizeof(double)) != 0)
  779                                 return (-1);
  780                         enable_fpu(td);
  781                 } else {
  782                         if (copyout(fpr, (void *)frame->dar,
  783                             sizeof(double)) != 0)
  784                                 return (-1);
  785                 }
  786                 return (0);
  787                 break;
  788         }
  789 
  790         return (-1);
  791 }
  792 
  793 #ifdef KDB
  794 int db_trap_glue(struct trapframe *);           /* Called from trap_subr.S */
  795 
  796 int
  797 db_trap_glue(struct trapframe *frame)
  798 {
  799         if (!(frame->srr1 & PSL_PR)
  800             && (frame->exc == EXC_TRC || frame->exc == EXC_RUNMODETRC
  801 #ifdef AIM
  802                 || (frame->exc == EXC_PGM
  803                     && (frame->srr1 & EXC_PGM_TRAP))
  804 #else
  805                 || (frame->exc == EXC_DEBUG)
  806 #endif
  807                 || frame->exc == EXC_BPT
  808                 || frame->exc == EXC_DSI)) {
  809                 int type = frame->exc;
  810 
  811                 /* Ignore DTrace traps. */
  812                 if (*(uint32_t *)frame->srr0 == EXC_DTRACE)
  813                         return (0);
  814 #ifdef AIM
  815                 if (type == EXC_PGM && (frame->srr1 & EXC_PGM_TRAP)) {
  816 #else
  817                 if (frame->cpu.booke.esr & ESR_PTR) {
  818 #endif
  819                         type = T_BREAKPOINT;
  820                 }
  821                 return (kdb_trap(type, 0, frame));
  822         }
  823 
  824         return (0);
  825 }
  826 #endif

Cache object: ad0b60a2084f21fbb03db1e55b9acce2


[ 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.