17c478bd9Sstevel@tonic-gate /* 27c478bd9Sstevel@tonic-gate * CDDL HEADER START 37c478bd9Sstevel@tonic-gate * 47c478bd9Sstevel@tonic-gate * The contents of this file are subject to the terms of the 520a1ce27Ssvemuri * Common Development and Distribution License (the "License"). 620a1ce27Ssvemuri * You may not use this file except in compliance with the License. 77c478bd9Sstevel@tonic-gate * 87c478bd9Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 97c478bd9Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 107c478bd9Sstevel@tonic-gate * See the License for the specific language governing permissions 117c478bd9Sstevel@tonic-gate * and limitations under the License. 127c478bd9Sstevel@tonic-gate * 137c478bd9Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 147c478bd9Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 157c478bd9Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 167c478bd9Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 177c478bd9Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 187c478bd9Sstevel@tonic-gate * 197c478bd9Sstevel@tonic-gate * CDDL HEADER END 207c478bd9Sstevel@tonic-gate */ 217c478bd9Sstevel@tonic-gate /* 22eb86370fSChristopher Baumbauer - Sun Microsystems - San Diego United States * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 237c478bd9Sstevel@tonic-gate * Use is subject to license terms. 247c478bd9Sstevel@tonic-gate */ 257c478bd9Sstevel@tonic-gate 267c478bd9Sstevel@tonic-gate /* common code with bug fixes from original version in trap.c */ 277c478bd9Sstevel@tonic-gate 287c478bd9Sstevel@tonic-gate #include <sys/param.h> 297c478bd9Sstevel@tonic-gate #include <sys/types.h> 307c478bd9Sstevel@tonic-gate #include <sys/systm.h> 317c478bd9Sstevel@tonic-gate #include <sys/archsystm.h> 327c478bd9Sstevel@tonic-gate #include <sys/vmsystm.h> 337c478bd9Sstevel@tonic-gate #include <sys/fpu/fpusystm.h> 347c478bd9Sstevel@tonic-gate #include <sys/fpu/fpu_simulator.h> 357c478bd9Sstevel@tonic-gate #include <sys/inline.h> 367c478bd9Sstevel@tonic-gate #include <sys/debug.h> 377c478bd9Sstevel@tonic-gate #include <sys/privregs.h> 387c478bd9Sstevel@tonic-gate #include <sys/machpcb.h> 397c478bd9Sstevel@tonic-gate #include <sys/simulate.h> 407c478bd9Sstevel@tonic-gate #include <sys/proc.h> 417c478bd9Sstevel@tonic-gate #include <sys/cmn_err.h> 427c478bd9Sstevel@tonic-gate #include <sys/stack.h> 437c478bd9Sstevel@tonic-gate #include <sys/watchpoint.h> 447c478bd9Sstevel@tonic-gate #include <sys/trap.h> 457c478bd9Sstevel@tonic-gate #include <sys/machtrap.h> 467c478bd9Sstevel@tonic-gate #include <sys/mman.h> 477c478bd9Sstevel@tonic-gate #include <sys/asi.h> 487c478bd9Sstevel@tonic-gate #include <sys/copyops.h> 497c478bd9Sstevel@tonic-gate #include <vm/as.h> 507c478bd9Sstevel@tonic-gate #include <vm/page.h> 517c478bd9Sstevel@tonic-gate #include <sys/model.h> 527c478bd9Sstevel@tonic-gate #include <vm/seg_vn.h> 534e8a0fa6Swsm #include <sys/byteorder.h> 54023e71deSHaik Aftandilian #include <sys/time.h> 557c478bd9Sstevel@tonic-gate 567c478bd9Sstevel@tonic-gate #define IS_IBIT_SET(x) (x & 0x2000) 577c478bd9Sstevel@tonic-gate #define IS_VIS1(op, op3)(op == 2 && op3 == 0x36) 5820a1ce27Ssvemuri #define IS_FLOAT_QUAD_OP(op, op3)(op == 2 && (op3 == 0x34 || \ 5920a1ce27Ssvemuri op3 == 0x35)) 607c478bd9Sstevel@tonic-gate #define IS_PARTIAL_OR_SHORT_FLOAT_LD_ST(op, op3, asi) \ 617c478bd9Sstevel@tonic-gate (op == 3 && (op3 == IOP_V8_LDDFA || \ 627c478bd9Sstevel@tonic-gate op3 == IOP_V8_STDFA) && asi > ASI_SNFL) 637c478bd9Sstevel@tonic-gate 647c478bd9Sstevel@tonic-gate static int aligndebug = 0; 657c478bd9Sstevel@tonic-gate 667c478bd9Sstevel@tonic-gate /* 677c478bd9Sstevel@tonic-gate * For the sake of those who must be compatible with unaligned 687c478bd9Sstevel@tonic-gate * architectures, users can link their programs to use a 697c478bd9Sstevel@tonic-gate * corrective trap handler that will fix unaligned references 707c478bd9Sstevel@tonic-gate * a special trap #6 (T_FIX_ALIGN) enables this 'feature'. 717c478bd9Sstevel@tonic-gate * Returns 1 for success, 0 for failure. 727c478bd9Sstevel@tonic-gate */ 737c478bd9Sstevel@tonic-gate 747c478bd9Sstevel@tonic-gate int 757c478bd9Sstevel@tonic-gate do_unaligned(struct regs *rp, caddr_t *badaddr) 767c478bd9Sstevel@tonic-gate { 777c478bd9Sstevel@tonic-gate uint_t inst, op3, asi = 0; 787c478bd9Sstevel@tonic-gate uint_t rd, rs1, rs2; 797c478bd9Sstevel@tonic-gate int sz, nf = 0, ltlend = 0; 807c478bd9Sstevel@tonic-gate int floatflg; 817c478bd9Sstevel@tonic-gate int fsrflg; 827c478bd9Sstevel@tonic-gate int immflg; 837c478bd9Sstevel@tonic-gate int lddstdflg; 847c478bd9Sstevel@tonic-gate caddr_t addr; 857c478bd9Sstevel@tonic-gate uint64_t val; 867c478bd9Sstevel@tonic-gate union { 877c478bd9Sstevel@tonic-gate uint64_t l[2]; 887c478bd9Sstevel@tonic-gate uint32_t i[4]; 897c478bd9Sstevel@tonic-gate uint16_t s[8]; 907c478bd9Sstevel@tonic-gate uint8_t c[16]; 917c478bd9Sstevel@tonic-gate } data; 927c478bd9Sstevel@tonic-gate 937c478bd9Sstevel@tonic-gate ASSERT(USERMODE(rp->r_tstate)); 947c478bd9Sstevel@tonic-gate inst = fetch_user_instr((caddr_t)rp->r_pc); 957c478bd9Sstevel@tonic-gate 967c478bd9Sstevel@tonic-gate op3 = (inst >> 19) & 0x3f; 977c478bd9Sstevel@tonic-gate rd = (inst >> 25) & 0x1f; 987c478bd9Sstevel@tonic-gate rs1 = (inst >> 14) & 0x1f; 997c478bd9Sstevel@tonic-gate rs2 = inst & 0x1f; 1007c478bd9Sstevel@tonic-gate floatflg = (inst >> 24) & 1; 1017c478bd9Sstevel@tonic-gate immflg = (inst >> 13) & 1; 1027c478bd9Sstevel@tonic-gate lddstdflg = fsrflg = 0; 1037c478bd9Sstevel@tonic-gate 1047c478bd9Sstevel@tonic-gate /* if not load or store do nothing */ 1057c478bd9Sstevel@tonic-gate if ((inst >> 30) != 3) 1067c478bd9Sstevel@tonic-gate return (0); 1077c478bd9Sstevel@tonic-gate 1087c478bd9Sstevel@tonic-gate /* if ldstub or swap, do nothing */ 1097c478bd9Sstevel@tonic-gate if ((inst & 0xc1680000) == 0xc0680000) 1107c478bd9Sstevel@tonic-gate return (0); 1117c478bd9Sstevel@tonic-gate 1127c478bd9Sstevel@tonic-gate /* if cas/casx, do nothing */ 1137c478bd9Sstevel@tonic-gate if ((inst & 0xc1e00000) == 0xc1e00000) 1147c478bd9Sstevel@tonic-gate return (0); 1157c478bd9Sstevel@tonic-gate 1167c478bd9Sstevel@tonic-gate if (floatflg) { 1177c478bd9Sstevel@tonic-gate switch ((inst >> 19) & 3) { /* map size bits to a number */ 1187c478bd9Sstevel@tonic-gate case 0: sz = 4; 1197c478bd9Sstevel@tonic-gate break; /* ldf{a}/stf{a} */ 1207c478bd9Sstevel@tonic-gate case 1: fsrflg = 1; 1217c478bd9Sstevel@tonic-gate if (rd == 0) 1227c478bd9Sstevel@tonic-gate sz = 4; /* ldfsr/stfsr */ 1237c478bd9Sstevel@tonic-gate else if (rd == 1) 1247c478bd9Sstevel@tonic-gate sz = 8; /* ldxfsr/stxfsr */ 1257c478bd9Sstevel@tonic-gate else 1267c478bd9Sstevel@tonic-gate return (SIMU_ILLEGAL); 1277c478bd9Sstevel@tonic-gate break; 1287c478bd9Sstevel@tonic-gate case 2: sz = 16; 1297c478bd9Sstevel@tonic-gate break; /* ldqf{a}/stqf{a} */ 1307c478bd9Sstevel@tonic-gate case 3: sz = 8; 1317c478bd9Sstevel@tonic-gate break; /* lddf{a}/stdf{a} */ 1327c478bd9Sstevel@tonic-gate } 1337c478bd9Sstevel@tonic-gate /* 1347c478bd9Sstevel@tonic-gate * Fix to access extra double register encoding plus 1357c478bd9Sstevel@tonic-gate * compensate to access the correct fpu_dreg. 1367c478bd9Sstevel@tonic-gate */ 1377c478bd9Sstevel@tonic-gate if ((sz > 4) && (fsrflg == 0)) { 1387c478bd9Sstevel@tonic-gate if ((rd & 1) == 1) 1397c478bd9Sstevel@tonic-gate rd = (rd & 0x1e) | 0x20; 1407c478bd9Sstevel@tonic-gate rd = rd >> 1; 1417c478bd9Sstevel@tonic-gate if ((sz == 16) && ((rd & 0x1) != 0)) 1427c478bd9Sstevel@tonic-gate return (SIMU_ILLEGAL); 1437c478bd9Sstevel@tonic-gate } 1447c478bd9Sstevel@tonic-gate } else { 1457c478bd9Sstevel@tonic-gate int sz_bits = (inst >> 19) & 0xf; 1467c478bd9Sstevel@tonic-gate switch (sz_bits) { /* map size bits to a number */ 1477c478bd9Sstevel@tonic-gate case 0: /* lduw{a} */ 1487c478bd9Sstevel@tonic-gate case 4: /* stw{a} */ 1497c478bd9Sstevel@tonic-gate case 8: /* ldsw{a} */ 1507c478bd9Sstevel@tonic-gate case 0xf: /* swap */ 1517c478bd9Sstevel@tonic-gate sz = 4; break; 1527c478bd9Sstevel@tonic-gate case 1: /* ldub{a} */ 1537c478bd9Sstevel@tonic-gate case 5: /* stb{a} */ 1547c478bd9Sstevel@tonic-gate case 9: /* ldsb{a} */ 1557c478bd9Sstevel@tonic-gate case 0xd: /* ldstub */ 1567c478bd9Sstevel@tonic-gate sz = 1; break; 1577c478bd9Sstevel@tonic-gate case 2: /* lduh{a} */ 1587c478bd9Sstevel@tonic-gate case 6: /* sth{a} */ 1597c478bd9Sstevel@tonic-gate case 0xa: /* ldsh{a} */ 1607c478bd9Sstevel@tonic-gate sz = 2; break; 1617c478bd9Sstevel@tonic-gate case 3: /* ldd{a} */ 1627c478bd9Sstevel@tonic-gate case 7: /* std{a} */ 1637c478bd9Sstevel@tonic-gate lddstdflg = 1; 1647c478bd9Sstevel@tonic-gate sz = 8; break; 1657c478bd9Sstevel@tonic-gate case 0xb: /* ldx{a} */ 1667c478bd9Sstevel@tonic-gate case 0xe: /* stx{a} */ 1677c478bd9Sstevel@tonic-gate sz = 8; break; 1687c478bd9Sstevel@tonic-gate } 1697c478bd9Sstevel@tonic-gate } 1707c478bd9Sstevel@tonic-gate 1717c478bd9Sstevel@tonic-gate 1727c478bd9Sstevel@tonic-gate /* only support primary and secondary asi's */ 1737c478bd9Sstevel@tonic-gate if ((op3 >> 4) & 1) { 1747c478bd9Sstevel@tonic-gate if (immflg) { 1757c478bd9Sstevel@tonic-gate asi = (uint_t)(rp->r_tstate >> TSTATE_ASI_SHIFT) & 1767c478bd9Sstevel@tonic-gate TSTATE_ASI_MASK; 1777c478bd9Sstevel@tonic-gate } else { 1787c478bd9Sstevel@tonic-gate asi = (inst >> 5) & 0xff; 1797c478bd9Sstevel@tonic-gate } 1807c478bd9Sstevel@tonic-gate switch (asi) { 1817c478bd9Sstevel@tonic-gate case ASI_P: 1827c478bd9Sstevel@tonic-gate case ASI_S: 1837c478bd9Sstevel@tonic-gate break; 1847c478bd9Sstevel@tonic-gate case ASI_PNF: 1857c478bd9Sstevel@tonic-gate case ASI_SNF: 1867c478bd9Sstevel@tonic-gate nf = 1; 1877c478bd9Sstevel@tonic-gate break; 1887c478bd9Sstevel@tonic-gate case ASI_PL: 1897c478bd9Sstevel@tonic-gate case ASI_SL: 1907c478bd9Sstevel@tonic-gate ltlend = 1; 1917c478bd9Sstevel@tonic-gate break; 1927c478bd9Sstevel@tonic-gate case ASI_PNFL: 1937c478bd9Sstevel@tonic-gate case ASI_SNFL: 1947c478bd9Sstevel@tonic-gate ltlend = 1; 1957c478bd9Sstevel@tonic-gate nf = 1; 1967c478bd9Sstevel@tonic-gate break; 1977c478bd9Sstevel@tonic-gate default: 1987c478bd9Sstevel@tonic-gate return (0); 1997c478bd9Sstevel@tonic-gate } 2007c478bd9Sstevel@tonic-gate /* 2017c478bd9Sstevel@tonic-gate * Non-faulting stores generate a data_access_exception trap, 2027c478bd9Sstevel@tonic-gate * according to the Spitfire manual, which should be signaled 2037c478bd9Sstevel@tonic-gate * as an illegal instruction trap, because it can't be fixed. 2047c478bd9Sstevel@tonic-gate */ 2057c478bd9Sstevel@tonic-gate if ((nf) && ((op3 == IOP_V8_STQFA) || (op3 == IOP_V8_STDFA))) 2067c478bd9Sstevel@tonic-gate return (SIMU_ILLEGAL); 2077c478bd9Sstevel@tonic-gate } 2087c478bd9Sstevel@tonic-gate 2097c478bd9Sstevel@tonic-gate if (aligndebug) { 2107c478bd9Sstevel@tonic-gate printf("unaligned access at %p, instruction: 0x%x\n", 2117c478bd9Sstevel@tonic-gate (void *)rp->r_pc, inst); 2127c478bd9Sstevel@tonic-gate printf("type %s", (((inst >> 21) & 1) ? "st" : "ld")); 2137c478bd9Sstevel@tonic-gate if (((inst >> 21) & 1) == 0) 2142f0fcb93SJason Beloro printf(" %s", (((inst >> 22) & 1) ? 2152f0fcb93SJason Beloro "signed" : "unsigned")); 2167c478bd9Sstevel@tonic-gate printf(" asi 0x%x size %d immflg %d\n", asi, sz, immflg); 2177c478bd9Sstevel@tonic-gate printf("rd = %d, op3 = 0x%x, rs1 = %d, rs2 = %d, imm13=0x%x\n", 2187c478bd9Sstevel@tonic-gate rd, op3, rs1, rs2, (inst & 0x1fff)); 2197c478bd9Sstevel@tonic-gate } 2207c478bd9Sstevel@tonic-gate 2217c478bd9Sstevel@tonic-gate (void) flush_user_windows_to_stack(NULL); 2227c478bd9Sstevel@tonic-gate if (getreg(rp, rs1, &val, badaddr)) 2237c478bd9Sstevel@tonic-gate return (SIMU_FAULT); 2247c478bd9Sstevel@tonic-gate addr = (caddr_t)val; /* convert to 32/64 bit address */ 2257c478bd9Sstevel@tonic-gate if (aligndebug) 2267c478bd9Sstevel@tonic-gate printf("addr 1 = %p\n", (void *)addr); 2277c478bd9Sstevel@tonic-gate 2287c478bd9Sstevel@tonic-gate /* check immediate bit and use immediate field or reg (rs2) */ 2297c478bd9Sstevel@tonic-gate if (immflg) { 2307c478bd9Sstevel@tonic-gate int imm; 2317c478bd9Sstevel@tonic-gate imm = inst & 0x1fff; /* mask out immediate field */ 2327c478bd9Sstevel@tonic-gate imm <<= 19; /* sign extend it */ 2337c478bd9Sstevel@tonic-gate imm >>= 19; 2347c478bd9Sstevel@tonic-gate addr += imm; /* compute address */ 2357c478bd9Sstevel@tonic-gate } else { 2367c478bd9Sstevel@tonic-gate if (getreg(rp, rs2, &val, badaddr)) 2377c478bd9Sstevel@tonic-gate return (SIMU_FAULT); 2387c478bd9Sstevel@tonic-gate addr += val; 2397c478bd9Sstevel@tonic-gate } 2407c478bd9Sstevel@tonic-gate 2417c478bd9Sstevel@tonic-gate /* 242aad98a6dSmathue * If this is a 32-bit program, chop the address accordingly. The 243aad98a6dSmathue * intermediate uintptr_t casts prevent warnings under a certain 244aad98a6dSmathue * compiler, and the temporary 32 bit storage is intended to force 245aad98a6dSmathue * proper code generation and break up what would otherwise be a 246aad98a6dSmathue * quadruple cast. 2477c478bd9Sstevel@tonic-gate */ 248aad98a6dSmathue if (curproc->p_model == DATAMODEL_ILP32) { 249aad98a6dSmathue caddr32_t addr32 = (caddr32_t)(uintptr_t)addr; 250aad98a6dSmathue addr = (caddr_t)(uintptr_t)addr32; 251aad98a6dSmathue } 2527c478bd9Sstevel@tonic-gate 2537c478bd9Sstevel@tonic-gate if (aligndebug) 2547c478bd9Sstevel@tonic-gate printf("addr 2 = %p\n", (void *)addr); 2557c478bd9Sstevel@tonic-gate 2567c478bd9Sstevel@tonic-gate if (addr >= curproc->p_as->a_userlimit) { 2577c478bd9Sstevel@tonic-gate *badaddr = addr; 2587c478bd9Sstevel@tonic-gate goto badret; 2597c478bd9Sstevel@tonic-gate } 2607c478bd9Sstevel@tonic-gate 2617c478bd9Sstevel@tonic-gate /* a single bit differentiates ld and st */ 2627c478bd9Sstevel@tonic-gate if ((inst >> 21) & 1) { /* store */ 2637c478bd9Sstevel@tonic-gate if (floatflg) { 2647c478bd9Sstevel@tonic-gate klwp_id_t lwp = ttolwp(curthread); 2657c478bd9Sstevel@tonic-gate kfpu_t *fp = lwptofpu(lwp); 2667c478bd9Sstevel@tonic-gate /* Ensure fp has been enabled */ 2677c478bd9Sstevel@tonic-gate if (fpu_exists) { 2687c478bd9Sstevel@tonic-gate if (!(_fp_read_fprs() & FPRS_FEF)) 2697c478bd9Sstevel@tonic-gate fp_enable(); 2707c478bd9Sstevel@tonic-gate } else { 2717c478bd9Sstevel@tonic-gate if (!fp->fpu_en) 2727c478bd9Sstevel@tonic-gate fp_enable(); 2737c478bd9Sstevel@tonic-gate } 2747c478bd9Sstevel@tonic-gate /* if fpu_exists read fpu reg */ 2757c478bd9Sstevel@tonic-gate if (fpu_exists) { 2767c478bd9Sstevel@tonic-gate if (fsrflg) { 2777c478bd9Sstevel@tonic-gate _fp_read_pfsr(&data.l[0]); 2787c478bd9Sstevel@tonic-gate } else { 2797c478bd9Sstevel@tonic-gate if (sz == 4) { 2807c478bd9Sstevel@tonic-gate data.i[0] = 0; 2817c478bd9Sstevel@tonic-gate _fp_read_pfreg( 2827c478bd9Sstevel@tonic-gate (unsigned *)&data.i[1], rd); 2837c478bd9Sstevel@tonic-gate } 2847c478bd9Sstevel@tonic-gate if (sz >= 8) 2857c478bd9Sstevel@tonic-gate _fp_read_pdreg( 2867c478bd9Sstevel@tonic-gate &data.l[0], rd); 2877c478bd9Sstevel@tonic-gate if (sz == 16) 2887c478bd9Sstevel@tonic-gate _fp_read_pdreg( 2897c478bd9Sstevel@tonic-gate &data.l[1], rd+1); 2907c478bd9Sstevel@tonic-gate } 2917c478bd9Sstevel@tonic-gate } else { 2927c478bd9Sstevel@tonic-gate if (fsrflg) { 2937c478bd9Sstevel@tonic-gate /* Clear reserved bits, set version=7 */ 2947c478bd9Sstevel@tonic-gate fp->fpu_fsr &= ~0x30301000; 2957c478bd9Sstevel@tonic-gate fp->fpu_fsr |= 0xE0000; 2967c478bd9Sstevel@tonic-gate data.l[0] = fp->fpu_fsr; 2977c478bd9Sstevel@tonic-gate } else { 2987c478bd9Sstevel@tonic-gate if (sz == 4) { 2997c478bd9Sstevel@tonic-gate data.i[0] = 0; 3007c478bd9Sstevel@tonic-gate data.i[1] = 3012f0fcb93SJason Beloro (unsigned)fp-> 3022f0fcb93SJason Beloro fpu_fr.fpu_regs[rd]; 3037c478bd9Sstevel@tonic-gate } 3047c478bd9Sstevel@tonic-gate if (sz >= 8) 3057c478bd9Sstevel@tonic-gate data.l[0] = 3067c478bd9Sstevel@tonic-gate fp->fpu_fr.fpu_dregs[rd]; 3077c478bd9Sstevel@tonic-gate if (sz == 16) 3087c478bd9Sstevel@tonic-gate data.l[1] = 3097c478bd9Sstevel@tonic-gate fp->fpu_fr.fpu_dregs[rd+1]; 3107c478bd9Sstevel@tonic-gate } 3117c478bd9Sstevel@tonic-gate } 3127c478bd9Sstevel@tonic-gate } else { 3134e8a0fa6Swsm if (lddstdflg) { /* combine the data */ 3147c478bd9Sstevel@tonic-gate if (getreg(rp, rd, &data.l[0], badaddr)) 3157c478bd9Sstevel@tonic-gate return (SIMU_FAULT); 3167c478bd9Sstevel@tonic-gate if (getreg(rp, rd+1, &data.l[1], badaddr)) 3177c478bd9Sstevel@tonic-gate return (SIMU_FAULT); 3184e8a0fa6Swsm if (ltlend) { 3194e8a0fa6Swsm /* 3204e8a0fa6Swsm * For STD, each 32-bit word is byte- 3214e8a0fa6Swsm * swapped individually. For 3224e8a0fa6Swsm * simplicity we don't want to do that 3234e8a0fa6Swsm * below, so we swap the words now to 3244e8a0fa6Swsm * get the desired result in the end. 3254e8a0fa6Swsm */ 3264e8a0fa6Swsm data.i[0] = data.i[3]; 3274e8a0fa6Swsm } else { 3284e8a0fa6Swsm data.i[0] = data.i[1]; 3297c478bd9Sstevel@tonic-gate data.i[1] = data.i[3]; 3304e8a0fa6Swsm } 3317c478bd9Sstevel@tonic-gate } else { 3327c478bd9Sstevel@tonic-gate if (getreg(rp, rd, &data.l[0], badaddr)) 3337c478bd9Sstevel@tonic-gate return (SIMU_FAULT); 3347c478bd9Sstevel@tonic-gate } 3357c478bd9Sstevel@tonic-gate } 3367c478bd9Sstevel@tonic-gate 3377c478bd9Sstevel@tonic-gate if (aligndebug) { 3387c478bd9Sstevel@tonic-gate if (sz == 16) { 3397c478bd9Sstevel@tonic-gate printf("data %x %x %x %x\n", 3407c478bd9Sstevel@tonic-gate data.i[0], data.i[1], data.i[2], data.c[3]); 3417c478bd9Sstevel@tonic-gate } else { 3427c478bd9Sstevel@tonic-gate printf("data %x %x %x %x %x %x %x %x\n", 3437c478bd9Sstevel@tonic-gate data.c[0], data.c[1], data.c[2], data.c[3], 3447c478bd9Sstevel@tonic-gate data.c[4], data.c[5], data.c[6], data.c[7]); 3457c478bd9Sstevel@tonic-gate } 3467c478bd9Sstevel@tonic-gate } 3477c478bd9Sstevel@tonic-gate 3487c478bd9Sstevel@tonic-gate if (ltlend) { 3497c478bd9Sstevel@tonic-gate if (sz == 1) { 3507c478bd9Sstevel@tonic-gate if (xcopyout_little(&data.c[7], addr, 3517c478bd9Sstevel@tonic-gate (size_t)sz) != 0) 3527c478bd9Sstevel@tonic-gate goto badret; 3537c478bd9Sstevel@tonic-gate } else if (sz == 2) { 3547c478bd9Sstevel@tonic-gate if (xcopyout_little(&data.s[3], addr, 3557c478bd9Sstevel@tonic-gate (size_t)sz) != 0) 3567c478bd9Sstevel@tonic-gate goto badret; 3577c478bd9Sstevel@tonic-gate } else if (sz == 4) { 3587c478bd9Sstevel@tonic-gate if (xcopyout_little(&data.i[1], addr, 3597c478bd9Sstevel@tonic-gate (size_t)sz) != 0) 3607c478bd9Sstevel@tonic-gate goto badret; 3617c478bd9Sstevel@tonic-gate } else { 3627c478bd9Sstevel@tonic-gate if (xcopyout_little(&data.l[0], addr, 3637c478bd9Sstevel@tonic-gate (size_t)sz) != 0) 3647c478bd9Sstevel@tonic-gate goto badret; 3657c478bd9Sstevel@tonic-gate } 3667c478bd9Sstevel@tonic-gate } else { 3677c478bd9Sstevel@tonic-gate if (sz == 1) { 3687c478bd9Sstevel@tonic-gate if (copyout(&data.c[7], addr, (size_t)sz) == -1) 3697c478bd9Sstevel@tonic-gate goto badret; 3707c478bd9Sstevel@tonic-gate } else if (sz == 2) { 3717c478bd9Sstevel@tonic-gate if (copyout(&data.s[3], addr, (size_t)sz) == -1) 3727c478bd9Sstevel@tonic-gate goto badret; 3737c478bd9Sstevel@tonic-gate } else if (sz == 4) { 3747c478bd9Sstevel@tonic-gate if (copyout(&data.i[1], addr, (size_t)sz) == -1) 3757c478bd9Sstevel@tonic-gate goto badret; 3767c478bd9Sstevel@tonic-gate } else { 3777c478bd9Sstevel@tonic-gate if (copyout(&data.l[0], addr, (size_t)sz) == -1) 3787c478bd9Sstevel@tonic-gate goto badret; 3797c478bd9Sstevel@tonic-gate } 3807c478bd9Sstevel@tonic-gate } 3817c478bd9Sstevel@tonic-gate } else { /* load */ 3827c478bd9Sstevel@tonic-gate if (sz == 1) { 3837c478bd9Sstevel@tonic-gate if (ltlend) { 3847c478bd9Sstevel@tonic-gate if (xcopyin_little(addr, &data.c[7], 3857c478bd9Sstevel@tonic-gate (size_t)sz) != 0) { 3867c478bd9Sstevel@tonic-gate if (nf) 3877c478bd9Sstevel@tonic-gate data.c[7] = 0; 3887c478bd9Sstevel@tonic-gate else 3897c478bd9Sstevel@tonic-gate goto badret; 3907c478bd9Sstevel@tonic-gate } 3917c478bd9Sstevel@tonic-gate } else { 3927c478bd9Sstevel@tonic-gate if (copyin(addr, &data.c[7], 3937c478bd9Sstevel@tonic-gate (size_t)sz) == -1) { 3947c478bd9Sstevel@tonic-gate if (nf) 3957c478bd9Sstevel@tonic-gate data.c[7] = 0; 3967c478bd9Sstevel@tonic-gate else 3977c478bd9Sstevel@tonic-gate goto badret; 3987c478bd9Sstevel@tonic-gate } 3997c478bd9Sstevel@tonic-gate } 4007c478bd9Sstevel@tonic-gate /* if signed and the sign bit is set extend it */ 4017c478bd9Sstevel@tonic-gate if (((inst >> 22) & 1) && ((data.c[7] >> 7) & 1)) { 4027c478bd9Sstevel@tonic-gate data.i[0] = (uint_t)-1; /* extend sign bit */ 4037c478bd9Sstevel@tonic-gate data.s[2] = (ushort_t)-1; 4047c478bd9Sstevel@tonic-gate data.c[6] = (uchar_t)-1; 4057c478bd9Sstevel@tonic-gate } else { 4067c478bd9Sstevel@tonic-gate data.i[0] = 0; /* clear upper 32+24 bits */ 4077c478bd9Sstevel@tonic-gate data.s[2] = 0; 4087c478bd9Sstevel@tonic-gate data.c[6] = 0; 4097c478bd9Sstevel@tonic-gate } 4107c478bd9Sstevel@tonic-gate } else if (sz == 2) { 4117c478bd9Sstevel@tonic-gate if (ltlend) { 4127c478bd9Sstevel@tonic-gate if (xcopyin_little(addr, &data.s[3], 4137c478bd9Sstevel@tonic-gate (size_t)sz) != 0) { 4147c478bd9Sstevel@tonic-gate if (nf) 4157c478bd9Sstevel@tonic-gate data.s[3] = 0; 4167c478bd9Sstevel@tonic-gate else 4177c478bd9Sstevel@tonic-gate goto badret; 4187c478bd9Sstevel@tonic-gate } 4197c478bd9Sstevel@tonic-gate } else { 4207c478bd9Sstevel@tonic-gate if (copyin(addr, &data.s[3], 4217c478bd9Sstevel@tonic-gate (size_t)sz) == -1) { 4227c478bd9Sstevel@tonic-gate if (nf) 4237c478bd9Sstevel@tonic-gate data.s[3] = 0; 4247c478bd9Sstevel@tonic-gate else 4257c478bd9Sstevel@tonic-gate goto badret; 4267c478bd9Sstevel@tonic-gate } 4277c478bd9Sstevel@tonic-gate } 4287c478bd9Sstevel@tonic-gate /* if signed and the sign bit is set extend it */ 4297c478bd9Sstevel@tonic-gate if (((inst >> 22) & 1) && ((data.s[3] >> 15) & 1)) { 4307c478bd9Sstevel@tonic-gate data.i[0] = (uint_t)-1; /* extend sign bit */ 4317c478bd9Sstevel@tonic-gate data.s[2] = (ushort_t)-1; 4327c478bd9Sstevel@tonic-gate } else { 4337c478bd9Sstevel@tonic-gate data.i[0] = 0; /* clear upper 32+16 bits */ 4347c478bd9Sstevel@tonic-gate data.s[2] = 0; 4357c478bd9Sstevel@tonic-gate } 4367c478bd9Sstevel@tonic-gate } else if (sz == 4) { 4377c478bd9Sstevel@tonic-gate if (ltlend) { 4387c478bd9Sstevel@tonic-gate if (xcopyin_little(addr, &data.i[1], 4397c478bd9Sstevel@tonic-gate (size_t)sz) != 0) { 4407c478bd9Sstevel@tonic-gate if (!nf) 4417c478bd9Sstevel@tonic-gate goto badret; 4427c478bd9Sstevel@tonic-gate data.i[1] = 0; 4437c478bd9Sstevel@tonic-gate } 4447c478bd9Sstevel@tonic-gate } else { 4457c478bd9Sstevel@tonic-gate if (copyin(addr, &data.i[1], 4467c478bd9Sstevel@tonic-gate (size_t)sz) == -1) { 4477c478bd9Sstevel@tonic-gate if (!nf) 4487c478bd9Sstevel@tonic-gate goto badret; 4497c478bd9Sstevel@tonic-gate data.i[1] = 0; 4507c478bd9Sstevel@tonic-gate } 4517c478bd9Sstevel@tonic-gate } 4527c478bd9Sstevel@tonic-gate /* if signed and the sign bit is set extend it */ 4537c478bd9Sstevel@tonic-gate if (((inst >> 22) & 1) && ((data.i[1] >> 31) & 1)) { 4547c478bd9Sstevel@tonic-gate data.i[0] = (uint_t)-1; /* extend sign bit */ 4557c478bd9Sstevel@tonic-gate } else { 4567c478bd9Sstevel@tonic-gate data.i[0] = 0; /* clear upper 32 bits */ 4577c478bd9Sstevel@tonic-gate } 4587c478bd9Sstevel@tonic-gate } else { 4597c478bd9Sstevel@tonic-gate if (ltlend) { 4607c478bd9Sstevel@tonic-gate if (xcopyin_little(addr, &data.l[0], 4617c478bd9Sstevel@tonic-gate (size_t)sz) != 0) { 4627c478bd9Sstevel@tonic-gate if (!nf) 4637c478bd9Sstevel@tonic-gate goto badret; 4647c478bd9Sstevel@tonic-gate data.l[0] = 0; 4657c478bd9Sstevel@tonic-gate } 4667c478bd9Sstevel@tonic-gate } else { 4677c478bd9Sstevel@tonic-gate if (copyin(addr, &data.l[0], 4687c478bd9Sstevel@tonic-gate (size_t)sz) == -1) { 4697c478bd9Sstevel@tonic-gate if (!nf) 4707c478bd9Sstevel@tonic-gate goto badret; 4717c478bd9Sstevel@tonic-gate data.l[0] = 0; 4727c478bd9Sstevel@tonic-gate } 4737c478bd9Sstevel@tonic-gate } 4747c478bd9Sstevel@tonic-gate } 4757c478bd9Sstevel@tonic-gate 4767c478bd9Sstevel@tonic-gate if (aligndebug) { 4777c478bd9Sstevel@tonic-gate if (sz == 16) { 4787c478bd9Sstevel@tonic-gate printf("data %x %x %x %x\n", 4797c478bd9Sstevel@tonic-gate data.i[0], data.i[1], data.i[2], data.c[3]); 4807c478bd9Sstevel@tonic-gate } else { 4817c478bd9Sstevel@tonic-gate printf("data %x %x %x %x %x %x %x %x\n", 4827c478bd9Sstevel@tonic-gate data.c[0], data.c[1], data.c[2], data.c[3], 4837c478bd9Sstevel@tonic-gate data.c[4], data.c[5], data.c[6], data.c[7]); 4847c478bd9Sstevel@tonic-gate } 4857c478bd9Sstevel@tonic-gate } 4867c478bd9Sstevel@tonic-gate 4877c478bd9Sstevel@tonic-gate if (floatflg) { /* if fpu_exists write fpu reg */ 4887c478bd9Sstevel@tonic-gate klwp_id_t lwp = ttolwp(curthread); 4897c478bd9Sstevel@tonic-gate kfpu_t *fp = lwptofpu(lwp); 4907c478bd9Sstevel@tonic-gate /* Ensure fp has been enabled */ 4917c478bd9Sstevel@tonic-gate if (fpu_exists) { 4927c478bd9Sstevel@tonic-gate if (!(_fp_read_fprs() & FPRS_FEF)) 4937c478bd9Sstevel@tonic-gate fp_enable(); 4947c478bd9Sstevel@tonic-gate } else { 4957c478bd9Sstevel@tonic-gate if (!fp->fpu_en) 4967c478bd9Sstevel@tonic-gate fp_enable(); 4977c478bd9Sstevel@tonic-gate } 4987c478bd9Sstevel@tonic-gate /* if fpu_exists read fpu reg */ 4997c478bd9Sstevel@tonic-gate if (fpu_exists) { 5007c478bd9Sstevel@tonic-gate if (fsrflg) { 5017c478bd9Sstevel@tonic-gate _fp_write_pfsr(&data.l[0]); 5027c478bd9Sstevel@tonic-gate } else { 5037c478bd9Sstevel@tonic-gate if (sz == 4) 5047c478bd9Sstevel@tonic-gate _fp_write_pfreg( 5057c478bd9Sstevel@tonic-gate (unsigned *)&data.i[1], rd); 5067c478bd9Sstevel@tonic-gate if (sz >= 8) 5077c478bd9Sstevel@tonic-gate _fp_write_pdreg( 5087c478bd9Sstevel@tonic-gate &data.l[0], rd); 5097c478bd9Sstevel@tonic-gate if (sz == 16) 5107c478bd9Sstevel@tonic-gate _fp_write_pdreg( 5117c478bd9Sstevel@tonic-gate &data.l[1], rd+1); 5127c478bd9Sstevel@tonic-gate } 5137c478bd9Sstevel@tonic-gate } else { 5147c478bd9Sstevel@tonic-gate if (fsrflg) { 5157c478bd9Sstevel@tonic-gate fp->fpu_fsr = data.l[0]; 5167c478bd9Sstevel@tonic-gate } else { 5177c478bd9Sstevel@tonic-gate if (sz == 4) 5187c478bd9Sstevel@tonic-gate fp->fpu_fr.fpu_regs[rd] = 5197c478bd9Sstevel@tonic-gate (unsigned)data.i[1]; 5207c478bd9Sstevel@tonic-gate if (sz >= 8) 5217c478bd9Sstevel@tonic-gate fp->fpu_fr.fpu_dregs[rd] = 5227c478bd9Sstevel@tonic-gate data.l[0]; 5237c478bd9Sstevel@tonic-gate if (sz == 16) 5247c478bd9Sstevel@tonic-gate fp->fpu_fr.fpu_dregs[rd+1] = 5257c478bd9Sstevel@tonic-gate data.l[1]; 5267c478bd9Sstevel@tonic-gate } 5277c478bd9Sstevel@tonic-gate } 5287c478bd9Sstevel@tonic-gate } else { 5297c478bd9Sstevel@tonic-gate if (lddstdflg) { /* split the data */ 5304e8a0fa6Swsm if (ltlend) { 5314e8a0fa6Swsm /* 5324e8a0fa6Swsm * For LDD, each 32-bit word is byte- 5334e8a0fa6Swsm * swapped individually. We didn't 5344e8a0fa6Swsm * do that above, but this will give 5354e8a0fa6Swsm * us the desired result. 5364e8a0fa6Swsm */ 5374e8a0fa6Swsm data.i[3] = data.i[0]; 5384e8a0fa6Swsm } else { 5397c478bd9Sstevel@tonic-gate data.i[3] = data.i[1]; 5407c478bd9Sstevel@tonic-gate data.i[1] = data.i[0]; 5414e8a0fa6Swsm } 5427c478bd9Sstevel@tonic-gate data.i[0] = 0; 5434e8a0fa6Swsm data.i[2] = 0; 5447c478bd9Sstevel@tonic-gate if (putreg(&data.l[0], rp, rd, badaddr) == -1) 5457c478bd9Sstevel@tonic-gate goto badret; 5467c478bd9Sstevel@tonic-gate if (putreg(&data.l[1], rp, rd+1, badaddr) == -1) 5477c478bd9Sstevel@tonic-gate goto badret; 5487c478bd9Sstevel@tonic-gate } else { 5497c478bd9Sstevel@tonic-gate if (putreg(&data.l[0], rp, rd, badaddr) == -1) 5507c478bd9Sstevel@tonic-gate goto badret; 5517c478bd9Sstevel@tonic-gate } 5527c478bd9Sstevel@tonic-gate } 5537c478bd9Sstevel@tonic-gate } 5547c478bd9Sstevel@tonic-gate return (SIMU_SUCCESS); 5557c478bd9Sstevel@tonic-gate badret: 5567c478bd9Sstevel@tonic-gate return (SIMU_FAULT); 5577c478bd9Sstevel@tonic-gate } 5587c478bd9Sstevel@tonic-gate 5594e8a0fa6Swsm 5604e8a0fa6Swsm int 5614e8a0fa6Swsm simulate_lddstd(struct regs *rp, caddr_t *badaddr) 5624e8a0fa6Swsm { 5634e8a0fa6Swsm uint_t inst, op3, asi = 0; 5644e8a0fa6Swsm uint_t rd, rs1, rs2; 5654e8a0fa6Swsm int nf = 0, ltlend = 0, usermode; 5664e8a0fa6Swsm int immflg; 5674e8a0fa6Swsm uint64_t reven; 5684e8a0fa6Swsm uint64_t rodd; 5694e8a0fa6Swsm caddr_t addr; 5704e8a0fa6Swsm uint64_t val; 5714e8a0fa6Swsm uint64_t data; 5724e8a0fa6Swsm 5734e8a0fa6Swsm usermode = USERMODE(rp->r_tstate); 5744e8a0fa6Swsm 5754e8a0fa6Swsm if (usermode) 5764e8a0fa6Swsm inst = fetch_user_instr((caddr_t)rp->r_pc); 5774e8a0fa6Swsm else 5784e8a0fa6Swsm inst = *(uint_t *)rp->r_pc; 5794e8a0fa6Swsm 5804e8a0fa6Swsm op3 = (inst >> 19) & 0x3f; 5814e8a0fa6Swsm rd = (inst >> 25) & 0x1f; 5824e8a0fa6Swsm rs1 = (inst >> 14) & 0x1f; 5834e8a0fa6Swsm rs2 = inst & 0x1f; 5844e8a0fa6Swsm immflg = (inst >> 13) & 1; 5854e8a0fa6Swsm 5864e8a0fa6Swsm if (USERMODE(rp->r_tstate)) 5874e8a0fa6Swsm (void) flush_user_windows_to_stack(NULL); 5884e8a0fa6Swsm else 5894e8a0fa6Swsm flush_windows(); 5904e8a0fa6Swsm 5914e8a0fa6Swsm if ((op3 >> 4) & 1) { /* is this LDDA/STDA? */ 5924e8a0fa6Swsm if (immflg) { 5934e8a0fa6Swsm asi = (uint_t)(rp->r_tstate >> TSTATE_ASI_SHIFT) & 5944e8a0fa6Swsm TSTATE_ASI_MASK; 5954e8a0fa6Swsm } else { 5964e8a0fa6Swsm asi = (inst >> 5) & 0xff; 5974e8a0fa6Swsm } 5984e8a0fa6Swsm switch (asi) { 5994e8a0fa6Swsm case ASI_P: 6004e8a0fa6Swsm case ASI_S: 6014e8a0fa6Swsm break; 6024e8a0fa6Swsm case ASI_PNF: 6034e8a0fa6Swsm case ASI_SNF: 6044e8a0fa6Swsm nf = 1; 6054e8a0fa6Swsm break; 6064e8a0fa6Swsm case ASI_PL: 6074e8a0fa6Swsm case ASI_SL: 6084e8a0fa6Swsm ltlend = 1; 6094e8a0fa6Swsm break; 6104e8a0fa6Swsm case ASI_PNFL: 6114e8a0fa6Swsm case ASI_SNFL: 6124e8a0fa6Swsm ltlend = 1; 6134e8a0fa6Swsm nf = 1; 6144e8a0fa6Swsm break; 6154e8a0fa6Swsm case ASI_AIUP: 6164e8a0fa6Swsm case ASI_AIUS: 6174e8a0fa6Swsm usermode = 1; 6184e8a0fa6Swsm break; 6194e8a0fa6Swsm case ASI_AIUPL: 6204e8a0fa6Swsm case ASI_AIUSL: 6214e8a0fa6Swsm usermode = 1; 6224e8a0fa6Swsm ltlend = 1; 6234e8a0fa6Swsm break; 6244e8a0fa6Swsm default: 6254e8a0fa6Swsm return (SIMU_ILLEGAL); 6264e8a0fa6Swsm } 6274e8a0fa6Swsm } 6284e8a0fa6Swsm 6294e8a0fa6Swsm if (getreg(rp, rs1, &val, badaddr)) 6304e8a0fa6Swsm return (SIMU_FAULT); 6314e8a0fa6Swsm addr = (caddr_t)val; /* convert to 32/64 bit address */ 6324e8a0fa6Swsm 6334e8a0fa6Swsm /* check immediate bit and use immediate field or reg (rs2) */ 6344e8a0fa6Swsm if (immflg) { 6354e8a0fa6Swsm int imm; 6364e8a0fa6Swsm imm = inst & 0x1fff; /* mask out immediate field */ 6374e8a0fa6Swsm imm <<= 19; /* sign extend it */ 6384e8a0fa6Swsm imm >>= 19; 6394e8a0fa6Swsm addr += imm; /* compute address */ 6404e8a0fa6Swsm } else { 6414e8a0fa6Swsm if (getreg(rp, rs2, &val, badaddr)) 6424e8a0fa6Swsm return (SIMU_FAULT); 6434e8a0fa6Swsm addr += val; 6444e8a0fa6Swsm } 6454e8a0fa6Swsm 6464e8a0fa6Swsm /* 6474e8a0fa6Swsm * T_UNIMP_LDD and T_UNIMP_STD are higher priority than 6484e8a0fa6Swsm * T_ALIGNMENT. So we have to make sure that the address is 6494e8a0fa6Swsm * kosher before trying to use it, because the hardware hasn't 6504e8a0fa6Swsm * checked it for us yet. 6514e8a0fa6Swsm */ 6524e8a0fa6Swsm if (((uintptr_t)addr & 0x7) != 0) { 6534e8a0fa6Swsm if (curproc->p_fixalignment) 6544e8a0fa6Swsm return (do_unaligned(rp, badaddr)); 6554e8a0fa6Swsm else 6564e8a0fa6Swsm return (SIMU_UNALIGN); 6574e8a0fa6Swsm } 6584e8a0fa6Swsm 6594e8a0fa6Swsm /* 660aad98a6dSmathue * If this is a 32-bit program, chop the address accordingly. The 661aad98a6dSmathue * intermediate uintptr_t casts prevent warnings under a certain 662aad98a6dSmathue * compiler, and the temporary 32 bit storage is intended to force 663aad98a6dSmathue * proper code generation and break up what would otherwise be a 664aad98a6dSmathue * quadruple cast. 6654e8a0fa6Swsm */ 666aad98a6dSmathue if (curproc->p_model == DATAMODEL_ILP32 && usermode) { 667aad98a6dSmathue caddr32_t addr32 = (caddr32_t)(uintptr_t)addr; 668aad98a6dSmathue addr = (caddr_t)(uintptr_t)addr32; 669aad98a6dSmathue } 6704e8a0fa6Swsm 6714e8a0fa6Swsm if ((inst >> 21) & 1) { /* store */ 6724e8a0fa6Swsm if (getreg(rp, rd, &reven, badaddr)) 6734e8a0fa6Swsm return (SIMU_FAULT); 6744e8a0fa6Swsm if (getreg(rp, rd+1, &rodd, badaddr)) 6754e8a0fa6Swsm return (SIMU_FAULT); 6764e8a0fa6Swsm if (ltlend) { 6774e8a0fa6Swsm reven = BSWAP_32(reven); 6784e8a0fa6Swsm rodd = BSWAP_32(rodd); 6794e8a0fa6Swsm } 6804e8a0fa6Swsm data = (reven << 32) | rodd; 6814e8a0fa6Swsm if (usermode) { 6824e8a0fa6Swsm if (suword64_nowatch(addr, data) == -1) 6834e8a0fa6Swsm return (SIMU_FAULT); 6844e8a0fa6Swsm } else { 6854e8a0fa6Swsm *(uint64_t *)addr = data; 6864e8a0fa6Swsm } 6874e8a0fa6Swsm } else { /* load */ 6884e8a0fa6Swsm if (usermode) { 6894e8a0fa6Swsm if (fuword64_nowatch(addr, &data)) { 6904e8a0fa6Swsm if (nf) 6914e8a0fa6Swsm data = 0; 6924e8a0fa6Swsm else 6934e8a0fa6Swsm return (SIMU_FAULT); 6944e8a0fa6Swsm } 6954e8a0fa6Swsm } else 6964e8a0fa6Swsm data = *(uint64_t *)addr; 6974e8a0fa6Swsm 6984e8a0fa6Swsm reven = (data >> 32); 6994e8a0fa6Swsm rodd = (uint64_t)(uint32_t)data; 7004e8a0fa6Swsm if (ltlend) { 7014e8a0fa6Swsm reven = BSWAP_32(reven); 7024e8a0fa6Swsm rodd = BSWAP_32(rodd); 7034e8a0fa6Swsm } 7044e8a0fa6Swsm 7054e8a0fa6Swsm if (putreg(&reven, rp, rd, badaddr) == -1) 7064e8a0fa6Swsm return (SIMU_FAULT); 7074e8a0fa6Swsm if (putreg(&rodd, rp, rd+1, badaddr) == -1) 7084e8a0fa6Swsm return (SIMU_FAULT); 7094e8a0fa6Swsm } 7104e8a0fa6Swsm return (SIMU_SUCCESS); 7114e8a0fa6Swsm } 7124e8a0fa6Swsm 7134e8a0fa6Swsm 7147c478bd9Sstevel@tonic-gate /* 7157c478bd9Sstevel@tonic-gate * simulate popc 7167c478bd9Sstevel@tonic-gate */ 7177c478bd9Sstevel@tonic-gate static int 7187c478bd9Sstevel@tonic-gate simulate_popc(struct regs *rp, caddr_t *badaddr, uint_t inst) 7197c478bd9Sstevel@tonic-gate { 7207c478bd9Sstevel@tonic-gate uint_t rd, rs2, rs1; 7217c478bd9Sstevel@tonic-gate uint_t immflg; 7227c478bd9Sstevel@tonic-gate uint64_t val, cnt = 0; 7237c478bd9Sstevel@tonic-gate 7247c478bd9Sstevel@tonic-gate rd = (inst >> 25) & 0x1f; 7257c478bd9Sstevel@tonic-gate rs1 = (inst >> 14) & 0x1f; 7267c478bd9Sstevel@tonic-gate rs2 = inst & 0x1f; 7277c478bd9Sstevel@tonic-gate immflg = (inst >> 13) & 1; 7287c478bd9Sstevel@tonic-gate 7297c478bd9Sstevel@tonic-gate if (rs1 > 0) 7307c478bd9Sstevel@tonic-gate return (SIMU_ILLEGAL); 7317c478bd9Sstevel@tonic-gate 7327c478bd9Sstevel@tonic-gate (void) flush_user_windows_to_stack(NULL); 7337c478bd9Sstevel@tonic-gate 7347c478bd9Sstevel@tonic-gate /* check immediate bit and use immediate field or reg (rs2) */ 7357c478bd9Sstevel@tonic-gate if (immflg) { 7367c478bd9Sstevel@tonic-gate int64_t imm; 7377c478bd9Sstevel@tonic-gate imm = inst & 0x1fff; /* mask out immediate field */ 7387c478bd9Sstevel@tonic-gate imm <<= 51; /* sign extend it */ 7397c478bd9Sstevel@tonic-gate imm >>= 51; 7407c478bd9Sstevel@tonic-gate if (imm != 0) { 7417c478bd9Sstevel@tonic-gate for (cnt = 0; imm != 0; imm &= imm-1) 7427c478bd9Sstevel@tonic-gate cnt++; 7437c478bd9Sstevel@tonic-gate } 7447c478bd9Sstevel@tonic-gate } else { 7457c478bd9Sstevel@tonic-gate if (getreg(rp, rs2, &val, badaddr)) 7467c478bd9Sstevel@tonic-gate return (SIMU_FAULT); 7477c478bd9Sstevel@tonic-gate if (val != 0) { 7487c478bd9Sstevel@tonic-gate for (cnt = 0; val != 0; val &= val-1) 7497c478bd9Sstevel@tonic-gate cnt++; 7507c478bd9Sstevel@tonic-gate } 7517c478bd9Sstevel@tonic-gate } 7527c478bd9Sstevel@tonic-gate 7537c478bd9Sstevel@tonic-gate if (putreg(&cnt, rp, rd, badaddr) == -1) 7547c478bd9Sstevel@tonic-gate return (SIMU_FAULT); 7557c478bd9Sstevel@tonic-gate 7567c478bd9Sstevel@tonic-gate return (SIMU_SUCCESS); 7577c478bd9Sstevel@tonic-gate } 7587c478bd9Sstevel@tonic-gate 7597c478bd9Sstevel@tonic-gate /* 7602f0fcb93SJason Beloro * simulate mulscc 7612f0fcb93SJason Beloro */ 7622f0fcb93SJason Beloro static int 7632f0fcb93SJason Beloro simulate_mulscc(struct regs *rp, caddr_t *badaddr, uint_t inst) 7642f0fcb93SJason Beloro { 7652f0fcb93SJason Beloro uint32_t s1, s2; 7662f0fcb93SJason Beloro uint32_t c, d, v; 7672f0fcb93SJason Beloro uint_t rd, rs1; 7682f0fcb93SJason Beloro int64_t d64; 7692f0fcb93SJason Beloro uint64_t ud64; 7702f0fcb93SJason Beloro uint64_t drs1; 7712f0fcb93SJason Beloro 7722f0fcb93SJason Beloro (void) flush_user_windows_to_stack(NULL); 7732f0fcb93SJason Beloro 7742f0fcb93SJason Beloro if ((inst >> 13) & 1) { /* immediate */ 7752f0fcb93SJason Beloro d64 = inst & 0x1fff; 7762f0fcb93SJason Beloro d64 <<= 51; /* sign extend it */ 7772f0fcb93SJason Beloro d64 >>= 51; 7782f0fcb93SJason Beloro } else { 7792f0fcb93SJason Beloro uint_t rs2; 7802f0fcb93SJason Beloro uint64_t drs2; 7812f0fcb93SJason Beloro 7822f0fcb93SJason Beloro if (inst & 0x1fe0) { 7832f0fcb93SJason Beloro return (SIMU_ILLEGAL); 7842f0fcb93SJason Beloro } 7852f0fcb93SJason Beloro rs2 = inst & 0x1f; 7862f0fcb93SJason Beloro if (getreg(rp, rs2, &drs2, badaddr)) { 7872f0fcb93SJason Beloro return (SIMU_FAULT); 7882f0fcb93SJason Beloro } 7892f0fcb93SJason Beloro d64 = (int64_t)drs2; 7902f0fcb93SJason Beloro } 7912f0fcb93SJason Beloro 7922f0fcb93SJason Beloro rs1 = (inst >> 14) & 0x1f; 7932f0fcb93SJason Beloro if (getreg(rp, rs1, &drs1, badaddr)) { 7942f0fcb93SJason Beloro return (SIMU_FAULT); 7952f0fcb93SJason Beloro } 7962f0fcb93SJason Beloro /* icc.n xor icc.v */ 7972f0fcb93SJason Beloro s1 = ((rp->r_tstate & TSTATE_IN) >> (TSTATE_CCR_SHIFT + 3)) ^ 7982f0fcb93SJason Beloro ((rp->r_tstate & TSTATE_IV) >> (TSTATE_CCR_SHIFT + 1)); 7992f0fcb93SJason Beloro s1 = (s1 << 31) | (((uint32_t)drs1) >> 1); 8002f0fcb93SJason Beloro 8012f0fcb93SJason Beloro if (rp->r_y & 1) { 8022f0fcb93SJason Beloro s2 = (uint32_t)d64; 8032f0fcb93SJason Beloro } else { 8042f0fcb93SJason Beloro s2 = 0; 8052f0fcb93SJason Beloro } 8062f0fcb93SJason Beloro d = s1 + s2; 8072f0fcb93SJason Beloro 8082f0fcb93SJason Beloro ud64 = (uint64_t)d; 8092f0fcb93SJason Beloro 8102f0fcb93SJason Beloro /* set the icc flags */ 8112f0fcb93SJason Beloro v = (s1 & s2 & ~d) | (~s1 & ~s2 & d); 8122f0fcb93SJason Beloro c = (s1 & s2) | (~d & (s1 | s2)); 8132f0fcb93SJason Beloro rp->r_tstate &= ~TSTATE_ICC; 8142f0fcb93SJason Beloro rp->r_tstate |= (uint64_t)((c >> 31) & 1) << (TSTATE_CCR_SHIFT + 0); 8152f0fcb93SJason Beloro rp->r_tstate |= (uint64_t)((v >> 31) & 1) << (TSTATE_CCR_SHIFT + 1); 8162f0fcb93SJason Beloro rp->r_tstate |= (uint64_t)(d ? 0 : 1) << (TSTATE_CCR_SHIFT + 2); 8172f0fcb93SJason Beloro rp->r_tstate |= (uint64_t)((d >> 31) & 1) << (TSTATE_CCR_SHIFT + 3); 8182f0fcb93SJason Beloro 8192f0fcb93SJason Beloro if (rp->r_tstate & TSTATE_IC) { 8202f0fcb93SJason Beloro ud64 |= (1ULL << 32); 8212f0fcb93SJason Beloro } 8222f0fcb93SJason Beloro 8232f0fcb93SJason Beloro /* set the xcc flags */ 8242f0fcb93SJason Beloro rp->r_tstate &= ~TSTATE_XCC; 8252f0fcb93SJason Beloro if (ud64 == 0) { 8262f0fcb93SJason Beloro rp->r_tstate |= TSTATE_XZ; 8272f0fcb93SJason Beloro } 8282f0fcb93SJason Beloro 8292f0fcb93SJason Beloro rd = (inst >> 25) & 0x1f; 8302f0fcb93SJason Beloro if (putreg(&ud64, rp, rd, badaddr)) { 8312f0fcb93SJason Beloro return (SIMU_FAULT); 8322f0fcb93SJason Beloro } 8332f0fcb93SJason Beloro 8342f0fcb93SJason Beloro d64 = (drs1 << 32) | (uint32_t)rp->r_y; 8352f0fcb93SJason Beloro d64 >>= 1; 8362f0fcb93SJason Beloro rp->r_y = (uint32_t)d64; 8372f0fcb93SJason Beloro 8382f0fcb93SJason Beloro return (SIMU_SUCCESS); 8392f0fcb93SJason Beloro } 8402f0fcb93SJason Beloro 8412f0fcb93SJason Beloro /* 8427c478bd9Sstevel@tonic-gate * simulate unimplemented instructions (popc, ldqf{a}, stqf{a}) 8437c478bd9Sstevel@tonic-gate */ 8447c478bd9Sstevel@tonic-gate int 8457c478bd9Sstevel@tonic-gate simulate_unimp(struct regs *rp, caddr_t *badaddr) 8467c478bd9Sstevel@tonic-gate { 8477c478bd9Sstevel@tonic-gate uint_t inst, optype, op3, asi; 8487c478bd9Sstevel@tonic-gate uint_t rs1, rd; 8497c478bd9Sstevel@tonic-gate uint_t ignor, i; 8507c478bd9Sstevel@tonic-gate machpcb_t *mpcb = lwptompcb(ttolwp(curthread)); 8517c478bd9Sstevel@tonic-gate int nomatch = 0; 8527c478bd9Sstevel@tonic-gate caddr_t addr = (caddr_t)rp->r_pc; 8537c478bd9Sstevel@tonic-gate struct as *as; 8547c478bd9Sstevel@tonic-gate caddr_t ka; 8557c478bd9Sstevel@tonic-gate pfn_t pfnum; 8567c478bd9Sstevel@tonic-gate page_t *pp; 8577c478bd9Sstevel@tonic-gate proc_t *p = ttoproc(curthread); 8587c478bd9Sstevel@tonic-gate struct seg *mapseg; 8597c478bd9Sstevel@tonic-gate struct segvn_data *svd; 8607c478bd9Sstevel@tonic-gate 8617c478bd9Sstevel@tonic-gate ASSERT(USERMODE(rp->r_tstate)); 8627c478bd9Sstevel@tonic-gate inst = fetch_user_instr(addr); 8637c478bd9Sstevel@tonic-gate if (inst == (uint_t)-1) { 8647c478bd9Sstevel@tonic-gate mpcb->mpcb_illexcaddr = addr; 8657c478bd9Sstevel@tonic-gate mpcb->mpcb_illexcinsn = (uint32_t)-1; 8667c478bd9Sstevel@tonic-gate return (SIMU_ILLEGAL); 8677c478bd9Sstevel@tonic-gate } 8687c478bd9Sstevel@tonic-gate 8697c478bd9Sstevel@tonic-gate /* 8707c478bd9Sstevel@tonic-gate * When fixing dirty v8 instructions there's a race if two processors 8717c478bd9Sstevel@tonic-gate * are executing the dirty executable at the same time. If one 8727c478bd9Sstevel@tonic-gate * cleans the instruction as the other is executing it the second 8737c478bd9Sstevel@tonic-gate * processor will see a clean instruction when it comes through this 8747c478bd9Sstevel@tonic-gate * code and will return SIMU_ILLEGAL. To work around the race 8757c478bd9Sstevel@tonic-gate * this code will keep track of the last illegal instruction seen 8767c478bd9Sstevel@tonic-gate * by each lwp and will only take action if the illegal instruction 8777c478bd9Sstevel@tonic-gate * is repeatable. 8787c478bd9Sstevel@tonic-gate */ 8797c478bd9Sstevel@tonic-gate if (addr != mpcb->mpcb_illexcaddr || 8807c478bd9Sstevel@tonic-gate inst != mpcb->mpcb_illexcinsn) 8817c478bd9Sstevel@tonic-gate nomatch = 1; 8827c478bd9Sstevel@tonic-gate mpcb->mpcb_illexcaddr = addr; 8837c478bd9Sstevel@tonic-gate mpcb->mpcb_illexcinsn = inst; 8847c478bd9Sstevel@tonic-gate 8857c478bd9Sstevel@tonic-gate /* instruction fields */ 8867c478bd9Sstevel@tonic-gate i = (inst >> 13) & 0x1; 8877c478bd9Sstevel@tonic-gate rd = (inst >> 25) & 0x1f; 8887c478bd9Sstevel@tonic-gate optype = (inst >> 30) & 0x3; 8897c478bd9Sstevel@tonic-gate op3 = (inst >> 19) & 0x3f; 8907c478bd9Sstevel@tonic-gate ignor = (inst >> 5) & 0xff; 8917c478bd9Sstevel@tonic-gate if (IS_IBIT_SET(inst)) { 8927c478bd9Sstevel@tonic-gate asi = (uint32_t)((rp->r_tstate >> TSTATE_ASI_SHIFT) & 8937c478bd9Sstevel@tonic-gate TSTATE_ASI_MASK); 8947c478bd9Sstevel@tonic-gate } else { 8957c478bd9Sstevel@tonic-gate asi = ignor; 8967c478bd9Sstevel@tonic-gate } 8977c478bd9Sstevel@tonic-gate 8987c478bd9Sstevel@tonic-gate if (IS_VIS1(optype, op3) || 89920a1ce27Ssvemuri IS_PARTIAL_OR_SHORT_FLOAT_LD_ST(optype, op3, asi) || 90020a1ce27Ssvemuri IS_FLOAT_QUAD_OP(optype, op3)) { 9017c478bd9Sstevel@tonic-gate klwp_t *lwp = ttolwp(curthread); 9027c478bd9Sstevel@tonic-gate kfpu_t *fp = lwptofpu(lwp); 9037c478bd9Sstevel@tonic-gate if (fpu_exists) { 9047c478bd9Sstevel@tonic-gate if (!(_fp_read_fprs() & FPRS_FEF)) 9057c478bd9Sstevel@tonic-gate fp_enable(); 9067c478bd9Sstevel@tonic-gate _fp_read_pfsr(&fp->fpu_fsr); 9077c478bd9Sstevel@tonic-gate } else { 9087c478bd9Sstevel@tonic-gate if (!fp->fpu_en) 9097c478bd9Sstevel@tonic-gate fp_enable(); 9107c478bd9Sstevel@tonic-gate } 9117c478bd9Sstevel@tonic-gate fp_precise(rp); 9127c478bd9Sstevel@tonic-gate return (SIMU_RETRY); 9137c478bd9Sstevel@tonic-gate } 9147c478bd9Sstevel@tonic-gate 9157c478bd9Sstevel@tonic-gate if (optype == 2 && op3 == IOP_V8_POPC) { 9167c478bd9Sstevel@tonic-gate return (simulate_popc(rp, badaddr, inst)); 9177c478bd9Sstevel@tonic-gate } else if (optype == 3 && op3 == IOP_V8_POPC) { 9187c478bd9Sstevel@tonic-gate return (SIMU_ILLEGAL); 9192f0fcb93SJason Beloro } else if (optype == OP_V8_ARITH && op3 == IOP_V8_MULScc) { 9202f0fcb93SJason Beloro return (simulate_mulscc(rp, badaddr, inst)); 9217c478bd9Sstevel@tonic-gate } 9227c478bd9Sstevel@tonic-gate 9237c478bd9Sstevel@tonic-gate if (optype == OP_V8_LDSTR) { 9247c478bd9Sstevel@tonic-gate if (op3 == IOP_V8_LDQF || op3 == IOP_V8_LDQFA || 9257c478bd9Sstevel@tonic-gate op3 == IOP_V8_STQF || op3 == IOP_V8_STQFA) 9267c478bd9Sstevel@tonic-gate return (do_unaligned(rp, badaddr)); 9277c478bd9Sstevel@tonic-gate } 9287c478bd9Sstevel@tonic-gate 929eb86370fSChristopher Baumbauer - Sun Microsystems - San Diego United States /* This is a new instruction so illexccnt should also be set. */ 930eb86370fSChristopher Baumbauer - Sun Microsystems - San Diego United States if (nomatch) { 931eb86370fSChristopher Baumbauer - Sun Microsystems - San Diego United States mpcb->mpcb_illexccnt = 0; 9327c478bd9Sstevel@tonic-gate return (SIMU_RETRY); 933eb86370fSChristopher Baumbauer - Sun Microsystems - San Diego United States } 934eb86370fSChristopher Baumbauer - Sun Microsystems - San Diego United States 935eb86370fSChristopher Baumbauer - Sun Microsystems - San Diego United States /* 936eb86370fSChristopher Baumbauer - Sun Microsystems - San Diego United States * In order to keep us from entering into an infinite loop while 937eb86370fSChristopher Baumbauer - Sun Microsystems - San Diego United States * attempting to clean up faulty instructions, we will return 938eb86370fSChristopher Baumbauer - Sun Microsystems - San Diego United States * SIMU_ILLEGAL once we've cleaned up the instruction as much 939eb86370fSChristopher Baumbauer - Sun Microsystems - San Diego United States * as we can, and still end up here. 940eb86370fSChristopher Baumbauer - Sun Microsystems - San Diego United States */ 941eb86370fSChristopher Baumbauer - Sun Microsystems - San Diego United States if (mpcb->mpcb_illexccnt >= 3) 942eb86370fSChristopher Baumbauer - Sun Microsystems - San Diego United States return (SIMU_ILLEGAL); 943eb86370fSChristopher Baumbauer - Sun Microsystems - San Diego United States 944eb86370fSChristopher Baumbauer - Sun Microsystems - San Diego United States mpcb->mpcb_illexccnt += 1; 9457c478bd9Sstevel@tonic-gate 9467c478bd9Sstevel@tonic-gate /* 9477c478bd9Sstevel@tonic-gate * The rest of the code handles v8 binaries with instructions 9487c478bd9Sstevel@tonic-gate * that have dirty (non-zero) bits in reserved or 'ignored' 9497c478bd9Sstevel@tonic-gate * fields; these will cause core dumps on v9 machines. 9507c478bd9Sstevel@tonic-gate * 9517c478bd9Sstevel@tonic-gate * We only clean dirty instructions in 32-bit programs (ie, v8) 9527c478bd9Sstevel@tonic-gate * running on SPARCv9 processors. True v9 programs are forced 9537c478bd9Sstevel@tonic-gate * to use the instruction set as intended. 9547c478bd9Sstevel@tonic-gate */ 9557c478bd9Sstevel@tonic-gate if (lwp_getdatamodel(curthread->t_lwp) != DATAMODEL_ILP32) 9567c478bd9Sstevel@tonic-gate return (SIMU_ILLEGAL); 9577c478bd9Sstevel@tonic-gate switch (optype) { 9587c478bd9Sstevel@tonic-gate case OP_V8_BRANCH: 9597c478bd9Sstevel@tonic-gate case OP_V8_CALL: 9607c478bd9Sstevel@tonic-gate return (SIMU_ILLEGAL); /* these don't have ignored fields */ 9617c478bd9Sstevel@tonic-gate /*NOTREACHED*/ 9627c478bd9Sstevel@tonic-gate case OP_V8_ARITH: 9637c478bd9Sstevel@tonic-gate switch (op3) { 9647c478bd9Sstevel@tonic-gate case IOP_V8_RETT: 9657c478bd9Sstevel@tonic-gate if (rd == 0 && !(i == 0 && ignor)) 9667c478bd9Sstevel@tonic-gate return (SIMU_ILLEGAL); 9677c478bd9Sstevel@tonic-gate if (rd) 9687c478bd9Sstevel@tonic-gate inst &= ~(0x1f << 25); 9697c478bd9Sstevel@tonic-gate if (i == 0 && ignor) 9707c478bd9Sstevel@tonic-gate inst &= ~(0xff << 5); 9717c478bd9Sstevel@tonic-gate break; 9727c478bd9Sstevel@tonic-gate case IOP_V8_TCC: 9737c478bd9Sstevel@tonic-gate if (i == 0 && ignor != 0) { 9747c478bd9Sstevel@tonic-gate inst &= ~(0xff << 5); 9757c478bd9Sstevel@tonic-gate } else if (i == 1 && (((inst >> 7) & 0x3f) != 0)) { 9767c478bd9Sstevel@tonic-gate inst &= ~(0x3f << 7); 9777c478bd9Sstevel@tonic-gate } else { 9787c478bd9Sstevel@tonic-gate return (SIMU_ILLEGAL); 9797c478bd9Sstevel@tonic-gate } 9807c478bd9Sstevel@tonic-gate break; 9817c478bd9Sstevel@tonic-gate case IOP_V8_JMPL: 9827c478bd9Sstevel@tonic-gate case IOP_V8_RESTORE: 9837c478bd9Sstevel@tonic-gate case IOP_V8_SAVE: 9847c478bd9Sstevel@tonic-gate if ((op3 == IOP_V8_RETT && rd) || 9857c478bd9Sstevel@tonic-gate (i == 0 && ignor)) { 9867c478bd9Sstevel@tonic-gate inst &= ~(0xff << 5); 9877c478bd9Sstevel@tonic-gate } else { 9887c478bd9Sstevel@tonic-gate return (SIMU_ILLEGAL); 9897c478bd9Sstevel@tonic-gate } 9907c478bd9Sstevel@tonic-gate break; 9917c478bd9Sstevel@tonic-gate case IOP_V8_FCMP: 9927c478bd9Sstevel@tonic-gate if (rd == 0) 9937c478bd9Sstevel@tonic-gate return (SIMU_ILLEGAL); 9947c478bd9Sstevel@tonic-gate inst &= ~(0x1f << 25); 9957c478bd9Sstevel@tonic-gate break; 9967c478bd9Sstevel@tonic-gate case IOP_V8_RDASR: 9977c478bd9Sstevel@tonic-gate rs1 = ((inst >> 14) & 0x1f); 9987c478bd9Sstevel@tonic-gate if (rs1 == 1 || (rs1 >= 7 && rs1 <= 14)) { 9997c478bd9Sstevel@tonic-gate /* 10007c478bd9Sstevel@tonic-gate * The instruction specifies an invalid 10017c478bd9Sstevel@tonic-gate * state register - better bail out than 10027c478bd9Sstevel@tonic-gate * "fix" it when we're not sure what was 10037c478bd9Sstevel@tonic-gate * intended. 10047c478bd9Sstevel@tonic-gate */ 10057c478bd9Sstevel@tonic-gate return (SIMU_ILLEGAL); 10067c478bd9Sstevel@tonic-gate } 10077c478bd9Sstevel@tonic-gate /* 10087c478bd9Sstevel@tonic-gate * Note: this case includes the 'stbar' 10097c478bd9Sstevel@tonic-gate * instruction (rs1 == 15 && i == 0). 10107c478bd9Sstevel@tonic-gate */ 10117c478bd9Sstevel@tonic-gate if ((ignor = (inst & 0x3fff)) != 0) 10127c478bd9Sstevel@tonic-gate inst &= ~(0x3fff); 10137c478bd9Sstevel@tonic-gate break; 10147c478bd9Sstevel@tonic-gate case IOP_V8_SRA: 10157c478bd9Sstevel@tonic-gate case IOP_V8_SRL: 10167c478bd9Sstevel@tonic-gate case IOP_V8_SLL: 10177c478bd9Sstevel@tonic-gate if (ignor == 0) 10187c478bd9Sstevel@tonic-gate return (SIMU_ILLEGAL); 10197c478bd9Sstevel@tonic-gate inst &= ~(0xff << 5); 10207c478bd9Sstevel@tonic-gate break; 10217c478bd9Sstevel@tonic-gate case IOP_V8_ADD: 10227c478bd9Sstevel@tonic-gate case IOP_V8_AND: 10237c478bd9Sstevel@tonic-gate case IOP_V8_OR: 10247c478bd9Sstevel@tonic-gate case IOP_V8_XOR: 10257c478bd9Sstevel@tonic-gate case IOP_V8_SUB: 10267c478bd9Sstevel@tonic-gate case IOP_V8_ANDN: 10277c478bd9Sstevel@tonic-gate case IOP_V8_ORN: 10287c478bd9Sstevel@tonic-gate case IOP_V8_XNOR: 10297c478bd9Sstevel@tonic-gate case IOP_V8_ADDC: 10307c478bd9Sstevel@tonic-gate case IOP_V8_UMUL: 10317c478bd9Sstevel@tonic-gate case IOP_V8_SMUL: 10327c478bd9Sstevel@tonic-gate case IOP_V8_SUBC: 10337c478bd9Sstevel@tonic-gate case IOP_V8_UDIV: 10347c478bd9Sstevel@tonic-gate case IOP_V8_SDIV: 10357c478bd9Sstevel@tonic-gate case IOP_V8_ADDcc: 10367c478bd9Sstevel@tonic-gate case IOP_V8_ANDcc: 10377c478bd9Sstevel@tonic-gate case IOP_V8_ORcc: 10387c478bd9Sstevel@tonic-gate case IOP_V8_XORcc: 10397c478bd9Sstevel@tonic-gate case IOP_V8_SUBcc: 10407c478bd9Sstevel@tonic-gate case IOP_V8_ANDNcc: 10417c478bd9Sstevel@tonic-gate case IOP_V8_ORNcc: 10427c478bd9Sstevel@tonic-gate case IOP_V8_XNORcc: 10437c478bd9Sstevel@tonic-gate case IOP_V8_ADDCcc: 10447c478bd9Sstevel@tonic-gate case IOP_V8_UMULcc: 10457c478bd9Sstevel@tonic-gate case IOP_V8_SMULcc: 10467c478bd9Sstevel@tonic-gate case IOP_V8_SUBCcc: 10477c478bd9Sstevel@tonic-gate case IOP_V8_UDIVcc: 10487c478bd9Sstevel@tonic-gate case IOP_V8_SDIVcc: 10497c478bd9Sstevel@tonic-gate case IOP_V8_TADDcc: 10507c478bd9Sstevel@tonic-gate case IOP_V8_TSUBcc: 10517c478bd9Sstevel@tonic-gate case IOP_V8_TADDccTV: 10527c478bd9Sstevel@tonic-gate case IOP_V8_TSUBccTV: 10537c478bd9Sstevel@tonic-gate case IOP_V8_MULScc: 10547c478bd9Sstevel@tonic-gate case IOP_V8_WRASR: 10557c478bd9Sstevel@tonic-gate case IOP_V8_FLUSH: 10567c478bd9Sstevel@tonic-gate if (i != 0 || ignor == 0) 10577c478bd9Sstevel@tonic-gate return (SIMU_ILLEGAL); 10587c478bd9Sstevel@tonic-gate inst &= ~(0xff << 5); 10597c478bd9Sstevel@tonic-gate break; 10607c478bd9Sstevel@tonic-gate default: 10617c478bd9Sstevel@tonic-gate return (SIMU_ILLEGAL); 10627c478bd9Sstevel@tonic-gate } 10637c478bd9Sstevel@tonic-gate break; 10647c478bd9Sstevel@tonic-gate case OP_V8_LDSTR: 10657c478bd9Sstevel@tonic-gate switch (op3) { 10667c478bd9Sstevel@tonic-gate case IOP_V8_STFSR: 10677c478bd9Sstevel@tonic-gate case IOP_V8_LDFSR: 10687c478bd9Sstevel@tonic-gate if (rd == 0 && !(i == 0 && ignor)) 10697c478bd9Sstevel@tonic-gate return (SIMU_ILLEGAL); 10707c478bd9Sstevel@tonic-gate if (rd) 10717c478bd9Sstevel@tonic-gate inst &= ~(0x1f << 25); 10727c478bd9Sstevel@tonic-gate if (i == 0 && ignor) 10737c478bd9Sstevel@tonic-gate inst &= ~(0xff << 5); 10747c478bd9Sstevel@tonic-gate break; 10757c478bd9Sstevel@tonic-gate default: 10767c478bd9Sstevel@tonic-gate if (optype == OP_V8_LDSTR && !IS_LDST_ALT(op3) && 10777c478bd9Sstevel@tonic-gate i == 0 && ignor) 10787c478bd9Sstevel@tonic-gate inst &= ~(0xff << 5); 10797c478bd9Sstevel@tonic-gate else 10807c478bd9Sstevel@tonic-gate return (SIMU_ILLEGAL); 10817c478bd9Sstevel@tonic-gate break; 10827c478bd9Sstevel@tonic-gate } 10837c478bd9Sstevel@tonic-gate break; 10847c478bd9Sstevel@tonic-gate default: 10857c478bd9Sstevel@tonic-gate return (SIMU_ILLEGAL); 10867c478bd9Sstevel@tonic-gate } 10877c478bd9Sstevel@tonic-gate 10887c478bd9Sstevel@tonic-gate as = p->p_as; 10897c478bd9Sstevel@tonic-gate 1090*dc32d872SJosef 'Jeff' Sipek AS_LOCK_ENTER(as, RW_READER); 10917c478bd9Sstevel@tonic-gate mapseg = as_findseg(as, (caddr_t)rp->r_pc, 0); 10927c478bd9Sstevel@tonic-gate ASSERT(mapseg != NULL); 10937c478bd9Sstevel@tonic-gate svd = (struct segvn_data *)mapseg->s_data; 10947c478bd9Sstevel@tonic-gate 10957c478bd9Sstevel@tonic-gate /* 10967c478bd9Sstevel@tonic-gate * We only create COW page for MAP_PRIVATE mappings. 10977c478bd9Sstevel@tonic-gate */ 10987c478bd9Sstevel@tonic-gate SEGVN_LOCK_ENTER(as, &svd->lock, RW_READER); 10997c478bd9Sstevel@tonic-gate if ((svd->type & MAP_TYPE) & MAP_SHARED) { 11007c478bd9Sstevel@tonic-gate SEGVN_LOCK_EXIT(as, &svd->lock); 1101*dc32d872SJosef 'Jeff' Sipek AS_LOCK_EXIT(as); 11027c478bd9Sstevel@tonic-gate return (SIMU_ILLEGAL); 11037c478bd9Sstevel@tonic-gate } 11047c478bd9Sstevel@tonic-gate SEGVN_LOCK_EXIT(as, &svd->lock); 1105*dc32d872SJosef 'Jeff' Sipek AS_LOCK_EXIT(as); 11067c478bd9Sstevel@tonic-gate 11077c478bd9Sstevel@tonic-gate /* 11087c478bd9Sstevel@tonic-gate * A "flush" instruction using the user PC's vaddr will not work 11097c478bd9Sstevel@tonic-gate * here, at least on Spitfire. Instead we create a temporary kernel 11107c478bd9Sstevel@tonic-gate * mapping to the user's text page, then modify and flush that. 11117c478bd9Sstevel@tonic-gate * Break COW by locking user page. 11127c478bd9Sstevel@tonic-gate */ 11137c478bd9Sstevel@tonic-gate if (as_fault(as->a_hat, as, (caddr_t)(rp->r_pc & PAGEMASK), PAGESIZE, 11147c478bd9Sstevel@tonic-gate F_SOFTLOCK, S_READ)) 11157c478bd9Sstevel@tonic-gate return (SIMU_FAULT); 11167c478bd9Sstevel@tonic-gate 1117*dc32d872SJosef 'Jeff' Sipek AS_LOCK_ENTER(as, RW_READER); 11187c478bd9Sstevel@tonic-gate pfnum = hat_getpfnum(as->a_hat, (caddr_t)rp->r_pc); 1119*dc32d872SJosef 'Jeff' Sipek AS_LOCK_EXIT(as); 11207c478bd9Sstevel@tonic-gate if (pf_is_memory(pfnum)) { 11217c478bd9Sstevel@tonic-gate pp = page_numtopp_nolock(pfnum); 11227c478bd9Sstevel@tonic-gate ASSERT(pp == NULL || PAGE_LOCKED(pp)); 11237c478bd9Sstevel@tonic-gate } else { 11247c478bd9Sstevel@tonic-gate (void) as_fault(as->a_hat, as, (caddr_t)(rp->r_pc & PAGEMASK), 11257c478bd9Sstevel@tonic-gate PAGESIZE, F_SOFTUNLOCK, S_READ); 11267c478bd9Sstevel@tonic-gate return (SIMU_FAULT); 11277c478bd9Sstevel@tonic-gate } 11287c478bd9Sstevel@tonic-gate 1129*dc32d872SJosef 'Jeff' Sipek AS_LOCK_ENTER(as, RW_READER); 11307c478bd9Sstevel@tonic-gate ka = ppmapin(pp, PROT_READ|PROT_WRITE, (caddr_t)rp->r_pc); 11317c478bd9Sstevel@tonic-gate *(uint_t *)(ka + (uintptr_t)(rp->r_pc % PAGESIZE)) = inst; 11327c478bd9Sstevel@tonic-gate doflush(ka + (uintptr_t)(rp->r_pc % PAGESIZE)); 11337c478bd9Sstevel@tonic-gate ppmapout(ka); 1134*dc32d872SJosef 'Jeff' Sipek AS_LOCK_EXIT(as); 11357c478bd9Sstevel@tonic-gate 11367c478bd9Sstevel@tonic-gate (void) as_fault(as->a_hat, as, (caddr_t)(rp->r_pc & PAGEMASK), 11377c478bd9Sstevel@tonic-gate PAGESIZE, F_SOFTUNLOCK, S_READ); 11387c478bd9Sstevel@tonic-gate return (SIMU_RETRY); 11397c478bd9Sstevel@tonic-gate } 11407c478bd9Sstevel@tonic-gate 11417c478bd9Sstevel@tonic-gate /* 1142023e71deSHaik Aftandilian * Simulate a "rd %tick" or "rd %stick" (%asr24) instruction. 1143023e71deSHaik Aftandilian */ 1144023e71deSHaik Aftandilian int 1145023e71deSHaik Aftandilian simulate_rdtick(struct regs *rp) 1146023e71deSHaik Aftandilian { 1147023e71deSHaik Aftandilian uint_t inst, op, op3, rd, rs1, i; 1148023e71deSHaik Aftandilian caddr_t badaddr; 1149023e71deSHaik Aftandilian 1150023e71deSHaik Aftandilian inst = fetch_user_instr((caddr_t)rp->r_pc); 1151023e71deSHaik Aftandilian op = (inst >> 30) & 0x3; 1152023e71deSHaik Aftandilian rd = (inst >> 25) & 0x1F; 1153023e71deSHaik Aftandilian op3 = (inst >> 19) & 0x3F; 1154023e71deSHaik Aftandilian i = (inst >> 13) & 0x1; 1155023e71deSHaik Aftandilian 1156023e71deSHaik Aftandilian /* 1157023e71deSHaik Aftandilian * Make sure this is either a %tick read (rs1 == 0x4) or 1158023e71deSHaik Aftandilian * a %stick read (rs1 == 0x18) instruction. 1159023e71deSHaik Aftandilian */ 1160023e71deSHaik Aftandilian if (op == 2 && op3 == 0x28 && i == 0) { 1161023e71deSHaik Aftandilian rs1 = (inst >> 14) & 0x1F; 1162023e71deSHaik Aftandilian 1163023e71deSHaik Aftandilian if (rs1 == 0x4) { 1164023e71deSHaik Aftandilian uint64_t tick; 1165023e71deSHaik Aftandilian (void) flush_user_windows_to_stack(NULL); 1166023e71deSHaik Aftandilian tick = gettick_counter(); 1167023e71deSHaik Aftandilian if (putreg(&tick, rp, rd, &badaddr) == 0) 1168023e71deSHaik Aftandilian return (SIMU_SUCCESS); 1169023e71deSHaik Aftandilian } else if (rs1 == 0x18) { 1170023e71deSHaik Aftandilian uint64_t stick; 1171023e71deSHaik Aftandilian (void) flush_user_windows_to_stack(NULL); 1172023e71deSHaik Aftandilian stick = gethrtime_unscaled(); 1173023e71deSHaik Aftandilian if (putreg(&stick, rp, rd, &badaddr) == 0) 1174023e71deSHaik Aftandilian return (SIMU_SUCCESS); 1175023e71deSHaik Aftandilian } 1176023e71deSHaik Aftandilian } 1177023e71deSHaik Aftandilian 1178023e71deSHaik Aftandilian return (SIMU_FAULT); 1179023e71deSHaik Aftandilian } 1180023e71deSHaik Aftandilian 1181023e71deSHaik Aftandilian /* 11827c478bd9Sstevel@tonic-gate * Get the value of a register for instruction simulation 11837c478bd9Sstevel@tonic-gate * by using the regs or window structure pointers. 11847c478bd9Sstevel@tonic-gate * Return 0 for success, and -1 for failure. If there is a failure, 11857c478bd9Sstevel@tonic-gate * save the faulting address using badaddr pointer. 11867c478bd9Sstevel@tonic-gate * We have 64 bit globals and outs, and 32 or 64 bit ins and locals. 11877c478bd9Sstevel@tonic-gate * Don't truncate globals/outs for 32 bit programs, for v8+ support. 11887c478bd9Sstevel@tonic-gate */ 11897c478bd9Sstevel@tonic-gate int 11907c478bd9Sstevel@tonic-gate getreg(struct regs *rp, uint_t reg, uint64_t *val, caddr_t *badaddr) 11917c478bd9Sstevel@tonic-gate { 11927c478bd9Sstevel@tonic-gate uint64_t *rgs, *sp; 11937c478bd9Sstevel@tonic-gate int rv = 0; 11947c478bd9Sstevel@tonic-gate 11957c478bd9Sstevel@tonic-gate rgs = (uint64_t *)&rp->r_ps; /* globals and outs */ 11967c478bd9Sstevel@tonic-gate sp = (uint64_t *)rp->r_sp; /* ins and locals */ 11977c478bd9Sstevel@tonic-gate if (reg == 0) { 11987c478bd9Sstevel@tonic-gate *val = 0; 11997c478bd9Sstevel@tonic-gate } else if (reg < 16) { 12007c478bd9Sstevel@tonic-gate *val = rgs[reg]; 12017c478bd9Sstevel@tonic-gate } else if (IS_V9STACK(sp)) { 12027c478bd9Sstevel@tonic-gate uint64_t *rw = (uint64_t *)((uintptr_t)sp + V9BIAS64); 12037c478bd9Sstevel@tonic-gate uint64_t *addr = (uint64_t *)&rw[reg - 16]; 12047c478bd9Sstevel@tonic-gate uint64_t res; 12057c478bd9Sstevel@tonic-gate 12067c478bd9Sstevel@tonic-gate if (USERMODE(rp->r_tstate)) { 12077c478bd9Sstevel@tonic-gate if (fuword64_nowatch(addr, &res) == -1) { 12087c478bd9Sstevel@tonic-gate *badaddr = (caddr_t)addr; 12097c478bd9Sstevel@tonic-gate rv = -1; 12107c478bd9Sstevel@tonic-gate } 12117c478bd9Sstevel@tonic-gate } else { 12127c478bd9Sstevel@tonic-gate res = *addr; 12137c478bd9Sstevel@tonic-gate } 12147c478bd9Sstevel@tonic-gate *val = res; 12157c478bd9Sstevel@tonic-gate } else { 1216aad98a6dSmathue caddr32_t sp32 = (caddr32_t)(uintptr_t)sp; 1217aad98a6dSmathue uint32_t *rw = (uint32_t *)(uintptr_t)sp32; 12187c478bd9Sstevel@tonic-gate uint32_t *addr = (uint32_t *)&rw[reg - 16]; 12197c478bd9Sstevel@tonic-gate uint32_t res; 12207c478bd9Sstevel@tonic-gate 12217c478bd9Sstevel@tonic-gate if (USERMODE(rp->r_tstate)) { 12227c478bd9Sstevel@tonic-gate if (fuword32_nowatch(addr, &res) == -1) { 12237c478bd9Sstevel@tonic-gate *badaddr = (caddr_t)addr; 12247c478bd9Sstevel@tonic-gate rv = -1; 12257c478bd9Sstevel@tonic-gate } 12267c478bd9Sstevel@tonic-gate } else { 12277c478bd9Sstevel@tonic-gate res = *addr; 12287c478bd9Sstevel@tonic-gate } 12297c478bd9Sstevel@tonic-gate *val = (uint64_t)res; 12307c478bd9Sstevel@tonic-gate } 12317c478bd9Sstevel@tonic-gate return (rv); 12327c478bd9Sstevel@tonic-gate } 12337c478bd9Sstevel@tonic-gate 12347c478bd9Sstevel@tonic-gate /* 12357c478bd9Sstevel@tonic-gate * Set the value of a register after instruction simulation 12367c478bd9Sstevel@tonic-gate * by using the regs or window structure pointers. 12377c478bd9Sstevel@tonic-gate * Return 0 for succes -1 failure. 12387c478bd9Sstevel@tonic-gate * save the faulting address using badaddr pointer. 12397c478bd9Sstevel@tonic-gate * We have 64 bit globals and outs, and 32 or 64 bit ins and locals. 12407c478bd9Sstevel@tonic-gate * Don't truncate globals/outs for 32 bit programs, for v8+ support. 12417c478bd9Sstevel@tonic-gate */ 12427c478bd9Sstevel@tonic-gate int 12437c478bd9Sstevel@tonic-gate putreg(uint64_t *data, struct regs *rp, uint_t reg, caddr_t *badaddr) 12447c478bd9Sstevel@tonic-gate { 12457c478bd9Sstevel@tonic-gate uint64_t *rgs, *sp; 12467c478bd9Sstevel@tonic-gate int rv = 0; 12477c478bd9Sstevel@tonic-gate 12487c478bd9Sstevel@tonic-gate rgs = (uint64_t *)&rp->r_ps; /* globals and outs */ 12497c478bd9Sstevel@tonic-gate sp = (uint64_t *)rp->r_sp; /* ins and locals */ 12507c478bd9Sstevel@tonic-gate if (reg == 0) { 12517c478bd9Sstevel@tonic-gate return (0); 12527c478bd9Sstevel@tonic-gate } else if (reg < 16) { 12537c478bd9Sstevel@tonic-gate rgs[reg] = *data; 12547c478bd9Sstevel@tonic-gate } else if (IS_V9STACK(sp)) { 12557c478bd9Sstevel@tonic-gate uint64_t *rw = (uint64_t *)((uintptr_t)sp + V9BIAS64); 12567c478bd9Sstevel@tonic-gate uint64_t *addr = (uint64_t *)&rw[reg - 16]; 12577c478bd9Sstevel@tonic-gate uint64_t res; 12587c478bd9Sstevel@tonic-gate 12597c478bd9Sstevel@tonic-gate if (USERMODE(rp->r_tstate)) { 12607c478bd9Sstevel@tonic-gate struct machpcb *mpcb = lwptompcb(curthread->t_lwp); 12617c478bd9Sstevel@tonic-gate 12627c478bd9Sstevel@tonic-gate res = *data; 12637c478bd9Sstevel@tonic-gate if (suword64_nowatch(addr, res) != 0) { 12647c478bd9Sstevel@tonic-gate *badaddr = (caddr_t)addr; 12657c478bd9Sstevel@tonic-gate rv = -1; 12667c478bd9Sstevel@tonic-gate } 12677c478bd9Sstevel@tonic-gate /* 12687c478bd9Sstevel@tonic-gate * We have changed a local or in register; 12697c478bd9Sstevel@tonic-gate * nuke the watchpoint return windows. 12707c478bd9Sstevel@tonic-gate */ 12717c478bd9Sstevel@tonic-gate mpcb->mpcb_rsp[0] = NULL; 12727c478bd9Sstevel@tonic-gate mpcb->mpcb_rsp[1] = NULL; 12737c478bd9Sstevel@tonic-gate } else { 12747c478bd9Sstevel@tonic-gate res = *data; 12757c478bd9Sstevel@tonic-gate *addr = res; 12767c478bd9Sstevel@tonic-gate } 12777c478bd9Sstevel@tonic-gate } else { 1278aad98a6dSmathue caddr32_t sp32 = (caddr32_t)(uintptr_t)sp; 1279aad98a6dSmathue uint32_t *rw = (uint32_t *)(uintptr_t)sp32; 12807c478bd9Sstevel@tonic-gate uint32_t *addr = (uint32_t *)&rw[reg - 16]; 12817c478bd9Sstevel@tonic-gate uint32_t res; 12827c478bd9Sstevel@tonic-gate 12837c478bd9Sstevel@tonic-gate if (USERMODE(rp->r_tstate)) { 12847c478bd9Sstevel@tonic-gate struct machpcb *mpcb = lwptompcb(curthread->t_lwp); 12857c478bd9Sstevel@tonic-gate 12867c478bd9Sstevel@tonic-gate res = (uint_t)*data; 12877c478bd9Sstevel@tonic-gate if (suword32_nowatch(addr, res) != 0) { 12887c478bd9Sstevel@tonic-gate *badaddr = (caddr_t)addr; 12897c478bd9Sstevel@tonic-gate rv = -1; 12907c478bd9Sstevel@tonic-gate } 12917c478bd9Sstevel@tonic-gate /* 12927c478bd9Sstevel@tonic-gate * We have changed a local or in register; 12937c478bd9Sstevel@tonic-gate * nuke the watchpoint return windows. 12947c478bd9Sstevel@tonic-gate */ 12957c478bd9Sstevel@tonic-gate mpcb->mpcb_rsp[0] = NULL; 12967c478bd9Sstevel@tonic-gate mpcb->mpcb_rsp[1] = NULL; 12977c478bd9Sstevel@tonic-gate 12987c478bd9Sstevel@tonic-gate } else { 12997c478bd9Sstevel@tonic-gate res = (uint_t)*data; 13007c478bd9Sstevel@tonic-gate *addr = res; 13017c478bd9Sstevel@tonic-gate } 13027c478bd9Sstevel@tonic-gate } 13037c478bd9Sstevel@tonic-gate return (rv); 13047c478bd9Sstevel@tonic-gate } 13057c478bd9Sstevel@tonic-gate 13067c478bd9Sstevel@tonic-gate /* 13077c478bd9Sstevel@tonic-gate * Calculate a memory reference address from instruction 13087c478bd9Sstevel@tonic-gate * operands, used to return the address of a fault, instead 13097c478bd9Sstevel@tonic-gate * of the instruction when an error occurs. This is code that is 13107c478bd9Sstevel@tonic-gate * common with most of the routines that simulate instructions. 13117c478bd9Sstevel@tonic-gate */ 13127c478bd9Sstevel@tonic-gate int 13137c478bd9Sstevel@tonic-gate calc_memaddr(struct regs *rp, caddr_t *badaddr) 13147c478bd9Sstevel@tonic-gate { 13157c478bd9Sstevel@tonic-gate uint_t inst; 13167c478bd9Sstevel@tonic-gate uint_t rd, rs1, rs2; 13177c478bd9Sstevel@tonic-gate int sz; 13187c478bd9Sstevel@tonic-gate int immflg; 13197c478bd9Sstevel@tonic-gate int floatflg; 13207c478bd9Sstevel@tonic-gate caddr_t addr; 13217c478bd9Sstevel@tonic-gate uint64_t val; 13227c478bd9Sstevel@tonic-gate 13237c478bd9Sstevel@tonic-gate if (USERMODE(rp->r_tstate)) 13247c478bd9Sstevel@tonic-gate inst = fetch_user_instr((caddr_t)rp->r_pc); 13257c478bd9Sstevel@tonic-gate else 13267c478bd9Sstevel@tonic-gate inst = *(uint_t *)rp->r_pc; 13277c478bd9Sstevel@tonic-gate 13287c478bd9Sstevel@tonic-gate rd = (inst >> 25) & 0x1f; 13297c478bd9Sstevel@tonic-gate rs1 = (inst >> 14) & 0x1f; 13307c478bd9Sstevel@tonic-gate rs2 = inst & 0x1f; 13317c478bd9Sstevel@tonic-gate floatflg = (inst >> 24) & 1; 13327c478bd9Sstevel@tonic-gate immflg = (inst >> 13) & 1; 13337c478bd9Sstevel@tonic-gate 13347c478bd9Sstevel@tonic-gate if (floatflg) { 13357c478bd9Sstevel@tonic-gate switch ((inst >> 19) & 3) { /* map size bits to a number */ 13367c478bd9Sstevel@tonic-gate case 0: sz = 4; break; /* ldf/stf */ 13377c478bd9Sstevel@tonic-gate case 1: return (0); /* ld[x]fsr/st[x]fsr */ 13387c478bd9Sstevel@tonic-gate case 2: sz = 16; break; /* ldqf/stqf */ 13397c478bd9Sstevel@tonic-gate case 3: sz = 8; break; /* lddf/stdf */ 13407c478bd9Sstevel@tonic-gate } 13417c478bd9Sstevel@tonic-gate /* 13427c478bd9Sstevel@tonic-gate * Fix to access extra double register encoding plus 13437c478bd9Sstevel@tonic-gate * compensate to access the correct fpu_dreg. 13447c478bd9Sstevel@tonic-gate */ 13457c478bd9Sstevel@tonic-gate if (sz > 4) { 13467c478bd9Sstevel@tonic-gate if ((rd & 1) == 1) 13477c478bd9Sstevel@tonic-gate rd = (rd & 0x1e) | 0x20; 13487c478bd9Sstevel@tonic-gate rd = rd >> 1; 13497c478bd9Sstevel@tonic-gate } 13507c478bd9Sstevel@tonic-gate } else { 13517c478bd9Sstevel@tonic-gate switch ((inst >> 19) & 0xf) { /* map size bits to a number */ 13527c478bd9Sstevel@tonic-gate case 0: /* lduw */ 13537c478bd9Sstevel@tonic-gate case 4: /* stw */ 13547c478bd9Sstevel@tonic-gate case 8: /* ldsw */ 13557c478bd9Sstevel@tonic-gate case 0xf: /* swap */ 13567c478bd9Sstevel@tonic-gate sz = 4; break; 13577c478bd9Sstevel@tonic-gate case 1: /* ldub */ 13587c478bd9Sstevel@tonic-gate case 5: /* stb */ 13597c478bd9Sstevel@tonic-gate case 9: /* ldsb */ 13607c478bd9Sstevel@tonic-gate case 0xd: /* ldstub */ 13617c478bd9Sstevel@tonic-gate sz = 1; break; 13627c478bd9Sstevel@tonic-gate case 2: /* lduh */ 13637c478bd9Sstevel@tonic-gate case 6: /* sth */ 13647c478bd9Sstevel@tonic-gate case 0xa: /* ldsh */ 13657c478bd9Sstevel@tonic-gate sz = 2; break; 13667c478bd9Sstevel@tonic-gate case 3: /* ldd */ 13677c478bd9Sstevel@tonic-gate case 7: /* std */ 13687c478bd9Sstevel@tonic-gate case 0xb: /* ldx */ 13697c478bd9Sstevel@tonic-gate case 0xe: /* stx */ 13707c478bd9Sstevel@tonic-gate sz = 8; break; 13717c478bd9Sstevel@tonic-gate } 13727c478bd9Sstevel@tonic-gate } 13737c478bd9Sstevel@tonic-gate 13747c478bd9Sstevel@tonic-gate if (USERMODE(rp->r_tstate)) 13757c478bd9Sstevel@tonic-gate (void) flush_user_windows_to_stack(NULL); 13767c478bd9Sstevel@tonic-gate else 13777c478bd9Sstevel@tonic-gate flush_windows(); 13787c478bd9Sstevel@tonic-gate 13797c478bd9Sstevel@tonic-gate if (getreg(rp, rs1, &val, badaddr)) 13807c478bd9Sstevel@tonic-gate return (SIMU_FAULT); 13817c478bd9Sstevel@tonic-gate addr = (caddr_t)val; 13827c478bd9Sstevel@tonic-gate 13837c478bd9Sstevel@tonic-gate /* check immediate bit and use immediate field or reg (rs2) */ 13847c478bd9Sstevel@tonic-gate if (immflg) { 13857c478bd9Sstevel@tonic-gate int imm; 13867c478bd9Sstevel@tonic-gate imm = inst & 0x1fff; /* mask out immediate field */ 13877c478bd9Sstevel@tonic-gate imm <<= 19; /* sign extend it */ 13887c478bd9Sstevel@tonic-gate imm >>= 19; 13897c478bd9Sstevel@tonic-gate addr += imm; /* compute address */ 13907c478bd9Sstevel@tonic-gate } else { 13917c478bd9Sstevel@tonic-gate if (getreg(rp, rs2, &val, badaddr)) 13927c478bd9Sstevel@tonic-gate return (SIMU_FAULT); 13937c478bd9Sstevel@tonic-gate addr += val; 13947c478bd9Sstevel@tonic-gate } 13957c478bd9Sstevel@tonic-gate 13967c478bd9Sstevel@tonic-gate /* 1397aad98a6dSmathue * If this is a 32-bit program, chop the address accordingly. The 1398aad98a6dSmathue * intermediate uintptr_t casts prevent warnings under a certain 1399aad98a6dSmathue * compiler, and the temporary 32 bit storage is intended to force 1400aad98a6dSmathue * proper code generation and break up what would otherwise be a 1401aad98a6dSmathue * quadruple cast. 14027c478bd9Sstevel@tonic-gate */ 1403aad98a6dSmathue if (curproc->p_model == DATAMODEL_ILP32 && USERMODE(rp->r_tstate)) { 1404aad98a6dSmathue caddr32_t addr32 = (caddr32_t)(uintptr_t)addr; 1405aad98a6dSmathue addr = (caddr_t)(uintptr_t)addr32; 1406aad98a6dSmathue } 14077c478bd9Sstevel@tonic-gate 14087c478bd9Sstevel@tonic-gate *badaddr = addr; 14097c478bd9Sstevel@tonic-gate return ((uintptr_t)addr & (sz - 1) ? SIMU_UNALIGN : SIMU_SUCCESS); 14107c478bd9Sstevel@tonic-gate } 14117c478bd9Sstevel@tonic-gate 14127c478bd9Sstevel@tonic-gate /* 14137c478bd9Sstevel@tonic-gate * Return the size of a load or store instruction (1, 2, 4, 8, 16, 64). 14147c478bd9Sstevel@tonic-gate * Also compute the precise address by instruction disassembly. 14157c478bd9Sstevel@tonic-gate * (v9 page faults only provide the page address via the hardware.) 14167c478bd9Sstevel@tonic-gate * Return 0 on failure (not a load or store instruction). 14177c478bd9Sstevel@tonic-gate */ 14187c478bd9Sstevel@tonic-gate int 14197c478bd9Sstevel@tonic-gate instr_size(struct regs *rp, caddr_t *addrp, enum seg_rw rdwr) 14207c478bd9Sstevel@tonic-gate { 14217c478bd9Sstevel@tonic-gate uint_t inst, op3, asi; 14227c478bd9Sstevel@tonic-gate uint_t rd, rs1, rs2; 14237c478bd9Sstevel@tonic-gate int sz = 0; 14247c478bd9Sstevel@tonic-gate int immflg; 14257c478bd9Sstevel@tonic-gate int floatflg; 14267c478bd9Sstevel@tonic-gate caddr_t addr; 14277c478bd9Sstevel@tonic-gate caddr_t badaddr; 14287c478bd9Sstevel@tonic-gate uint64_t val; 14297c478bd9Sstevel@tonic-gate 14307c478bd9Sstevel@tonic-gate if (rdwr == S_EXEC) { 14317c478bd9Sstevel@tonic-gate *addrp = (caddr_t)rp->r_pc; 14327c478bd9Sstevel@tonic-gate return (4); 14337c478bd9Sstevel@tonic-gate } 14347c478bd9Sstevel@tonic-gate 14357c478bd9Sstevel@tonic-gate /* 14367c478bd9Sstevel@tonic-gate * Fetch the instruction from user-level. 14377c478bd9Sstevel@tonic-gate * We would like to assert this: 14387c478bd9Sstevel@tonic-gate * ASSERT(USERMODE(rp->r_tstate)); 14397c478bd9Sstevel@tonic-gate * but we can't because we can reach this point from a 14407c478bd9Sstevel@tonic-gate * register window underflow/overflow and the v9 wbuf 14417c478bd9Sstevel@tonic-gate * traps call trap() with T_USER even though r_tstate 14427c478bd9Sstevel@tonic-gate * indicates a system trap, not a user trap. 14437c478bd9Sstevel@tonic-gate */ 14447c478bd9Sstevel@tonic-gate inst = fetch_user_instr((caddr_t)rp->r_pc); 14457c478bd9Sstevel@tonic-gate 14467c478bd9Sstevel@tonic-gate op3 = (inst >> 19) & 0x3f; 14477c478bd9Sstevel@tonic-gate rd = (inst >> 25) & 0x1f; 14487c478bd9Sstevel@tonic-gate rs1 = (inst >> 14) & 0x1f; 14497c478bd9Sstevel@tonic-gate rs2 = inst & 0x1f; 14507c478bd9Sstevel@tonic-gate floatflg = (inst >> 24) & 1; 14517c478bd9Sstevel@tonic-gate immflg = (inst >> 13) & 1; 14527c478bd9Sstevel@tonic-gate 14537c478bd9Sstevel@tonic-gate /* if not load or store do nothing. can't happen? */ 14547c478bd9Sstevel@tonic-gate if ((inst >> 30) != 3) 14557c478bd9Sstevel@tonic-gate return (0); 14567c478bd9Sstevel@tonic-gate 14577c478bd9Sstevel@tonic-gate if (immflg) 14587c478bd9Sstevel@tonic-gate asi = (uint_t)((rp->r_tstate >> TSTATE_ASI_SHIFT) & 14597c478bd9Sstevel@tonic-gate TSTATE_ASI_MASK); 14607c478bd9Sstevel@tonic-gate else 14617c478bd9Sstevel@tonic-gate asi = (inst >> 5) & 0xff; 14627c478bd9Sstevel@tonic-gate 14637c478bd9Sstevel@tonic-gate if (floatflg) { 14647c478bd9Sstevel@tonic-gate /* check for ld/st alternate and highest defined V9 asi */ 14657c478bd9Sstevel@tonic-gate if ((op3 & 0x30) == 0x30 && asi > ASI_SNFL) { 14667c478bd9Sstevel@tonic-gate sz = extended_asi_size(asi); 14677c478bd9Sstevel@tonic-gate } else { 14687c478bd9Sstevel@tonic-gate switch (op3 & 3) { 14697c478bd9Sstevel@tonic-gate case 0: 14707c478bd9Sstevel@tonic-gate sz = 4; /* ldf/stf/cas */ 14717c478bd9Sstevel@tonic-gate break; 14727c478bd9Sstevel@tonic-gate case 1: 14737c478bd9Sstevel@tonic-gate if (rd == 0) 14747c478bd9Sstevel@tonic-gate sz = 4; /* ldfsr/stfsr */ 14757c478bd9Sstevel@tonic-gate else 14767c478bd9Sstevel@tonic-gate sz = 8; /* ldxfsr/stxfsr */ 14777c478bd9Sstevel@tonic-gate break; 14787c478bd9Sstevel@tonic-gate case 2: 14797c478bd9Sstevel@tonic-gate if (op3 == 0x3e) 14807c478bd9Sstevel@tonic-gate sz = 8; /* casx */ 14817c478bd9Sstevel@tonic-gate else 14827c478bd9Sstevel@tonic-gate sz = 16; /* ldqf/stqf */ 14837c478bd9Sstevel@tonic-gate break; 14847c478bd9Sstevel@tonic-gate case 3: 14857c478bd9Sstevel@tonic-gate sz = 8; /* lddf/stdf */ 14867c478bd9Sstevel@tonic-gate break; 14877c478bd9Sstevel@tonic-gate } 14887c478bd9Sstevel@tonic-gate } 14897c478bd9Sstevel@tonic-gate } else { 14907c478bd9Sstevel@tonic-gate switch (op3 & 0xf) { /* map size bits to a number */ 14917c478bd9Sstevel@tonic-gate case 0: /* lduw */ 14927c478bd9Sstevel@tonic-gate case 4: /* stw */ 14937c478bd9Sstevel@tonic-gate case 8: /* ldsw */ 14947c478bd9Sstevel@tonic-gate case 0xf: /* swap */ 14957c478bd9Sstevel@tonic-gate sz = 4; break; 14967c478bd9Sstevel@tonic-gate case 1: /* ldub */ 14977c478bd9Sstevel@tonic-gate case 5: /* stb */ 14987c478bd9Sstevel@tonic-gate case 9: /* ldsb */ 14997c478bd9Sstevel@tonic-gate case 0xd: /* ldstub */ 15007c478bd9Sstevel@tonic-gate sz = 1; break; 15017c478bd9Sstevel@tonic-gate case 2: /* lduh */ 15027c478bd9Sstevel@tonic-gate case 6: /* sth */ 15037c478bd9Sstevel@tonic-gate case 0xa: /* ldsh */ 15047c478bd9Sstevel@tonic-gate sz = 2; break; 15057c478bd9Sstevel@tonic-gate case 3: /* ldd */ 15067c478bd9Sstevel@tonic-gate case 7: /* std */ 15077c478bd9Sstevel@tonic-gate case 0xb: /* ldx */ 15087c478bd9Sstevel@tonic-gate case 0xe: /* stx */ 15097c478bd9Sstevel@tonic-gate sz = 8; break; 15107c478bd9Sstevel@tonic-gate } 15117c478bd9Sstevel@tonic-gate } 15127c478bd9Sstevel@tonic-gate 15137c478bd9Sstevel@tonic-gate if (sz == 0) /* can't happen? */ 15147c478bd9Sstevel@tonic-gate return (0); 15157c478bd9Sstevel@tonic-gate (void) flush_user_windows_to_stack(NULL); 15167c478bd9Sstevel@tonic-gate 15177c478bd9Sstevel@tonic-gate if (getreg(rp, rs1, &val, &badaddr)) 15187c478bd9Sstevel@tonic-gate return (0); 15197c478bd9Sstevel@tonic-gate addr = (caddr_t)val; 15207c478bd9Sstevel@tonic-gate 15217c478bd9Sstevel@tonic-gate /* cas/casx don't use rs2 / simm13 to compute the address */ 15227c478bd9Sstevel@tonic-gate if ((op3 & 0x3d) != 0x3c) { 15237c478bd9Sstevel@tonic-gate /* check immediate bit and use immediate field or reg (rs2) */ 15247c478bd9Sstevel@tonic-gate if (immflg) { 15257c478bd9Sstevel@tonic-gate int imm; 15267c478bd9Sstevel@tonic-gate imm = inst & 0x1fff; /* mask out immediate field */ 15277c478bd9Sstevel@tonic-gate imm <<= 19; /* sign extend it */ 15287c478bd9Sstevel@tonic-gate imm >>= 19; 15297c478bd9Sstevel@tonic-gate addr += imm; /* compute address */ 15307c478bd9Sstevel@tonic-gate } else { 15317c478bd9Sstevel@tonic-gate /* 15327c478bd9Sstevel@tonic-gate * asi's in the 0xCx range are partial store 15337c478bd9Sstevel@tonic-gate * instructions. For these, rs2 is a mask, not part of 15347c478bd9Sstevel@tonic-gate * the address. 15357c478bd9Sstevel@tonic-gate */ 15367c478bd9Sstevel@tonic-gate if (!(floatflg && (asi & 0xf0) == 0xc0)) { 15377c478bd9Sstevel@tonic-gate if (getreg(rp, rs2, &val, &badaddr)) 15387c478bd9Sstevel@tonic-gate return (0); 15397c478bd9Sstevel@tonic-gate addr += val; 15407c478bd9Sstevel@tonic-gate } 15417c478bd9Sstevel@tonic-gate } 15427c478bd9Sstevel@tonic-gate } 15437c478bd9Sstevel@tonic-gate 15447c478bd9Sstevel@tonic-gate /* 1545aad98a6dSmathue * If this is a 32-bit program, chop the address accordingly. The 1546aad98a6dSmathue * intermediate uintptr_t casts prevent warnings under a certain 1547aad98a6dSmathue * compiler, and the temporary 32 bit storage is intended to force 1548aad98a6dSmathue * proper code generation and break up what would otherwise be a 1549aad98a6dSmathue * quadruple cast. 15507c478bd9Sstevel@tonic-gate */ 1551aad98a6dSmathue if (curproc->p_model == DATAMODEL_ILP32) { 1552aad98a6dSmathue caddr32_t addr32 = (caddr32_t)(uintptr_t)addr; 1553aad98a6dSmathue addr = (caddr_t)(uintptr_t)addr32; 1554aad98a6dSmathue } 15557c478bd9Sstevel@tonic-gate 15567c478bd9Sstevel@tonic-gate *addrp = addr; 15577c478bd9Sstevel@tonic-gate ASSERT(sz != 0); 15587c478bd9Sstevel@tonic-gate return (sz); 15597c478bd9Sstevel@tonic-gate } 15607c478bd9Sstevel@tonic-gate 15617c478bd9Sstevel@tonic-gate /* 15627c478bd9Sstevel@tonic-gate * Fetch an instruction from user-level. 15637c478bd9Sstevel@tonic-gate * Deal with watchpoints, if they are in effect. 15647c478bd9Sstevel@tonic-gate */ 15657c478bd9Sstevel@tonic-gate int32_t 15667c478bd9Sstevel@tonic-gate fetch_user_instr(caddr_t vaddr) 15677c478bd9Sstevel@tonic-gate { 15687c478bd9Sstevel@tonic-gate proc_t *p = curproc; 15697c478bd9Sstevel@tonic-gate int32_t instr; 15707c478bd9Sstevel@tonic-gate 15717c478bd9Sstevel@tonic-gate /* 1572aad98a6dSmathue * If this is a 32-bit program, chop the address accordingly. The 1573aad98a6dSmathue * intermediate uintptr_t casts prevent warnings under a certain 1574aad98a6dSmathue * compiler, and the temporary 32 bit storage is intended to force 1575aad98a6dSmathue * proper code generation and break up what would otherwise be a 1576aad98a6dSmathue * quadruple cast. 15777c478bd9Sstevel@tonic-gate */ 1578aad98a6dSmathue if (p->p_model == DATAMODEL_ILP32) { 1579aad98a6dSmathue caddr32_t vaddr32 = (caddr32_t)(uintptr_t)vaddr; 1580aad98a6dSmathue vaddr = (caddr_t)(uintptr_t)vaddr32; 1581aad98a6dSmathue } 15827c478bd9Sstevel@tonic-gate 15837c478bd9Sstevel@tonic-gate if (fuword32_nowatch(vaddr, (uint32_t *)&instr) == -1) 15847c478bd9Sstevel@tonic-gate instr = -1; 15857c478bd9Sstevel@tonic-gate 15867c478bd9Sstevel@tonic-gate return (instr); 15877c478bd9Sstevel@tonic-gate } 1588