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.2/sys/powerpc/powerpc/trap.c 333204 2018-05-03 07:47:03Z avg $");
   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                                         (*dtrace_pid_probe_ptr)(frame);
  303                                         break;
  304                                 }
  305 #endif
  306                                 sig = SIGTRAP;
  307                                 ucode = TRAP_BRKPT;
  308                         } else {
  309                                 sig = ppc_instr_emulate(frame, td->td_pcb);
  310                                 if (sig == SIGILL) {
  311                                         if (frame->srr1 & EXC_PGM_PRIV)
  312                                                 ucode = ILL_PRVOPC;
  313                                         else if (frame->srr1 & EXC_PGM_ILLEGAL)
  314                                                 ucode = ILL_ILLOPC;
  315                                 } else if (sig == SIGFPE)
  316                                         ucode = FPE_FLTINV;     /* Punt for now, invalid operation. */
  317                         }
  318                         break;
  319 
  320                 case EXC_MCHK:
  321                         /*
  322                          * Note that this may not be recoverable for the user
  323                          * process, depending on the type of machine check,
  324                          * but it at least prevents the kernel from dying.
  325                          */
  326                         sig = SIGBUS;
  327                         ucode = BUS_OBJERR;
  328                         break;
  329 
  330                 default:
  331                         trap_fatal(frame);
  332                 }
  333         } else {
  334                 /* Kernel Mode Traps */
  335 
  336                 KASSERT(cold || td->td_ucred != NULL,
  337                     ("kernel trap doesn't have ucred"));
  338                 switch (type) {
  339 #ifdef KDTRACE_HOOKS
  340                 case EXC_PGM:
  341                         if (frame->srr1 & EXC_PGM_TRAP) {
  342                                 if (*(uint32_t *)frame->srr0 == EXC_DTRACE) {
  343                                         if (dtrace_invop_jump_addr != NULL) {
  344                                                 dtrace_invop_jump_addr(frame);
  345                                                 return;
  346                                         }
  347                                 }
  348                         }
  349                         break;
  350 #endif
  351 #ifdef __powerpc64__
  352                 case EXC_DSE:
  353                         if ((frame->dar & SEGMENT_MASK) == USER_ADDR) {
  354                                 __asm __volatile ("slbmte %0, %1" ::
  355                                         "r"(td->td_pcb->pcb_cpu.aim.usr_vsid),
  356                                         "r"(USER_SLB_SLBE));
  357                                 return;
  358                         }
  359                         break;
  360 #endif
  361                 case EXC_DSI:
  362                         if (trap_pfault(frame, 0) == 0)
  363                                 return;
  364                         break;
  365                 case EXC_MCHK:
  366                         if (handle_onfault(frame))
  367                                 return;
  368                         break;
  369                 default:
  370                         break;
  371                 }
  372                 trap_fatal(frame);
  373         }
  374 
  375         if (sig != 0) {
  376                 if (p->p_sysent->sv_transtrap != NULL)
  377                         sig = (p->p_sysent->sv_transtrap)(sig, type);
  378                 ksiginfo_init_trap(&ksi);
  379                 ksi.ksi_signo = sig;
  380                 ksi.ksi_code = (int) ucode; /* XXX, not POSIX */
  381                 /* ksi.ksi_addr = ? */
  382                 ksi.ksi_trapno = type;
  383                 trapsignal(td, &ksi);
  384         }
  385 
  386         userret(td, frame);
  387 }
  388 
  389 static void
  390 trap_fatal(struct trapframe *frame)
  391 {
  392 #ifdef KDB
  393         bool handled;
  394 #endif
  395 
  396         printtrap(frame->exc, frame, 1, (frame->srr1 & PSL_PR));
  397 #ifdef KDB
  398         if (debugger_on_panic) {
  399                 kdb_why = KDB_WHY_TRAP;
  400                 handled = kdb_trap(frame->exc, 0, frame);
  401                 kdb_why = KDB_WHY_UNSET;
  402                 if (handled)
  403                         return;
  404         }
  405 #endif
  406         panic("%s trap", trapname(frame->exc));
  407 }
  408 
  409 static void
  410 printtrap(u_int vector, struct trapframe *frame, int isfatal, int user)
  411 {
  412         uint16_t ver;
  413 #ifdef BOOKE
  414         vm_paddr_t pa;
  415 #endif
  416 
  417         printf("\n");
  418         printf("%s %s trap:\n", isfatal ? "fatal" : "handled",
  419             user ? "user" : "kernel");
  420         printf("\n");
  421         printf("   exception       = 0x%x (%s)\n", vector, trapname(vector));
  422         switch (vector) {
  423         case EXC_DSE:
  424         case EXC_DSI:
  425         case EXC_DTMISS:
  426                 printf("   virtual address = 0x%" PRIxPTR "\n", frame->dar);
  427 #ifdef AIM
  428                 printf("   dsisr           = 0x%lx\n",
  429                     (u_long)frame->cpu.aim.dsisr);
  430 #endif
  431                 break;
  432         case EXC_ISE:
  433         case EXC_ISI:
  434         case EXC_ITMISS:
  435                 printf("   virtual address = 0x%" PRIxPTR "\n", frame->srr0);
  436                 break;
  437         case EXC_MCHK:
  438                 ver = mfpvr() >> 16;
  439 #if defined(AIM)
  440                 if (MPC745X_P(ver))
  441                         printf("    msssr0         = 0x%lx\n",
  442                             (u_long)mfspr(SPR_MSSSR0));
  443 #elif defined(BOOKE)
  444                 pa = mfspr(SPR_MCARU);
  445                 pa = (pa << 32) | (u_register_t)mfspr(SPR_MCAR);
  446                 printf("   mcsr            = 0x%lx\n", (u_long)mfspr(SPR_MCSR));
  447                 printf("   mcar            = 0x%jx\n", (uintmax_t)pa);
  448 #endif
  449                 break;
  450         }
  451 #ifdef BOOKE
  452         printf("   esr             = 0x%" PRIxPTR "\n",
  453             frame->cpu.booke.esr);
  454 #endif
  455         printf("   srr0            = 0x%" PRIxPTR "\n", frame->srr0);
  456         printf("   srr1            = 0x%lx\n", (u_long)frame->srr1);
  457         printf("   lr              = 0x%" PRIxPTR "\n", frame->lr);
  458         printf("   curthread       = %p\n", curthread);
  459         if (curthread != NULL)
  460                 printf("          pid = %d, comm = %s\n",
  461                     curthread->td_proc->p_pid, curthread->td_name);
  462         printf("\n");
  463 }
  464 
  465 /*
  466  * Handles a fatal fault when we have onfault state to recover.  Returns
  467  * non-zero if there was onfault recovery state available.
  468  */
  469 static int
  470 handle_onfault(struct trapframe *frame)
  471 {
  472         struct          thread *td;
  473         jmp_buf         *fb;
  474 
  475         td = curthread;
  476         fb = td->td_pcb->pcb_onfault;
  477         if (fb != NULL) {
  478                 frame->srr0 = (*fb)->_jb[FAULTBUF_LR];
  479                 frame->fixreg[1] = (*fb)->_jb[FAULTBUF_R1];
  480                 frame->fixreg[2] = (*fb)->_jb[FAULTBUF_R2];
  481                 frame->fixreg[3] = 1;
  482                 frame->cr = (*fb)->_jb[FAULTBUF_CR];
  483                 bcopy(&(*fb)->_jb[FAULTBUF_R14], &frame->fixreg[14],
  484                     18 * sizeof(register_t));
  485                 td->td_pcb->pcb_onfault = NULL; /* Returns twice, not thrice */
  486                 return (1);
  487         }
  488         return (0);
  489 }
  490 
  491 int
  492 cpu_fetch_syscall_args(struct thread *td)
  493 {
  494         struct proc *p;
  495         struct trapframe *frame;
  496         struct syscall_args *sa;
  497         caddr_t params;
  498         size_t argsz;
  499         int error, n, i;
  500 
  501         p = td->td_proc;
  502         frame = td->td_frame;
  503         sa = &td->td_sa;
  504 
  505         sa->code = frame->fixreg[0];
  506         params = (caddr_t)(frame->fixreg + FIRSTARG);
  507         n = NARGREG;
  508 
  509         if (sa->code == SYS_syscall) {
  510                 /*
  511                  * code is first argument,
  512                  * followed by actual args.
  513                  */
  514                 sa->code = *(register_t *) params;
  515                 params += sizeof(register_t);
  516                 n -= 1;
  517         } else if (sa->code == SYS___syscall) {
  518                 /*
  519                  * Like syscall, but code is a quad,
  520                  * so as to maintain quad alignment
  521                  * for the rest of the args.
  522                  */
  523                 if (SV_PROC_FLAG(p, SV_ILP32)) {
  524                         params += sizeof(register_t);
  525                         sa->code = *(register_t *) params;
  526                         params += sizeof(register_t);
  527                         n -= 2;
  528                 } else {
  529                         sa->code = *(register_t *) params;
  530                         params += sizeof(register_t);
  531                         n -= 1;
  532                 }
  533         }
  534 
  535         if (p->p_sysent->sv_mask)
  536                 sa->code &= p->p_sysent->sv_mask;
  537         if (sa->code >= p->p_sysent->sv_size)
  538                 sa->callp = &p->p_sysent->sv_table[0];
  539         else
  540                 sa->callp = &p->p_sysent->sv_table[sa->code];
  541 
  542         sa->narg = sa->callp->sy_narg;
  543 
  544         if (SV_PROC_FLAG(p, SV_ILP32)) {
  545                 argsz = sizeof(uint32_t);
  546 
  547                 for (i = 0; i < n; i++)
  548                         sa->args[i] = ((u_register_t *)(params))[i] &
  549                             0xffffffff;
  550         } else {
  551                 argsz = sizeof(uint64_t);
  552 
  553                 for (i = 0; i < n; i++)
  554                         sa->args[i] = ((u_register_t *)(params))[i];
  555         }
  556 
  557         if (sa->narg > n)
  558                 error = copyin(MOREARGS(frame->fixreg[1]), sa->args + n,
  559                                (sa->narg - n) * argsz);
  560         else
  561                 error = 0;
  562 
  563 #ifdef __powerpc64__
  564         if (SV_PROC_FLAG(p, SV_ILP32) && sa->narg > n) {
  565                 /* Expand the size of arguments copied from the stack */
  566 
  567                 for (i = sa->narg; i >= n; i--)
  568                         sa->args[i] = ((uint32_t *)(&sa->args[n]))[i-n];
  569         }
  570 #endif
  571 
  572         if (error == 0) {
  573                 td->td_retval[0] = 0;
  574                 td->td_retval[1] = frame->fixreg[FIRSTARG + 1];
  575         }
  576         return (error);
  577 }
  578 
  579 #include "../../kern/subr_syscall.c"
  580 
  581 void
  582 syscall(struct trapframe *frame)
  583 {
  584         struct thread *td;
  585         int error;
  586 
  587         td = curthread;
  588         td->td_frame = frame;
  589 
  590 #ifdef __powerpc64__
  591         /*
  592          * Speculatively restore last user SLB segment, which we know is
  593          * invalid already, since we are likely to do copyin()/copyout().
  594          */
  595         __asm __volatile ("slbmte %0, %1; isync" ::
  596             "r"(td->td_pcb->pcb_cpu.aim.usr_vsid), "r"(USER_SLB_SLBE));
  597 #endif
  598 
  599         error = syscallenter(td);
  600         syscallret(td, error);
  601 }
  602 
  603 #ifdef __powerpc64__
  604 /* Handle kernel SLB faults -- runs in real mode, all seat belts off */
  605 void
  606 handle_kernel_slb_spill(int type, register_t dar, register_t srr0)
  607 {
  608         struct slb *slbcache;
  609         uint64_t slbe, slbv;
  610         uint64_t esid, addr;
  611         int i;
  612 
  613         addr = (type == EXC_ISE) ? srr0 : dar;
  614         slbcache = PCPU_GET(slb);
  615         esid = (uintptr_t)addr >> ADDR_SR_SHFT;
  616         slbe = (esid << SLBE_ESID_SHIFT) | SLBE_VALID;
  617         
  618         /* See if the hardware flushed this somehow (can happen in LPARs) */
  619         for (i = 0; i < n_slbs; i++)
  620                 if (slbcache[i].slbe == (slbe | (uint64_t)i))
  621                         return;
  622 
  623         /* Not in the map, needs to actually be added */
  624         slbv = kernel_va_to_slbv(addr);
  625         if (slbcache[USER_SLB_SLOT].slbe == 0) {
  626                 for (i = 0; i < n_slbs; i++) {
  627                         if (i == USER_SLB_SLOT)
  628                                 continue;
  629                         if (!(slbcache[i].slbe & SLBE_VALID))
  630                                 goto fillkernslb;
  631                 }
  632 
  633                 if (i == n_slbs)
  634                         slbcache[USER_SLB_SLOT].slbe = 1;
  635         }
  636 
  637         /* Sacrifice a random SLB entry that is not the user entry */
  638         i = mftb() % n_slbs;
  639         if (i == USER_SLB_SLOT)
  640                 i = (i+1) % n_slbs;
  641 
  642 fillkernslb:
  643         /* Write new entry */
  644         slbcache[i].slbv = slbv;
  645         slbcache[i].slbe = slbe | (uint64_t)i;
  646 
  647         /* Trap handler will restore from cache on exit */
  648 }
  649 
  650 static int 
  651 handle_user_slb_spill(pmap_t pm, vm_offset_t addr)
  652 {
  653         struct slb *user_entry;
  654         uint64_t esid;
  655         int i;
  656 
  657         esid = (uintptr_t)addr >> ADDR_SR_SHFT;
  658 
  659         PMAP_LOCK(pm);
  660         user_entry = user_va_to_slb_entry(pm, addr);
  661 
  662         if (user_entry == NULL) {
  663                 /* allocate_vsid auto-spills it */
  664                 (void)allocate_user_vsid(pm, esid, 0);
  665         } else {
  666                 /*
  667                  * Check that another CPU has not already mapped this.
  668                  * XXX: Per-thread SLB caches would be better.
  669                  */
  670                 for (i = 0; i < pm->pm_slb_len; i++)
  671                         if (pm->pm_slb[i] == user_entry)
  672                                 break;
  673 
  674                 if (i == pm->pm_slb_len)
  675                         slb_insert_user(pm, user_entry);
  676         }
  677         PMAP_UNLOCK(pm);
  678 
  679         return (0);
  680 }
  681 #endif
  682 
  683 static int
  684 trap_pfault(struct trapframe *frame, int user)
  685 {
  686         vm_offset_t     eva, va;
  687         struct          thread *td;
  688         struct          proc *p;
  689         vm_map_t        map;
  690         vm_prot_t       ftype;
  691         int             rv;
  692 #ifdef AIM
  693         register_t      user_sr;
  694 #endif
  695 
  696         td = curthread;
  697         p = td->td_proc;
  698         if (frame->exc == EXC_ISI) {
  699                 eva = frame->srr0;
  700                 ftype = VM_PROT_EXECUTE;
  701                 if (frame->srr1 & SRR1_ISI_PFAULT)
  702                         ftype |= VM_PROT_READ;
  703         } else {
  704                 eva = frame->dar;
  705 #ifdef BOOKE
  706                 if (frame->cpu.booke.esr & ESR_ST)
  707 #else
  708                 if (frame->cpu.aim.dsisr & DSISR_STORE)
  709 #endif
  710                         ftype = VM_PROT_WRITE;
  711                 else
  712                         ftype = VM_PROT_READ;
  713         }
  714 
  715         if (user) {
  716                 KASSERT(p->p_vmspace != NULL, ("trap_pfault: vmspace  NULL"));
  717                 map = &p->p_vmspace->vm_map;
  718         } else {
  719 #ifdef BOOKE
  720                 if (eva < VM_MAXUSER_ADDRESS) {
  721 #else
  722                 if ((eva >> ADDR_SR_SHFT) == (USER_ADDR >> ADDR_SR_SHFT)) {
  723 #endif
  724                         map = &p->p_vmspace->vm_map;
  725 
  726 #ifdef AIM
  727                         user_sr = td->td_pcb->pcb_cpu.aim.usr_segm;
  728                         eva &= ADDR_PIDX | ADDR_POFF;
  729                         eva |= user_sr << ADDR_SR_SHFT;
  730 #endif
  731                 } else {
  732                         map = kernel_map;
  733                 }
  734         }
  735         va = trunc_page(eva);
  736 
  737         /* Fault in the page. */
  738         rv = vm_fault(map, va, ftype, VM_FAULT_NORMAL);
  739         /*
  740          * XXXDTRACE: add dtrace_doubletrap_func here?
  741          */
  742 
  743         if (rv == KERN_SUCCESS)
  744                 return (0);
  745 
  746         if (!user && handle_onfault(frame))
  747                 return (0);
  748 
  749         return (SIGSEGV);
  750 }
  751 
  752 /*
  753  * For now, this only deals with the particular unaligned access case
  754  * that gcc tends to generate.  Eventually it should handle all of the
  755  * possibilities that can happen on a 32-bit PowerPC in big-endian mode.
  756  */
  757 
  758 static int
  759 fix_unaligned(struct thread *td, struct trapframe *frame)
  760 {
  761         struct thread   *fputhread;
  762         int             indicator, reg;
  763         double          *fpr;
  764 
  765         indicator = EXC_ALI_OPCODE_INDICATOR(frame->cpu.aim.dsisr);
  766 
  767         switch (indicator) {
  768         case EXC_ALI_LFD:
  769         case EXC_ALI_STFD:
  770                 reg = EXC_ALI_RST(frame->cpu.aim.dsisr);
  771                 fpr = &td->td_pcb->pcb_fpu.fpr[reg].fpr;
  772                 fputhread = PCPU_GET(fputhread);
  773 
  774                 /* Juggle the FPU to ensure that we've initialized
  775                  * the FPRs, and that their current state is in
  776                  * the PCB.
  777                  */
  778                 if (fputhread != td) {
  779                         if (fputhread)
  780                                 save_fpu(fputhread);
  781                         enable_fpu(td);
  782                 }
  783                 save_fpu(td);
  784 
  785                 if (indicator == EXC_ALI_LFD) {
  786                         if (copyin((void *)frame->dar, fpr,
  787                             sizeof(double)) != 0)
  788                                 return (-1);
  789                         enable_fpu(td);
  790                 } else {
  791                         if (copyout(fpr, (void *)frame->dar,
  792                             sizeof(double)) != 0)
  793                                 return (-1);
  794                 }
  795                 return (0);
  796                 break;
  797         }
  798 
  799         return (-1);
  800 }
  801 
  802 #ifdef KDB
  803 int db_trap_glue(struct trapframe *);           /* Called from trap_subr.S */
  804 
  805 int
  806 db_trap_glue(struct trapframe *frame)
  807 {
  808         if (!(frame->srr1 & PSL_PR)
  809             && (frame->exc == EXC_TRC || frame->exc == EXC_RUNMODETRC
  810 #ifdef AIM
  811                 || (frame->exc == EXC_PGM
  812                     && (frame->srr1 & EXC_PGM_TRAP))
  813 #else
  814                 || (frame->exc == EXC_DEBUG)
  815 #endif
  816                 || frame->exc == EXC_BPT
  817                 || frame->exc == EXC_DSI)) {
  818                 int type = frame->exc;
  819 
  820                 /* Ignore DTrace traps. */
  821                 if (*(uint32_t *)frame->srr0 == EXC_DTRACE)
  822                         return (0);
  823 #ifdef AIM
  824                 if (type == EXC_PGM && (frame->srr1 & EXC_PGM_TRAP)) {
  825 #else
  826                 if (frame->cpu.booke.esr & ESR_PTR) {
  827 #endif
  828                         type = T_BREAKPOINT;
  829                 }
  830                 return (kdb_trap(type, 0, frame));
  831         }
  832 
  833         return (0);
  834 }
  835 #endif

Cache object: 8e9181134612e65d3a0fe832cfbece65


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