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

Cache object: ce582b0d2f01751ba612e99de45e7f18


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