xref: /onnv-gate/usr/src/uts/sparc/v9/os/simulator.c (revision 11172:a792f425ae2e)
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