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
do_unaligned(struct regs * rp,caddr_t * badaddr)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
simulate_lddstd(struct regs * rp,caddr_t * badaddr)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
simulate_popc(struct regs * rp,caddr_t * badaddr,uint_t inst)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
simulate_mulscc(struct regs * rp,caddr_t * badaddr,uint_t inst)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
simulate_unimp(struct regs * rp,caddr_t * badaddr)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*fd435bccSJosef '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*fd435bccSJosef '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*fd435bccSJosef '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*fd435bccSJosef 'Jeff' Sipek AS_LOCK_ENTER(as, RW_READER);
11187c478bd9Sstevel@tonic-gate pfnum = hat_getpfnum(as->a_hat, (caddr_t)rp->r_pc);
1119*fd435bccSJosef '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*fd435bccSJosef '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*fd435bccSJosef '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
simulate_rdtick(struct regs * rp)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
getreg(struct regs * rp,uint_t reg,uint64_t * val,caddr_t * badaddr)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
putreg(uint64_t * data,struct regs * rp,uint_t reg,caddr_t * badaddr)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
calc_memaddr(struct regs * rp,caddr_t * badaddr)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
instr_size(struct regs * rp,caddr_t * addrp,enum seg_rw rdwr)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
fetch_user_instr(caddr_t vaddr)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