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

Cache object: b49ebe76bd4a8fe08911596c6abeeebc


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