1*0Sstevel@tonic-gate /* 2*0Sstevel@tonic-gate * CDDL HEADER START 3*0Sstevel@tonic-gate * 4*0Sstevel@tonic-gate * The contents of this file are subject to the terms of the 5*0Sstevel@tonic-gate * Common Development and Distribution License, Version 1.0 only 6*0Sstevel@tonic-gate * (the "License"). You may not use this file except in compliance 7*0Sstevel@tonic-gate * with the License. 8*0Sstevel@tonic-gate * 9*0Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10*0Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 11*0Sstevel@tonic-gate * See the License for the specific language governing permissions 12*0Sstevel@tonic-gate * and limitations under the License. 13*0Sstevel@tonic-gate * 14*0Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 15*0Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16*0Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 17*0Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 18*0Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 19*0Sstevel@tonic-gate * 20*0Sstevel@tonic-gate * CDDL HEADER END 21*0Sstevel@tonic-gate */ 22*0Sstevel@tonic-gate /* 23*0Sstevel@tonic-gate * Copyright 2005 Sun Microsystems, Inc. All rights reserved. 24*0Sstevel@tonic-gate * Use is subject to license terms. 25*0Sstevel@tonic-gate */ 26*0Sstevel@tonic-gate 27*0Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 28*0Sstevel@tonic-gate 29*0Sstevel@tonic-gate #include <sys/mmu.h> 30*0Sstevel@tonic-gate #include <sys/systm.h> 31*0Sstevel@tonic-gate #include <sys/trap.h> 32*0Sstevel@tonic-gate #include <sys/machtrap.h> 33*0Sstevel@tonic-gate #include <sys/vtrace.h> 34*0Sstevel@tonic-gate #include <sys/prsystm.h> 35*0Sstevel@tonic-gate #include <sys/archsystm.h> 36*0Sstevel@tonic-gate #include <sys/machsystm.h> 37*0Sstevel@tonic-gate #include <sys/fpu/fpusystm.h> 38*0Sstevel@tonic-gate #include <sys/tnf.h> 39*0Sstevel@tonic-gate #include <sys/tnf_probe.h> 40*0Sstevel@tonic-gate #include <sys/simulate.h> 41*0Sstevel@tonic-gate #include <sys/ftrace.h> 42*0Sstevel@tonic-gate #include <sys/ontrap.h> 43*0Sstevel@tonic-gate #include <sys/kcpc.h> 44*0Sstevel@tonic-gate #include <sys/kobj.h> 45*0Sstevel@tonic-gate #include <sys/procfs.h> 46*0Sstevel@tonic-gate #include <sys/sun4asi.h> 47*0Sstevel@tonic-gate #include <sys/sdt.h> 48*0Sstevel@tonic-gate #include <sys/fpras.h> 49*0Sstevel@tonic-gate 50*0Sstevel@tonic-gate #ifdef TRAPTRACE 51*0Sstevel@tonic-gate #include <sys/traptrace.h> 52*0Sstevel@tonic-gate #endif 53*0Sstevel@tonic-gate 54*0Sstevel@tonic-gate int tudebug = 0; 55*0Sstevel@tonic-gate static int tudebugbpt = 0; 56*0Sstevel@tonic-gate static int tudebugfpe = 0; 57*0Sstevel@tonic-gate 58*0Sstevel@tonic-gate static int alignfaults = 0; 59*0Sstevel@tonic-gate 60*0Sstevel@tonic-gate #if defined(TRAPDEBUG) || defined(lint) 61*0Sstevel@tonic-gate static int lodebug = 0; 62*0Sstevel@tonic-gate #else 63*0Sstevel@tonic-gate #define lodebug 0 64*0Sstevel@tonic-gate #endif /* defined(TRAPDEBUG) || defined(lint) */ 65*0Sstevel@tonic-gate 66*0Sstevel@tonic-gate 67*0Sstevel@tonic-gate int vis1_partial_support(struct regs *rp, k_siginfo_t *siginfo, uint_t *fault); 68*0Sstevel@tonic-gate #pragma weak vis1_partial_support 69*0Sstevel@tonic-gate 70*0Sstevel@tonic-gate void showregs(unsigned, struct regs *, caddr_t, uint_t); 71*0Sstevel@tonic-gate #pragma weak showregs 72*0Sstevel@tonic-gate 73*0Sstevel@tonic-gate void trap_async_hwerr(void); 74*0Sstevel@tonic-gate #pragma weak trap_async_hwerr 75*0Sstevel@tonic-gate 76*0Sstevel@tonic-gate void trap_async_berr_bto(int, struct regs *); 77*0Sstevel@tonic-gate #pragma weak trap_async_berr_bto 78*0Sstevel@tonic-gate 79*0Sstevel@tonic-gate static enum seg_rw get_accesstype(struct regs *); 80*0Sstevel@tonic-gate static int nfload(struct regs *, int *); 81*0Sstevel@tonic-gate static int swap_nc(struct regs *, int); 82*0Sstevel@tonic-gate static int ldstub_nc(struct regs *, int); 83*0Sstevel@tonic-gate void trap_cleanup(struct regs *, uint_t, k_siginfo_t *, int); 84*0Sstevel@tonic-gate void trap_rtt(void); 85*0Sstevel@tonic-gate 86*0Sstevel@tonic-gate static int 87*0Sstevel@tonic-gate die(unsigned type, struct regs *rp, caddr_t addr, uint_t mmu_fsr) 88*0Sstevel@tonic-gate { 89*0Sstevel@tonic-gate struct trap_info ti; 90*0Sstevel@tonic-gate 91*0Sstevel@tonic-gate #ifdef TRAPTRACE 92*0Sstevel@tonic-gate TRAPTRACE_FREEZE; 93*0Sstevel@tonic-gate #endif 94*0Sstevel@tonic-gate 95*0Sstevel@tonic-gate ti.trap_regs = rp; 96*0Sstevel@tonic-gate ti.trap_type = type; 97*0Sstevel@tonic-gate ti.trap_addr = addr; 98*0Sstevel@tonic-gate ti.trap_mmu_fsr = mmu_fsr; 99*0Sstevel@tonic-gate 100*0Sstevel@tonic-gate curthread->t_panic_trap = &ti; 101*0Sstevel@tonic-gate 102*0Sstevel@tonic-gate if (type == T_DATA_MMU_MISS && addr < (caddr_t)KERNELBASE) { 103*0Sstevel@tonic-gate panic("BAD TRAP: type=%x rp=%p addr=%p mmu_fsr=%x " 104*0Sstevel@tonic-gate "occurred in module \"%s\" due to %s", 105*0Sstevel@tonic-gate type, (void *)rp, (void *)addr, mmu_fsr, 106*0Sstevel@tonic-gate mod_containing_pc((caddr_t)rp->r_pc), 107*0Sstevel@tonic-gate addr < (caddr_t)PAGESIZE ? 108*0Sstevel@tonic-gate "a NULL pointer dereference" : 109*0Sstevel@tonic-gate "an illegal access to a user address"); 110*0Sstevel@tonic-gate } else { 111*0Sstevel@tonic-gate panic("BAD TRAP: type=%x rp=%p addr=%p mmu_fsr=%x", 112*0Sstevel@tonic-gate type, (void *)rp, (void *)addr, mmu_fsr); 113*0Sstevel@tonic-gate } 114*0Sstevel@tonic-gate 115*0Sstevel@tonic-gate return (0); /* avoid optimization of restore in call's delay slot */ 116*0Sstevel@tonic-gate } 117*0Sstevel@tonic-gate 118*0Sstevel@tonic-gate #if defined(SF_ERRATA_23) || defined(SF_ERRATA_30) /* call ... illegal-insn */ 119*0Sstevel@tonic-gate int ill_calls; 120*0Sstevel@tonic-gate #endif 121*0Sstevel@tonic-gate 122*0Sstevel@tonic-gate /* 123*0Sstevel@tonic-gate * Currently, the only PREFETCH/PREFETCHA instructions which cause traps 124*0Sstevel@tonic-gate * are the "strong" prefetches (fcn=20-23). But we check for all flavors of 125*0Sstevel@tonic-gate * PREFETCH, in case some future variant also causes a DATA_MMU_MISS. 126*0Sstevel@tonic-gate */ 127*0Sstevel@tonic-gate #define IS_PREFETCH(i) (((i) & 0xc1780000) == 0xc1680000) 128*0Sstevel@tonic-gate 129*0Sstevel@tonic-gate #define IS_FLUSH(i) (((i) & 0xc1f80000) == 0x81d80000) 130*0Sstevel@tonic-gate #define IS_SWAP(i) (((i) & 0xc1f80000) == 0xc0780000) 131*0Sstevel@tonic-gate #define IS_LDSTUB(i) (((i) & 0xc1f80000) == 0xc0680000) 132*0Sstevel@tonic-gate #define IS_FLOAT(i) (((i) & 0x1000000) != 0) 133*0Sstevel@tonic-gate #define IS_STORE(i) (((i) >> 21) & 1) 134*0Sstevel@tonic-gate 135*0Sstevel@tonic-gate /* 136*0Sstevel@tonic-gate * Called from the trap handler when a processor trap occurs. 137*0Sstevel@tonic-gate */ 138*0Sstevel@tonic-gate /*VARARGS2*/ 139*0Sstevel@tonic-gate void 140*0Sstevel@tonic-gate trap(struct regs *rp, caddr_t addr, uint32_t type, uint32_t mmu_fsr) 141*0Sstevel@tonic-gate { 142*0Sstevel@tonic-gate proc_t *p = ttoproc(curthread); 143*0Sstevel@tonic-gate klwp_id_t lwp = ttolwp(curthread); 144*0Sstevel@tonic-gate struct machpcb *mpcb = NULL; 145*0Sstevel@tonic-gate k_siginfo_t siginfo; 146*0Sstevel@tonic-gate uint_t op3, fault = 0; 147*0Sstevel@tonic-gate int stepped = 0; 148*0Sstevel@tonic-gate greg_t oldpc; 149*0Sstevel@tonic-gate int mstate; 150*0Sstevel@tonic-gate char *badaddr; 151*0Sstevel@tonic-gate faultcode_t res; 152*0Sstevel@tonic-gate enum fault_type fault_type; 153*0Sstevel@tonic-gate enum seg_rw rw; 154*0Sstevel@tonic-gate uintptr_t lofault; 155*0Sstevel@tonic-gate int instr; 156*0Sstevel@tonic-gate int iskernel; 157*0Sstevel@tonic-gate int watchcode; 158*0Sstevel@tonic-gate int watchpage; 159*0Sstevel@tonic-gate extern faultcode_t pagefault(caddr_t, enum fault_type, 160*0Sstevel@tonic-gate enum seg_rw, int); 161*0Sstevel@tonic-gate 162*0Sstevel@tonic-gate CPU_STATS_ADDQ(CPU, sys, trap, 1); 163*0Sstevel@tonic-gate 164*0Sstevel@tonic-gate #ifdef SF_ERRATA_23 /* call causes illegal-insn */ 165*0Sstevel@tonic-gate ASSERT((curthread->t_schedflag & TS_DONT_SWAP) || 166*0Sstevel@tonic-gate (type == T_UNIMP_INSTR)); 167*0Sstevel@tonic-gate #else 168*0Sstevel@tonic-gate ASSERT(curthread->t_schedflag & TS_DONT_SWAP); 169*0Sstevel@tonic-gate #endif /* SF_ERRATA_23 */ 170*0Sstevel@tonic-gate 171*0Sstevel@tonic-gate if (USERMODE(rp->r_tstate) || (type & T_USER)) { 172*0Sstevel@tonic-gate /* 173*0Sstevel@tonic-gate * Set lwp_state before trying to acquire any 174*0Sstevel@tonic-gate * adaptive lock 175*0Sstevel@tonic-gate */ 176*0Sstevel@tonic-gate ASSERT(lwp != NULL); 177*0Sstevel@tonic-gate lwp->lwp_state = LWP_SYS; 178*0Sstevel@tonic-gate /* 179*0Sstevel@tonic-gate * Set up the current cred to use during this trap. u_cred 180*0Sstevel@tonic-gate * no longer exists. t_cred is used instead. 181*0Sstevel@tonic-gate * The current process credential applies to the thread for 182*0Sstevel@tonic-gate * the entire trap. If trapping from the kernel, this 183*0Sstevel@tonic-gate * should already be set up. 184*0Sstevel@tonic-gate */ 185*0Sstevel@tonic-gate if (curthread->t_cred != p->p_cred) { 186*0Sstevel@tonic-gate cred_t *oldcred = curthread->t_cred; 187*0Sstevel@tonic-gate /* 188*0Sstevel@tonic-gate * DTrace accesses t_cred in probe context. t_cred 189*0Sstevel@tonic-gate * must always be either NULL, or point to a valid, 190*0Sstevel@tonic-gate * allocated cred structure. 191*0Sstevel@tonic-gate */ 192*0Sstevel@tonic-gate curthread->t_cred = crgetcred(); 193*0Sstevel@tonic-gate crfree(oldcred); 194*0Sstevel@tonic-gate } 195*0Sstevel@tonic-gate type |= T_USER; 196*0Sstevel@tonic-gate ASSERT((type == (T_SYS_RTT_PAGE | T_USER)) || 197*0Sstevel@tonic-gate (type == (T_SYS_RTT_ALIGN | T_USER)) || 198*0Sstevel@tonic-gate lwp->lwp_regs == rp); 199*0Sstevel@tonic-gate mpcb = lwptompcb(lwp); 200*0Sstevel@tonic-gate switch (type) { 201*0Sstevel@tonic-gate case T_WIN_OVERFLOW + T_USER: 202*0Sstevel@tonic-gate case T_WIN_UNDERFLOW + T_USER: 203*0Sstevel@tonic-gate case T_SYS_RTT_PAGE + T_USER: 204*0Sstevel@tonic-gate case T_DATA_MMU_MISS + T_USER: 205*0Sstevel@tonic-gate mstate = LMS_DFAULT; 206*0Sstevel@tonic-gate break; 207*0Sstevel@tonic-gate case T_INSTR_MMU_MISS + T_USER: 208*0Sstevel@tonic-gate mstate = LMS_TFAULT; 209*0Sstevel@tonic-gate break; 210*0Sstevel@tonic-gate default: 211*0Sstevel@tonic-gate mstate = LMS_TRAP; 212*0Sstevel@tonic-gate break; 213*0Sstevel@tonic-gate } 214*0Sstevel@tonic-gate /* Kernel probe */ 215*0Sstevel@tonic-gate TNF_PROBE_1(thread_state, "thread", /* CSTYLED */, 216*0Sstevel@tonic-gate tnf_microstate, state, (char)mstate); 217*0Sstevel@tonic-gate mstate = new_mstate(curthread, mstate); 218*0Sstevel@tonic-gate siginfo.si_signo = 0; 219*0Sstevel@tonic-gate stepped = 220*0Sstevel@tonic-gate lwp->lwp_pcb.pcb_step != STEP_NONE && 221*0Sstevel@tonic-gate ((oldpc = rp->r_pc), prundostep()) && 222*0Sstevel@tonic-gate mmu_btop((uintptr_t)addr) == mmu_btop((uintptr_t)oldpc); 223*0Sstevel@tonic-gate /* this assignment must not precede call to prundostep() */ 224*0Sstevel@tonic-gate oldpc = rp->r_pc; 225*0Sstevel@tonic-gate } 226*0Sstevel@tonic-gate 227*0Sstevel@tonic-gate TRACE_1(TR_FAC_TRAP, TR_C_TRAP_HANDLER_ENTER, 228*0Sstevel@tonic-gate "C_trap_handler_enter:type %x", type); 229*0Sstevel@tonic-gate 230*0Sstevel@tonic-gate #ifdef F_DEFERRED 231*0Sstevel@tonic-gate /* 232*0Sstevel@tonic-gate * Take any pending floating point exceptions now. 233*0Sstevel@tonic-gate * If the floating point unit has an exception to handle, 234*0Sstevel@tonic-gate * just return to user-level to let the signal handler run. 235*0Sstevel@tonic-gate * The instruction that got us to trap() will be reexecuted on 236*0Sstevel@tonic-gate * return from the signal handler and we will trap to here again. 237*0Sstevel@tonic-gate * This is necessary to disambiguate simultaneous traps which 238*0Sstevel@tonic-gate * happen when a floating-point exception is pending and a 239*0Sstevel@tonic-gate * machine fault is incurred. 240*0Sstevel@tonic-gate */ 241*0Sstevel@tonic-gate if (type & USER) { 242*0Sstevel@tonic-gate /* 243*0Sstevel@tonic-gate * FP_TRAPPED is set only by sendsig() when it copies 244*0Sstevel@tonic-gate * out the floating-point queue for the signal handler. 245*0Sstevel@tonic-gate * It is set there so we can test it here and in syscall(). 246*0Sstevel@tonic-gate */ 247*0Sstevel@tonic-gate mpcb->mpcb_flags &= ~FP_TRAPPED; 248*0Sstevel@tonic-gate syncfpu(); 249*0Sstevel@tonic-gate if (mpcb->mpcb_flags & FP_TRAPPED) { 250*0Sstevel@tonic-gate /* 251*0Sstevel@tonic-gate * trap() has have been called recursively and may 252*0Sstevel@tonic-gate * have stopped the process, so do single step 253*0Sstevel@tonic-gate * support for /proc. 254*0Sstevel@tonic-gate */ 255*0Sstevel@tonic-gate mpcb->mpcb_flags &= ~FP_TRAPPED; 256*0Sstevel@tonic-gate goto out; 257*0Sstevel@tonic-gate } 258*0Sstevel@tonic-gate } 259*0Sstevel@tonic-gate #endif 260*0Sstevel@tonic-gate switch (type) { 261*0Sstevel@tonic-gate case T_DATA_MMU_MISS: 262*0Sstevel@tonic-gate case T_INSTR_MMU_MISS + T_USER: 263*0Sstevel@tonic-gate case T_DATA_MMU_MISS + T_USER: 264*0Sstevel@tonic-gate case T_DATA_PROT + T_USER: 265*0Sstevel@tonic-gate case T_AST + T_USER: 266*0Sstevel@tonic-gate case T_SYS_RTT_PAGE + T_USER: 267*0Sstevel@tonic-gate case T_FLUSH_PCB + T_USER: 268*0Sstevel@tonic-gate case T_FLUSHW + T_USER: 269*0Sstevel@tonic-gate break; 270*0Sstevel@tonic-gate 271*0Sstevel@tonic-gate default: 272*0Sstevel@tonic-gate FTRACE_3("trap(): type=0x%lx, regs=0x%lx, addr=0x%lx", 273*0Sstevel@tonic-gate (ulong_t)type, (ulong_t)rp, (ulong_t)addr); 274*0Sstevel@tonic-gate break; 275*0Sstevel@tonic-gate } 276*0Sstevel@tonic-gate 277*0Sstevel@tonic-gate switch (type) { 278*0Sstevel@tonic-gate 279*0Sstevel@tonic-gate default: 280*0Sstevel@tonic-gate /* 281*0Sstevel@tonic-gate * Check for user software trap. 282*0Sstevel@tonic-gate */ 283*0Sstevel@tonic-gate if (type & T_USER) { 284*0Sstevel@tonic-gate if (tudebug) 285*0Sstevel@tonic-gate showregs(type, rp, (caddr_t)0, 0); 286*0Sstevel@tonic-gate if ((type & ~T_USER) >= T_SOFTWARE_TRAP) { 287*0Sstevel@tonic-gate bzero(&siginfo, sizeof (siginfo)); 288*0Sstevel@tonic-gate siginfo.si_signo = SIGILL; 289*0Sstevel@tonic-gate siginfo.si_code = ILL_ILLTRP; 290*0Sstevel@tonic-gate siginfo.si_addr = (caddr_t)rp->r_pc; 291*0Sstevel@tonic-gate siginfo.si_trapno = type &~ T_USER; 292*0Sstevel@tonic-gate fault = FLTILL; 293*0Sstevel@tonic-gate break; 294*0Sstevel@tonic-gate } 295*0Sstevel@tonic-gate } 296*0Sstevel@tonic-gate addr = (caddr_t)rp->r_pc; 297*0Sstevel@tonic-gate (void) die(type, rp, addr, 0); 298*0Sstevel@tonic-gate /*NOTREACHED*/ 299*0Sstevel@tonic-gate 300*0Sstevel@tonic-gate case T_ALIGNMENT: /* supv alignment error */ 301*0Sstevel@tonic-gate if (nfload(rp, NULL)) 302*0Sstevel@tonic-gate goto cleanup; 303*0Sstevel@tonic-gate 304*0Sstevel@tonic-gate if (curthread->t_lofault) { 305*0Sstevel@tonic-gate if (lodebug) { 306*0Sstevel@tonic-gate showregs(type, rp, addr, 0); 307*0Sstevel@tonic-gate traceback((caddr_t)rp->r_sp); 308*0Sstevel@tonic-gate } 309*0Sstevel@tonic-gate rp->r_g1 = EFAULT; 310*0Sstevel@tonic-gate rp->r_pc = curthread->t_lofault; 311*0Sstevel@tonic-gate rp->r_npc = rp->r_pc + 4; 312*0Sstevel@tonic-gate goto cleanup; 313*0Sstevel@tonic-gate } 314*0Sstevel@tonic-gate (void) die(type, rp, addr, 0); 315*0Sstevel@tonic-gate /*NOTREACHED*/ 316*0Sstevel@tonic-gate 317*0Sstevel@tonic-gate case T_INSTR_EXCEPTION: /* sys instruction access exception */ 318*0Sstevel@tonic-gate addr = (caddr_t)rp->r_pc; 319*0Sstevel@tonic-gate (void) die(type, rp, addr, mmu_fsr); 320*0Sstevel@tonic-gate /*NOTREACHED*/ 321*0Sstevel@tonic-gate 322*0Sstevel@tonic-gate case T_INSTR_MMU_MISS: /* sys instruction mmu miss */ 323*0Sstevel@tonic-gate addr = (caddr_t)rp->r_pc; 324*0Sstevel@tonic-gate (void) die(type, rp, addr, 0); 325*0Sstevel@tonic-gate /*NOTREACHED*/ 326*0Sstevel@tonic-gate 327*0Sstevel@tonic-gate case T_DATA_EXCEPTION: /* system data access exception */ 328*0Sstevel@tonic-gate switch (X_FAULT_TYPE(mmu_fsr)) { 329*0Sstevel@tonic-gate case FT_RANGE: 330*0Sstevel@tonic-gate /* 331*0Sstevel@tonic-gate * This happens when we attempt to dereference an 332*0Sstevel@tonic-gate * address in the address hole. If t_ontrap is set, 333*0Sstevel@tonic-gate * then break and fall through to T_DATA_MMU_MISS / 334*0Sstevel@tonic-gate * T_DATA_PROT case below. If lofault is set, then 335*0Sstevel@tonic-gate * honour it (perhaps the user gave us a bogus 336*0Sstevel@tonic-gate * address in the hole to copyin from or copyout to?) 337*0Sstevel@tonic-gate */ 338*0Sstevel@tonic-gate 339*0Sstevel@tonic-gate if (curthread->t_ontrap != NULL) 340*0Sstevel@tonic-gate break; 341*0Sstevel@tonic-gate 342*0Sstevel@tonic-gate addr = (caddr_t)((uintptr_t)addr & TAGACC_VADDR_MASK); 343*0Sstevel@tonic-gate if (curthread->t_lofault) { 344*0Sstevel@tonic-gate if (lodebug) { 345*0Sstevel@tonic-gate showregs(type, rp, addr, 0); 346*0Sstevel@tonic-gate traceback((caddr_t)rp->r_sp); 347*0Sstevel@tonic-gate } 348*0Sstevel@tonic-gate rp->r_g1 = EFAULT; 349*0Sstevel@tonic-gate rp->r_pc = curthread->t_lofault; 350*0Sstevel@tonic-gate rp->r_npc = rp->r_pc + 4; 351*0Sstevel@tonic-gate goto cleanup; 352*0Sstevel@tonic-gate } 353*0Sstevel@tonic-gate (void) die(type, rp, addr, mmu_fsr); 354*0Sstevel@tonic-gate /*NOTREACHED*/ 355*0Sstevel@tonic-gate 356*0Sstevel@tonic-gate case FT_PRIV: 357*0Sstevel@tonic-gate /* 358*0Sstevel@tonic-gate * This can happen if we access ASI_USER from a kernel 359*0Sstevel@tonic-gate * thread. To support pxfs, we need to honor lofault if 360*0Sstevel@tonic-gate * we're doing a copyin/copyout from a kernel thread. 361*0Sstevel@tonic-gate */ 362*0Sstevel@tonic-gate 363*0Sstevel@tonic-gate if (nfload(rp, NULL)) 364*0Sstevel@tonic-gate goto cleanup; 365*0Sstevel@tonic-gate addr = (caddr_t)((uintptr_t)addr & TAGACC_VADDR_MASK); 366*0Sstevel@tonic-gate if (curthread->t_lofault) { 367*0Sstevel@tonic-gate if (lodebug) { 368*0Sstevel@tonic-gate showregs(type, rp, addr, 0); 369*0Sstevel@tonic-gate traceback((caddr_t)rp->r_sp); 370*0Sstevel@tonic-gate } 371*0Sstevel@tonic-gate rp->r_g1 = EFAULT; 372*0Sstevel@tonic-gate rp->r_pc = curthread->t_lofault; 373*0Sstevel@tonic-gate rp->r_npc = rp->r_pc + 4; 374*0Sstevel@tonic-gate goto cleanup; 375*0Sstevel@tonic-gate } 376*0Sstevel@tonic-gate (void) die(type, rp, addr, mmu_fsr); 377*0Sstevel@tonic-gate /*NOTREACHED*/ 378*0Sstevel@tonic-gate 379*0Sstevel@tonic-gate default: 380*0Sstevel@tonic-gate if (nfload(rp, NULL)) 381*0Sstevel@tonic-gate goto cleanup; 382*0Sstevel@tonic-gate addr = (caddr_t)((uintptr_t)addr & TAGACC_VADDR_MASK); 383*0Sstevel@tonic-gate (void) die(type, rp, addr, mmu_fsr); 384*0Sstevel@tonic-gate /*NOTREACHED*/ 385*0Sstevel@tonic-gate 386*0Sstevel@tonic-gate case FT_NFO: 387*0Sstevel@tonic-gate break; 388*0Sstevel@tonic-gate } 389*0Sstevel@tonic-gate /* fall into ... */ 390*0Sstevel@tonic-gate 391*0Sstevel@tonic-gate case T_DATA_MMU_MISS: /* system data mmu miss */ 392*0Sstevel@tonic-gate case T_DATA_PROT: /* system data protection fault */ 393*0Sstevel@tonic-gate if (nfload(rp, &instr)) 394*0Sstevel@tonic-gate goto cleanup; 395*0Sstevel@tonic-gate 396*0Sstevel@tonic-gate /* 397*0Sstevel@tonic-gate * If we're under on_trap() protection (see <sys/ontrap.h>), 398*0Sstevel@tonic-gate * set ot_trap and return from the trap to the trampoline. 399*0Sstevel@tonic-gate */ 400*0Sstevel@tonic-gate if (curthread->t_ontrap != NULL) { 401*0Sstevel@tonic-gate on_trap_data_t *otp = curthread->t_ontrap; 402*0Sstevel@tonic-gate 403*0Sstevel@tonic-gate TRACE_0(TR_FAC_TRAP, TR_C_TRAP_HANDLER_EXIT, 404*0Sstevel@tonic-gate "C_trap_handler_exit"); 405*0Sstevel@tonic-gate TRACE_0(TR_FAC_TRAP, TR_TRAP_END, "trap_end"); 406*0Sstevel@tonic-gate 407*0Sstevel@tonic-gate if (otp->ot_prot & OT_DATA_ACCESS) { 408*0Sstevel@tonic-gate otp->ot_trap |= OT_DATA_ACCESS; 409*0Sstevel@tonic-gate rp->r_pc = otp->ot_trampoline; 410*0Sstevel@tonic-gate rp->r_npc = rp->r_pc + 4; 411*0Sstevel@tonic-gate goto cleanup; 412*0Sstevel@tonic-gate } 413*0Sstevel@tonic-gate } 414*0Sstevel@tonic-gate lofault = curthread->t_lofault; 415*0Sstevel@tonic-gate curthread->t_lofault = 0; 416*0Sstevel@tonic-gate 417*0Sstevel@tonic-gate mstate = new_mstate(curthread, LMS_KFAULT); 418*0Sstevel@tonic-gate 419*0Sstevel@tonic-gate switch (type) { 420*0Sstevel@tonic-gate case T_DATA_PROT: 421*0Sstevel@tonic-gate fault_type = F_PROT; 422*0Sstevel@tonic-gate rw = S_WRITE; 423*0Sstevel@tonic-gate break; 424*0Sstevel@tonic-gate case T_INSTR_MMU_MISS: 425*0Sstevel@tonic-gate fault_type = F_INVAL; 426*0Sstevel@tonic-gate rw = S_EXEC; 427*0Sstevel@tonic-gate break; 428*0Sstevel@tonic-gate case T_DATA_MMU_MISS: 429*0Sstevel@tonic-gate case T_DATA_EXCEPTION: 430*0Sstevel@tonic-gate /* 431*0Sstevel@tonic-gate * The hardware doesn't update the sfsr on mmu 432*0Sstevel@tonic-gate * misses so it is not easy to find out whether 433*0Sstevel@tonic-gate * the access was a read or a write so we need 434*0Sstevel@tonic-gate * to decode the actual instruction. 435*0Sstevel@tonic-gate */ 436*0Sstevel@tonic-gate fault_type = F_INVAL; 437*0Sstevel@tonic-gate rw = get_accesstype(rp); 438*0Sstevel@tonic-gate break; 439*0Sstevel@tonic-gate default: 440*0Sstevel@tonic-gate cmn_err(CE_PANIC, "trap: unknown type %x", type); 441*0Sstevel@tonic-gate break; 442*0Sstevel@tonic-gate } 443*0Sstevel@tonic-gate /* 444*0Sstevel@tonic-gate * We determine if access was done to kernel or user 445*0Sstevel@tonic-gate * address space. The addr passed into trap is really the 446*0Sstevel@tonic-gate * tag access register. 447*0Sstevel@tonic-gate */ 448*0Sstevel@tonic-gate iskernel = (((uintptr_t)addr & TAGACC_CTX_MASK) == KCONTEXT); 449*0Sstevel@tonic-gate addr = (caddr_t)((uintptr_t)addr & TAGACC_VADDR_MASK); 450*0Sstevel@tonic-gate 451*0Sstevel@tonic-gate res = pagefault(addr, fault_type, rw, iskernel); 452*0Sstevel@tonic-gate if (!iskernel && res == FC_NOMAP && 453*0Sstevel@tonic-gate addr < p->p_usrstack && grow(addr)) 454*0Sstevel@tonic-gate res = 0; 455*0Sstevel@tonic-gate 456*0Sstevel@tonic-gate (void) new_mstate(curthread, mstate); 457*0Sstevel@tonic-gate 458*0Sstevel@tonic-gate /* 459*0Sstevel@tonic-gate * Restore lofault. If we resolved the fault, exit. 460*0Sstevel@tonic-gate * If we didn't and lofault wasn't set, die. 461*0Sstevel@tonic-gate */ 462*0Sstevel@tonic-gate curthread->t_lofault = lofault; 463*0Sstevel@tonic-gate 464*0Sstevel@tonic-gate if (res == 0) 465*0Sstevel@tonic-gate goto cleanup; 466*0Sstevel@tonic-gate 467*0Sstevel@tonic-gate if (IS_PREFETCH(instr)) { 468*0Sstevel@tonic-gate /* skip prefetch instructions in kernel-land */ 469*0Sstevel@tonic-gate rp->r_pc = rp->r_npc; 470*0Sstevel@tonic-gate rp->r_npc += 4; 471*0Sstevel@tonic-gate goto cleanup; 472*0Sstevel@tonic-gate } 473*0Sstevel@tonic-gate 474*0Sstevel@tonic-gate if ((lofault == 0 || lodebug) && 475*0Sstevel@tonic-gate (calc_memaddr(rp, &badaddr) == SIMU_SUCCESS)) 476*0Sstevel@tonic-gate addr = badaddr; 477*0Sstevel@tonic-gate if (lofault == 0) 478*0Sstevel@tonic-gate (void) die(type, rp, addr, 0); 479*0Sstevel@tonic-gate /* 480*0Sstevel@tonic-gate * Cannot resolve fault. Return to lofault. 481*0Sstevel@tonic-gate */ 482*0Sstevel@tonic-gate if (lodebug) { 483*0Sstevel@tonic-gate showregs(type, rp, addr, 0); 484*0Sstevel@tonic-gate traceback((caddr_t)rp->r_sp); 485*0Sstevel@tonic-gate } 486*0Sstevel@tonic-gate if (FC_CODE(res) == FC_OBJERR) 487*0Sstevel@tonic-gate res = FC_ERRNO(res); 488*0Sstevel@tonic-gate else 489*0Sstevel@tonic-gate res = EFAULT; 490*0Sstevel@tonic-gate rp->r_g1 = res; 491*0Sstevel@tonic-gate rp->r_pc = curthread->t_lofault; 492*0Sstevel@tonic-gate rp->r_npc = curthread->t_lofault + 4; 493*0Sstevel@tonic-gate goto cleanup; 494*0Sstevel@tonic-gate 495*0Sstevel@tonic-gate case T_INSTR_EXCEPTION + T_USER: /* user insn access exception */ 496*0Sstevel@tonic-gate bzero(&siginfo, sizeof (siginfo)); 497*0Sstevel@tonic-gate siginfo.si_addr = (caddr_t)rp->r_pc; 498*0Sstevel@tonic-gate siginfo.si_signo = SIGSEGV; 499*0Sstevel@tonic-gate siginfo.si_code = X_FAULT_TYPE(mmu_fsr) == FT_PRIV ? 500*0Sstevel@tonic-gate SEGV_ACCERR : SEGV_MAPERR; 501*0Sstevel@tonic-gate fault = FLTBOUNDS; 502*0Sstevel@tonic-gate break; 503*0Sstevel@tonic-gate 504*0Sstevel@tonic-gate case T_WIN_OVERFLOW + T_USER: /* window overflow in ??? */ 505*0Sstevel@tonic-gate case T_WIN_UNDERFLOW + T_USER: /* window underflow in ??? */ 506*0Sstevel@tonic-gate case T_SYS_RTT_PAGE + T_USER: /* window underflow in user_rtt */ 507*0Sstevel@tonic-gate case T_INSTR_MMU_MISS + T_USER: /* user instruction mmu miss */ 508*0Sstevel@tonic-gate case T_DATA_MMU_MISS + T_USER: /* user data mmu miss */ 509*0Sstevel@tonic-gate case T_DATA_PROT + T_USER: /* user data protection fault */ 510*0Sstevel@tonic-gate switch (type) { 511*0Sstevel@tonic-gate case T_INSTR_MMU_MISS + T_USER: 512*0Sstevel@tonic-gate addr = (caddr_t)rp->r_pc; 513*0Sstevel@tonic-gate fault_type = F_INVAL; 514*0Sstevel@tonic-gate rw = S_EXEC; 515*0Sstevel@tonic-gate break; 516*0Sstevel@tonic-gate 517*0Sstevel@tonic-gate case T_DATA_MMU_MISS + T_USER: 518*0Sstevel@tonic-gate addr = (caddr_t)((uintptr_t)addr & TAGACC_VADDR_MASK); 519*0Sstevel@tonic-gate fault_type = F_INVAL; 520*0Sstevel@tonic-gate /* 521*0Sstevel@tonic-gate * The hardware doesn't update the sfsr on mmu misses 522*0Sstevel@tonic-gate * so it is not easy to find out whether the access 523*0Sstevel@tonic-gate * was a read or a write so we need to decode the 524*0Sstevel@tonic-gate * actual instruction. XXX BUGLY HW 525*0Sstevel@tonic-gate */ 526*0Sstevel@tonic-gate rw = get_accesstype(rp); 527*0Sstevel@tonic-gate break; 528*0Sstevel@tonic-gate 529*0Sstevel@tonic-gate case T_DATA_PROT + T_USER: 530*0Sstevel@tonic-gate addr = (caddr_t)((uintptr_t)addr & TAGACC_VADDR_MASK); 531*0Sstevel@tonic-gate fault_type = F_PROT; 532*0Sstevel@tonic-gate rw = S_WRITE; 533*0Sstevel@tonic-gate break; 534*0Sstevel@tonic-gate 535*0Sstevel@tonic-gate case T_WIN_OVERFLOW + T_USER: 536*0Sstevel@tonic-gate addr = (caddr_t)((uintptr_t)addr & TAGACC_VADDR_MASK); 537*0Sstevel@tonic-gate fault_type = F_INVAL; 538*0Sstevel@tonic-gate rw = S_WRITE; 539*0Sstevel@tonic-gate break; 540*0Sstevel@tonic-gate 541*0Sstevel@tonic-gate case T_WIN_UNDERFLOW + T_USER: 542*0Sstevel@tonic-gate case T_SYS_RTT_PAGE + T_USER: 543*0Sstevel@tonic-gate addr = (caddr_t)((uintptr_t)addr & TAGACC_VADDR_MASK); 544*0Sstevel@tonic-gate fault_type = F_INVAL; 545*0Sstevel@tonic-gate rw = S_READ; 546*0Sstevel@tonic-gate break; 547*0Sstevel@tonic-gate 548*0Sstevel@tonic-gate default: 549*0Sstevel@tonic-gate cmn_err(CE_PANIC, "trap: unknown type %x", type); 550*0Sstevel@tonic-gate break; 551*0Sstevel@tonic-gate } 552*0Sstevel@tonic-gate 553*0Sstevel@tonic-gate /* 554*0Sstevel@tonic-gate * If we are single stepping do not call pagefault 555*0Sstevel@tonic-gate */ 556*0Sstevel@tonic-gate if (stepped) { 557*0Sstevel@tonic-gate res = FC_NOMAP; 558*0Sstevel@tonic-gate } else { 559*0Sstevel@tonic-gate caddr_t vaddr = addr; 560*0Sstevel@tonic-gate size_t sz; 561*0Sstevel@tonic-gate int ta; 562*0Sstevel@tonic-gate 563*0Sstevel@tonic-gate ASSERT(!(curthread->t_flag & T_WATCHPT)); 564*0Sstevel@tonic-gate watchpage = (pr_watch_active(p) && 565*0Sstevel@tonic-gate type != T_WIN_OVERFLOW + T_USER && 566*0Sstevel@tonic-gate type != T_WIN_UNDERFLOW + T_USER && 567*0Sstevel@tonic-gate type != T_SYS_RTT_PAGE + T_USER && 568*0Sstevel@tonic-gate pr_is_watchpage(addr, rw)); 569*0Sstevel@tonic-gate 570*0Sstevel@tonic-gate if (!watchpage || 571*0Sstevel@tonic-gate (sz = instr_size(rp, &vaddr, rw)) <= 0) 572*0Sstevel@tonic-gate /* EMPTY */; 573*0Sstevel@tonic-gate else if ((watchcode = pr_is_watchpoint(&vaddr, &ta, 574*0Sstevel@tonic-gate sz, NULL, rw)) != 0) { 575*0Sstevel@tonic-gate if (ta) { 576*0Sstevel@tonic-gate do_watch_step(vaddr, sz, rw, 577*0Sstevel@tonic-gate watchcode, rp->r_pc); 578*0Sstevel@tonic-gate fault_type = F_INVAL; 579*0Sstevel@tonic-gate } else { 580*0Sstevel@tonic-gate bzero(&siginfo, sizeof (siginfo)); 581*0Sstevel@tonic-gate siginfo.si_signo = SIGTRAP; 582*0Sstevel@tonic-gate siginfo.si_code = watchcode; 583*0Sstevel@tonic-gate siginfo.si_addr = vaddr; 584*0Sstevel@tonic-gate siginfo.si_trapafter = 0; 585*0Sstevel@tonic-gate siginfo.si_pc = (caddr_t)rp->r_pc; 586*0Sstevel@tonic-gate fault = FLTWATCH; 587*0Sstevel@tonic-gate break; 588*0Sstevel@tonic-gate } 589*0Sstevel@tonic-gate } else { 590*0Sstevel@tonic-gate if (rw != S_EXEC && 591*0Sstevel@tonic-gate pr_watch_emul(rp, vaddr, rw)) 592*0Sstevel@tonic-gate goto out; 593*0Sstevel@tonic-gate do_watch_step(vaddr, sz, rw, 0, 0); 594*0Sstevel@tonic-gate fault_type = F_INVAL; 595*0Sstevel@tonic-gate } 596*0Sstevel@tonic-gate 597*0Sstevel@tonic-gate if (pr_watch_active(p) && 598*0Sstevel@tonic-gate (type == T_WIN_OVERFLOW + T_USER || 599*0Sstevel@tonic-gate type == T_WIN_UNDERFLOW + T_USER || 600*0Sstevel@tonic-gate type == T_SYS_RTT_PAGE + T_USER)) { 601*0Sstevel@tonic-gate int dotwo = (type == T_WIN_UNDERFLOW + T_USER); 602*0Sstevel@tonic-gate if (copy_return_window(dotwo)) 603*0Sstevel@tonic-gate goto out; 604*0Sstevel@tonic-gate fault_type = F_INVAL; 605*0Sstevel@tonic-gate } 606*0Sstevel@tonic-gate 607*0Sstevel@tonic-gate res = pagefault(addr, fault_type, rw, 0); 608*0Sstevel@tonic-gate 609*0Sstevel@tonic-gate /* 610*0Sstevel@tonic-gate * If pagefault succeed, ok. 611*0Sstevel@tonic-gate * Otherwise grow the stack automatically. 612*0Sstevel@tonic-gate */ 613*0Sstevel@tonic-gate if (res == 0 || 614*0Sstevel@tonic-gate (res == FC_NOMAP && 615*0Sstevel@tonic-gate type != T_INSTR_MMU_MISS + T_USER && 616*0Sstevel@tonic-gate addr < p->p_usrstack && 617*0Sstevel@tonic-gate grow(addr))) { 618*0Sstevel@tonic-gate int ismem = prismember(&p->p_fltmask, FLTPAGE); 619*0Sstevel@tonic-gate 620*0Sstevel@tonic-gate /* 621*0Sstevel@tonic-gate * instr_size() is used to get the exact 622*0Sstevel@tonic-gate * address of the fault, instead of the 623*0Sstevel@tonic-gate * page of the fault. Unfortunately it is 624*0Sstevel@tonic-gate * very slow, and this is an important 625*0Sstevel@tonic-gate * code path. Don't call it unless 626*0Sstevel@tonic-gate * correctness is needed. ie. if FLTPAGE 627*0Sstevel@tonic-gate * is set, or we're profiling. 628*0Sstevel@tonic-gate */ 629*0Sstevel@tonic-gate 630*0Sstevel@tonic-gate if (curthread->t_rprof != NULL || ismem) 631*0Sstevel@tonic-gate (void) instr_size(rp, &addr, rw); 632*0Sstevel@tonic-gate 633*0Sstevel@tonic-gate lwp->lwp_lastfault = FLTPAGE; 634*0Sstevel@tonic-gate lwp->lwp_lastfaddr = addr; 635*0Sstevel@tonic-gate 636*0Sstevel@tonic-gate if (ismem) { 637*0Sstevel@tonic-gate bzero(&siginfo, sizeof (siginfo)); 638*0Sstevel@tonic-gate siginfo.si_addr = addr; 639*0Sstevel@tonic-gate (void) stop_on_fault(FLTPAGE, &siginfo); 640*0Sstevel@tonic-gate } 641*0Sstevel@tonic-gate goto out; 642*0Sstevel@tonic-gate } 643*0Sstevel@tonic-gate 644*0Sstevel@tonic-gate if (type != (T_INSTR_MMU_MISS + T_USER)) { 645*0Sstevel@tonic-gate /* 646*0Sstevel@tonic-gate * check for non-faulting loads, also 647*0Sstevel@tonic-gate * fetch the instruction to check for 648*0Sstevel@tonic-gate * flush 649*0Sstevel@tonic-gate */ 650*0Sstevel@tonic-gate if (nfload(rp, &instr)) 651*0Sstevel@tonic-gate goto out; 652*0Sstevel@tonic-gate 653*0Sstevel@tonic-gate /* skip userland prefetch instructions */ 654*0Sstevel@tonic-gate if (IS_PREFETCH(instr)) { 655*0Sstevel@tonic-gate rp->r_pc = rp->r_npc; 656*0Sstevel@tonic-gate rp->r_npc += 4; 657*0Sstevel@tonic-gate goto out; 658*0Sstevel@tonic-gate /*NOTREACHED*/ 659*0Sstevel@tonic-gate } 660*0Sstevel@tonic-gate 661*0Sstevel@tonic-gate /* 662*0Sstevel@tonic-gate * check if the instruction was a 663*0Sstevel@tonic-gate * flush. ABI allows users to specify 664*0Sstevel@tonic-gate * an illegal address on the flush 665*0Sstevel@tonic-gate * instruction so we simply return in 666*0Sstevel@tonic-gate * this case. 667*0Sstevel@tonic-gate * 668*0Sstevel@tonic-gate * NB: the hardware should set a bit 669*0Sstevel@tonic-gate * indicating this trap was caused by 670*0Sstevel@tonic-gate * a flush instruction. Instruction 671*0Sstevel@tonic-gate * decoding is bugly! 672*0Sstevel@tonic-gate */ 673*0Sstevel@tonic-gate if (IS_FLUSH(instr)) { 674*0Sstevel@tonic-gate /* skip the flush instruction */ 675*0Sstevel@tonic-gate rp->r_pc = rp->r_npc; 676*0Sstevel@tonic-gate rp->r_npc += 4; 677*0Sstevel@tonic-gate goto out; 678*0Sstevel@tonic-gate /*NOTREACHED*/ 679*0Sstevel@tonic-gate } 680*0Sstevel@tonic-gate } else if (res == FC_PROT) { 681*0Sstevel@tonic-gate report_stack_exec(p, addr); 682*0Sstevel@tonic-gate } 683*0Sstevel@tonic-gate 684*0Sstevel@tonic-gate if (tudebug) 685*0Sstevel@tonic-gate showregs(type, rp, addr, 0); 686*0Sstevel@tonic-gate } 687*0Sstevel@tonic-gate 688*0Sstevel@tonic-gate /* 689*0Sstevel@tonic-gate * In the case where both pagefault and grow fail, 690*0Sstevel@tonic-gate * set the code to the value provided by pagefault. 691*0Sstevel@tonic-gate */ 692*0Sstevel@tonic-gate (void) instr_size(rp, &addr, rw); 693*0Sstevel@tonic-gate bzero(&siginfo, sizeof (siginfo)); 694*0Sstevel@tonic-gate siginfo.si_addr = addr; 695*0Sstevel@tonic-gate if (FC_CODE(res) == FC_OBJERR) { 696*0Sstevel@tonic-gate siginfo.si_errno = FC_ERRNO(res); 697*0Sstevel@tonic-gate if (siginfo.si_errno != EINTR) { 698*0Sstevel@tonic-gate siginfo.si_signo = SIGBUS; 699*0Sstevel@tonic-gate siginfo.si_code = BUS_OBJERR; 700*0Sstevel@tonic-gate fault = FLTACCESS; 701*0Sstevel@tonic-gate } 702*0Sstevel@tonic-gate } else { /* FC_NOMAP || FC_PROT */ 703*0Sstevel@tonic-gate siginfo.si_signo = SIGSEGV; 704*0Sstevel@tonic-gate siginfo.si_code = (res == FC_NOMAP) ? 705*0Sstevel@tonic-gate SEGV_MAPERR : SEGV_ACCERR; 706*0Sstevel@tonic-gate fault = FLTBOUNDS; 707*0Sstevel@tonic-gate } 708*0Sstevel@tonic-gate /* 709*0Sstevel@tonic-gate * If this is the culmination of a single-step, 710*0Sstevel@tonic-gate * reset the addr, code, signal and fault to 711*0Sstevel@tonic-gate * indicate a hardware trace trap. 712*0Sstevel@tonic-gate */ 713*0Sstevel@tonic-gate if (stepped) { 714*0Sstevel@tonic-gate pcb_t *pcb = &lwp->lwp_pcb; 715*0Sstevel@tonic-gate 716*0Sstevel@tonic-gate siginfo.si_signo = 0; 717*0Sstevel@tonic-gate fault = 0; 718*0Sstevel@tonic-gate if (pcb->pcb_step == STEP_WASACTIVE) { 719*0Sstevel@tonic-gate pcb->pcb_step = STEP_NONE; 720*0Sstevel@tonic-gate pcb->pcb_tracepc = NULL; 721*0Sstevel@tonic-gate oldpc = rp->r_pc - 4; 722*0Sstevel@tonic-gate } 723*0Sstevel@tonic-gate /* 724*0Sstevel@tonic-gate * If both NORMAL_STEP and WATCH_STEP are in 725*0Sstevel@tonic-gate * effect, give precedence to NORMAL_STEP. 726*0Sstevel@tonic-gate * One or the other must be set at this point. 727*0Sstevel@tonic-gate */ 728*0Sstevel@tonic-gate ASSERT(pcb->pcb_flags & (NORMAL_STEP|WATCH_STEP)); 729*0Sstevel@tonic-gate if (pcb->pcb_flags & NORMAL_STEP) { 730*0Sstevel@tonic-gate siginfo.si_signo = SIGTRAP; 731*0Sstevel@tonic-gate siginfo.si_code = TRAP_TRACE; 732*0Sstevel@tonic-gate siginfo.si_addr = (caddr_t)rp->r_pc; 733*0Sstevel@tonic-gate fault = FLTTRACE; 734*0Sstevel@tonic-gate if (pcb->pcb_flags & WATCH_STEP) 735*0Sstevel@tonic-gate (void) undo_watch_step(NULL); 736*0Sstevel@tonic-gate } else { 737*0Sstevel@tonic-gate fault = undo_watch_step(&siginfo); 738*0Sstevel@tonic-gate } 739*0Sstevel@tonic-gate pcb->pcb_flags &= ~(NORMAL_STEP|WATCH_STEP); 740*0Sstevel@tonic-gate } 741*0Sstevel@tonic-gate break; 742*0Sstevel@tonic-gate 743*0Sstevel@tonic-gate case T_DATA_EXCEPTION + T_USER: /* user data access exception */ 744*0Sstevel@tonic-gate 745*0Sstevel@tonic-gate if (&vis1_partial_support != NULL) { 746*0Sstevel@tonic-gate bzero(&siginfo, sizeof (siginfo)); 747*0Sstevel@tonic-gate if (vis1_partial_support(rp, 748*0Sstevel@tonic-gate &siginfo, &fault) == 0) 749*0Sstevel@tonic-gate goto out; 750*0Sstevel@tonic-gate } 751*0Sstevel@tonic-gate 752*0Sstevel@tonic-gate if (nfload(rp, &instr)) 753*0Sstevel@tonic-gate goto out; 754*0Sstevel@tonic-gate if (IS_FLUSH(instr)) { 755*0Sstevel@tonic-gate /* skip the flush instruction */ 756*0Sstevel@tonic-gate rp->r_pc = rp->r_npc; 757*0Sstevel@tonic-gate rp->r_npc += 4; 758*0Sstevel@tonic-gate goto out; 759*0Sstevel@tonic-gate /*NOTREACHED*/ 760*0Sstevel@tonic-gate } 761*0Sstevel@tonic-gate bzero(&siginfo, sizeof (siginfo)); 762*0Sstevel@tonic-gate siginfo.si_addr = addr; 763*0Sstevel@tonic-gate switch (X_FAULT_TYPE(mmu_fsr)) { 764*0Sstevel@tonic-gate case FT_ATOMIC_NC: 765*0Sstevel@tonic-gate if ((IS_SWAP(instr) && swap_nc(rp, instr)) || 766*0Sstevel@tonic-gate (IS_LDSTUB(instr) && ldstub_nc(rp, instr))) { 767*0Sstevel@tonic-gate /* skip the atomic */ 768*0Sstevel@tonic-gate rp->r_pc = rp->r_npc; 769*0Sstevel@tonic-gate rp->r_npc += 4; 770*0Sstevel@tonic-gate goto out; 771*0Sstevel@tonic-gate } 772*0Sstevel@tonic-gate /* fall into ... */ 773*0Sstevel@tonic-gate case FT_PRIV: 774*0Sstevel@tonic-gate siginfo.si_signo = SIGSEGV; 775*0Sstevel@tonic-gate siginfo.si_code = SEGV_ACCERR; 776*0Sstevel@tonic-gate fault = FLTBOUNDS; 777*0Sstevel@tonic-gate break; 778*0Sstevel@tonic-gate case FT_SPEC_LD: 779*0Sstevel@tonic-gate case FT_ILL_ALT: 780*0Sstevel@tonic-gate siginfo.si_signo = SIGILL; 781*0Sstevel@tonic-gate siginfo.si_code = ILL_ILLADR; 782*0Sstevel@tonic-gate fault = FLTILL; 783*0Sstevel@tonic-gate break; 784*0Sstevel@tonic-gate default: 785*0Sstevel@tonic-gate siginfo.si_signo = SIGSEGV; 786*0Sstevel@tonic-gate siginfo.si_code = SEGV_MAPERR; 787*0Sstevel@tonic-gate fault = FLTBOUNDS; 788*0Sstevel@tonic-gate break; 789*0Sstevel@tonic-gate } 790*0Sstevel@tonic-gate break; 791*0Sstevel@tonic-gate 792*0Sstevel@tonic-gate case T_SYS_RTT_ALIGN + T_USER: /* user alignment error */ 793*0Sstevel@tonic-gate case T_ALIGNMENT + T_USER: /* user alignment error */ 794*0Sstevel@tonic-gate if (tudebug) 795*0Sstevel@tonic-gate showregs(type, rp, addr, 0); 796*0Sstevel@tonic-gate /* 797*0Sstevel@tonic-gate * If the user has to do unaligned references 798*0Sstevel@tonic-gate * the ugly stuff gets done here. 799*0Sstevel@tonic-gate */ 800*0Sstevel@tonic-gate alignfaults++; 801*0Sstevel@tonic-gate if (&vis1_partial_support != NULL) { 802*0Sstevel@tonic-gate bzero(&siginfo, sizeof (siginfo)); 803*0Sstevel@tonic-gate if (vis1_partial_support(rp, 804*0Sstevel@tonic-gate &siginfo, &fault) == 0) 805*0Sstevel@tonic-gate goto out; 806*0Sstevel@tonic-gate } 807*0Sstevel@tonic-gate 808*0Sstevel@tonic-gate if (nfload(rp, NULL)) 809*0Sstevel@tonic-gate goto out; 810*0Sstevel@tonic-gate bzero(&siginfo, sizeof (siginfo)); 811*0Sstevel@tonic-gate if (type == T_SYS_RTT_ALIGN + T_USER) { 812*0Sstevel@tonic-gate /* 813*0Sstevel@tonic-gate * Can't do unaligned stack access 814*0Sstevel@tonic-gate */ 815*0Sstevel@tonic-gate siginfo.si_signo = SIGBUS; 816*0Sstevel@tonic-gate siginfo.si_code = BUS_ADRALN; 817*0Sstevel@tonic-gate siginfo.si_addr = addr; 818*0Sstevel@tonic-gate fault = FLTACCESS; 819*0Sstevel@tonic-gate break; 820*0Sstevel@tonic-gate } 821*0Sstevel@tonic-gate if (p->p_fixalignment) { 822*0Sstevel@tonic-gate if (do_unaligned(rp, &badaddr) == SIMU_SUCCESS) { 823*0Sstevel@tonic-gate rp->r_pc = rp->r_npc; 824*0Sstevel@tonic-gate rp->r_npc += 4; 825*0Sstevel@tonic-gate goto out; 826*0Sstevel@tonic-gate } 827*0Sstevel@tonic-gate siginfo.si_signo = SIGSEGV; 828*0Sstevel@tonic-gate siginfo.si_code = SEGV_MAPERR; 829*0Sstevel@tonic-gate siginfo.si_addr = badaddr; 830*0Sstevel@tonic-gate fault = FLTBOUNDS; 831*0Sstevel@tonic-gate } else { 832*0Sstevel@tonic-gate siginfo.si_signo = SIGBUS; 833*0Sstevel@tonic-gate siginfo.si_code = BUS_ADRALN; 834*0Sstevel@tonic-gate if (rp->r_pc & 3) { /* offending address, if pc */ 835*0Sstevel@tonic-gate siginfo.si_addr = (caddr_t)rp->r_pc; 836*0Sstevel@tonic-gate } else { 837*0Sstevel@tonic-gate if (calc_memaddr(rp, &badaddr) == SIMU_UNALIGN) 838*0Sstevel@tonic-gate siginfo.si_addr = badaddr; 839*0Sstevel@tonic-gate else 840*0Sstevel@tonic-gate siginfo.si_addr = (caddr_t)rp->r_pc; 841*0Sstevel@tonic-gate } 842*0Sstevel@tonic-gate fault = FLTACCESS; 843*0Sstevel@tonic-gate } 844*0Sstevel@tonic-gate break; 845*0Sstevel@tonic-gate 846*0Sstevel@tonic-gate case T_PRIV_INSTR + T_USER: /* privileged instruction fault */ 847*0Sstevel@tonic-gate if (tudebug) 848*0Sstevel@tonic-gate showregs(type, rp, (caddr_t)0, 0); 849*0Sstevel@tonic-gate bzero(&siginfo, sizeof (siginfo)); 850*0Sstevel@tonic-gate siginfo.si_signo = SIGILL; 851*0Sstevel@tonic-gate siginfo.si_code = ILL_PRVOPC; 852*0Sstevel@tonic-gate siginfo.si_addr = (caddr_t)rp->r_pc; 853*0Sstevel@tonic-gate fault = FLTILL; 854*0Sstevel@tonic-gate break; 855*0Sstevel@tonic-gate 856*0Sstevel@tonic-gate case T_UNIMP_INSTR: /* priv illegal instruction fault */ 857*0Sstevel@tonic-gate if (fpras_implemented) { 858*0Sstevel@tonic-gate /* 859*0Sstevel@tonic-gate * Call fpras_chktrap indicating that 860*0Sstevel@tonic-gate * we've come from a trap handler and pass 861*0Sstevel@tonic-gate * the regs. That function may choose to panic 862*0Sstevel@tonic-gate * (in which case it won't return) or it may 863*0Sstevel@tonic-gate * determine that a reboot is desired. In the 864*0Sstevel@tonic-gate * latter case it must alter pc/npc to skip 865*0Sstevel@tonic-gate * the illegal instruction and continue at 866*0Sstevel@tonic-gate * a controlled address. 867*0Sstevel@tonic-gate */ 868*0Sstevel@tonic-gate if (&fpras_chktrap) { 869*0Sstevel@tonic-gate if (fpras_chktrap(rp)) 870*0Sstevel@tonic-gate goto cleanup; 871*0Sstevel@tonic-gate } 872*0Sstevel@tonic-gate } 873*0Sstevel@tonic-gate #if defined(SF_ERRATA_23) || defined(SF_ERRATA_30) /* call ... illegal-insn */ 874*0Sstevel@tonic-gate instr = *(int *)rp->r_pc; 875*0Sstevel@tonic-gate if ((instr & 0xc0000000) == 0x40000000) { 876*0Sstevel@tonic-gate long pc; 877*0Sstevel@tonic-gate 878*0Sstevel@tonic-gate rp->r_o7 = (long long)rp->r_pc; 879*0Sstevel@tonic-gate pc = rp->r_pc + ((instr & 0x3fffffff) << 2); 880*0Sstevel@tonic-gate rp->r_pc = rp->r_npc; 881*0Sstevel@tonic-gate rp->r_npc = pc; 882*0Sstevel@tonic-gate ill_calls++; 883*0Sstevel@tonic-gate goto cleanup; 884*0Sstevel@tonic-gate } 885*0Sstevel@tonic-gate #endif /* SF_ERRATA_23 || SF_ERRATA_30 */ 886*0Sstevel@tonic-gate /* 887*0Sstevel@tonic-gate * It's not an fpras failure and it's not SF_ERRATA_23 - die 888*0Sstevel@tonic-gate */ 889*0Sstevel@tonic-gate addr = (caddr_t)rp->r_pc; 890*0Sstevel@tonic-gate (void) die(type, rp, addr, 0); 891*0Sstevel@tonic-gate /*NOTREACHED*/ 892*0Sstevel@tonic-gate 893*0Sstevel@tonic-gate case T_UNIMP_INSTR + T_USER: /* illegal instruction fault */ 894*0Sstevel@tonic-gate #if defined(SF_ERRATA_23) || defined(SF_ERRATA_30) /* call ... illegal-insn */ 895*0Sstevel@tonic-gate instr = fetch_user_instr((caddr_t)rp->r_pc); 896*0Sstevel@tonic-gate if ((instr & 0xc0000000) == 0x40000000) { 897*0Sstevel@tonic-gate long pc; 898*0Sstevel@tonic-gate 899*0Sstevel@tonic-gate rp->r_o7 = (long long)rp->r_pc; 900*0Sstevel@tonic-gate pc = rp->r_pc + ((instr & 0x3fffffff) << 2); 901*0Sstevel@tonic-gate rp->r_pc = rp->r_npc; 902*0Sstevel@tonic-gate rp->r_npc = pc; 903*0Sstevel@tonic-gate ill_calls++; 904*0Sstevel@tonic-gate goto out; 905*0Sstevel@tonic-gate } 906*0Sstevel@tonic-gate #endif /* SF_ERRATA_23 || SF_ERRATA_30 */ 907*0Sstevel@tonic-gate if (tudebug) 908*0Sstevel@tonic-gate showregs(type, rp, (caddr_t)0, 0); 909*0Sstevel@tonic-gate bzero(&siginfo, sizeof (siginfo)); 910*0Sstevel@tonic-gate /* 911*0Sstevel@tonic-gate * Try to simulate the instruction. 912*0Sstevel@tonic-gate */ 913*0Sstevel@tonic-gate switch (simulate_unimp(rp, &badaddr)) { 914*0Sstevel@tonic-gate case SIMU_RETRY: 915*0Sstevel@tonic-gate goto out; /* regs are already set up */ 916*0Sstevel@tonic-gate /*NOTREACHED*/ 917*0Sstevel@tonic-gate 918*0Sstevel@tonic-gate case SIMU_SUCCESS: 919*0Sstevel@tonic-gate /* skip the successfully simulated instruction */ 920*0Sstevel@tonic-gate rp->r_pc = rp->r_npc; 921*0Sstevel@tonic-gate rp->r_npc += 4; 922*0Sstevel@tonic-gate goto out; 923*0Sstevel@tonic-gate /*NOTREACHED*/ 924*0Sstevel@tonic-gate 925*0Sstevel@tonic-gate case SIMU_FAULT: 926*0Sstevel@tonic-gate siginfo.si_signo = SIGSEGV; 927*0Sstevel@tonic-gate siginfo.si_code = SEGV_MAPERR; 928*0Sstevel@tonic-gate siginfo.si_addr = badaddr; 929*0Sstevel@tonic-gate fault = FLTBOUNDS; 930*0Sstevel@tonic-gate break; 931*0Sstevel@tonic-gate 932*0Sstevel@tonic-gate case SIMU_DZERO: 933*0Sstevel@tonic-gate siginfo.si_signo = SIGFPE; 934*0Sstevel@tonic-gate siginfo.si_code = FPE_INTDIV; 935*0Sstevel@tonic-gate siginfo.si_addr = (caddr_t)rp->r_pc; 936*0Sstevel@tonic-gate fault = FLTIZDIV; 937*0Sstevel@tonic-gate break; 938*0Sstevel@tonic-gate 939*0Sstevel@tonic-gate case SIMU_UNALIGN: 940*0Sstevel@tonic-gate siginfo.si_signo = SIGBUS; 941*0Sstevel@tonic-gate siginfo.si_code = BUS_ADRALN; 942*0Sstevel@tonic-gate siginfo.si_addr = badaddr; 943*0Sstevel@tonic-gate fault = FLTACCESS; 944*0Sstevel@tonic-gate break; 945*0Sstevel@tonic-gate 946*0Sstevel@tonic-gate case SIMU_ILLEGAL: 947*0Sstevel@tonic-gate default: 948*0Sstevel@tonic-gate siginfo.si_signo = SIGILL; 949*0Sstevel@tonic-gate op3 = (instr >> 19) & 0x3F; 950*0Sstevel@tonic-gate if ((IS_FLOAT(instr) && (op3 == IOP_V8_STQFA) || 951*0Sstevel@tonic-gate (op3 == IOP_V8_STDFA))) 952*0Sstevel@tonic-gate siginfo.si_code = ILL_ILLADR; 953*0Sstevel@tonic-gate else 954*0Sstevel@tonic-gate siginfo.si_code = ILL_ILLOPC; 955*0Sstevel@tonic-gate siginfo.si_addr = (caddr_t)rp->r_pc; 956*0Sstevel@tonic-gate fault = FLTILL; 957*0Sstevel@tonic-gate break; 958*0Sstevel@tonic-gate } 959*0Sstevel@tonic-gate break; 960*0Sstevel@tonic-gate 961*0Sstevel@tonic-gate case T_IDIV0 + T_USER: /* integer divide by zero */ 962*0Sstevel@tonic-gate case T_DIV0 + T_USER: /* integer divide by zero */ 963*0Sstevel@tonic-gate if (tudebug && tudebugfpe) 964*0Sstevel@tonic-gate showregs(type, rp, (caddr_t)0, 0); 965*0Sstevel@tonic-gate bzero(&siginfo, sizeof (siginfo)); 966*0Sstevel@tonic-gate siginfo.si_signo = SIGFPE; 967*0Sstevel@tonic-gate siginfo.si_code = FPE_INTDIV; 968*0Sstevel@tonic-gate siginfo.si_addr = (caddr_t)rp->r_pc; 969*0Sstevel@tonic-gate fault = FLTIZDIV; 970*0Sstevel@tonic-gate break; 971*0Sstevel@tonic-gate 972*0Sstevel@tonic-gate case T_INT_OVERFLOW + T_USER: /* integer overflow */ 973*0Sstevel@tonic-gate if (tudebug && tudebugfpe) 974*0Sstevel@tonic-gate showregs(type, rp, (caddr_t)0, 0); 975*0Sstevel@tonic-gate bzero(&siginfo, sizeof (siginfo)); 976*0Sstevel@tonic-gate siginfo.si_signo = SIGFPE; 977*0Sstevel@tonic-gate siginfo.si_code = FPE_INTOVF; 978*0Sstevel@tonic-gate siginfo.si_addr = (caddr_t)rp->r_pc; 979*0Sstevel@tonic-gate fault = FLTIOVF; 980*0Sstevel@tonic-gate break; 981*0Sstevel@tonic-gate 982*0Sstevel@tonic-gate case T_BREAKPOINT + T_USER: /* breakpoint trap (t 1) */ 983*0Sstevel@tonic-gate if (tudebug && tudebugbpt) 984*0Sstevel@tonic-gate showregs(type, rp, (caddr_t)0, 0); 985*0Sstevel@tonic-gate bzero(&siginfo, sizeof (siginfo)); 986*0Sstevel@tonic-gate siginfo.si_signo = SIGTRAP; 987*0Sstevel@tonic-gate siginfo.si_code = TRAP_BRKPT; 988*0Sstevel@tonic-gate siginfo.si_addr = (caddr_t)rp->r_pc; 989*0Sstevel@tonic-gate fault = FLTBPT; 990*0Sstevel@tonic-gate break; 991*0Sstevel@tonic-gate 992*0Sstevel@tonic-gate case T_TAG_OVERFLOW + T_USER: /* tag overflow (taddcctv, tsubcctv) */ 993*0Sstevel@tonic-gate if (tudebug) 994*0Sstevel@tonic-gate showregs(type, rp, (caddr_t)0, 0); 995*0Sstevel@tonic-gate bzero(&siginfo, sizeof (siginfo)); 996*0Sstevel@tonic-gate siginfo.si_signo = SIGEMT; 997*0Sstevel@tonic-gate siginfo.si_code = EMT_TAGOVF; 998*0Sstevel@tonic-gate siginfo.si_addr = (caddr_t)rp->r_pc; 999*0Sstevel@tonic-gate fault = FLTACCESS; 1000*0Sstevel@tonic-gate break; 1001*0Sstevel@tonic-gate 1002*0Sstevel@tonic-gate case T_FLUSH_PCB + T_USER: /* finish user window overflow */ 1003*0Sstevel@tonic-gate case T_FLUSHW + T_USER: /* finish user window flush */ 1004*0Sstevel@tonic-gate /* 1005*0Sstevel@tonic-gate * This trap is entered from sys_rtt in locore.s when, 1006*0Sstevel@tonic-gate * upon return to user is is found that there are user 1007*0Sstevel@tonic-gate * windows in pcb_wbuf. This happens because they could 1008*0Sstevel@tonic-gate * not be saved on the user stack, either because it 1009*0Sstevel@tonic-gate * wasn't resident or because it was misaligned. 1010*0Sstevel@tonic-gate */ 1011*0Sstevel@tonic-gate { 1012*0Sstevel@tonic-gate int error; 1013*0Sstevel@tonic-gate caddr_t sp; 1014*0Sstevel@tonic-gate 1015*0Sstevel@tonic-gate error = flush_user_windows_to_stack(&sp); 1016*0Sstevel@tonic-gate /* 1017*0Sstevel@tonic-gate * Possible errors: 1018*0Sstevel@tonic-gate * error copying out 1019*0Sstevel@tonic-gate * unaligned stack pointer 1020*0Sstevel@tonic-gate * The first is given to us as the return value 1021*0Sstevel@tonic-gate * from flush_user_windows_to_stack(). The second 1022*0Sstevel@tonic-gate * results in residual windows in the pcb. 1023*0Sstevel@tonic-gate */ 1024*0Sstevel@tonic-gate if (error != 0) { 1025*0Sstevel@tonic-gate /* 1026*0Sstevel@tonic-gate * EINTR comes from a signal during copyout; 1027*0Sstevel@tonic-gate * we should not post another signal. 1028*0Sstevel@tonic-gate */ 1029*0Sstevel@tonic-gate if (error != EINTR) { 1030*0Sstevel@tonic-gate /* 1031*0Sstevel@tonic-gate * Zap the process with a SIGSEGV - process 1032*0Sstevel@tonic-gate * may be managing its own stack growth by 1033*0Sstevel@tonic-gate * taking SIGSEGVs on a different signal stack. 1034*0Sstevel@tonic-gate */ 1035*0Sstevel@tonic-gate bzero(&siginfo, sizeof (siginfo)); 1036*0Sstevel@tonic-gate siginfo.si_signo = SIGSEGV; 1037*0Sstevel@tonic-gate siginfo.si_code = SEGV_MAPERR; 1038*0Sstevel@tonic-gate siginfo.si_addr = sp; 1039*0Sstevel@tonic-gate fault = FLTBOUNDS; 1040*0Sstevel@tonic-gate } 1041*0Sstevel@tonic-gate break; 1042*0Sstevel@tonic-gate } else if (mpcb->mpcb_wbcnt) { 1043*0Sstevel@tonic-gate bzero(&siginfo, sizeof (siginfo)); 1044*0Sstevel@tonic-gate siginfo.si_signo = SIGILL; 1045*0Sstevel@tonic-gate siginfo.si_code = ILL_BADSTK; 1046*0Sstevel@tonic-gate siginfo.si_addr = (caddr_t)rp->r_pc; 1047*0Sstevel@tonic-gate fault = FLTILL; 1048*0Sstevel@tonic-gate break; 1049*0Sstevel@tonic-gate } 1050*0Sstevel@tonic-gate } 1051*0Sstevel@tonic-gate 1052*0Sstevel@tonic-gate /* 1053*0Sstevel@tonic-gate * T_FLUSHW is used when handling a ta 0x3 -- the old flush 1054*0Sstevel@tonic-gate * window trap -- which is implemented by executing the 1055*0Sstevel@tonic-gate * flushw instruction. The flushw can trap if any of the 1056*0Sstevel@tonic-gate * stack pages are not writable for whatever reason. In this 1057*0Sstevel@tonic-gate * case only, we advance the pc to the next instruction so 1058*0Sstevel@tonic-gate * that the user thread doesn't needlessly execute the trap 1059*0Sstevel@tonic-gate * again. Normally this wouldn't be a problem -- we'll 1060*0Sstevel@tonic-gate * usually only end up here if this is the first touch to a 1061*0Sstevel@tonic-gate * stack page -- since the second execution won't trap, but 1062*0Sstevel@tonic-gate * if there's a watchpoint on the stack page the user thread 1063*0Sstevel@tonic-gate * would spin, continuously executing the trap instruction. 1064*0Sstevel@tonic-gate */ 1065*0Sstevel@tonic-gate if (type == T_FLUSHW + T_USER) { 1066*0Sstevel@tonic-gate rp->r_pc = rp->r_npc; 1067*0Sstevel@tonic-gate rp->r_npc += 4; 1068*0Sstevel@tonic-gate } 1069*0Sstevel@tonic-gate goto out; 1070*0Sstevel@tonic-gate 1071*0Sstevel@tonic-gate case T_AST + T_USER: /* profiling or resched pseudo trap */ 1072*0Sstevel@tonic-gate if (lwp->lwp_pcb.pcb_flags & CPC_OVERFLOW) { 1073*0Sstevel@tonic-gate lwp->lwp_pcb.pcb_flags &= ~CPC_OVERFLOW; 1074*0Sstevel@tonic-gate if (kcpc_overflow_ast()) { 1075*0Sstevel@tonic-gate /* 1076*0Sstevel@tonic-gate * Signal performance counter overflow 1077*0Sstevel@tonic-gate */ 1078*0Sstevel@tonic-gate if (tudebug) 1079*0Sstevel@tonic-gate showregs(type, rp, (caddr_t)0, 0); 1080*0Sstevel@tonic-gate bzero(&siginfo, sizeof (siginfo)); 1081*0Sstevel@tonic-gate siginfo.si_signo = SIGEMT; 1082*0Sstevel@tonic-gate siginfo.si_code = EMT_CPCOVF; 1083*0Sstevel@tonic-gate siginfo.si_addr = (caddr_t)rp->r_pc; 1084*0Sstevel@tonic-gate /* for trap_cleanup(), below */ 1085*0Sstevel@tonic-gate oldpc = rp->r_pc - 4; 1086*0Sstevel@tonic-gate fault = FLTCPCOVF; 1087*0Sstevel@tonic-gate } 1088*0Sstevel@tonic-gate } 1089*0Sstevel@tonic-gate 1090*0Sstevel@tonic-gate /* 1091*0Sstevel@tonic-gate * The CPC_OVERFLOW check above may already have populated 1092*0Sstevel@tonic-gate * siginfo and set fault, so the checks below must not 1093*0Sstevel@tonic-gate * touch these and the functions they call must use 1094*0Sstevel@tonic-gate * trapsig() directly. 1095*0Sstevel@tonic-gate */ 1096*0Sstevel@tonic-gate 1097*0Sstevel@tonic-gate if (lwp->lwp_pcb.pcb_flags & ASYNC_HWERR) { 1098*0Sstevel@tonic-gate lwp->lwp_pcb.pcb_flags &= ~ASYNC_HWERR; 1099*0Sstevel@tonic-gate trap_async_hwerr(); 1100*0Sstevel@tonic-gate } 1101*0Sstevel@tonic-gate 1102*0Sstevel@tonic-gate if (lwp->lwp_pcb.pcb_flags & ASYNC_BERR) { 1103*0Sstevel@tonic-gate lwp->lwp_pcb.pcb_flags &= ~ASYNC_BERR; 1104*0Sstevel@tonic-gate trap_async_berr_bto(ASYNC_BERR, rp); 1105*0Sstevel@tonic-gate } 1106*0Sstevel@tonic-gate 1107*0Sstevel@tonic-gate if (lwp->lwp_pcb.pcb_flags & ASYNC_BTO) { 1108*0Sstevel@tonic-gate lwp->lwp_pcb.pcb_flags &= ~ASYNC_BTO; 1109*0Sstevel@tonic-gate trap_async_berr_bto(ASYNC_BTO, rp); 1110*0Sstevel@tonic-gate } 1111*0Sstevel@tonic-gate 1112*0Sstevel@tonic-gate break; 1113*0Sstevel@tonic-gate } 1114*0Sstevel@tonic-gate 1115*0Sstevel@tonic-gate trap_cleanup(rp, fault, &siginfo, oldpc == rp->r_pc); 1116*0Sstevel@tonic-gate 1117*0Sstevel@tonic-gate out: /* We can't get here from a system trap */ 1118*0Sstevel@tonic-gate ASSERT(type & T_USER); 1119*0Sstevel@tonic-gate trap_rtt(); 1120*0Sstevel@tonic-gate (void) new_mstate(curthread, mstate); 1121*0Sstevel@tonic-gate /* Kernel probe */ 1122*0Sstevel@tonic-gate TNF_PROBE_1(thread_state, "thread", /* CSTYLED */, 1123*0Sstevel@tonic-gate tnf_microstate, state, LMS_USER); 1124*0Sstevel@tonic-gate 1125*0Sstevel@tonic-gate TRACE_0(TR_FAC_TRAP, TR_C_TRAP_HANDLER_EXIT, "C_trap_handler_exit"); 1126*0Sstevel@tonic-gate return; 1127*0Sstevel@tonic-gate 1128*0Sstevel@tonic-gate cleanup: /* system traps end up here */ 1129*0Sstevel@tonic-gate ASSERT(!(type & T_USER)); 1130*0Sstevel@tonic-gate 1131*0Sstevel@tonic-gate TRACE_0(TR_FAC_TRAP, TR_C_TRAP_HANDLER_EXIT, "C_trap_handler_exit"); 1132*0Sstevel@tonic-gate } 1133*0Sstevel@tonic-gate 1134*0Sstevel@tonic-gate void 1135*0Sstevel@tonic-gate trap_cleanup( 1136*0Sstevel@tonic-gate struct regs *rp, 1137*0Sstevel@tonic-gate uint_t fault, 1138*0Sstevel@tonic-gate k_siginfo_t *sip, 1139*0Sstevel@tonic-gate int restartable) 1140*0Sstevel@tonic-gate { 1141*0Sstevel@tonic-gate extern void aio_cleanup(); 1142*0Sstevel@tonic-gate proc_t *p = ttoproc(curthread); 1143*0Sstevel@tonic-gate klwp_id_t lwp = ttolwp(curthread); 1144*0Sstevel@tonic-gate 1145*0Sstevel@tonic-gate if (fault) { 1146*0Sstevel@tonic-gate /* 1147*0Sstevel@tonic-gate * Remember the fault and fault address 1148*0Sstevel@tonic-gate * for real-time (SIGPROF) profiling. 1149*0Sstevel@tonic-gate */ 1150*0Sstevel@tonic-gate lwp->lwp_lastfault = fault; 1151*0Sstevel@tonic-gate lwp->lwp_lastfaddr = sip->si_addr; 1152*0Sstevel@tonic-gate 1153*0Sstevel@tonic-gate DTRACE_PROC2(fault, int, fault, ksiginfo_t *, sip); 1154*0Sstevel@tonic-gate 1155*0Sstevel@tonic-gate /* 1156*0Sstevel@tonic-gate * If a debugger has declared this fault to be an 1157*0Sstevel@tonic-gate * event of interest, stop the lwp. Otherwise just 1158*0Sstevel@tonic-gate * deliver the associated signal. 1159*0Sstevel@tonic-gate */ 1160*0Sstevel@tonic-gate if (sip->si_signo != SIGKILL && 1161*0Sstevel@tonic-gate prismember(&p->p_fltmask, fault) && 1162*0Sstevel@tonic-gate stop_on_fault(fault, sip) == 0) 1163*0Sstevel@tonic-gate sip->si_signo = 0; 1164*0Sstevel@tonic-gate } 1165*0Sstevel@tonic-gate 1166*0Sstevel@tonic-gate if (sip->si_signo) 1167*0Sstevel@tonic-gate trapsig(sip, restartable); 1168*0Sstevel@tonic-gate 1169*0Sstevel@tonic-gate if (lwp->lwp_oweupc) 1170*0Sstevel@tonic-gate profil_tick(rp->r_pc); 1171*0Sstevel@tonic-gate 1172*0Sstevel@tonic-gate if (curthread->t_astflag | curthread->t_sig_check) { 1173*0Sstevel@tonic-gate /* 1174*0Sstevel@tonic-gate * Turn off the AST flag before checking all the conditions that 1175*0Sstevel@tonic-gate * may have caused an AST. This flag is on whenever a signal or 1176*0Sstevel@tonic-gate * unusual condition should be handled after the next trap or 1177*0Sstevel@tonic-gate * syscall. 1178*0Sstevel@tonic-gate */ 1179*0Sstevel@tonic-gate astoff(curthread); 1180*0Sstevel@tonic-gate curthread->t_sig_check = 0; 1181*0Sstevel@tonic-gate 1182*0Sstevel@tonic-gate mutex_enter(&p->p_lock); 1183*0Sstevel@tonic-gate if (curthread->t_proc_flag & TP_CHANGEBIND) { 1184*0Sstevel@tonic-gate timer_lwpbind(); 1185*0Sstevel@tonic-gate curthread->t_proc_flag &= ~TP_CHANGEBIND; 1186*0Sstevel@tonic-gate } 1187*0Sstevel@tonic-gate mutex_exit(&p->p_lock); 1188*0Sstevel@tonic-gate 1189*0Sstevel@tonic-gate /* 1190*0Sstevel@tonic-gate * for kaio requests that are on the per-process poll queue, 1191*0Sstevel@tonic-gate * aiop->aio_pollq, they're AIO_POLL bit is set, the kernel 1192*0Sstevel@tonic-gate * should copyout their result_t to user memory. by copying 1193*0Sstevel@tonic-gate * out the result_t, the user can poll on memory waiting 1194*0Sstevel@tonic-gate * for the kaio request to complete. 1195*0Sstevel@tonic-gate */ 1196*0Sstevel@tonic-gate if (p->p_aio) 1197*0Sstevel@tonic-gate aio_cleanup(0); 1198*0Sstevel@tonic-gate 1199*0Sstevel@tonic-gate /* 1200*0Sstevel@tonic-gate * If this LWP was asked to hold, call holdlwp(), which will 1201*0Sstevel@tonic-gate * stop. holdlwps() sets this up and calls pokelwps() which 1202*0Sstevel@tonic-gate * sets the AST flag. 1203*0Sstevel@tonic-gate * 1204*0Sstevel@tonic-gate * Also check TP_EXITLWP, since this is used by fresh new LWPs 1205*0Sstevel@tonic-gate * through lwp_rtt(). That flag is set if the lwp_create(2) 1206*0Sstevel@tonic-gate * syscall failed after creating the LWP. 1207*0Sstevel@tonic-gate */ 1208*0Sstevel@tonic-gate if (ISHOLD(p)) 1209*0Sstevel@tonic-gate holdlwp(); 1210*0Sstevel@tonic-gate 1211*0Sstevel@tonic-gate /* 1212*0Sstevel@tonic-gate * All code that sets signals and makes ISSIG evaluate true must 1213*0Sstevel@tonic-gate * set t_astflag afterwards. 1214*0Sstevel@tonic-gate */ 1215*0Sstevel@tonic-gate if (ISSIG_PENDING(curthread, lwp, p)) { 1216*0Sstevel@tonic-gate if (issig(FORREAL)) 1217*0Sstevel@tonic-gate psig(); 1218*0Sstevel@tonic-gate curthread->t_sig_check = 1; 1219*0Sstevel@tonic-gate } 1220*0Sstevel@tonic-gate 1221*0Sstevel@tonic-gate if (curthread->t_rprof != NULL) { 1222*0Sstevel@tonic-gate realsigprof(0, 0); 1223*0Sstevel@tonic-gate curthread->t_sig_check = 1; 1224*0Sstevel@tonic-gate } 1225*0Sstevel@tonic-gate } 1226*0Sstevel@tonic-gate } 1227*0Sstevel@tonic-gate 1228*0Sstevel@tonic-gate /* 1229*0Sstevel@tonic-gate * Called from fp_traps when a floating point trap occurs. 1230*0Sstevel@tonic-gate * Note that the T_DATA_EXCEPTION case does not use X_FAULT_TYPE(mmu_fsr), 1231*0Sstevel@tonic-gate * because mmu_fsr (now changed to code) is always 0. 1232*0Sstevel@tonic-gate * Note that the T_UNIMP_INSTR case does not call simulate_unimp(), 1233*0Sstevel@tonic-gate * because the simulator only simulates multiply and divide instructions, 1234*0Sstevel@tonic-gate * which would not cause floating point traps in the first place. 1235*0Sstevel@tonic-gate * XXX - Supervisor mode floating point traps? 1236*0Sstevel@tonic-gate */ 1237*0Sstevel@tonic-gate void 1238*0Sstevel@tonic-gate fpu_trap(struct regs *rp, caddr_t addr, uint32_t type, uint32_t code) 1239*0Sstevel@tonic-gate { 1240*0Sstevel@tonic-gate proc_t *p = ttoproc(curthread); 1241*0Sstevel@tonic-gate klwp_id_t lwp = ttolwp(curthread); 1242*0Sstevel@tonic-gate k_siginfo_t siginfo; 1243*0Sstevel@tonic-gate uint_t op3, fault = 0; 1244*0Sstevel@tonic-gate int mstate; 1245*0Sstevel@tonic-gate char *badaddr; 1246*0Sstevel@tonic-gate kfpu_t *fp; 1247*0Sstevel@tonic-gate struct fpq *pfpq; 1248*0Sstevel@tonic-gate uint32_t inst; 1249*0Sstevel@tonic-gate utrap_handler_t *utrapp; 1250*0Sstevel@tonic-gate 1251*0Sstevel@tonic-gate CPU_STATS_ADDQ(CPU, sys, trap, 1); 1252*0Sstevel@tonic-gate 1253*0Sstevel@tonic-gate ASSERT(curthread->t_schedflag & TS_DONT_SWAP); 1254*0Sstevel@tonic-gate 1255*0Sstevel@tonic-gate if (USERMODE(rp->r_tstate)) { 1256*0Sstevel@tonic-gate /* 1257*0Sstevel@tonic-gate * Set lwp_state before trying to acquire any 1258*0Sstevel@tonic-gate * adaptive lock 1259*0Sstevel@tonic-gate */ 1260*0Sstevel@tonic-gate ASSERT(lwp != NULL); 1261*0Sstevel@tonic-gate lwp->lwp_state = LWP_SYS; 1262*0Sstevel@tonic-gate /* 1263*0Sstevel@tonic-gate * Set up the current cred to use during this trap. u_cred 1264*0Sstevel@tonic-gate * no longer exists. t_cred is used instead. 1265*0Sstevel@tonic-gate * The current process credential applies to the thread for 1266*0Sstevel@tonic-gate * the entire trap. If trapping from the kernel, this 1267*0Sstevel@tonic-gate * should already be set up. 1268*0Sstevel@tonic-gate */ 1269*0Sstevel@tonic-gate if (curthread->t_cred != p->p_cred) { 1270*0Sstevel@tonic-gate cred_t *oldcred = curthread->t_cred; 1271*0Sstevel@tonic-gate /* 1272*0Sstevel@tonic-gate * DTrace accesses t_cred in probe context. t_cred 1273*0Sstevel@tonic-gate * must always be either NULL, or point to a valid, 1274*0Sstevel@tonic-gate * allocated cred structure. 1275*0Sstevel@tonic-gate */ 1276*0Sstevel@tonic-gate curthread->t_cred = crgetcred(); 1277*0Sstevel@tonic-gate crfree(oldcred); 1278*0Sstevel@tonic-gate } 1279*0Sstevel@tonic-gate ASSERT(lwp->lwp_regs == rp); 1280*0Sstevel@tonic-gate mstate = new_mstate(curthread, LMS_TRAP); 1281*0Sstevel@tonic-gate siginfo.si_signo = 0; 1282*0Sstevel@tonic-gate type |= T_USER; 1283*0Sstevel@tonic-gate } 1284*0Sstevel@tonic-gate 1285*0Sstevel@tonic-gate TRACE_1(TR_FAC_TRAP, TR_C_TRAP_HANDLER_ENTER, 1286*0Sstevel@tonic-gate "C_fpu_trap_handler_enter:type %x", type); 1287*0Sstevel@tonic-gate 1288*0Sstevel@tonic-gate if (tudebug && tudebugfpe) 1289*0Sstevel@tonic-gate showregs(type, rp, addr, 0); 1290*0Sstevel@tonic-gate 1291*0Sstevel@tonic-gate bzero(&siginfo, sizeof (siginfo)); 1292*0Sstevel@tonic-gate siginfo.si_code = code; 1293*0Sstevel@tonic-gate siginfo.si_addr = addr; 1294*0Sstevel@tonic-gate 1295*0Sstevel@tonic-gate switch (type) { 1296*0Sstevel@tonic-gate 1297*0Sstevel@tonic-gate case T_FP_EXCEPTION_IEEE + T_USER: /* FPU arithmetic exception */ 1298*0Sstevel@tonic-gate /* 1299*0Sstevel@tonic-gate * FPU arithmetic exception - fake up a fpq if we 1300*0Sstevel@tonic-gate * came here directly from _fp_ieee_exception, 1301*0Sstevel@tonic-gate * which is indicated by a zero fpu_qcnt. 1302*0Sstevel@tonic-gate */ 1303*0Sstevel@tonic-gate fp = lwptofpu(curthread->t_lwp); 1304*0Sstevel@tonic-gate utrapp = curthread->t_procp->p_utraps; 1305*0Sstevel@tonic-gate if (fp->fpu_qcnt == 0) { 1306*0Sstevel@tonic-gate inst = fetch_user_instr((caddr_t)rp->r_pc); 1307*0Sstevel@tonic-gate lwp->lwp_state = LWP_SYS; 1308*0Sstevel@tonic-gate pfpq = &fp->fpu_q->FQu.fpq; 1309*0Sstevel@tonic-gate pfpq->fpq_addr = (uint32_t *)rp->r_pc; 1310*0Sstevel@tonic-gate pfpq->fpq_instr = inst; 1311*0Sstevel@tonic-gate fp->fpu_qcnt = 1; 1312*0Sstevel@tonic-gate fp->fpu_q_entrysize = sizeof (struct fpq); 1313*0Sstevel@tonic-gate #ifdef SF_V9_TABLE_28 1314*0Sstevel@tonic-gate /* 1315*0Sstevel@tonic-gate * Spitfire and blackbird followed the SPARC V9 manual 1316*0Sstevel@tonic-gate * paragraph 3 of section 5.1.7.9 FSR_current_exception 1317*0Sstevel@tonic-gate * (cexc) for setting fsr.cexc bits on underflow and 1318*0Sstevel@tonic-gate * overflow traps when the fsr.tem.inexact bit is set, 1319*0Sstevel@tonic-gate * instead of following Table 28. Bugid 1263234. 1320*0Sstevel@tonic-gate */ 1321*0Sstevel@tonic-gate { 1322*0Sstevel@tonic-gate extern int spitfire_bb_fsr_bug; 1323*0Sstevel@tonic-gate 1324*0Sstevel@tonic-gate if (spitfire_bb_fsr_bug && 1325*0Sstevel@tonic-gate (fp->fpu_fsr & FSR_TEM_NX)) { 1326*0Sstevel@tonic-gate if (((fp->fpu_fsr & FSR_TEM_OF) == 0) && 1327*0Sstevel@tonic-gate (fp->fpu_fsr & FSR_CEXC_OF)) { 1328*0Sstevel@tonic-gate fp->fpu_fsr &= ~FSR_CEXC_OF; 1329*0Sstevel@tonic-gate fp->fpu_fsr |= FSR_CEXC_NX; 1330*0Sstevel@tonic-gate _fp_write_pfsr(&fp->fpu_fsr); 1331*0Sstevel@tonic-gate siginfo.si_code = FPE_FLTRES; 1332*0Sstevel@tonic-gate } 1333*0Sstevel@tonic-gate if (((fp->fpu_fsr & FSR_TEM_UF) == 0) && 1334*0Sstevel@tonic-gate (fp->fpu_fsr & FSR_CEXC_UF)) { 1335*0Sstevel@tonic-gate fp->fpu_fsr &= ~FSR_CEXC_UF; 1336*0Sstevel@tonic-gate fp->fpu_fsr |= FSR_CEXC_NX; 1337*0Sstevel@tonic-gate _fp_write_pfsr(&fp->fpu_fsr); 1338*0Sstevel@tonic-gate siginfo.si_code = FPE_FLTRES; 1339*0Sstevel@tonic-gate } 1340*0Sstevel@tonic-gate } 1341*0Sstevel@tonic-gate } 1342*0Sstevel@tonic-gate #endif /* SF_V9_TABLE_28 */ 1343*0Sstevel@tonic-gate rp->r_pc = rp->r_npc; 1344*0Sstevel@tonic-gate rp->r_npc += 4; 1345*0Sstevel@tonic-gate } else if (utrapp && utrapp[UT_FP_EXCEPTION_IEEE_754]) { 1346*0Sstevel@tonic-gate /* 1347*0Sstevel@tonic-gate * The user had a trap handler installed. Jump to 1348*0Sstevel@tonic-gate * the trap handler instead of signalling the process. 1349*0Sstevel@tonic-gate */ 1350*0Sstevel@tonic-gate rp->r_pc = (long)utrapp[UT_FP_EXCEPTION_IEEE_754]; 1351*0Sstevel@tonic-gate rp->r_npc = rp->r_pc + 4; 1352*0Sstevel@tonic-gate break; 1353*0Sstevel@tonic-gate } 1354*0Sstevel@tonic-gate siginfo.si_signo = SIGFPE; 1355*0Sstevel@tonic-gate fault = FLTFPE; 1356*0Sstevel@tonic-gate break; 1357*0Sstevel@tonic-gate 1358*0Sstevel@tonic-gate case T_DATA_EXCEPTION + T_USER: /* user data access exception */ 1359*0Sstevel@tonic-gate siginfo.si_signo = SIGSEGV; 1360*0Sstevel@tonic-gate fault = FLTBOUNDS; 1361*0Sstevel@tonic-gate break; 1362*0Sstevel@tonic-gate 1363*0Sstevel@tonic-gate case T_LDDF_ALIGN + T_USER: /* 64 bit user lddfa alignment error */ 1364*0Sstevel@tonic-gate case T_STDF_ALIGN + T_USER: /* 64 bit user stdfa alignment error */ 1365*0Sstevel@tonic-gate alignfaults++; 1366*0Sstevel@tonic-gate lwp->lwp_state = LWP_SYS; 1367*0Sstevel@tonic-gate if (do_unaligned(rp, &badaddr) == SIMU_SUCCESS) { 1368*0Sstevel@tonic-gate rp->r_pc = rp->r_npc; 1369*0Sstevel@tonic-gate rp->r_npc += 4; 1370*0Sstevel@tonic-gate goto out; 1371*0Sstevel@tonic-gate } 1372*0Sstevel@tonic-gate fp = lwptofpu(curthread->t_lwp); 1373*0Sstevel@tonic-gate fp->fpu_qcnt = 0; 1374*0Sstevel@tonic-gate siginfo.si_signo = SIGSEGV; 1375*0Sstevel@tonic-gate siginfo.si_code = SEGV_MAPERR; 1376*0Sstevel@tonic-gate siginfo.si_addr = badaddr; 1377*0Sstevel@tonic-gate fault = FLTBOUNDS; 1378*0Sstevel@tonic-gate break; 1379*0Sstevel@tonic-gate 1380*0Sstevel@tonic-gate case T_ALIGNMENT + T_USER: /* user alignment error */ 1381*0Sstevel@tonic-gate /* 1382*0Sstevel@tonic-gate * If the user has to do unaligned references 1383*0Sstevel@tonic-gate * the ugly stuff gets done here. 1384*0Sstevel@tonic-gate * Only handles vanilla loads and stores. 1385*0Sstevel@tonic-gate */ 1386*0Sstevel@tonic-gate alignfaults++; 1387*0Sstevel@tonic-gate if (p->p_fixalignment) { 1388*0Sstevel@tonic-gate if (do_unaligned(rp, &badaddr) == SIMU_SUCCESS) { 1389*0Sstevel@tonic-gate rp->r_pc = rp->r_npc; 1390*0Sstevel@tonic-gate rp->r_npc += 4; 1391*0Sstevel@tonic-gate goto out; 1392*0Sstevel@tonic-gate } 1393*0Sstevel@tonic-gate siginfo.si_signo = SIGSEGV; 1394*0Sstevel@tonic-gate siginfo.si_code = SEGV_MAPERR; 1395*0Sstevel@tonic-gate siginfo.si_addr = badaddr; 1396*0Sstevel@tonic-gate fault = FLTBOUNDS; 1397*0Sstevel@tonic-gate } else { 1398*0Sstevel@tonic-gate siginfo.si_signo = SIGBUS; 1399*0Sstevel@tonic-gate siginfo.si_code = BUS_ADRALN; 1400*0Sstevel@tonic-gate if (rp->r_pc & 3) { /* offending address, if pc */ 1401*0Sstevel@tonic-gate siginfo.si_addr = (caddr_t)rp->r_pc; 1402*0Sstevel@tonic-gate } else { 1403*0Sstevel@tonic-gate if (calc_memaddr(rp, &badaddr) == SIMU_UNALIGN) 1404*0Sstevel@tonic-gate siginfo.si_addr = badaddr; 1405*0Sstevel@tonic-gate else 1406*0Sstevel@tonic-gate siginfo.si_addr = (caddr_t)rp->r_pc; 1407*0Sstevel@tonic-gate } 1408*0Sstevel@tonic-gate fault = FLTACCESS; 1409*0Sstevel@tonic-gate } 1410*0Sstevel@tonic-gate break; 1411*0Sstevel@tonic-gate 1412*0Sstevel@tonic-gate case T_UNIMP_INSTR + T_USER: /* illegal instruction fault */ 1413*0Sstevel@tonic-gate siginfo.si_signo = SIGILL; 1414*0Sstevel@tonic-gate inst = fetch_user_instr((caddr_t)rp->r_pc); 1415*0Sstevel@tonic-gate op3 = (inst >> 19) & 0x3F; 1416*0Sstevel@tonic-gate if ((op3 == IOP_V8_STQFA) || (op3 == IOP_V8_STDFA)) 1417*0Sstevel@tonic-gate siginfo.si_code = ILL_ILLADR; 1418*0Sstevel@tonic-gate else 1419*0Sstevel@tonic-gate siginfo.si_code = ILL_ILLTRP; 1420*0Sstevel@tonic-gate fault = FLTILL; 1421*0Sstevel@tonic-gate break; 1422*0Sstevel@tonic-gate 1423*0Sstevel@tonic-gate default: 1424*0Sstevel@tonic-gate (void) die(type, rp, addr, 0); 1425*0Sstevel@tonic-gate /*NOTREACHED*/ 1426*0Sstevel@tonic-gate } 1427*0Sstevel@tonic-gate 1428*0Sstevel@tonic-gate /* 1429*0Sstevel@tonic-gate * We can't get here from a system trap 1430*0Sstevel@tonic-gate * Never restart any instruction which got here from an fp trap. 1431*0Sstevel@tonic-gate */ 1432*0Sstevel@tonic-gate ASSERT(type & T_USER); 1433*0Sstevel@tonic-gate 1434*0Sstevel@tonic-gate trap_cleanup(rp, fault, &siginfo, 0); 1435*0Sstevel@tonic-gate out: 1436*0Sstevel@tonic-gate trap_rtt(); 1437*0Sstevel@tonic-gate (void) new_mstate(curthread, mstate); 1438*0Sstevel@tonic-gate } 1439*0Sstevel@tonic-gate 1440*0Sstevel@tonic-gate void 1441*0Sstevel@tonic-gate trap_rtt(void) 1442*0Sstevel@tonic-gate { 1443*0Sstevel@tonic-gate klwp_id_t lwp = ttolwp(curthread); 1444*0Sstevel@tonic-gate 1445*0Sstevel@tonic-gate /* 1446*0Sstevel@tonic-gate * Restore register window if a debugger modified it. 1447*0Sstevel@tonic-gate * Set up to perform a single-step if a debugger requested it. 1448*0Sstevel@tonic-gate */ 1449*0Sstevel@tonic-gate if (lwp->lwp_pcb.pcb_xregstat != XREGNONE) 1450*0Sstevel@tonic-gate xregrestore(lwp, 0); 1451*0Sstevel@tonic-gate 1452*0Sstevel@tonic-gate /* 1453*0Sstevel@tonic-gate * Set state to LWP_USER here so preempt won't give us a kernel 1454*0Sstevel@tonic-gate * priority if it occurs after this point. Call CL_TRAPRET() to 1455*0Sstevel@tonic-gate * restore the user-level priority. 1456*0Sstevel@tonic-gate * 1457*0Sstevel@tonic-gate * It is important that no locks (other than spinlocks) be entered 1458*0Sstevel@tonic-gate * after this point before returning to user mode (unless lwp_state 1459*0Sstevel@tonic-gate * is set back to LWP_SYS). 1460*0Sstevel@tonic-gate */ 1461*0Sstevel@tonic-gate lwp->lwp_state = LWP_USER; 1462*0Sstevel@tonic-gate if (curthread->t_trapret) { 1463*0Sstevel@tonic-gate curthread->t_trapret = 0; 1464*0Sstevel@tonic-gate thread_lock(curthread); 1465*0Sstevel@tonic-gate CL_TRAPRET(curthread); 1466*0Sstevel@tonic-gate thread_unlock(curthread); 1467*0Sstevel@tonic-gate } 1468*0Sstevel@tonic-gate if (CPU->cpu_runrun) 1469*0Sstevel@tonic-gate preempt(); 1470*0Sstevel@tonic-gate if (lwp->lwp_pcb.pcb_step != STEP_NONE) 1471*0Sstevel@tonic-gate prdostep(); 1472*0Sstevel@tonic-gate 1473*0Sstevel@tonic-gate TRACE_0(TR_FAC_TRAP, TR_C_TRAP_HANDLER_EXIT, "C_trap_handler_exit"); 1474*0Sstevel@tonic-gate } 1475*0Sstevel@tonic-gate 1476*0Sstevel@tonic-gate #define IS_LDASI(o) \ 1477*0Sstevel@tonic-gate ((o) == (uint32_t)0xC0C00000 || (o) == (uint32_t)0xC0800000 || \ 1478*0Sstevel@tonic-gate (o) == (uint32_t)0xC1800000) 1479*0Sstevel@tonic-gate #define IS_IMM_ASI(i) (((i) & 0x2000) == 0) 1480*0Sstevel@tonic-gate #define IS_ASINF(a) (((a) & 0xF6) == 0x82) 1481*0Sstevel@tonic-gate #define IS_LDDA(i) (((i) & 0xC1F80000) == 0xC0980000) 1482*0Sstevel@tonic-gate 1483*0Sstevel@tonic-gate static int 1484*0Sstevel@tonic-gate nfload(struct regs *rp, int *instrp) 1485*0Sstevel@tonic-gate { 1486*0Sstevel@tonic-gate uint_t instr, asi, op3, rd; 1487*0Sstevel@tonic-gate size_t len; 1488*0Sstevel@tonic-gate struct as *as; 1489*0Sstevel@tonic-gate caddr_t addr; 1490*0Sstevel@tonic-gate FPU_DREGS_TYPE zero; 1491*0Sstevel@tonic-gate extern int segnf_create(); 1492*0Sstevel@tonic-gate 1493*0Sstevel@tonic-gate if (USERMODE(rp->r_tstate)) 1494*0Sstevel@tonic-gate instr = fetch_user_instr((caddr_t)rp->r_pc); 1495*0Sstevel@tonic-gate else 1496*0Sstevel@tonic-gate instr = *(int *)rp->r_pc; 1497*0Sstevel@tonic-gate 1498*0Sstevel@tonic-gate if (instrp) 1499*0Sstevel@tonic-gate *instrp = instr; 1500*0Sstevel@tonic-gate 1501*0Sstevel@tonic-gate op3 = (uint_t)(instr & 0xC1E00000); 1502*0Sstevel@tonic-gate if (!IS_LDASI(op3)) 1503*0Sstevel@tonic-gate return (0); 1504*0Sstevel@tonic-gate if (IS_IMM_ASI(instr)) 1505*0Sstevel@tonic-gate asi = (instr & 0x1FE0) >> 5; 1506*0Sstevel@tonic-gate else 1507*0Sstevel@tonic-gate asi = (uint_t)((rp->r_tstate >> TSTATE_ASI_SHIFT) & 1508*0Sstevel@tonic-gate TSTATE_ASI_MASK); 1509*0Sstevel@tonic-gate if (!IS_ASINF(asi)) 1510*0Sstevel@tonic-gate return (0); 1511*0Sstevel@tonic-gate if (calc_memaddr(rp, &addr) == SIMU_SUCCESS) { 1512*0Sstevel@tonic-gate len = 1; 1513*0Sstevel@tonic-gate as = USERMODE(rp->r_tstate) ? ttoproc(curthread)->p_as : &kas; 1514*0Sstevel@tonic-gate as_rangelock(as); 1515*0Sstevel@tonic-gate if (as_gap(as, len, &addr, &len, 0, addr) == 0) 1516*0Sstevel@tonic-gate (void) as_map(as, addr, len, segnf_create, NULL); 1517*0Sstevel@tonic-gate as_rangeunlock(as); 1518*0Sstevel@tonic-gate } 1519*0Sstevel@tonic-gate zero = 0; 1520*0Sstevel@tonic-gate rd = (instr >> 25) & 0x1f; 1521*0Sstevel@tonic-gate if (IS_FLOAT(instr)) { 1522*0Sstevel@tonic-gate uint_t dbflg = ((instr >> 19) & 3) == 3; 1523*0Sstevel@tonic-gate 1524*0Sstevel@tonic-gate if (dbflg) { /* clever v9 reg encoding */ 1525*0Sstevel@tonic-gate if (rd & 1) 1526*0Sstevel@tonic-gate rd = (rd & 0x1e) | 0x20; 1527*0Sstevel@tonic-gate rd >>= 1; 1528*0Sstevel@tonic-gate } 1529*0Sstevel@tonic-gate if (fpu_exists) { 1530*0Sstevel@tonic-gate if (!(_fp_read_fprs() & FPRS_FEF)) 1531*0Sstevel@tonic-gate fp_enable(); 1532*0Sstevel@tonic-gate 1533*0Sstevel@tonic-gate if (dbflg) 1534*0Sstevel@tonic-gate _fp_write_pdreg(&zero, rd); 1535*0Sstevel@tonic-gate else 1536*0Sstevel@tonic-gate _fp_write_pfreg((uint_t *)&zero, rd); 1537*0Sstevel@tonic-gate } else { 1538*0Sstevel@tonic-gate kfpu_t *fp = lwptofpu(curthread->t_lwp); 1539*0Sstevel@tonic-gate 1540*0Sstevel@tonic-gate if (!fp->fpu_en) 1541*0Sstevel@tonic-gate fp_enable(); 1542*0Sstevel@tonic-gate 1543*0Sstevel@tonic-gate if (dbflg) 1544*0Sstevel@tonic-gate fp->fpu_fr.fpu_dregs[rd] = zero; 1545*0Sstevel@tonic-gate else 1546*0Sstevel@tonic-gate fp->fpu_fr.fpu_regs[rd] = 0; 1547*0Sstevel@tonic-gate } 1548*0Sstevel@tonic-gate } else { 1549*0Sstevel@tonic-gate (void) putreg(&zero, rp, rd, &addr); 1550*0Sstevel@tonic-gate if (IS_LDDA(instr)) 1551*0Sstevel@tonic-gate (void) putreg(&zero, rp, rd + 1, &addr); 1552*0Sstevel@tonic-gate } 1553*0Sstevel@tonic-gate rp->r_pc = rp->r_npc; 1554*0Sstevel@tonic-gate rp->r_npc += 4; 1555*0Sstevel@tonic-gate return (1); 1556*0Sstevel@tonic-gate } 1557*0Sstevel@tonic-gate 1558*0Sstevel@tonic-gate kmutex_t atomic_nc_mutex; 1559*0Sstevel@tonic-gate 1560*0Sstevel@tonic-gate /* 1561*0Sstevel@tonic-gate * The following couple of routines are for userland drivers which 1562*0Sstevel@tonic-gate * do atomics to noncached addresses. This sort of worked on previous 1563*0Sstevel@tonic-gate * platforms -- the operation really wasn't atomic, but it didn't generate 1564*0Sstevel@tonic-gate * a trap as sun4u systems do. 1565*0Sstevel@tonic-gate */ 1566*0Sstevel@tonic-gate static int 1567*0Sstevel@tonic-gate swap_nc(struct regs *rp, int instr) 1568*0Sstevel@tonic-gate { 1569*0Sstevel@tonic-gate uint64_t rdata, mdata; 1570*0Sstevel@tonic-gate caddr_t addr, badaddr; 1571*0Sstevel@tonic-gate uint_t tmp, rd; 1572*0Sstevel@tonic-gate 1573*0Sstevel@tonic-gate (void) flush_user_windows_to_stack(NULL); 1574*0Sstevel@tonic-gate rd = (instr >> 25) & 0x1f; 1575*0Sstevel@tonic-gate if (calc_memaddr(rp, &addr) != SIMU_SUCCESS) 1576*0Sstevel@tonic-gate return (0); 1577*0Sstevel@tonic-gate if (getreg(rp, rd, &rdata, &badaddr)) 1578*0Sstevel@tonic-gate return (0); 1579*0Sstevel@tonic-gate mutex_enter(&atomic_nc_mutex); 1580*0Sstevel@tonic-gate if (fuword32(addr, &tmp) == -1) { 1581*0Sstevel@tonic-gate mutex_exit(&atomic_nc_mutex); 1582*0Sstevel@tonic-gate return (0); 1583*0Sstevel@tonic-gate } 1584*0Sstevel@tonic-gate mdata = (u_longlong_t)tmp; 1585*0Sstevel@tonic-gate if (suword32(addr, (uint32_t)rdata) == -1) { 1586*0Sstevel@tonic-gate mutex_exit(&atomic_nc_mutex); 1587*0Sstevel@tonic-gate return (0); 1588*0Sstevel@tonic-gate } 1589*0Sstevel@tonic-gate (void) putreg(&mdata, rp, rd, &badaddr); 1590*0Sstevel@tonic-gate mutex_exit(&atomic_nc_mutex); 1591*0Sstevel@tonic-gate return (1); 1592*0Sstevel@tonic-gate } 1593*0Sstevel@tonic-gate 1594*0Sstevel@tonic-gate static int 1595*0Sstevel@tonic-gate ldstub_nc(struct regs *rp, int instr) 1596*0Sstevel@tonic-gate { 1597*0Sstevel@tonic-gate uint64_t mdata; 1598*0Sstevel@tonic-gate caddr_t addr, badaddr; 1599*0Sstevel@tonic-gate uint_t rd; 1600*0Sstevel@tonic-gate uint8_t tmp; 1601*0Sstevel@tonic-gate 1602*0Sstevel@tonic-gate (void) flush_user_windows_to_stack(NULL); 1603*0Sstevel@tonic-gate rd = (instr >> 25) & 0x1f; 1604*0Sstevel@tonic-gate if (calc_memaddr(rp, &addr) != SIMU_SUCCESS) 1605*0Sstevel@tonic-gate return (0); 1606*0Sstevel@tonic-gate mutex_enter(&atomic_nc_mutex); 1607*0Sstevel@tonic-gate if (fuword8(addr, &tmp) == -1) { 1608*0Sstevel@tonic-gate mutex_exit(&atomic_nc_mutex); 1609*0Sstevel@tonic-gate return (0); 1610*0Sstevel@tonic-gate } 1611*0Sstevel@tonic-gate mdata = (u_longlong_t)tmp; 1612*0Sstevel@tonic-gate if (suword8(addr, (uint8_t)0xff) == -1) { 1613*0Sstevel@tonic-gate mutex_exit(&atomic_nc_mutex); 1614*0Sstevel@tonic-gate return (0); 1615*0Sstevel@tonic-gate } 1616*0Sstevel@tonic-gate (void) putreg(&mdata, rp, rd, &badaddr); 1617*0Sstevel@tonic-gate mutex_exit(&atomic_nc_mutex); 1618*0Sstevel@tonic-gate return (1); 1619*0Sstevel@tonic-gate } 1620*0Sstevel@tonic-gate 1621*0Sstevel@tonic-gate /* 1622*0Sstevel@tonic-gate * This function helps instr_size() determine the operand size. 1623*0Sstevel@tonic-gate * It is called for the extended ldda/stda asi's. 1624*0Sstevel@tonic-gate */ 1625*0Sstevel@tonic-gate int 1626*0Sstevel@tonic-gate extended_asi_size(int asi) 1627*0Sstevel@tonic-gate { 1628*0Sstevel@tonic-gate switch (asi) { 1629*0Sstevel@tonic-gate case ASI_PST8_P: 1630*0Sstevel@tonic-gate case ASI_PST8_S: 1631*0Sstevel@tonic-gate case ASI_PST16_P: 1632*0Sstevel@tonic-gate case ASI_PST16_S: 1633*0Sstevel@tonic-gate case ASI_PST32_P: 1634*0Sstevel@tonic-gate case ASI_PST32_S: 1635*0Sstevel@tonic-gate case ASI_PST8_PL: 1636*0Sstevel@tonic-gate case ASI_PST8_SL: 1637*0Sstevel@tonic-gate case ASI_PST16_PL: 1638*0Sstevel@tonic-gate case ASI_PST16_SL: 1639*0Sstevel@tonic-gate case ASI_PST32_PL: 1640*0Sstevel@tonic-gate case ASI_PST32_SL: 1641*0Sstevel@tonic-gate return (8); 1642*0Sstevel@tonic-gate case ASI_FL8_P: 1643*0Sstevel@tonic-gate case ASI_FL8_S: 1644*0Sstevel@tonic-gate case ASI_FL8_PL: 1645*0Sstevel@tonic-gate case ASI_FL8_SL: 1646*0Sstevel@tonic-gate return (1); 1647*0Sstevel@tonic-gate case ASI_FL16_P: 1648*0Sstevel@tonic-gate case ASI_FL16_S: 1649*0Sstevel@tonic-gate case ASI_FL16_PL: 1650*0Sstevel@tonic-gate case ASI_FL16_SL: 1651*0Sstevel@tonic-gate return (2); 1652*0Sstevel@tonic-gate case ASI_BLK_P: 1653*0Sstevel@tonic-gate case ASI_BLK_S: 1654*0Sstevel@tonic-gate case ASI_BLK_PL: 1655*0Sstevel@tonic-gate case ASI_BLK_SL: 1656*0Sstevel@tonic-gate case ASI_BLK_COMMIT_P: 1657*0Sstevel@tonic-gate case ASI_BLK_COMMIT_S: 1658*0Sstevel@tonic-gate return (64); 1659*0Sstevel@tonic-gate } 1660*0Sstevel@tonic-gate 1661*0Sstevel@tonic-gate return (0); 1662*0Sstevel@tonic-gate } 1663*0Sstevel@tonic-gate 1664*0Sstevel@tonic-gate /* 1665*0Sstevel@tonic-gate * Patch non-zero to disable preemption of threads in the kernel. 1666*0Sstevel@tonic-gate */ 1667*0Sstevel@tonic-gate int IGNORE_KERNEL_PREEMPTION = 0; /* XXX - delete this someday */ 1668*0Sstevel@tonic-gate 1669*0Sstevel@tonic-gate struct kpreempt_cnts { /* kernel preemption statistics */ 1670*0Sstevel@tonic-gate int kpc_idle; /* executing idle thread */ 1671*0Sstevel@tonic-gate int kpc_intr; /* executing interrupt thread */ 1672*0Sstevel@tonic-gate int kpc_clock; /* executing clock thread */ 1673*0Sstevel@tonic-gate int kpc_blocked; /* thread has blocked preemption (t_preempt) */ 1674*0Sstevel@tonic-gate int kpc_notonproc; /* thread is surrendering processor */ 1675*0Sstevel@tonic-gate int kpc_inswtch; /* thread has ratified scheduling decision */ 1676*0Sstevel@tonic-gate int kpc_prilevel; /* processor interrupt level is too high */ 1677*0Sstevel@tonic-gate int kpc_apreempt; /* asynchronous preemption */ 1678*0Sstevel@tonic-gate int kpc_spreempt; /* synchronous preemption */ 1679*0Sstevel@tonic-gate } kpreempt_cnts; 1680*0Sstevel@tonic-gate 1681*0Sstevel@tonic-gate /* 1682*0Sstevel@tonic-gate * kernel preemption: forced rescheduling 1683*0Sstevel@tonic-gate * preempt the running kernel thread. 1684*0Sstevel@tonic-gate */ 1685*0Sstevel@tonic-gate void 1686*0Sstevel@tonic-gate kpreempt(int asyncspl) 1687*0Sstevel@tonic-gate { 1688*0Sstevel@tonic-gate if (IGNORE_KERNEL_PREEMPTION) { 1689*0Sstevel@tonic-gate aston(CPU->cpu_dispthread); 1690*0Sstevel@tonic-gate return; 1691*0Sstevel@tonic-gate } 1692*0Sstevel@tonic-gate /* 1693*0Sstevel@tonic-gate * Check that conditions are right for kernel preemption 1694*0Sstevel@tonic-gate */ 1695*0Sstevel@tonic-gate do { 1696*0Sstevel@tonic-gate if (curthread->t_preempt) { 1697*0Sstevel@tonic-gate /* 1698*0Sstevel@tonic-gate * either a privileged thread (idle, panic, interrupt) 1699*0Sstevel@tonic-gate * or will check when t_preempt is lowered 1700*0Sstevel@tonic-gate */ 1701*0Sstevel@tonic-gate if (curthread->t_pri < 0) 1702*0Sstevel@tonic-gate kpreempt_cnts.kpc_idle++; 1703*0Sstevel@tonic-gate else if (curthread->t_flag & T_INTR_THREAD) { 1704*0Sstevel@tonic-gate kpreempt_cnts.kpc_intr++; 1705*0Sstevel@tonic-gate if (curthread->t_pil == CLOCK_LEVEL) 1706*0Sstevel@tonic-gate kpreempt_cnts.kpc_clock++; 1707*0Sstevel@tonic-gate } else 1708*0Sstevel@tonic-gate kpreempt_cnts.kpc_blocked++; 1709*0Sstevel@tonic-gate aston(CPU->cpu_dispthread); 1710*0Sstevel@tonic-gate return; 1711*0Sstevel@tonic-gate } 1712*0Sstevel@tonic-gate if (curthread->t_state != TS_ONPROC || 1713*0Sstevel@tonic-gate curthread->t_disp_queue != CPU->cpu_disp) { 1714*0Sstevel@tonic-gate /* this thread will be calling swtch() shortly */ 1715*0Sstevel@tonic-gate kpreempt_cnts.kpc_notonproc++; 1716*0Sstevel@tonic-gate if (CPU->cpu_thread != CPU->cpu_dispthread) { 1717*0Sstevel@tonic-gate /* already in swtch(), force another */ 1718*0Sstevel@tonic-gate kpreempt_cnts.kpc_inswtch++; 1719*0Sstevel@tonic-gate siron(); 1720*0Sstevel@tonic-gate } 1721*0Sstevel@tonic-gate return; 1722*0Sstevel@tonic-gate } 1723*0Sstevel@tonic-gate 1724*0Sstevel@tonic-gate if (((asyncspl != KPREEMPT_SYNC) ? spltoipl(asyncspl) : 1725*0Sstevel@tonic-gate getpil()) >= DISP_LEVEL) { 1726*0Sstevel@tonic-gate /* 1727*0Sstevel@tonic-gate * We can't preempt this thread if it is at 1728*0Sstevel@tonic-gate * a PIL >= DISP_LEVEL since it may be holding 1729*0Sstevel@tonic-gate * a spin lock (like sched_lock). 1730*0Sstevel@tonic-gate */ 1731*0Sstevel@tonic-gate siron(); /* check back later */ 1732*0Sstevel@tonic-gate kpreempt_cnts.kpc_prilevel++; 1733*0Sstevel@tonic-gate return; 1734*0Sstevel@tonic-gate } 1735*0Sstevel@tonic-gate 1736*0Sstevel@tonic-gate /* 1737*0Sstevel@tonic-gate * block preemption so we don't have multiple preemptions 1738*0Sstevel@tonic-gate * pending on the interrupt stack 1739*0Sstevel@tonic-gate */ 1740*0Sstevel@tonic-gate curthread->t_preempt++; 1741*0Sstevel@tonic-gate if (asyncspl != KPREEMPT_SYNC) { 1742*0Sstevel@tonic-gate splx(asyncspl); 1743*0Sstevel@tonic-gate kpreempt_cnts.kpc_apreempt++; 1744*0Sstevel@tonic-gate } else 1745*0Sstevel@tonic-gate kpreempt_cnts.kpc_spreempt++; 1746*0Sstevel@tonic-gate 1747*0Sstevel@tonic-gate preempt(); 1748*0Sstevel@tonic-gate curthread->t_preempt--; 1749*0Sstevel@tonic-gate } while (CPU->cpu_kprunrun); 1750*0Sstevel@tonic-gate } 1751*0Sstevel@tonic-gate 1752*0Sstevel@tonic-gate static enum seg_rw 1753*0Sstevel@tonic-gate get_accesstype(struct regs *rp) 1754*0Sstevel@tonic-gate { 1755*0Sstevel@tonic-gate uint32_t instr; 1756*0Sstevel@tonic-gate 1757*0Sstevel@tonic-gate if (USERMODE(rp->r_tstate)) 1758*0Sstevel@tonic-gate instr = fetch_user_instr((caddr_t)rp->r_pc); 1759*0Sstevel@tonic-gate else 1760*0Sstevel@tonic-gate instr = *(uint32_t *)rp->r_pc; 1761*0Sstevel@tonic-gate 1762*0Sstevel@tonic-gate if (IS_FLUSH(instr)) 1763*0Sstevel@tonic-gate return (S_OTHER); 1764*0Sstevel@tonic-gate 1765*0Sstevel@tonic-gate if (IS_STORE(instr)) 1766*0Sstevel@tonic-gate return (S_WRITE); 1767*0Sstevel@tonic-gate else 1768*0Sstevel@tonic-gate return (S_READ); 1769*0Sstevel@tonic-gate } 1770