xref: /illumos-gate/usr/src/uts/sparc/v9/os/simulator.c (revision dc32d872cbeb56532bcea030255db9cd79bac7da)
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*dc32d872SJosef 'Jeff' Sipek 	AS_LOCK_ENTER(as, RW_READER);
10917c478bd9Sstevel@tonic-gate 	mapseg = as_findseg(as, (caddr_t)rp->r_pc, 0);
10927c478bd9Sstevel@tonic-gate 	ASSERT(mapseg != NULL);
10937c478bd9Sstevel@tonic-gate 	svd = (struct segvn_data *)mapseg->s_data;
10947c478bd9Sstevel@tonic-gate 
10957c478bd9Sstevel@tonic-gate 	/*
10967c478bd9Sstevel@tonic-gate 	 * We only create COW page for MAP_PRIVATE mappings.
10977c478bd9Sstevel@tonic-gate 	 */
10987c478bd9Sstevel@tonic-gate 	SEGVN_LOCK_ENTER(as, &svd->lock, RW_READER);
10997c478bd9Sstevel@tonic-gate 	if ((svd->type & MAP_TYPE) & MAP_SHARED) {
11007c478bd9Sstevel@tonic-gate 		SEGVN_LOCK_EXIT(as, &svd->lock);
1101*dc32d872SJosef 'Jeff' Sipek 		AS_LOCK_EXIT(as);
11027c478bd9Sstevel@tonic-gate 		return (SIMU_ILLEGAL);
11037c478bd9Sstevel@tonic-gate 	}
11047c478bd9Sstevel@tonic-gate 	SEGVN_LOCK_EXIT(as, &svd->lock);
1105*dc32d872SJosef 'Jeff' Sipek 	AS_LOCK_EXIT(as);
11067c478bd9Sstevel@tonic-gate 
11077c478bd9Sstevel@tonic-gate 	/*
11087c478bd9Sstevel@tonic-gate 	 * A "flush" instruction using the user PC's vaddr will not work
11097c478bd9Sstevel@tonic-gate 	 * here, at least on Spitfire. Instead we create a temporary kernel
11107c478bd9Sstevel@tonic-gate 	 * mapping to the user's text page, then modify and flush that.
11117c478bd9Sstevel@tonic-gate 	 * Break COW by locking user page.
11127c478bd9Sstevel@tonic-gate 	 */
11137c478bd9Sstevel@tonic-gate 	if (as_fault(as->a_hat, as, (caddr_t)(rp->r_pc & PAGEMASK), PAGESIZE,
11147c478bd9Sstevel@tonic-gate 	    F_SOFTLOCK, S_READ))
11157c478bd9Sstevel@tonic-gate 		return (SIMU_FAULT);
11167c478bd9Sstevel@tonic-gate 
1117*dc32d872SJosef 'Jeff' Sipek 	AS_LOCK_ENTER(as, RW_READER);
11187c478bd9Sstevel@tonic-gate 	pfnum = hat_getpfnum(as->a_hat, (caddr_t)rp->r_pc);
1119*dc32d872SJosef 'Jeff' Sipek 	AS_LOCK_EXIT(as);
11207c478bd9Sstevel@tonic-gate 	if (pf_is_memory(pfnum)) {
11217c478bd9Sstevel@tonic-gate 		pp = page_numtopp_nolock(pfnum);
11227c478bd9Sstevel@tonic-gate 		ASSERT(pp == NULL || PAGE_LOCKED(pp));
11237c478bd9Sstevel@tonic-gate 	} else {
11247c478bd9Sstevel@tonic-gate 		(void) as_fault(as->a_hat, as, (caddr_t)(rp->r_pc & PAGEMASK),
11257c478bd9Sstevel@tonic-gate 		    PAGESIZE, F_SOFTUNLOCK, S_READ);
11267c478bd9Sstevel@tonic-gate 		return (SIMU_FAULT);
11277c478bd9Sstevel@tonic-gate 	}
11287c478bd9Sstevel@tonic-gate 
1129*dc32d872SJosef 'Jeff' Sipek 	AS_LOCK_ENTER(as, RW_READER);
11307c478bd9Sstevel@tonic-gate 	ka = ppmapin(pp, PROT_READ|PROT_WRITE, (caddr_t)rp->r_pc);
11317c478bd9Sstevel@tonic-gate 	*(uint_t *)(ka + (uintptr_t)(rp->r_pc % PAGESIZE)) = inst;
11327c478bd9Sstevel@tonic-gate 	doflush(ka + (uintptr_t)(rp->r_pc % PAGESIZE));
11337c478bd9Sstevel@tonic-gate 	ppmapout(ka);
1134*dc32d872SJosef 'Jeff' Sipek 	AS_LOCK_EXIT(as);
11357c478bd9Sstevel@tonic-gate 
11367c478bd9Sstevel@tonic-gate 	(void) as_fault(as->a_hat, as, (caddr_t)(rp->r_pc & PAGEMASK),
11377c478bd9Sstevel@tonic-gate 	    PAGESIZE, F_SOFTUNLOCK, S_READ);
11387c478bd9Sstevel@tonic-gate 	return (SIMU_RETRY);
11397c478bd9Sstevel@tonic-gate }
11407c478bd9Sstevel@tonic-gate 
11417c478bd9Sstevel@tonic-gate /*
1142023e71deSHaik Aftandilian  * Simulate a "rd %tick" or "rd %stick" (%asr24) instruction.
1143023e71deSHaik Aftandilian  */
1144023e71deSHaik Aftandilian int
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