10Sstevel@tonic-gate /*
20Sstevel@tonic-gate * CDDL HEADER START
30Sstevel@tonic-gate *
40Sstevel@tonic-gate * The contents of this file are subject to the terms of the
53398Ssvemuri * Common Development and Distribution License (the "License").
63398Ssvemuri * You may not use this file except in compliance with the License.
70Sstevel@tonic-gate *
80Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
90Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing.
100Sstevel@tonic-gate * See the License for the specific language governing permissions
110Sstevel@tonic-gate * and limitations under the License.
120Sstevel@tonic-gate *
130Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each
140Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
150Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the
160Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying
170Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner]
180Sstevel@tonic-gate *
190Sstevel@tonic-gate * CDDL HEADER END
200Sstevel@tonic-gate */
210Sstevel@tonic-gate /*
229195SChristopher.Baumbauer@Sun.COM * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
230Sstevel@tonic-gate * Use is subject to license terms.
240Sstevel@tonic-gate */
250Sstevel@tonic-gate
260Sstevel@tonic-gate /* common code with bug fixes from original version in trap.c */
270Sstevel@tonic-gate
280Sstevel@tonic-gate #include <sys/param.h>
290Sstevel@tonic-gate #include <sys/types.h>
300Sstevel@tonic-gate #include <sys/systm.h>
310Sstevel@tonic-gate #include <sys/archsystm.h>
320Sstevel@tonic-gate #include <sys/vmsystm.h>
330Sstevel@tonic-gate #include <sys/fpu/fpusystm.h>
340Sstevel@tonic-gate #include <sys/fpu/fpu_simulator.h>
350Sstevel@tonic-gate #include <sys/inline.h>
360Sstevel@tonic-gate #include <sys/debug.h>
370Sstevel@tonic-gate #include <sys/privregs.h>
380Sstevel@tonic-gate #include <sys/machpcb.h>
390Sstevel@tonic-gate #include <sys/simulate.h>
400Sstevel@tonic-gate #include <sys/proc.h>
410Sstevel@tonic-gate #include <sys/cmn_err.h>
420Sstevel@tonic-gate #include <sys/stack.h>
430Sstevel@tonic-gate #include <sys/watchpoint.h>
440Sstevel@tonic-gate #include <sys/trap.h>
450Sstevel@tonic-gate #include <sys/machtrap.h>
460Sstevel@tonic-gate #include <sys/mman.h>
470Sstevel@tonic-gate #include <sys/asi.h>
480Sstevel@tonic-gate #include <sys/copyops.h>
490Sstevel@tonic-gate #include <vm/as.h>
500Sstevel@tonic-gate #include <vm/page.h>
510Sstevel@tonic-gate #include <sys/model.h>
520Sstevel@tonic-gate #include <vm/seg_vn.h>
53518Swsm #include <sys/byteorder.h>
54*11172SHaik.Aftandilian@Sun.COM #include <sys/time.h>
550Sstevel@tonic-gate
560Sstevel@tonic-gate #define IS_IBIT_SET(x) (x & 0x2000)
570Sstevel@tonic-gate #define IS_VIS1(op, op3)(op == 2 && op3 == 0x36)
583398Ssvemuri #define IS_FLOAT_QUAD_OP(op, op3)(op == 2 && (op3 == 0x34 || \
593398Ssvemuri op3 == 0x35))
600Sstevel@tonic-gate #define IS_PARTIAL_OR_SHORT_FLOAT_LD_ST(op, op3, asi) \
610Sstevel@tonic-gate (op == 3 && (op3 == IOP_V8_LDDFA || \
620Sstevel@tonic-gate op3 == IOP_V8_STDFA) && asi > ASI_SNFL)
630Sstevel@tonic-gate
640Sstevel@tonic-gate static int aligndebug = 0;
650Sstevel@tonic-gate
660Sstevel@tonic-gate /*
670Sstevel@tonic-gate * For the sake of those who must be compatible with unaligned
680Sstevel@tonic-gate * architectures, users can link their programs to use a
690Sstevel@tonic-gate * corrective trap handler that will fix unaligned references
700Sstevel@tonic-gate * a special trap #6 (T_FIX_ALIGN) enables this 'feature'.
710Sstevel@tonic-gate * Returns 1 for success, 0 for failure.
720Sstevel@tonic-gate */
730Sstevel@tonic-gate
740Sstevel@tonic-gate int
do_unaligned(struct regs * rp,caddr_t * badaddr)750Sstevel@tonic-gate do_unaligned(struct regs *rp, caddr_t *badaddr)
760Sstevel@tonic-gate {
770Sstevel@tonic-gate uint_t inst, op3, asi = 0;
780Sstevel@tonic-gate uint_t rd, rs1, rs2;
790Sstevel@tonic-gate int sz, nf = 0, ltlend = 0;
800Sstevel@tonic-gate int floatflg;
810Sstevel@tonic-gate int fsrflg;
820Sstevel@tonic-gate int immflg;
830Sstevel@tonic-gate int lddstdflg;
840Sstevel@tonic-gate caddr_t addr;
850Sstevel@tonic-gate uint64_t val;
860Sstevel@tonic-gate union {
870Sstevel@tonic-gate uint64_t l[2];
880Sstevel@tonic-gate uint32_t i[4];
890Sstevel@tonic-gate uint16_t s[8];
900Sstevel@tonic-gate uint8_t c[16];
910Sstevel@tonic-gate } data;
920Sstevel@tonic-gate
930Sstevel@tonic-gate ASSERT(USERMODE(rp->r_tstate));
940Sstevel@tonic-gate inst = fetch_user_instr((caddr_t)rp->r_pc);
950Sstevel@tonic-gate
960Sstevel@tonic-gate op3 = (inst >> 19) & 0x3f;
970Sstevel@tonic-gate rd = (inst >> 25) & 0x1f;
980Sstevel@tonic-gate rs1 = (inst >> 14) & 0x1f;
990Sstevel@tonic-gate rs2 = inst & 0x1f;
1000Sstevel@tonic-gate floatflg = (inst >> 24) & 1;
1010Sstevel@tonic-gate immflg = (inst >> 13) & 1;
1020Sstevel@tonic-gate lddstdflg = fsrflg = 0;
1030Sstevel@tonic-gate
1040Sstevel@tonic-gate /* if not load or store do nothing */
1050Sstevel@tonic-gate if ((inst >> 30) != 3)
1060Sstevel@tonic-gate return (0);
1070Sstevel@tonic-gate
1080Sstevel@tonic-gate /* if ldstub or swap, do nothing */
1090Sstevel@tonic-gate if ((inst & 0xc1680000) == 0xc0680000)
1100Sstevel@tonic-gate return (0);
1110Sstevel@tonic-gate
1120Sstevel@tonic-gate /* if cas/casx, do nothing */
1130Sstevel@tonic-gate if ((inst & 0xc1e00000) == 0xc1e00000)
1140Sstevel@tonic-gate return (0);
1150Sstevel@tonic-gate
1160Sstevel@tonic-gate if (floatflg) {
1170Sstevel@tonic-gate switch ((inst >> 19) & 3) { /* map size bits to a number */
1180Sstevel@tonic-gate case 0: sz = 4;
1190Sstevel@tonic-gate break; /* ldf{a}/stf{a} */
1200Sstevel@tonic-gate case 1: fsrflg = 1;
1210Sstevel@tonic-gate if (rd == 0)
1220Sstevel@tonic-gate sz = 4; /* ldfsr/stfsr */
1230Sstevel@tonic-gate else if (rd == 1)
1240Sstevel@tonic-gate sz = 8; /* ldxfsr/stxfsr */
1250Sstevel@tonic-gate else
1260Sstevel@tonic-gate return (SIMU_ILLEGAL);
1270Sstevel@tonic-gate break;
1280Sstevel@tonic-gate case 2: sz = 16;
1290Sstevel@tonic-gate break; /* ldqf{a}/stqf{a} */
1300Sstevel@tonic-gate case 3: sz = 8;
1310Sstevel@tonic-gate break; /* lddf{a}/stdf{a} */
1320Sstevel@tonic-gate }
1330Sstevel@tonic-gate /*
1340Sstevel@tonic-gate * Fix to access extra double register encoding plus
1350Sstevel@tonic-gate * compensate to access the correct fpu_dreg.
1360Sstevel@tonic-gate */
1370Sstevel@tonic-gate if ((sz > 4) && (fsrflg == 0)) {
1380Sstevel@tonic-gate if ((rd & 1) == 1)
1390Sstevel@tonic-gate rd = (rd & 0x1e) | 0x20;
1400Sstevel@tonic-gate rd = rd >> 1;
1410Sstevel@tonic-gate if ((sz == 16) && ((rd & 0x1) != 0))
1420Sstevel@tonic-gate return (SIMU_ILLEGAL);
1430Sstevel@tonic-gate }
1440Sstevel@tonic-gate } else {
1450Sstevel@tonic-gate int sz_bits = (inst >> 19) & 0xf;
1460Sstevel@tonic-gate switch (sz_bits) { /* map size bits to a number */
1470Sstevel@tonic-gate case 0: /* lduw{a} */
1480Sstevel@tonic-gate case 4: /* stw{a} */
1490Sstevel@tonic-gate case 8: /* ldsw{a} */
1500Sstevel@tonic-gate case 0xf: /* swap */
1510Sstevel@tonic-gate sz = 4; break;
1520Sstevel@tonic-gate case 1: /* ldub{a} */
1530Sstevel@tonic-gate case 5: /* stb{a} */
1540Sstevel@tonic-gate case 9: /* ldsb{a} */
1550Sstevel@tonic-gate case 0xd: /* ldstub */
1560Sstevel@tonic-gate sz = 1; break;
1570Sstevel@tonic-gate case 2: /* lduh{a} */
1580Sstevel@tonic-gate case 6: /* sth{a} */
1590Sstevel@tonic-gate case 0xa: /* ldsh{a} */
1600Sstevel@tonic-gate sz = 2; break;
1610Sstevel@tonic-gate case 3: /* ldd{a} */
1620Sstevel@tonic-gate case 7: /* std{a} */
1630Sstevel@tonic-gate lddstdflg = 1;
1640Sstevel@tonic-gate sz = 8; break;
1650Sstevel@tonic-gate case 0xb: /* ldx{a} */
1660Sstevel@tonic-gate case 0xe: /* stx{a} */
1670Sstevel@tonic-gate sz = 8; break;
1680Sstevel@tonic-gate }
1690Sstevel@tonic-gate }
1700Sstevel@tonic-gate
1710Sstevel@tonic-gate
1720Sstevel@tonic-gate /* only support primary and secondary asi's */
1730Sstevel@tonic-gate if ((op3 >> 4) & 1) {
1740Sstevel@tonic-gate if (immflg) {
1750Sstevel@tonic-gate asi = (uint_t)(rp->r_tstate >> TSTATE_ASI_SHIFT) &
1767718SJason.Beloro@Sun.COM TSTATE_ASI_MASK;
1770Sstevel@tonic-gate } else {
1780Sstevel@tonic-gate asi = (inst >> 5) & 0xff;
1790Sstevel@tonic-gate }
1800Sstevel@tonic-gate switch (asi) {
1810Sstevel@tonic-gate case ASI_P:
1820Sstevel@tonic-gate case ASI_S:
1830Sstevel@tonic-gate break;
1840Sstevel@tonic-gate case ASI_PNF:
1850Sstevel@tonic-gate case ASI_SNF:
1860Sstevel@tonic-gate nf = 1;
1870Sstevel@tonic-gate break;
1880Sstevel@tonic-gate case ASI_PL:
1890Sstevel@tonic-gate case ASI_SL:
1900Sstevel@tonic-gate ltlend = 1;
1910Sstevel@tonic-gate break;
1920Sstevel@tonic-gate case ASI_PNFL:
1930Sstevel@tonic-gate case ASI_SNFL:
1940Sstevel@tonic-gate ltlend = 1;
1950Sstevel@tonic-gate nf = 1;
1960Sstevel@tonic-gate break;
1970Sstevel@tonic-gate default:
1980Sstevel@tonic-gate return (0);
1990Sstevel@tonic-gate }
2000Sstevel@tonic-gate /*
2010Sstevel@tonic-gate * Non-faulting stores generate a data_access_exception trap,
2020Sstevel@tonic-gate * according to the Spitfire manual, which should be signaled
2030Sstevel@tonic-gate * as an illegal instruction trap, because it can't be fixed.
2040Sstevel@tonic-gate */
2050Sstevel@tonic-gate if ((nf) && ((op3 == IOP_V8_STQFA) || (op3 == IOP_V8_STDFA)))
2060Sstevel@tonic-gate return (SIMU_ILLEGAL);
2070Sstevel@tonic-gate }
2080Sstevel@tonic-gate
2090Sstevel@tonic-gate if (aligndebug) {
2100Sstevel@tonic-gate printf("unaligned access at %p, instruction: 0x%x\n",
2110Sstevel@tonic-gate (void *)rp->r_pc, inst);
2120Sstevel@tonic-gate printf("type %s", (((inst >> 21) & 1) ? "st" : "ld"));
2130Sstevel@tonic-gate if (((inst >> 21) & 1) == 0)
2147718SJason.Beloro@Sun.COM printf(" %s", (((inst >> 22) & 1) ?
2157718SJason.Beloro@Sun.COM "signed" : "unsigned"));
2160Sstevel@tonic-gate printf(" asi 0x%x size %d immflg %d\n", asi, sz, immflg);
2170Sstevel@tonic-gate printf("rd = %d, op3 = 0x%x, rs1 = %d, rs2 = %d, imm13=0x%x\n",
2187718SJason.Beloro@Sun.COM rd, op3, rs1, rs2, (inst & 0x1fff));
2190Sstevel@tonic-gate }
2200Sstevel@tonic-gate
2210Sstevel@tonic-gate (void) flush_user_windows_to_stack(NULL);
2220Sstevel@tonic-gate if (getreg(rp, rs1, &val, badaddr))
2230Sstevel@tonic-gate return (SIMU_FAULT);
2240Sstevel@tonic-gate addr = (caddr_t)val; /* convert to 32/64 bit address */
2250Sstevel@tonic-gate if (aligndebug)
2260Sstevel@tonic-gate printf("addr 1 = %p\n", (void *)addr);
2270Sstevel@tonic-gate
2280Sstevel@tonic-gate /* check immediate bit and use immediate field or reg (rs2) */
2290Sstevel@tonic-gate if (immflg) {
2300Sstevel@tonic-gate int imm;
2310Sstevel@tonic-gate imm = inst & 0x1fff; /* mask out immediate field */
2320Sstevel@tonic-gate imm <<= 19; /* sign extend it */
2330Sstevel@tonic-gate imm >>= 19;
2340Sstevel@tonic-gate addr += imm; /* compute address */
2350Sstevel@tonic-gate } else {
2360Sstevel@tonic-gate if (getreg(rp, rs2, &val, badaddr))
2370Sstevel@tonic-gate return (SIMU_FAULT);
2380Sstevel@tonic-gate addr += val;
2390Sstevel@tonic-gate }
2400Sstevel@tonic-gate
2410Sstevel@tonic-gate /*
2421030Smathue * If this is a 32-bit program, chop the address accordingly. The
2431030Smathue * intermediate uintptr_t casts prevent warnings under a certain
2441030Smathue * compiler, and the temporary 32 bit storage is intended to force
2451030Smathue * proper code generation and break up what would otherwise be a
2461030Smathue * quadruple cast.
2470Sstevel@tonic-gate */
2481030Smathue if (curproc->p_model == DATAMODEL_ILP32) {
2491030Smathue caddr32_t addr32 = (caddr32_t)(uintptr_t)addr;
2501030Smathue addr = (caddr_t)(uintptr_t)addr32;
2511030Smathue }
2520Sstevel@tonic-gate
2530Sstevel@tonic-gate if (aligndebug)
2540Sstevel@tonic-gate printf("addr 2 = %p\n", (void *)addr);
2550Sstevel@tonic-gate
2560Sstevel@tonic-gate if (addr >= curproc->p_as->a_userlimit) {
2570Sstevel@tonic-gate *badaddr = addr;
2580Sstevel@tonic-gate goto badret;
2590Sstevel@tonic-gate }
2600Sstevel@tonic-gate
2610Sstevel@tonic-gate /* a single bit differentiates ld and st */
2620Sstevel@tonic-gate if ((inst >> 21) & 1) { /* store */
2630Sstevel@tonic-gate if (floatflg) {
2640Sstevel@tonic-gate klwp_id_t lwp = ttolwp(curthread);
2650Sstevel@tonic-gate kfpu_t *fp = lwptofpu(lwp);
2660Sstevel@tonic-gate /* Ensure fp has been enabled */
2670Sstevel@tonic-gate if (fpu_exists) {
2680Sstevel@tonic-gate if (!(_fp_read_fprs() & FPRS_FEF))
2690Sstevel@tonic-gate fp_enable();
2700Sstevel@tonic-gate } else {
2710Sstevel@tonic-gate if (!fp->fpu_en)
2720Sstevel@tonic-gate fp_enable();
2730Sstevel@tonic-gate }
2740Sstevel@tonic-gate /* if fpu_exists read fpu reg */
2750Sstevel@tonic-gate if (fpu_exists) {
2760Sstevel@tonic-gate if (fsrflg) {
2770Sstevel@tonic-gate _fp_read_pfsr(&data.l[0]);
2780Sstevel@tonic-gate } else {
2790Sstevel@tonic-gate if (sz == 4) {
2800Sstevel@tonic-gate data.i[0] = 0;
2810Sstevel@tonic-gate _fp_read_pfreg(
2820Sstevel@tonic-gate (unsigned *)&data.i[1], rd);
2830Sstevel@tonic-gate }
2840Sstevel@tonic-gate if (sz >= 8)
2850Sstevel@tonic-gate _fp_read_pdreg(
2867718SJason.Beloro@Sun.COM &data.l[0], rd);
2870Sstevel@tonic-gate if (sz == 16)
2880Sstevel@tonic-gate _fp_read_pdreg(
2897718SJason.Beloro@Sun.COM &data.l[1], rd+1);
2900Sstevel@tonic-gate }
2910Sstevel@tonic-gate } else {
2920Sstevel@tonic-gate if (fsrflg) {
2930Sstevel@tonic-gate /* Clear reserved bits, set version=7 */
2940Sstevel@tonic-gate fp->fpu_fsr &= ~0x30301000;
2950Sstevel@tonic-gate fp->fpu_fsr |= 0xE0000;
2960Sstevel@tonic-gate data.l[0] = fp->fpu_fsr;
2970Sstevel@tonic-gate } else {
2980Sstevel@tonic-gate if (sz == 4) {
2990Sstevel@tonic-gate data.i[0] = 0;
3000Sstevel@tonic-gate data.i[1] =
3017718SJason.Beloro@Sun.COM (unsigned)fp->
3027718SJason.Beloro@Sun.COM fpu_fr.fpu_regs[rd];
3030Sstevel@tonic-gate }
3040Sstevel@tonic-gate if (sz >= 8)
3050Sstevel@tonic-gate data.l[0] =
3060Sstevel@tonic-gate fp->fpu_fr.fpu_dregs[rd];
3070Sstevel@tonic-gate if (sz == 16)
3080Sstevel@tonic-gate data.l[1] =
3090Sstevel@tonic-gate fp->fpu_fr.fpu_dregs[rd+1];
3100Sstevel@tonic-gate }
3110Sstevel@tonic-gate }
3120Sstevel@tonic-gate } else {
313518Swsm if (lddstdflg) { /* combine the data */
3140Sstevel@tonic-gate if (getreg(rp, rd, &data.l[0], badaddr))
3150Sstevel@tonic-gate return (SIMU_FAULT);
3160Sstevel@tonic-gate if (getreg(rp, rd+1, &data.l[1], badaddr))
3170Sstevel@tonic-gate return (SIMU_FAULT);
318518Swsm if (ltlend) {
319518Swsm /*
320518Swsm * For STD, each 32-bit word is byte-
321518Swsm * swapped individually. For
322518Swsm * simplicity we don't want to do that
323518Swsm * below, so we swap the words now to
324518Swsm * get the desired result in the end.
325518Swsm */
326518Swsm data.i[0] = data.i[3];
327518Swsm } else {
328518Swsm data.i[0] = data.i[1];
329518Swsm data.i[1] = data.i[3];
330518Swsm }
3310Sstevel@tonic-gate } else {
3320Sstevel@tonic-gate if (getreg(rp, rd, &data.l[0], badaddr))
3330Sstevel@tonic-gate return (SIMU_FAULT);
3340Sstevel@tonic-gate }
3350Sstevel@tonic-gate }
3360Sstevel@tonic-gate
3370Sstevel@tonic-gate if (aligndebug) {
3380Sstevel@tonic-gate if (sz == 16) {
3390Sstevel@tonic-gate printf("data %x %x %x %x\n",
3400Sstevel@tonic-gate data.i[0], data.i[1], data.i[2], data.c[3]);
3410Sstevel@tonic-gate } else {
3420Sstevel@tonic-gate printf("data %x %x %x %x %x %x %x %x\n",
3430Sstevel@tonic-gate data.c[0], data.c[1], data.c[2], data.c[3],
3440Sstevel@tonic-gate data.c[4], data.c[5], data.c[6], data.c[7]);
3450Sstevel@tonic-gate }
3460Sstevel@tonic-gate }
3470Sstevel@tonic-gate
3480Sstevel@tonic-gate if (ltlend) {
3490Sstevel@tonic-gate if (sz == 1) {
3500Sstevel@tonic-gate if (xcopyout_little(&data.c[7], addr,
3510Sstevel@tonic-gate (size_t)sz) != 0)
3520Sstevel@tonic-gate goto badret;
3530Sstevel@tonic-gate } else if (sz == 2) {
3540Sstevel@tonic-gate if (xcopyout_little(&data.s[3], addr,
3550Sstevel@tonic-gate (size_t)sz) != 0)
3560Sstevel@tonic-gate goto badret;
3570Sstevel@tonic-gate } else if (sz == 4) {
3580Sstevel@tonic-gate if (xcopyout_little(&data.i[1], addr,
3590Sstevel@tonic-gate (size_t)sz) != 0)
3600Sstevel@tonic-gate goto badret;
3610Sstevel@tonic-gate } else {
3620Sstevel@tonic-gate if (xcopyout_little(&data.l[0], addr,
3630Sstevel@tonic-gate (size_t)sz) != 0)
3640Sstevel@tonic-gate goto badret;
3650Sstevel@tonic-gate }
3660Sstevel@tonic-gate } else {
3670Sstevel@tonic-gate if (sz == 1) {
3680Sstevel@tonic-gate if (copyout(&data.c[7], addr, (size_t)sz) == -1)
3690Sstevel@tonic-gate goto badret;
3700Sstevel@tonic-gate } else if (sz == 2) {
3710Sstevel@tonic-gate if (copyout(&data.s[3], addr, (size_t)sz) == -1)
3720Sstevel@tonic-gate goto badret;
3730Sstevel@tonic-gate } else if (sz == 4) {
3740Sstevel@tonic-gate if (copyout(&data.i[1], addr, (size_t)sz) == -1)
3750Sstevel@tonic-gate goto badret;
3760Sstevel@tonic-gate } else {
3770Sstevel@tonic-gate if (copyout(&data.l[0], addr, (size_t)sz) == -1)
3780Sstevel@tonic-gate goto badret;
3790Sstevel@tonic-gate }
3800Sstevel@tonic-gate }
3810Sstevel@tonic-gate } else { /* load */
3820Sstevel@tonic-gate if (sz == 1) {
3830Sstevel@tonic-gate if (ltlend) {
3840Sstevel@tonic-gate if (xcopyin_little(addr, &data.c[7],
3850Sstevel@tonic-gate (size_t)sz) != 0) {
3860Sstevel@tonic-gate if (nf)
3870Sstevel@tonic-gate data.c[7] = 0;
3880Sstevel@tonic-gate else
3890Sstevel@tonic-gate goto badret;
3900Sstevel@tonic-gate }
3910Sstevel@tonic-gate } else {
3920Sstevel@tonic-gate if (copyin(addr, &data.c[7],
3930Sstevel@tonic-gate (size_t)sz) == -1) {
3940Sstevel@tonic-gate if (nf)
3950Sstevel@tonic-gate data.c[7] = 0;
3960Sstevel@tonic-gate else
3970Sstevel@tonic-gate goto badret;
3980Sstevel@tonic-gate }
3990Sstevel@tonic-gate }
4000Sstevel@tonic-gate /* if signed and the sign bit is set extend it */
4010Sstevel@tonic-gate if (((inst >> 22) & 1) && ((data.c[7] >> 7) & 1)) {
4020Sstevel@tonic-gate data.i[0] = (uint_t)-1; /* extend sign bit */
4030Sstevel@tonic-gate data.s[2] = (ushort_t)-1;
4040Sstevel@tonic-gate data.c[6] = (uchar_t)-1;
4050Sstevel@tonic-gate } else {
4060Sstevel@tonic-gate data.i[0] = 0; /* clear upper 32+24 bits */
4070Sstevel@tonic-gate data.s[2] = 0;
4080Sstevel@tonic-gate data.c[6] = 0;
4090Sstevel@tonic-gate }
4100Sstevel@tonic-gate } else if (sz == 2) {
4110Sstevel@tonic-gate if (ltlend) {
4120Sstevel@tonic-gate if (xcopyin_little(addr, &data.s[3],
4130Sstevel@tonic-gate (size_t)sz) != 0) {
4140Sstevel@tonic-gate if (nf)
4150Sstevel@tonic-gate data.s[3] = 0;
4160Sstevel@tonic-gate else
4170Sstevel@tonic-gate goto badret;
4180Sstevel@tonic-gate }
4190Sstevel@tonic-gate } else {
4200Sstevel@tonic-gate if (copyin(addr, &data.s[3],
4210Sstevel@tonic-gate (size_t)sz) == -1) {
4220Sstevel@tonic-gate if (nf)
4230Sstevel@tonic-gate data.s[3] = 0;
4240Sstevel@tonic-gate else
4250Sstevel@tonic-gate goto badret;
4260Sstevel@tonic-gate }
4270Sstevel@tonic-gate }
4280Sstevel@tonic-gate /* if signed and the sign bit is set extend it */
4290Sstevel@tonic-gate if (((inst >> 22) & 1) && ((data.s[3] >> 15) & 1)) {
4300Sstevel@tonic-gate data.i[0] = (uint_t)-1; /* extend sign bit */
4310Sstevel@tonic-gate data.s[2] = (ushort_t)-1;
4320Sstevel@tonic-gate } else {
4330Sstevel@tonic-gate data.i[0] = 0; /* clear upper 32+16 bits */
4340Sstevel@tonic-gate data.s[2] = 0;
4350Sstevel@tonic-gate }
4360Sstevel@tonic-gate } else if (sz == 4) {
4370Sstevel@tonic-gate if (ltlend) {
4380Sstevel@tonic-gate if (xcopyin_little(addr, &data.i[1],
4390Sstevel@tonic-gate (size_t)sz) != 0) {
4400Sstevel@tonic-gate if (!nf)
4410Sstevel@tonic-gate goto badret;
4420Sstevel@tonic-gate data.i[1] = 0;
4430Sstevel@tonic-gate }
4440Sstevel@tonic-gate } else {
4450Sstevel@tonic-gate if (copyin(addr, &data.i[1],
4460Sstevel@tonic-gate (size_t)sz) == -1) {
4470Sstevel@tonic-gate if (!nf)
4480Sstevel@tonic-gate goto badret;
4490Sstevel@tonic-gate data.i[1] = 0;
4500Sstevel@tonic-gate }
4510Sstevel@tonic-gate }
4520Sstevel@tonic-gate /* if signed and the sign bit is set extend it */
4530Sstevel@tonic-gate if (((inst >> 22) & 1) && ((data.i[1] >> 31) & 1)) {
4540Sstevel@tonic-gate data.i[0] = (uint_t)-1; /* extend sign bit */
4550Sstevel@tonic-gate } else {
4560Sstevel@tonic-gate data.i[0] = 0; /* clear upper 32 bits */
4570Sstevel@tonic-gate }
4580Sstevel@tonic-gate } else {
4590Sstevel@tonic-gate if (ltlend) {
4600Sstevel@tonic-gate if (xcopyin_little(addr, &data.l[0],
4610Sstevel@tonic-gate (size_t)sz) != 0) {
4620Sstevel@tonic-gate if (!nf)
4630Sstevel@tonic-gate goto badret;
4640Sstevel@tonic-gate data.l[0] = 0;
4650Sstevel@tonic-gate }
4660Sstevel@tonic-gate } else {
4670Sstevel@tonic-gate if (copyin(addr, &data.l[0],
4680Sstevel@tonic-gate (size_t)sz) == -1) {
4690Sstevel@tonic-gate if (!nf)
4700Sstevel@tonic-gate goto badret;
4710Sstevel@tonic-gate data.l[0] = 0;
4720Sstevel@tonic-gate }
4730Sstevel@tonic-gate }
4740Sstevel@tonic-gate }
4750Sstevel@tonic-gate
4760Sstevel@tonic-gate if (aligndebug) {
4770Sstevel@tonic-gate if (sz == 16) {
4780Sstevel@tonic-gate printf("data %x %x %x %x\n",
4790Sstevel@tonic-gate data.i[0], data.i[1], data.i[2], data.c[3]);
4800Sstevel@tonic-gate } else {
4810Sstevel@tonic-gate printf("data %x %x %x %x %x %x %x %x\n",
4820Sstevel@tonic-gate data.c[0], data.c[1], data.c[2], data.c[3],
4830Sstevel@tonic-gate data.c[4], data.c[5], data.c[6], data.c[7]);
4840Sstevel@tonic-gate }
4850Sstevel@tonic-gate }
4860Sstevel@tonic-gate
4870Sstevel@tonic-gate if (floatflg) { /* if fpu_exists write fpu reg */
4880Sstevel@tonic-gate klwp_id_t lwp = ttolwp(curthread);
4890Sstevel@tonic-gate kfpu_t *fp = lwptofpu(lwp);
4900Sstevel@tonic-gate /* Ensure fp has been enabled */
4910Sstevel@tonic-gate if (fpu_exists) {
4920Sstevel@tonic-gate if (!(_fp_read_fprs() & FPRS_FEF))
4930Sstevel@tonic-gate fp_enable();
4940Sstevel@tonic-gate } else {
4950Sstevel@tonic-gate if (!fp->fpu_en)
4960Sstevel@tonic-gate fp_enable();
4970Sstevel@tonic-gate }
4980Sstevel@tonic-gate /* if fpu_exists read fpu reg */
4990Sstevel@tonic-gate if (fpu_exists) {
5000Sstevel@tonic-gate if (fsrflg) {
5010Sstevel@tonic-gate _fp_write_pfsr(&data.l[0]);
5020Sstevel@tonic-gate } else {
5030Sstevel@tonic-gate if (sz == 4)
5040Sstevel@tonic-gate _fp_write_pfreg(
5050Sstevel@tonic-gate (unsigned *)&data.i[1], rd);
5060Sstevel@tonic-gate if (sz >= 8)
5070Sstevel@tonic-gate _fp_write_pdreg(
5087718SJason.Beloro@Sun.COM &data.l[0], rd);
5090Sstevel@tonic-gate if (sz == 16)
5100Sstevel@tonic-gate _fp_write_pdreg(
5117718SJason.Beloro@Sun.COM &data.l[1], rd+1);
5120Sstevel@tonic-gate }
5130Sstevel@tonic-gate } else {
5140Sstevel@tonic-gate if (fsrflg) {
5150Sstevel@tonic-gate fp->fpu_fsr = data.l[0];
5160Sstevel@tonic-gate } else {
5170Sstevel@tonic-gate if (sz == 4)
5180Sstevel@tonic-gate fp->fpu_fr.fpu_regs[rd] =
5197718SJason.Beloro@Sun.COM (unsigned)data.i[1];
5200Sstevel@tonic-gate if (sz >= 8)
5210Sstevel@tonic-gate fp->fpu_fr.fpu_dregs[rd] =
5227718SJason.Beloro@Sun.COM data.l[0];
5230Sstevel@tonic-gate if (sz == 16)
5240Sstevel@tonic-gate fp->fpu_fr.fpu_dregs[rd+1] =
5257718SJason.Beloro@Sun.COM data.l[1];
5260Sstevel@tonic-gate }
5270Sstevel@tonic-gate }
5280Sstevel@tonic-gate } else {
5290Sstevel@tonic-gate if (lddstdflg) { /* split the data */
530518Swsm if (ltlend) {
531518Swsm /*
532518Swsm * For LDD, each 32-bit word is byte-
533518Swsm * swapped individually. We didn't
534518Swsm * do that above, but this will give
535518Swsm * us the desired result.
536518Swsm */
537518Swsm data.i[3] = data.i[0];
538518Swsm } else {
539518Swsm data.i[3] = data.i[1];
540518Swsm data.i[1] = data.i[0];
541518Swsm }
542518Swsm data.i[0] = 0;
5430Sstevel@tonic-gate data.i[2] = 0;
5440Sstevel@tonic-gate if (putreg(&data.l[0], rp, rd, badaddr) == -1)
5450Sstevel@tonic-gate goto badret;
5460Sstevel@tonic-gate if (putreg(&data.l[1], rp, rd+1, badaddr) == -1)
5470Sstevel@tonic-gate goto badret;
5480Sstevel@tonic-gate } else {
5490Sstevel@tonic-gate if (putreg(&data.l[0], rp, rd, badaddr) == -1)
5500Sstevel@tonic-gate goto badret;
5510Sstevel@tonic-gate }
5520Sstevel@tonic-gate }
5530Sstevel@tonic-gate }
5540Sstevel@tonic-gate return (SIMU_SUCCESS);
5550Sstevel@tonic-gate badret:
5560Sstevel@tonic-gate return (SIMU_FAULT);
5570Sstevel@tonic-gate }
5580Sstevel@tonic-gate
559518Swsm
560518Swsm int
simulate_lddstd(struct regs * rp,caddr_t * badaddr)561518Swsm simulate_lddstd(struct regs *rp, caddr_t *badaddr)
562518Swsm {
563518Swsm uint_t inst, op3, asi = 0;
564518Swsm uint_t rd, rs1, rs2;
565518Swsm int nf = 0, ltlend = 0, usermode;
566518Swsm int immflg;
567518Swsm uint64_t reven;
568518Swsm uint64_t rodd;
569518Swsm caddr_t addr;
570518Swsm uint64_t val;
571518Swsm uint64_t data;
572518Swsm
573518Swsm usermode = USERMODE(rp->r_tstate);
574518Swsm
575518Swsm if (usermode)
576518Swsm inst = fetch_user_instr((caddr_t)rp->r_pc);
577518Swsm else
578518Swsm inst = *(uint_t *)rp->r_pc;
579518Swsm
580518Swsm op3 = (inst >> 19) & 0x3f;
581518Swsm rd = (inst >> 25) & 0x1f;
582518Swsm rs1 = (inst >> 14) & 0x1f;
583518Swsm rs2 = inst & 0x1f;
584518Swsm immflg = (inst >> 13) & 1;
585518Swsm
586518Swsm if (USERMODE(rp->r_tstate))
587518Swsm (void) flush_user_windows_to_stack(NULL);
588518Swsm else
589518Swsm flush_windows();
590518Swsm
591518Swsm if ((op3 >> 4) & 1) { /* is this LDDA/STDA? */
592518Swsm if (immflg) {
593518Swsm asi = (uint_t)(rp->r_tstate >> TSTATE_ASI_SHIFT) &
5947718SJason.Beloro@Sun.COM TSTATE_ASI_MASK;
595518Swsm } else {
596518Swsm asi = (inst >> 5) & 0xff;
597518Swsm }
598518Swsm switch (asi) {
599518Swsm case ASI_P:
600518Swsm case ASI_S:
601518Swsm break;
602518Swsm case ASI_PNF:
603518Swsm case ASI_SNF:
604518Swsm nf = 1;
605518Swsm break;
606518Swsm case ASI_PL:
607518Swsm case ASI_SL:
608518Swsm ltlend = 1;
609518Swsm break;
610518Swsm case ASI_PNFL:
611518Swsm case ASI_SNFL:
612518Swsm ltlend = 1;
613518Swsm nf = 1;
614518Swsm break;
615518Swsm case ASI_AIUP:
616518Swsm case ASI_AIUS:
617518Swsm usermode = 1;
618518Swsm break;
619518Swsm case ASI_AIUPL:
620518Swsm case ASI_AIUSL:
621518Swsm usermode = 1;
622518Swsm ltlend = 1;
623518Swsm break;
624518Swsm default:
625518Swsm return (SIMU_ILLEGAL);
626518Swsm }
627518Swsm }
628518Swsm
629518Swsm if (getreg(rp, rs1, &val, badaddr))
630518Swsm return (SIMU_FAULT);
631518Swsm addr = (caddr_t)val; /* convert to 32/64 bit address */
632518Swsm
633518Swsm /* check immediate bit and use immediate field or reg (rs2) */
634518Swsm if (immflg) {
635518Swsm int imm;
636518Swsm imm = inst & 0x1fff; /* mask out immediate field */
637518Swsm imm <<= 19; /* sign extend it */
638518Swsm imm >>= 19;
639518Swsm addr += imm; /* compute address */
640518Swsm } else {
641518Swsm if (getreg(rp, rs2, &val, badaddr))
642518Swsm return (SIMU_FAULT);
643518Swsm addr += val;
644518Swsm }
645518Swsm
646518Swsm /*
647518Swsm * T_UNIMP_LDD and T_UNIMP_STD are higher priority than
648518Swsm * T_ALIGNMENT. So we have to make sure that the address is
649518Swsm * kosher before trying to use it, because the hardware hasn't
650518Swsm * checked it for us yet.
651518Swsm */
652518Swsm if (((uintptr_t)addr & 0x7) != 0) {
653518Swsm if (curproc->p_fixalignment)
654518Swsm return (do_unaligned(rp, badaddr));
655518Swsm else
656518Swsm return (SIMU_UNALIGN);
657518Swsm }
658518Swsm
659518Swsm /*
6601030Smathue * If this is a 32-bit program, chop the address accordingly. The
6611030Smathue * intermediate uintptr_t casts prevent warnings under a certain
6621030Smathue * compiler, and the temporary 32 bit storage is intended to force
6631030Smathue * proper code generation and break up what would otherwise be a
6641030Smathue * quadruple cast.
665518Swsm */
6661030Smathue if (curproc->p_model == DATAMODEL_ILP32 && usermode) {
6671030Smathue caddr32_t addr32 = (caddr32_t)(uintptr_t)addr;
6681030Smathue addr = (caddr_t)(uintptr_t)addr32;
6691030Smathue }
670518Swsm
671518Swsm if ((inst >> 21) & 1) { /* store */
672518Swsm if (getreg(rp, rd, &reven, badaddr))
673518Swsm return (SIMU_FAULT);
674518Swsm if (getreg(rp, rd+1, &rodd, badaddr))
675518Swsm return (SIMU_FAULT);
676518Swsm if (ltlend) {
677518Swsm reven = BSWAP_32(reven);
678518Swsm rodd = BSWAP_32(rodd);
679518Swsm }
680518Swsm data = (reven << 32) | rodd;
681518Swsm if (usermode) {
682518Swsm if (suword64_nowatch(addr, data) == -1)
683518Swsm return (SIMU_FAULT);
684518Swsm } else {
685518Swsm *(uint64_t *)addr = data;
686518Swsm }
687518Swsm } else { /* load */
688518Swsm if (usermode) {
689518Swsm if (fuword64_nowatch(addr, &data)) {
690518Swsm if (nf)
691518Swsm data = 0;
692518Swsm else
693518Swsm return (SIMU_FAULT);
694518Swsm }
695518Swsm } else
696518Swsm data = *(uint64_t *)addr;
697518Swsm
698518Swsm reven = (data >> 32);
699518Swsm rodd = (uint64_t)(uint32_t)data;
700518Swsm if (ltlend) {
701518Swsm reven = BSWAP_32(reven);
702518Swsm rodd = BSWAP_32(rodd);
703518Swsm }
704518Swsm
705518Swsm if (putreg(&reven, rp, rd, badaddr) == -1)
706518Swsm return (SIMU_FAULT);
707518Swsm if (putreg(&rodd, rp, rd+1, badaddr) == -1)
708518Swsm return (SIMU_FAULT);
709518Swsm }
710518Swsm return (SIMU_SUCCESS);
711518Swsm }
712518Swsm
713518Swsm
7140Sstevel@tonic-gate /*
7150Sstevel@tonic-gate * simulate popc
7160Sstevel@tonic-gate */
7170Sstevel@tonic-gate static int
simulate_popc(struct regs * rp,caddr_t * badaddr,uint_t inst)7180Sstevel@tonic-gate simulate_popc(struct regs *rp, caddr_t *badaddr, uint_t inst)
7190Sstevel@tonic-gate {
7200Sstevel@tonic-gate uint_t rd, rs2, rs1;
7210Sstevel@tonic-gate uint_t immflg;
7220Sstevel@tonic-gate uint64_t val, cnt = 0;
7230Sstevel@tonic-gate
7240Sstevel@tonic-gate rd = (inst >> 25) & 0x1f;
7250Sstevel@tonic-gate rs1 = (inst >> 14) & 0x1f;
7260Sstevel@tonic-gate rs2 = inst & 0x1f;
7270Sstevel@tonic-gate immflg = (inst >> 13) & 1;
7280Sstevel@tonic-gate
7290Sstevel@tonic-gate if (rs1 > 0)
7300Sstevel@tonic-gate return (SIMU_ILLEGAL);
7310Sstevel@tonic-gate
7320Sstevel@tonic-gate (void) flush_user_windows_to_stack(NULL);
7330Sstevel@tonic-gate
7340Sstevel@tonic-gate /* check immediate bit and use immediate field or reg (rs2) */
7350Sstevel@tonic-gate if (immflg) {
7360Sstevel@tonic-gate int64_t imm;
7370Sstevel@tonic-gate imm = inst & 0x1fff; /* mask out immediate field */
7380Sstevel@tonic-gate imm <<= 51; /* sign extend it */
7390Sstevel@tonic-gate imm >>= 51;
7400Sstevel@tonic-gate if (imm != 0) {
7410Sstevel@tonic-gate for (cnt = 0; imm != 0; imm &= imm-1)
7420Sstevel@tonic-gate cnt++;
7430Sstevel@tonic-gate }
7440Sstevel@tonic-gate } else {
7450Sstevel@tonic-gate if (getreg(rp, rs2, &val, badaddr))
7460Sstevel@tonic-gate return (SIMU_FAULT);
7470Sstevel@tonic-gate if (val != 0) {
7480Sstevel@tonic-gate for (cnt = 0; val != 0; val &= val-1)
7490Sstevel@tonic-gate cnt++;
7500Sstevel@tonic-gate }
7510Sstevel@tonic-gate }
7520Sstevel@tonic-gate
7530Sstevel@tonic-gate if (putreg(&cnt, rp, rd, badaddr) == -1)
7540Sstevel@tonic-gate return (SIMU_FAULT);
7550Sstevel@tonic-gate
7560Sstevel@tonic-gate return (SIMU_SUCCESS);
7570Sstevel@tonic-gate }
7580Sstevel@tonic-gate
7590Sstevel@tonic-gate /*
7607718SJason.Beloro@Sun.COM * simulate mulscc
7617718SJason.Beloro@Sun.COM */
7627718SJason.Beloro@Sun.COM static int
simulate_mulscc(struct regs * rp,caddr_t * badaddr,uint_t inst)7637718SJason.Beloro@Sun.COM simulate_mulscc(struct regs *rp, caddr_t *badaddr, uint_t inst)
7647718SJason.Beloro@Sun.COM {
7657718SJason.Beloro@Sun.COM uint32_t s1, s2;
7667718SJason.Beloro@Sun.COM uint32_t c, d, v;
7677718SJason.Beloro@Sun.COM uint_t rd, rs1;
7687718SJason.Beloro@Sun.COM int64_t d64;
7697718SJason.Beloro@Sun.COM uint64_t ud64;
7707718SJason.Beloro@Sun.COM uint64_t drs1;
7717718SJason.Beloro@Sun.COM
7727718SJason.Beloro@Sun.COM (void) flush_user_windows_to_stack(NULL);
7737718SJason.Beloro@Sun.COM
7747718SJason.Beloro@Sun.COM if ((inst >> 13) & 1) { /* immediate */
7757718SJason.Beloro@Sun.COM d64 = inst & 0x1fff;
7767718SJason.Beloro@Sun.COM d64 <<= 51; /* sign extend it */
7777718SJason.Beloro@Sun.COM d64 >>= 51;
7787718SJason.Beloro@Sun.COM } else {
7797718SJason.Beloro@Sun.COM uint_t rs2;
7807718SJason.Beloro@Sun.COM uint64_t drs2;
7817718SJason.Beloro@Sun.COM
7827718SJason.Beloro@Sun.COM if (inst & 0x1fe0) {
7837718SJason.Beloro@Sun.COM return (SIMU_ILLEGAL);
7847718SJason.Beloro@Sun.COM }
7857718SJason.Beloro@Sun.COM rs2 = inst & 0x1f;
7867718SJason.Beloro@Sun.COM if (getreg(rp, rs2, &drs2, badaddr)) {
7877718SJason.Beloro@Sun.COM return (SIMU_FAULT);
7887718SJason.Beloro@Sun.COM }
7897718SJason.Beloro@Sun.COM d64 = (int64_t)drs2;
7907718SJason.Beloro@Sun.COM }
7917718SJason.Beloro@Sun.COM
7927718SJason.Beloro@Sun.COM rs1 = (inst >> 14) & 0x1f;
7937718SJason.Beloro@Sun.COM if (getreg(rp, rs1, &drs1, badaddr)) {
7947718SJason.Beloro@Sun.COM return (SIMU_FAULT);
7957718SJason.Beloro@Sun.COM }
7967718SJason.Beloro@Sun.COM /* icc.n xor icc.v */
7977718SJason.Beloro@Sun.COM s1 = ((rp->r_tstate & TSTATE_IN) >> (TSTATE_CCR_SHIFT + 3)) ^
7987718SJason.Beloro@Sun.COM ((rp->r_tstate & TSTATE_IV) >> (TSTATE_CCR_SHIFT + 1));
7997718SJason.Beloro@Sun.COM s1 = (s1 << 31) | (((uint32_t)drs1) >> 1);
8007718SJason.Beloro@Sun.COM
8017718SJason.Beloro@Sun.COM if (rp->r_y & 1) {
8027718SJason.Beloro@Sun.COM s2 = (uint32_t)d64;
8037718SJason.Beloro@Sun.COM } else {
8047718SJason.Beloro@Sun.COM s2 = 0;
8057718SJason.Beloro@Sun.COM }
8067718SJason.Beloro@Sun.COM d = s1 + s2;
8077718SJason.Beloro@Sun.COM
8087718SJason.Beloro@Sun.COM ud64 = (uint64_t)d;
8097718SJason.Beloro@Sun.COM
8107718SJason.Beloro@Sun.COM /* set the icc flags */
8117718SJason.Beloro@Sun.COM v = (s1 & s2 & ~d) | (~s1 & ~s2 & d);
8127718SJason.Beloro@Sun.COM c = (s1 & s2) | (~d & (s1 | s2));
8137718SJason.Beloro@Sun.COM rp->r_tstate &= ~TSTATE_ICC;
8147718SJason.Beloro@Sun.COM rp->r_tstate |= (uint64_t)((c >> 31) & 1) << (TSTATE_CCR_SHIFT + 0);
8157718SJason.Beloro@Sun.COM rp->r_tstate |= (uint64_t)((v >> 31) & 1) << (TSTATE_CCR_SHIFT + 1);
8167718SJason.Beloro@Sun.COM rp->r_tstate |= (uint64_t)(d ? 0 : 1) << (TSTATE_CCR_SHIFT + 2);
8177718SJason.Beloro@Sun.COM rp->r_tstate |= (uint64_t)((d >> 31) & 1) << (TSTATE_CCR_SHIFT + 3);
8187718SJason.Beloro@Sun.COM
8197718SJason.Beloro@Sun.COM if (rp->r_tstate & TSTATE_IC) {
8207718SJason.Beloro@Sun.COM ud64 |= (1ULL << 32);
8217718SJason.Beloro@Sun.COM }
8227718SJason.Beloro@Sun.COM
8237718SJason.Beloro@Sun.COM /* set the xcc flags */
8247718SJason.Beloro@Sun.COM rp->r_tstate &= ~TSTATE_XCC;
8257718SJason.Beloro@Sun.COM if (ud64 == 0) {
8267718SJason.Beloro@Sun.COM rp->r_tstate |= TSTATE_XZ;
8277718SJason.Beloro@Sun.COM }
8287718SJason.Beloro@Sun.COM
8297718SJason.Beloro@Sun.COM rd = (inst >> 25) & 0x1f;
8307718SJason.Beloro@Sun.COM if (putreg(&ud64, rp, rd, badaddr)) {
8317718SJason.Beloro@Sun.COM return (SIMU_FAULT);
8327718SJason.Beloro@Sun.COM }
8337718SJason.Beloro@Sun.COM
8347718SJason.Beloro@Sun.COM d64 = (drs1 << 32) | (uint32_t)rp->r_y;
8357718SJason.Beloro@Sun.COM d64 >>= 1;
8367718SJason.Beloro@Sun.COM rp->r_y = (uint32_t)d64;
8377718SJason.Beloro@Sun.COM
8387718SJason.Beloro@Sun.COM return (SIMU_SUCCESS);
8397718SJason.Beloro@Sun.COM }
8407718SJason.Beloro@Sun.COM
8417718SJason.Beloro@Sun.COM /*
8420Sstevel@tonic-gate * simulate unimplemented instructions (popc, ldqf{a}, stqf{a})
8430Sstevel@tonic-gate */
8440Sstevel@tonic-gate int
simulate_unimp(struct regs * rp,caddr_t * badaddr)8450Sstevel@tonic-gate simulate_unimp(struct regs *rp, caddr_t *badaddr)
8460Sstevel@tonic-gate {
8470Sstevel@tonic-gate uint_t inst, optype, op3, asi;
8480Sstevel@tonic-gate uint_t rs1, rd;
8490Sstevel@tonic-gate uint_t ignor, i;
8500Sstevel@tonic-gate machpcb_t *mpcb = lwptompcb(ttolwp(curthread));
8510Sstevel@tonic-gate int nomatch = 0;
8520Sstevel@tonic-gate caddr_t addr = (caddr_t)rp->r_pc;
8530Sstevel@tonic-gate struct as *as;
8540Sstevel@tonic-gate caddr_t ka;
8550Sstevel@tonic-gate pfn_t pfnum;
8560Sstevel@tonic-gate page_t *pp;
8570Sstevel@tonic-gate proc_t *p = ttoproc(curthread);
8580Sstevel@tonic-gate struct seg *mapseg;
8590Sstevel@tonic-gate struct segvn_data *svd;
8600Sstevel@tonic-gate
8610Sstevel@tonic-gate ASSERT(USERMODE(rp->r_tstate));
8620Sstevel@tonic-gate inst = fetch_user_instr(addr);
8630Sstevel@tonic-gate if (inst == (uint_t)-1) {
8640Sstevel@tonic-gate mpcb->mpcb_illexcaddr = addr;
8650Sstevel@tonic-gate mpcb->mpcb_illexcinsn = (uint32_t)-1;
8660Sstevel@tonic-gate return (SIMU_ILLEGAL);
8670Sstevel@tonic-gate }
8680Sstevel@tonic-gate
8690Sstevel@tonic-gate /*
8700Sstevel@tonic-gate * When fixing dirty v8 instructions there's a race if two processors
8710Sstevel@tonic-gate * are executing the dirty executable at the same time. If one
8720Sstevel@tonic-gate * cleans the instruction as the other is executing it the second
8730Sstevel@tonic-gate * processor will see a clean instruction when it comes through this
8740Sstevel@tonic-gate * code and will return SIMU_ILLEGAL. To work around the race
8750Sstevel@tonic-gate * this code will keep track of the last illegal instruction seen
8760Sstevel@tonic-gate * by each lwp and will only take action if the illegal instruction
8770Sstevel@tonic-gate * is repeatable.
8780Sstevel@tonic-gate */
8790Sstevel@tonic-gate if (addr != mpcb->mpcb_illexcaddr ||
8800Sstevel@tonic-gate inst != mpcb->mpcb_illexcinsn)
8810Sstevel@tonic-gate nomatch = 1;
8820Sstevel@tonic-gate mpcb->mpcb_illexcaddr = addr;
8830Sstevel@tonic-gate mpcb->mpcb_illexcinsn = inst;
8840Sstevel@tonic-gate
8850Sstevel@tonic-gate /* instruction fields */
8860Sstevel@tonic-gate i = (inst >> 13) & 0x1;
8870Sstevel@tonic-gate rd = (inst >> 25) & 0x1f;
8880Sstevel@tonic-gate optype = (inst >> 30) & 0x3;
8890Sstevel@tonic-gate op3 = (inst >> 19) & 0x3f;
8900Sstevel@tonic-gate ignor = (inst >> 5) & 0xff;
8910Sstevel@tonic-gate if (IS_IBIT_SET(inst)) {
8920Sstevel@tonic-gate asi = (uint32_t)((rp->r_tstate >> TSTATE_ASI_SHIFT) &
8930Sstevel@tonic-gate TSTATE_ASI_MASK);
8940Sstevel@tonic-gate } else {
8950Sstevel@tonic-gate asi = ignor;
8960Sstevel@tonic-gate }
8970Sstevel@tonic-gate
8980Sstevel@tonic-gate if (IS_VIS1(optype, op3) ||
8993398Ssvemuri IS_PARTIAL_OR_SHORT_FLOAT_LD_ST(optype, op3, asi) ||
9003398Ssvemuri IS_FLOAT_QUAD_OP(optype, op3)) {
9010Sstevel@tonic-gate klwp_t *lwp = ttolwp(curthread);
9020Sstevel@tonic-gate kfpu_t *fp = lwptofpu(lwp);
9030Sstevel@tonic-gate if (fpu_exists) {
9040Sstevel@tonic-gate if (!(_fp_read_fprs() & FPRS_FEF))
9050Sstevel@tonic-gate fp_enable();
9060Sstevel@tonic-gate _fp_read_pfsr(&fp->fpu_fsr);
9070Sstevel@tonic-gate } else {
9080Sstevel@tonic-gate if (!fp->fpu_en)
9090Sstevel@tonic-gate fp_enable();
9100Sstevel@tonic-gate }
9110Sstevel@tonic-gate fp_precise(rp);
9120Sstevel@tonic-gate return (SIMU_RETRY);
9130Sstevel@tonic-gate }
9140Sstevel@tonic-gate
9150Sstevel@tonic-gate if (optype == 2 && op3 == IOP_V8_POPC) {
9160Sstevel@tonic-gate return (simulate_popc(rp, badaddr, inst));
9170Sstevel@tonic-gate } else if (optype == 3 && op3 == IOP_V8_POPC) {
9180Sstevel@tonic-gate return (SIMU_ILLEGAL);
9197718SJason.Beloro@Sun.COM } else if (optype == OP_V8_ARITH && op3 == IOP_V8_MULScc) {
9207718SJason.Beloro@Sun.COM return (simulate_mulscc(rp, badaddr, inst));
9210Sstevel@tonic-gate }
9220Sstevel@tonic-gate
9230Sstevel@tonic-gate if (optype == OP_V8_LDSTR) {
9240Sstevel@tonic-gate if (op3 == IOP_V8_LDQF || op3 == IOP_V8_LDQFA ||
9250Sstevel@tonic-gate op3 == IOP_V8_STQF || op3 == IOP_V8_STQFA)
9260Sstevel@tonic-gate return (do_unaligned(rp, badaddr));
9270Sstevel@tonic-gate }
9280Sstevel@tonic-gate
9299195SChristopher.Baumbauer@Sun.COM /* This is a new instruction so illexccnt should also be set. */
9309195SChristopher.Baumbauer@Sun.COM if (nomatch) {
9319195SChristopher.Baumbauer@Sun.COM mpcb->mpcb_illexccnt = 0;
9320Sstevel@tonic-gate return (SIMU_RETRY);
9339195SChristopher.Baumbauer@Sun.COM }
9349195SChristopher.Baumbauer@Sun.COM
9359195SChristopher.Baumbauer@Sun.COM /*
9369195SChristopher.Baumbauer@Sun.COM * In order to keep us from entering into an infinite loop while
9379195SChristopher.Baumbauer@Sun.COM * attempting to clean up faulty instructions, we will return
9389195SChristopher.Baumbauer@Sun.COM * SIMU_ILLEGAL once we've cleaned up the instruction as much
9399195SChristopher.Baumbauer@Sun.COM * as we can, and still end up here.
9409195SChristopher.Baumbauer@Sun.COM */
9419195SChristopher.Baumbauer@Sun.COM if (mpcb->mpcb_illexccnt >= 3)
9429195SChristopher.Baumbauer@Sun.COM return (SIMU_ILLEGAL);
9439195SChristopher.Baumbauer@Sun.COM
9449195SChristopher.Baumbauer@Sun.COM mpcb->mpcb_illexccnt += 1;
9450Sstevel@tonic-gate
9460Sstevel@tonic-gate /*
9470Sstevel@tonic-gate * The rest of the code handles v8 binaries with instructions
9480Sstevel@tonic-gate * that have dirty (non-zero) bits in reserved or 'ignored'
9490Sstevel@tonic-gate * fields; these will cause core dumps on v9 machines.
9500Sstevel@tonic-gate *
9510Sstevel@tonic-gate * We only clean dirty instructions in 32-bit programs (ie, v8)
9520Sstevel@tonic-gate * running on SPARCv9 processors. True v9 programs are forced
9530Sstevel@tonic-gate * to use the instruction set as intended.
9540Sstevel@tonic-gate */
9550Sstevel@tonic-gate if (lwp_getdatamodel(curthread->t_lwp) != DATAMODEL_ILP32)
9560Sstevel@tonic-gate return (SIMU_ILLEGAL);
9570Sstevel@tonic-gate switch (optype) {
9580Sstevel@tonic-gate case OP_V8_BRANCH:
9590Sstevel@tonic-gate case OP_V8_CALL:
9600Sstevel@tonic-gate return (SIMU_ILLEGAL); /* these don't have ignored fields */
9610Sstevel@tonic-gate /*NOTREACHED*/
9620Sstevel@tonic-gate case OP_V8_ARITH:
9630Sstevel@tonic-gate switch (op3) {
9640Sstevel@tonic-gate case IOP_V8_RETT:
9650Sstevel@tonic-gate if (rd == 0 && !(i == 0 && ignor))
9660Sstevel@tonic-gate return (SIMU_ILLEGAL);
9670Sstevel@tonic-gate if (rd)
9680Sstevel@tonic-gate inst &= ~(0x1f << 25);
9690Sstevel@tonic-gate if (i == 0 && ignor)
9700Sstevel@tonic-gate inst &= ~(0xff << 5);
9710Sstevel@tonic-gate break;
9720Sstevel@tonic-gate case IOP_V8_TCC:
9730Sstevel@tonic-gate if (i == 0 && ignor != 0) {
9740Sstevel@tonic-gate inst &= ~(0xff << 5);
9750Sstevel@tonic-gate } else if (i == 1 && (((inst >> 7) & 0x3f) != 0)) {
9760Sstevel@tonic-gate inst &= ~(0x3f << 7);
9770Sstevel@tonic-gate } else {
9780Sstevel@tonic-gate return (SIMU_ILLEGAL);
9790Sstevel@tonic-gate }
9800Sstevel@tonic-gate break;
9810Sstevel@tonic-gate case IOP_V8_JMPL:
9820Sstevel@tonic-gate case IOP_V8_RESTORE:
9830Sstevel@tonic-gate case IOP_V8_SAVE:
9840Sstevel@tonic-gate if ((op3 == IOP_V8_RETT && rd) ||
9850Sstevel@tonic-gate (i == 0 && ignor)) {
9860Sstevel@tonic-gate inst &= ~(0xff << 5);
9870Sstevel@tonic-gate } else {
9880Sstevel@tonic-gate return (SIMU_ILLEGAL);
9890Sstevel@tonic-gate }
9900Sstevel@tonic-gate break;
9910Sstevel@tonic-gate case IOP_V8_FCMP:
9920Sstevel@tonic-gate if (rd == 0)
9930Sstevel@tonic-gate return (SIMU_ILLEGAL);
9940Sstevel@tonic-gate inst &= ~(0x1f << 25);
9950Sstevel@tonic-gate break;
9960Sstevel@tonic-gate case IOP_V8_RDASR:
9970Sstevel@tonic-gate rs1 = ((inst >> 14) & 0x1f);
9980Sstevel@tonic-gate if (rs1 == 1 || (rs1 >= 7 && rs1 <= 14)) {
9990Sstevel@tonic-gate /*
10000Sstevel@tonic-gate * The instruction specifies an invalid
10010Sstevel@tonic-gate * state register - better bail out than
10020Sstevel@tonic-gate * "fix" it when we're not sure what was
10030Sstevel@tonic-gate * intended.
10040Sstevel@tonic-gate */
10050Sstevel@tonic-gate return (SIMU_ILLEGAL);
10060Sstevel@tonic-gate }
10070Sstevel@tonic-gate /*
10080Sstevel@tonic-gate * Note: this case includes the 'stbar'
10090Sstevel@tonic-gate * instruction (rs1 == 15 && i == 0).
10100Sstevel@tonic-gate */
10110Sstevel@tonic-gate if ((ignor = (inst & 0x3fff)) != 0)
10120Sstevel@tonic-gate inst &= ~(0x3fff);
10130Sstevel@tonic-gate break;
10140Sstevel@tonic-gate case IOP_V8_SRA:
10150Sstevel@tonic-gate case IOP_V8_SRL:
10160Sstevel@tonic-gate case IOP_V8_SLL:
10170Sstevel@tonic-gate if (ignor == 0)
10180Sstevel@tonic-gate return (SIMU_ILLEGAL);
10190Sstevel@tonic-gate inst &= ~(0xff << 5);
10200Sstevel@tonic-gate break;
10210Sstevel@tonic-gate case IOP_V8_ADD:
10220Sstevel@tonic-gate case IOP_V8_AND:
10230Sstevel@tonic-gate case IOP_V8_OR:
10240Sstevel@tonic-gate case IOP_V8_XOR:
10250Sstevel@tonic-gate case IOP_V8_SUB:
10260Sstevel@tonic-gate case IOP_V8_ANDN:
10270Sstevel@tonic-gate case IOP_V8_ORN:
10280Sstevel@tonic-gate case IOP_V8_XNOR:
10290Sstevel@tonic-gate case IOP_V8_ADDC:
10300Sstevel@tonic-gate case IOP_V8_UMUL:
10310Sstevel@tonic-gate case IOP_V8_SMUL:
10320Sstevel@tonic-gate case IOP_V8_SUBC:
10330Sstevel@tonic-gate case IOP_V8_UDIV:
10340Sstevel@tonic-gate case IOP_V8_SDIV:
10350Sstevel@tonic-gate case IOP_V8_ADDcc:
10360Sstevel@tonic-gate case IOP_V8_ANDcc:
10370Sstevel@tonic-gate case IOP_V8_ORcc:
10380Sstevel@tonic-gate case IOP_V8_XORcc:
10390Sstevel@tonic-gate case IOP_V8_SUBcc:
10400Sstevel@tonic-gate case IOP_V8_ANDNcc:
10410Sstevel@tonic-gate case IOP_V8_ORNcc:
10420Sstevel@tonic-gate case IOP_V8_XNORcc:
10430Sstevel@tonic-gate case IOP_V8_ADDCcc:
10440Sstevel@tonic-gate case IOP_V8_UMULcc:
10450Sstevel@tonic-gate case IOP_V8_SMULcc:
10460Sstevel@tonic-gate case IOP_V8_SUBCcc:
10470Sstevel@tonic-gate case IOP_V8_UDIVcc:
10480Sstevel@tonic-gate case IOP_V8_SDIVcc:
10490Sstevel@tonic-gate case IOP_V8_TADDcc:
10500Sstevel@tonic-gate case IOP_V8_TSUBcc:
10510Sstevel@tonic-gate case IOP_V8_TADDccTV:
10520Sstevel@tonic-gate case IOP_V8_TSUBccTV:
10530Sstevel@tonic-gate case IOP_V8_MULScc:
10540Sstevel@tonic-gate case IOP_V8_WRASR:
10550Sstevel@tonic-gate case IOP_V8_FLUSH:
10560Sstevel@tonic-gate if (i != 0 || ignor == 0)
10570Sstevel@tonic-gate return (SIMU_ILLEGAL);
10580Sstevel@tonic-gate inst &= ~(0xff << 5);
10590Sstevel@tonic-gate break;
10600Sstevel@tonic-gate default:
10610Sstevel@tonic-gate return (SIMU_ILLEGAL);
10620Sstevel@tonic-gate }
10630Sstevel@tonic-gate break;
10640Sstevel@tonic-gate case OP_V8_LDSTR:
10650Sstevel@tonic-gate switch (op3) {
10660Sstevel@tonic-gate case IOP_V8_STFSR:
10670Sstevel@tonic-gate case IOP_V8_LDFSR:
10680Sstevel@tonic-gate if (rd == 0 && !(i == 0 && ignor))
10690Sstevel@tonic-gate return (SIMU_ILLEGAL);
10700Sstevel@tonic-gate if (rd)
10710Sstevel@tonic-gate inst &= ~(0x1f << 25);
10720Sstevel@tonic-gate if (i == 0 && ignor)
10730Sstevel@tonic-gate inst &= ~(0xff << 5);
10740Sstevel@tonic-gate break;
10750Sstevel@tonic-gate default:
10760Sstevel@tonic-gate if (optype == OP_V8_LDSTR && !IS_LDST_ALT(op3) &&
10770Sstevel@tonic-gate i == 0 && ignor)
10780Sstevel@tonic-gate inst &= ~(0xff << 5);
10790Sstevel@tonic-gate else
10800Sstevel@tonic-gate return (SIMU_ILLEGAL);
10810Sstevel@tonic-gate break;
10820Sstevel@tonic-gate }
10830Sstevel@tonic-gate break;
10840Sstevel@tonic-gate default:
10850Sstevel@tonic-gate return (SIMU_ILLEGAL);
10860Sstevel@tonic-gate }
10870Sstevel@tonic-gate
10880Sstevel@tonic-gate as = p->p_as;
10890Sstevel@tonic-gate
10900Sstevel@tonic-gate AS_LOCK_ENTER(as, &as->a_lock, RW_READER);
10910Sstevel@tonic-gate mapseg = as_findseg(as, (caddr_t)rp->r_pc, 0);
10920Sstevel@tonic-gate ASSERT(mapseg != NULL);
10930Sstevel@tonic-gate svd = (struct segvn_data *)mapseg->s_data;
10940Sstevel@tonic-gate
10950Sstevel@tonic-gate /*
10960Sstevel@tonic-gate * We only create COW page for MAP_PRIVATE mappings.
10970Sstevel@tonic-gate */
10980Sstevel@tonic-gate SEGVN_LOCK_ENTER(as, &svd->lock, RW_READER);
10990Sstevel@tonic-gate if ((svd->type & MAP_TYPE) & MAP_SHARED) {
11000Sstevel@tonic-gate SEGVN_LOCK_EXIT(as, &svd->lock);
11010Sstevel@tonic-gate AS_LOCK_EXIT(as, &as->a_lock);
11020Sstevel@tonic-gate return (SIMU_ILLEGAL);
11030Sstevel@tonic-gate }
11040Sstevel@tonic-gate SEGVN_LOCK_EXIT(as, &svd->lock);
11050Sstevel@tonic-gate AS_LOCK_EXIT(as, &as->a_lock);
11060Sstevel@tonic-gate
11070Sstevel@tonic-gate /*
11080Sstevel@tonic-gate * A "flush" instruction using the user PC's vaddr will not work
11090Sstevel@tonic-gate * here, at least on Spitfire. Instead we create a temporary kernel
11100Sstevel@tonic-gate * mapping to the user's text page, then modify and flush that.
11110Sstevel@tonic-gate * Break COW by locking user page.
11120Sstevel@tonic-gate */
11130Sstevel@tonic-gate if (as_fault(as->a_hat, as, (caddr_t)(rp->r_pc & PAGEMASK), PAGESIZE,
11140Sstevel@tonic-gate F_SOFTLOCK, S_READ))
11150Sstevel@tonic-gate return (SIMU_FAULT);
11160Sstevel@tonic-gate
11170Sstevel@tonic-gate AS_LOCK_ENTER(as, &as->a_lock, RW_READER);
11180Sstevel@tonic-gate pfnum = hat_getpfnum(as->a_hat, (caddr_t)rp->r_pc);
11190Sstevel@tonic-gate AS_LOCK_EXIT(as, &as->a_lock);
11200Sstevel@tonic-gate if (pf_is_memory(pfnum)) {
11210Sstevel@tonic-gate pp = page_numtopp_nolock(pfnum);
11220Sstevel@tonic-gate ASSERT(pp == NULL || PAGE_LOCKED(pp));
11230Sstevel@tonic-gate } else {
11240Sstevel@tonic-gate (void) as_fault(as->a_hat, as, (caddr_t)(rp->r_pc & PAGEMASK),
11250Sstevel@tonic-gate PAGESIZE, F_SOFTUNLOCK, S_READ);
11260Sstevel@tonic-gate return (SIMU_FAULT);
11270Sstevel@tonic-gate }
11280Sstevel@tonic-gate
11290Sstevel@tonic-gate AS_LOCK_ENTER(as, &as->a_lock, RW_READER);
11300Sstevel@tonic-gate ka = ppmapin(pp, PROT_READ|PROT_WRITE, (caddr_t)rp->r_pc);
11310Sstevel@tonic-gate *(uint_t *)(ka + (uintptr_t)(rp->r_pc % PAGESIZE)) = inst;
11320Sstevel@tonic-gate doflush(ka + (uintptr_t)(rp->r_pc % PAGESIZE));
11330Sstevel@tonic-gate ppmapout(ka);
11340Sstevel@tonic-gate AS_LOCK_EXIT(as, &as->a_lock);
11350Sstevel@tonic-gate
11360Sstevel@tonic-gate (void) as_fault(as->a_hat, as, (caddr_t)(rp->r_pc & PAGEMASK),
11370Sstevel@tonic-gate PAGESIZE, F_SOFTUNLOCK, S_READ);
11380Sstevel@tonic-gate return (SIMU_RETRY);
11390Sstevel@tonic-gate }
11400Sstevel@tonic-gate
11410Sstevel@tonic-gate /*
1142*11172SHaik.Aftandilian@Sun.COM * Simulate a "rd %tick" or "rd %stick" (%asr24) instruction.
1143*11172SHaik.Aftandilian@Sun.COM */
1144*11172SHaik.Aftandilian@Sun.COM int
simulate_rdtick(struct regs * rp)1145*11172SHaik.Aftandilian@Sun.COM simulate_rdtick(struct regs *rp)
1146*11172SHaik.Aftandilian@Sun.COM {
1147*11172SHaik.Aftandilian@Sun.COM uint_t inst, op, op3, rd, rs1, i;
1148*11172SHaik.Aftandilian@Sun.COM caddr_t badaddr;
1149*11172SHaik.Aftandilian@Sun.COM
1150*11172SHaik.Aftandilian@Sun.COM inst = fetch_user_instr((caddr_t)rp->r_pc);
1151*11172SHaik.Aftandilian@Sun.COM op = (inst >> 30) & 0x3;
1152*11172SHaik.Aftandilian@Sun.COM rd = (inst >> 25) & 0x1F;
1153*11172SHaik.Aftandilian@Sun.COM op3 = (inst >> 19) & 0x3F;
1154*11172SHaik.Aftandilian@Sun.COM i = (inst >> 13) & 0x1;
1155*11172SHaik.Aftandilian@Sun.COM
1156*11172SHaik.Aftandilian@Sun.COM /*
1157*11172SHaik.Aftandilian@Sun.COM * Make sure this is either a %tick read (rs1 == 0x4) or
1158*11172SHaik.Aftandilian@Sun.COM * a %stick read (rs1 == 0x18) instruction.
1159*11172SHaik.Aftandilian@Sun.COM */
1160*11172SHaik.Aftandilian@Sun.COM if (op == 2 && op3 == 0x28 && i == 0) {
1161*11172SHaik.Aftandilian@Sun.COM rs1 = (inst >> 14) & 0x1F;
1162*11172SHaik.Aftandilian@Sun.COM
1163*11172SHaik.Aftandilian@Sun.COM if (rs1 == 0x4) {
1164*11172SHaik.Aftandilian@Sun.COM uint64_t tick;
1165*11172SHaik.Aftandilian@Sun.COM (void) flush_user_windows_to_stack(NULL);
1166*11172SHaik.Aftandilian@Sun.COM tick = gettick_counter();
1167*11172SHaik.Aftandilian@Sun.COM if (putreg(&tick, rp, rd, &badaddr) == 0)
1168*11172SHaik.Aftandilian@Sun.COM return (SIMU_SUCCESS);
1169*11172SHaik.Aftandilian@Sun.COM } else if (rs1 == 0x18) {
1170*11172SHaik.Aftandilian@Sun.COM uint64_t stick;
1171*11172SHaik.Aftandilian@Sun.COM (void) flush_user_windows_to_stack(NULL);
1172*11172SHaik.Aftandilian@Sun.COM stick = gethrtime_unscaled();
1173*11172SHaik.Aftandilian@Sun.COM if (putreg(&stick, rp, rd, &badaddr) == 0)
1174*11172SHaik.Aftandilian@Sun.COM return (SIMU_SUCCESS);
1175*11172SHaik.Aftandilian@Sun.COM }
1176*11172SHaik.Aftandilian@Sun.COM }
1177*11172SHaik.Aftandilian@Sun.COM
1178*11172SHaik.Aftandilian@Sun.COM return (SIMU_FAULT);
1179*11172SHaik.Aftandilian@Sun.COM }
1180*11172SHaik.Aftandilian@Sun.COM
1181*11172SHaik.Aftandilian@Sun.COM /*
11820Sstevel@tonic-gate * Get the value of a register for instruction simulation
11830Sstevel@tonic-gate * by using the regs or window structure pointers.
11840Sstevel@tonic-gate * Return 0 for success, and -1 for failure. If there is a failure,
11850Sstevel@tonic-gate * save the faulting address using badaddr pointer.
11860Sstevel@tonic-gate * We have 64 bit globals and outs, and 32 or 64 bit ins and locals.
11870Sstevel@tonic-gate * Don't truncate globals/outs for 32 bit programs, for v8+ support.
11880Sstevel@tonic-gate */
11890Sstevel@tonic-gate int
getreg(struct regs * rp,uint_t reg,uint64_t * val,caddr_t * badaddr)11900Sstevel@tonic-gate getreg(struct regs *rp, uint_t reg, uint64_t *val, caddr_t *badaddr)
11910Sstevel@tonic-gate {
11920Sstevel@tonic-gate uint64_t *rgs, *sp;
11930Sstevel@tonic-gate int rv = 0;
11940Sstevel@tonic-gate
11950Sstevel@tonic-gate rgs = (uint64_t *)&rp->r_ps; /* globals and outs */
11960Sstevel@tonic-gate sp = (uint64_t *)rp->r_sp; /* ins and locals */
11970Sstevel@tonic-gate if (reg == 0) {
11980Sstevel@tonic-gate *val = 0;
11990Sstevel@tonic-gate } else if (reg < 16) {
12000Sstevel@tonic-gate *val = rgs[reg];
12010Sstevel@tonic-gate } else if (IS_V9STACK(sp)) {
12020Sstevel@tonic-gate uint64_t *rw = (uint64_t *)((uintptr_t)sp + V9BIAS64);
12030Sstevel@tonic-gate uint64_t *addr = (uint64_t *)&rw[reg - 16];
12040Sstevel@tonic-gate uint64_t res;
12050Sstevel@tonic-gate
12060Sstevel@tonic-gate if (USERMODE(rp->r_tstate)) {
12070Sstevel@tonic-gate if (fuword64_nowatch(addr, &res) == -1) {
12080Sstevel@tonic-gate *badaddr = (caddr_t)addr;
12090Sstevel@tonic-gate rv = -1;
12100Sstevel@tonic-gate }
12110Sstevel@tonic-gate } else {
12120Sstevel@tonic-gate res = *addr;
12130Sstevel@tonic-gate }
12140Sstevel@tonic-gate *val = res;
12150Sstevel@tonic-gate } else {
12161030Smathue caddr32_t sp32 = (caddr32_t)(uintptr_t)sp;
12171030Smathue uint32_t *rw = (uint32_t *)(uintptr_t)sp32;
12180Sstevel@tonic-gate uint32_t *addr = (uint32_t *)&rw[reg - 16];
12190Sstevel@tonic-gate uint32_t res;
12200Sstevel@tonic-gate
12210Sstevel@tonic-gate if (USERMODE(rp->r_tstate)) {
12220Sstevel@tonic-gate if (fuword32_nowatch(addr, &res) == -1) {
12230Sstevel@tonic-gate *badaddr = (caddr_t)addr;
12240Sstevel@tonic-gate rv = -1;
12250Sstevel@tonic-gate }
12260Sstevel@tonic-gate } else {
12270Sstevel@tonic-gate res = *addr;
12280Sstevel@tonic-gate }
12290Sstevel@tonic-gate *val = (uint64_t)res;
12300Sstevel@tonic-gate }
12310Sstevel@tonic-gate return (rv);
12320Sstevel@tonic-gate }
12330Sstevel@tonic-gate
12340Sstevel@tonic-gate /*
12350Sstevel@tonic-gate * Set the value of a register after instruction simulation
12360Sstevel@tonic-gate * by using the regs or window structure pointers.
12370Sstevel@tonic-gate * Return 0 for succes -1 failure.
12380Sstevel@tonic-gate * save the faulting address using badaddr pointer.
12390Sstevel@tonic-gate * We have 64 bit globals and outs, and 32 or 64 bit ins and locals.
12400Sstevel@tonic-gate * Don't truncate globals/outs for 32 bit programs, for v8+ support.
12410Sstevel@tonic-gate */
12420Sstevel@tonic-gate int
putreg(uint64_t * data,struct regs * rp,uint_t reg,caddr_t * badaddr)12430Sstevel@tonic-gate putreg(uint64_t *data, struct regs *rp, uint_t reg, caddr_t *badaddr)
12440Sstevel@tonic-gate {
12450Sstevel@tonic-gate uint64_t *rgs, *sp;
12460Sstevel@tonic-gate int rv = 0;
12470Sstevel@tonic-gate
12480Sstevel@tonic-gate rgs = (uint64_t *)&rp->r_ps; /* globals and outs */
12490Sstevel@tonic-gate sp = (uint64_t *)rp->r_sp; /* ins and locals */
12500Sstevel@tonic-gate if (reg == 0) {
12510Sstevel@tonic-gate return (0);
12520Sstevel@tonic-gate } else if (reg < 16) {
12530Sstevel@tonic-gate rgs[reg] = *data;
12540Sstevel@tonic-gate } else if (IS_V9STACK(sp)) {
12550Sstevel@tonic-gate uint64_t *rw = (uint64_t *)((uintptr_t)sp + V9BIAS64);
12560Sstevel@tonic-gate uint64_t *addr = (uint64_t *)&rw[reg - 16];
12570Sstevel@tonic-gate uint64_t res;
12580Sstevel@tonic-gate
12590Sstevel@tonic-gate if (USERMODE(rp->r_tstate)) {
12600Sstevel@tonic-gate struct machpcb *mpcb = lwptompcb(curthread->t_lwp);
12610Sstevel@tonic-gate
12620Sstevel@tonic-gate res = *data;
12630Sstevel@tonic-gate if (suword64_nowatch(addr, res) != 0) {
12640Sstevel@tonic-gate *badaddr = (caddr_t)addr;
12650Sstevel@tonic-gate rv = -1;
12660Sstevel@tonic-gate }
12670Sstevel@tonic-gate /*
12680Sstevel@tonic-gate * We have changed a local or in register;
12690Sstevel@tonic-gate * nuke the watchpoint return windows.
12700Sstevel@tonic-gate */
12710Sstevel@tonic-gate mpcb->mpcb_rsp[0] = NULL;
12720Sstevel@tonic-gate mpcb->mpcb_rsp[1] = NULL;
12730Sstevel@tonic-gate } else {
12740Sstevel@tonic-gate res = *data;
12750Sstevel@tonic-gate *addr = res;
12760Sstevel@tonic-gate }
12770Sstevel@tonic-gate } else {
12781030Smathue caddr32_t sp32 = (caddr32_t)(uintptr_t)sp;
12791030Smathue uint32_t *rw = (uint32_t *)(uintptr_t)sp32;
12800Sstevel@tonic-gate uint32_t *addr = (uint32_t *)&rw[reg - 16];
12810Sstevel@tonic-gate uint32_t res;
12820Sstevel@tonic-gate
12830Sstevel@tonic-gate if (USERMODE(rp->r_tstate)) {
12840Sstevel@tonic-gate struct machpcb *mpcb = lwptompcb(curthread->t_lwp);
12850Sstevel@tonic-gate
12860Sstevel@tonic-gate res = (uint_t)*data;
12870Sstevel@tonic-gate if (suword32_nowatch(addr, res) != 0) {
12880Sstevel@tonic-gate *badaddr = (caddr_t)addr;
12890Sstevel@tonic-gate rv = -1;
12900Sstevel@tonic-gate }
12910Sstevel@tonic-gate /*
12920Sstevel@tonic-gate * We have changed a local or in register;
12930Sstevel@tonic-gate * nuke the watchpoint return windows.
12940Sstevel@tonic-gate */
12950Sstevel@tonic-gate mpcb->mpcb_rsp[0] = NULL;
12960Sstevel@tonic-gate mpcb->mpcb_rsp[1] = NULL;
12970Sstevel@tonic-gate
12980Sstevel@tonic-gate } else {
12990Sstevel@tonic-gate res = (uint_t)*data;
13000Sstevel@tonic-gate *addr = res;
13010Sstevel@tonic-gate }
13020Sstevel@tonic-gate }
13030Sstevel@tonic-gate return (rv);
13040Sstevel@tonic-gate }
13050Sstevel@tonic-gate
13060Sstevel@tonic-gate /*
13070Sstevel@tonic-gate * Calculate a memory reference address from instruction
13080Sstevel@tonic-gate * operands, used to return the address of a fault, instead
13090Sstevel@tonic-gate * of the instruction when an error occurs. This is code that is
13100Sstevel@tonic-gate * common with most of the routines that simulate instructions.
13110Sstevel@tonic-gate */
13120Sstevel@tonic-gate int
calc_memaddr(struct regs * rp,caddr_t * badaddr)13130Sstevel@tonic-gate calc_memaddr(struct regs *rp, caddr_t *badaddr)
13140Sstevel@tonic-gate {
13150Sstevel@tonic-gate uint_t inst;
13160Sstevel@tonic-gate uint_t rd, rs1, rs2;
13170Sstevel@tonic-gate int sz;
13180Sstevel@tonic-gate int immflg;
13190Sstevel@tonic-gate int floatflg;
13200Sstevel@tonic-gate caddr_t addr;
13210Sstevel@tonic-gate uint64_t val;
13220Sstevel@tonic-gate
13230Sstevel@tonic-gate if (USERMODE(rp->r_tstate))
13240Sstevel@tonic-gate inst = fetch_user_instr((caddr_t)rp->r_pc);
13250Sstevel@tonic-gate else
13260Sstevel@tonic-gate inst = *(uint_t *)rp->r_pc;
13270Sstevel@tonic-gate
13280Sstevel@tonic-gate rd = (inst >> 25) & 0x1f;
13290Sstevel@tonic-gate rs1 = (inst >> 14) & 0x1f;
13300Sstevel@tonic-gate rs2 = inst & 0x1f;
13310Sstevel@tonic-gate floatflg = (inst >> 24) & 1;
13320Sstevel@tonic-gate immflg = (inst >> 13) & 1;
13330Sstevel@tonic-gate
13340Sstevel@tonic-gate if (floatflg) {
13350Sstevel@tonic-gate switch ((inst >> 19) & 3) { /* map size bits to a number */
13360Sstevel@tonic-gate case 0: sz = 4; break; /* ldf/stf */
13370Sstevel@tonic-gate case 1: return (0); /* ld[x]fsr/st[x]fsr */
13380Sstevel@tonic-gate case 2: sz = 16; break; /* ldqf/stqf */
13390Sstevel@tonic-gate case 3: sz = 8; break; /* lddf/stdf */
13400Sstevel@tonic-gate }
13410Sstevel@tonic-gate /*
13420Sstevel@tonic-gate * Fix to access extra double register encoding plus
13430Sstevel@tonic-gate * compensate to access the correct fpu_dreg.
13440Sstevel@tonic-gate */
13450Sstevel@tonic-gate if (sz > 4) {
13460Sstevel@tonic-gate if ((rd & 1) == 1)
13470Sstevel@tonic-gate rd = (rd & 0x1e) | 0x20;
13480Sstevel@tonic-gate rd = rd >> 1;
13490Sstevel@tonic-gate }
13500Sstevel@tonic-gate } else {
13510Sstevel@tonic-gate switch ((inst >> 19) & 0xf) { /* map size bits to a number */
13520Sstevel@tonic-gate case 0: /* lduw */
13530Sstevel@tonic-gate case 4: /* stw */
13540Sstevel@tonic-gate case 8: /* ldsw */
13550Sstevel@tonic-gate case 0xf: /* swap */
13560Sstevel@tonic-gate sz = 4; break;
13570Sstevel@tonic-gate case 1: /* ldub */
13580Sstevel@tonic-gate case 5: /* stb */
13590Sstevel@tonic-gate case 9: /* ldsb */
13600Sstevel@tonic-gate case 0xd: /* ldstub */
13610Sstevel@tonic-gate sz = 1; break;
13620Sstevel@tonic-gate case 2: /* lduh */
13630Sstevel@tonic-gate case 6: /* sth */
13640Sstevel@tonic-gate case 0xa: /* ldsh */
13650Sstevel@tonic-gate sz = 2; break;
13660Sstevel@tonic-gate case 3: /* ldd */
13670Sstevel@tonic-gate case 7: /* std */
13680Sstevel@tonic-gate case 0xb: /* ldx */
13690Sstevel@tonic-gate case 0xe: /* stx */
13700Sstevel@tonic-gate sz = 8; break;
13710Sstevel@tonic-gate }
13720Sstevel@tonic-gate }
13730Sstevel@tonic-gate
13740Sstevel@tonic-gate if (USERMODE(rp->r_tstate))
13750Sstevel@tonic-gate (void) flush_user_windows_to_stack(NULL);
13760Sstevel@tonic-gate else
13770Sstevel@tonic-gate flush_windows();
13780Sstevel@tonic-gate
13790Sstevel@tonic-gate if (getreg(rp, rs1, &val, badaddr))
13800Sstevel@tonic-gate return (SIMU_FAULT);
13810Sstevel@tonic-gate addr = (caddr_t)val;
13820Sstevel@tonic-gate
13830Sstevel@tonic-gate /* check immediate bit and use immediate field or reg (rs2) */
13840Sstevel@tonic-gate if (immflg) {
13850Sstevel@tonic-gate int imm;
13860Sstevel@tonic-gate imm = inst & 0x1fff; /* mask out immediate field */
13870Sstevel@tonic-gate imm <<= 19; /* sign extend it */
13880Sstevel@tonic-gate imm >>= 19;
13890Sstevel@tonic-gate addr += imm; /* compute address */
13900Sstevel@tonic-gate } else {
13910Sstevel@tonic-gate if (getreg(rp, rs2, &val, badaddr))
13920Sstevel@tonic-gate return (SIMU_FAULT);
13930Sstevel@tonic-gate addr += val;
13940Sstevel@tonic-gate }
13950Sstevel@tonic-gate
13960Sstevel@tonic-gate /*
13971030Smathue * If this is a 32-bit program, chop the address accordingly. The
13981030Smathue * intermediate uintptr_t casts prevent warnings under a certain
13991030Smathue * compiler, and the temporary 32 bit storage is intended to force
14001030Smathue * proper code generation and break up what would otherwise be a
14011030Smathue * quadruple cast.
14020Sstevel@tonic-gate */
14031030Smathue if (curproc->p_model == DATAMODEL_ILP32 && USERMODE(rp->r_tstate)) {
14041030Smathue caddr32_t addr32 = (caddr32_t)(uintptr_t)addr;
14051030Smathue addr = (caddr_t)(uintptr_t)addr32;
14061030Smathue }
14070Sstevel@tonic-gate
14080Sstevel@tonic-gate *badaddr = addr;
14090Sstevel@tonic-gate return ((uintptr_t)addr & (sz - 1) ? SIMU_UNALIGN : SIMU_SUCCESS);
14100Sstevel@tonic-gate }
14110Sstevel@tonic-gate
14120Sstevel@tonic-gate /*
14130Sstevel@tonic-gate * Return the size of a load or store instruction (1, 2, 4, 8, 16, 64).
14140Sstevel@tonic-gate * Also compute the precise address by instruction disassembly.
14150Sstevel@tonic-gate * (v9 page faults only provide the page address via the hardware.)
14160Sstevel@tonic-gate * Return 0 on failure (not a load or store instruction).
14170Sstevel@tonic-gate */
14180Sstevel@tonic-gate int
instr_size(struct regs * rp,caddr_t * addrp,enum seg_rw rdwr)14190Sstevel@tonic-gate instr_size(struct regs *rp, caddr_t *addrp, enum seg_rw rdwr)
14200Sstevel@tonic-gate {
14210Sstevel@tonic-gate uint_t inst, op3, asi;
14220Sstevel@tonic-gate uint_t rd, rs1, rs2;
14230Sstevel@tonic-gate int sz = 0;
14240Sstevel@tonic-gate int immflg;
14250Sstevel@tonic-gate int floatflg;
14260Sstevel@tonic-gate caddr_t addr;
14270Sstevel@tonic-gate caddr_t badaddr;
14280Sstevel@tonic-gate uint64_t val;
14290Sstevel@tonic-gate
14300Sstevel@tonic-gate if (rdwr == S_EXEC) {
14310Sstevel@tonic-gate *addrp = (caddr_t)rp->r_pc;
14320Sstevel@tonic-gate return (4);
14330Sstevel@tonic-gate }
14340Sstevel@tonic-gate
14350Sstevel@tonic-gate /*
14360Sstevel@tonic-gate * Fetch the instruction from user-level.
14370Sstevel@tonic-gate * We would like to assert this:
14380Sstevel@tonic-gate * ASSERT(USERMODE(rp->r_tstate));
14390Sstevel@tonic-gate * but we can't because we can reach this point from a
14400Sstevel@tonic-gate * register window underflow/overflow and the v9 wbuf
14410Sstevel@tonic-gate * traps call trap() with T_USER even though r_tstate
14420Sstevel@tonic-gate * indicates a system trap, not a user trap.
14430Sstevel@tonic-gate */
14440Sstevel@tonic-gate inst = fetch_user_instr((caddr_t)rp->r_pc);
14450Sstevel@tonic-gate
14460Sstevel@tonic-gate op3 = (inst >> 19) & 0x3f;
14470Sstevel@tonic-gate rd = (inst >> 25) & 0x1f;
14480Sstevel@tonic-gate rs1 = (inst >> 14) & 0x1f;
14490Sstevel@tonic-gate rs2 = inst & 0x1f;
14500Sstevel@tonic-gate floatflg = (inst >> 24) & 1;
14510Sstevel@tonic-gate immflg = (inst >> 13) & 1;
14520Sstevel@tonic-gate
14530Sstevel@tonic-gate /* if not load or store do nothing. can't happen? */
14540Sstevel@tonic-gate if ((inst >> 30) != 3)
14550Sstevel@tonic-gate return (0);
14560Sstevel@tonic-gate
14570Sstevel@tonic-gate if (immflg)
14580Sstevel@tonic-gate asi = (uint_t)((rp->r_tstate >> TSTATE_ASI_SHIFT) &
14597718SJason.Beloro@Sun.COM TSTATE_ASI_MASK);
14600Sstevel@tonic-gate else
14610Sstevel@tonic-gate asi = (inst >> 5) & 0xff;
14620Sstevel@tonic-gate
14630Sstevel@tonic-gate if (floatflg) {
14640Sstevel@tonic-gate /* check for ld/st alternate and highest defined V9 asi */
14650Sstevel@tonic-gate if ((op3 & 0x30) == 0x30 && asi > ASI_SNFL) {
14660Sstevel@tonic-gate sz = extended_asi_size(asi);
14670Sstevel@tonic-gate } else {
14680Sstevel@tonic-gate switch (op3 & 3) {
14690Sstevel@tonic-gate case 0:
14700Sstevel@tonic-gate sz = 4; /* ldf/stf/cas */
14710Sstevel@tonic-gate break;
14720Sstevel@tonic-gate case 1:
14730Sstevel@tonic-gate if (rd == 0)
14740Sstevel@tonic-gate sz = 4; /* ldfsr/stfsr */
14750Sstevel@tonic-gate else
14760Sstevel@tonic-gate sz = 8; /* ldxfsr/stxfsr */
14770Sstevel@tonic-gate break;
14780Sstevel@tonic-gate case 2:
14790Sstevel@tonic-gate if (op3 == 0x3e)
14800Sstevel@tonic-gate sz = 8; /* casx */
14810Sstevel@tonic-gate else
14820Sstevel@tonic-gate sz = 16; /* ldqf/stqf */
14830Sstevel@tonic-gate break;
14840Sstevel@tonic-gate case 3:
14850Sstevel@tonic-gate sz = 8; /* lddf/stdf */
14860Sstevel@tonic-gate break;
14870Sstevel@tonic-gate }
14880Sstevel@tonic-gate }
14890Sstevel@tonic-gate } else {
14900Sstevel@tonic-gate switch (op3 & 0xf) { /* map size bits to a number */
14910Sstevel@tonic-gate case 0: /* lduw */
14920Sstevel@tonic-gate case 4: /* stw */
14930Sstevel@tonic-gate case 8: /* ldsw */
14940Sstevel@tonic-gate case 0xf: /* swap */
14950Sstevel@tonic-gate sz = 4; break;
14960Sstevel@tonic-gate case 1: /* ldub */
14970Sstevel@tonic-gate case 5: /* stb */
14980Sstevel@tonic-gate case 9: /* ldsb */
14990Sstevel@tonic-gate case 0xd: /* ldstub */
15000Sstevel@tonic-gate sz = 1; break;
15010Sstevel@tonic-gate case 2: /* lduh */
15020Sstevel@tonic-gate case 6: /* sth */
15030Sstevel@tonic-gate case 0xa: /* ldsh */
15040Sstevel@tonic-gate sz = 2; break;
15050Sstevel@tonic-gate case 3: /* ldd */
15060Sstevel@tonic-gate case 7: /* std */
15070Sstevel@tonic-gate case 0xb: /* ldx */
15080Sstevel@tonic-gate case 0xe: /* stx */
15090Sstevel@tonic-gate sz = 8; break;
15100Sstevel@tonic-gate }
15110Sstevel@tonic-gate }
15120Sstevel@tonic-gate
15130Sstevel@tonic-gate if (sz == 0) /* can't happen? */
15140Sstevel@tonic-gate return (0);
15150Sstevel@tonic-gate (void) flush_user_windows_to_stack(NULL);
15160Sstevel@tonic-gate
15170Sstevel@tonic-gate if (getreg(rp, rs1, &val, &badaddr))
15180Sstevel@tonic-gate return (0);
15190Sstevel@tonic-gate addr = (caddr_t)val;
15200Sstevel@tonic-gate
15210Sstevel@tonic-gate /* cas/casx don't use rs2 / simm13 to compute the address */
15220Sstevel@tonic-gate if ((op3 & 0x3d) != 0x3c) {
15230Sstevel@tonic-gate /* check immediate bit and use immediate field or reg (rs2) */
15240Sstevel@tonic-gate if (immflg) {
15250Sstevel@tonic-gate int imm;
15260Sstevel@tonic-gate imm = inst & 0x1fff; /* mask out immediate field */
15270Sstevel@tonic-gate imm <<= 19; /* sign extend it */
15280Sstevel@tonic-gate imm >>= 19;
15290Sstevel@tonic-gate addr += imm; /* compute address */
15300Sstevel@tonic-gate } else {
15310Sstevel@tonic-gate /*
15320Sstevel@tonic-gate * asi's in the 0xCx range are partial store
15330Sstevel@tonic-gate * instructions. For these, rs2 is a mask, not part of
15340Sstevel@tonic-gate * the address.
15350Sstevel@tonic-gate */
15360Sstevel@tonic-gate if (!(floatflg && (asi & 0xf0) == 0xc0)) {
15370Sstevel@tonic-gate if (getreg(rp, rs2, &val, &badaddr))
15380Sstevel@tonic-gate return (0);
15390Sstevel@tonic-gate addr += val;
15400Sstevel@tonic-gate }
15410Sstevel@tonic-gate }
15420Sstevel@tonic-gate }
15430Sstevel@tonic-gate
15440Sstevel@tonic-gate /*
15451030Smathue * If this is a 32-bit program, chop the address accordingly. The
15461030Smathue * intermediate uintptr_t casts prevent warnings under a certain
15471030Smathue * compiler, and the temporary 32 bit storage is intended to force
15481030Smathue * proper code generation and break up what would otherwise be a
15491030Smathue * quadruple cast.
15500Sstevel@tonic-gate */
15511030Smathue if (curproc->p_model == DATAMODEL_ILP32) {
15521030Smathue caddr32_t addr32 = (caddr32_t)(uintptr_t)addr;
15531030Smathue addr = (caddr_t)(uintptr_t)addr32;
15541030Smathue }
15550Sstevel@tonic-gate
15560Sstevel@tonic-gate *addrp = addr;
15570Sstevel@tonic-gate ASSERT(sz != 0);
15580Sstevel@tonic-gate return (sz);
15590Sstevel@tonic-gate }
15600Sstevel@tonic-gate
15610Sstevel@tonic-gate /*
15620Sstevel@tonic-gate * Fetch an instruction from user-level.
15630Sstevel@tonic-gate * Deal with watchpoints, if they are in effect.
15640Sstevel@tonic-gate */
15650Sstevel@tonic-gate int32_t
fetch_user_instr(caddr_t vaddr)15660Sstevel@tonic-gate fetch_user_instr(caddr_t vaddr)
15670Sstevel@tonic-gate {
15680Sstevel@tonic-gate proc_t *p = curproc;
15690Sstevel@tonic-gate int32_t instr;
15700Sstevel@tonic-gate
15710Sstevel@tonic-gate /*
15721030Smathue * If this is a 32-bit program, chop the address accordingly. The
15731030Smathue * intermediate uintptr_t casts prevent warnings under a certain
15741030Smathue * compiler, and the temporary 32 bit storage is intended to force
15751030Smathue * proper code generation and break up what would otherwise be a
15761030Smathue * quadruple cast.
15770Sstevel@tonic-gate */
15781030Smathue if (p->p_model == DATAMODEL_ILP32) {
15791030Smathue caddr32_t vaddr32 = (caddr32_t)(uintptr_t)vaddr;
15801030Smathue vaddr = (caddr_t)(uintptr_t)vaddr32;
15811030Smathue }
15820Sstevel@tonic-gate
15830Sstevel@tonic-gate if (fuword32_nowatch(vaddr, (uint32_t *)&instr) == -1)
15840Sstevel@tonic-gate instr = -1;
15850Sstevel@tonic-gate
15860Sstevel@tonic-gate return (instr);
15870Sstevel@tonic-gate }
1588