xref: /illumos-gate/usr/src/uts/sparc/fs/proc/prmachdep.c (revision 75521904d7c3dbe11337904d9bead2518c94cc50)
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
57c478bd9Sstevel@tonic-gate  * Common Development and Distribution License, Version 1.0 only
67c478bd9Sstevel@tonic-gate  * (the "License").  You may not use this file except in compliance
77c478bd9Sstevel@tonic-gate  * with the License.
87c478bd9Sstevel@tonic-gate  *
97c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
107c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
117c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
127c478bd9Sstevel@tonic-gate  * and limitations under the License.
137c478bd9Sstevel@tonic-gate  *
147c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
157c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
167c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
177c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
187c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
197c478bd9Sstevel@tonic-gate  *
207c478bd9Sstevel@tonic-gate  * CDDL HEADER END
217c478bd9Sstevel@tonic-gate  */
22*75521904Sraf 
237c478bd9Sstevel@tonic-gate /*
247c478bd9Sstevel@tonic-gate  * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
257c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
267c478bd9Sstevel@tonic-gate  */
277c478bd9Sstevel@tonic-gate 
287c478bd9Sstevel@tonic-gate /*	Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T	*/
297c478bd9Sstevel@tonic-gate /*	  All Rights Reserved  	*/
307c478bd9Sstevel@tonic-gate 
317c478bd9Sstevel@tonic-gate 
327c478bd9Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"	/* SVr4.0 1.8 */
337c478bd9Sstevel@tonic-gate 
347c478bd9Sstevel@tonic-gate #include <sys/types.h>
357c478bd9Sstevel@tonic-gate #include <sys/t_lock.h>
367c478bd9Sstevel@tonic-gate #include <sys/param.h>
377c478bd9Sstevel@tonic-gate #include <sys/cred.h>
387c478bd9Sstevel@tonic-gate #include <sys/debug.h>
397c478bd9Sstevel@tonic-gate #include <sys/inline.h>
407c478bd9Sstevel@tonic-gate #include <sys/kmem.h>
417c478bd9Sstevel@tonic-gate #include <sys/proc.h>
427c478bd9Sstevel@tonic-gate #include <sys/sysmacros.h>
437c478bd9Sstevel@tonic-gate #include <sys/systm.h>
447c478bd9Sstevel@tonic-gate #include <sys/vmsystm.h>
457c478bd9Sstevel@tonic-gate #include <sys/vfs.h>
467c478bd9Sstevel@tonic-gate #include <sys/vnode.h>
477c478bd9Sstevel@tonic-gate #include <sys/pcb.h>
487c478bd9Sstevel@tonic-gate #include <sys/buf.h>
497c478bd9Sstevel@tonic-gate #include <sys/signal.h>
507c478bd9Sstevel@tonic-gate #include <sys/user.h>
517c478bd9Sstevel@tonic-gate #include <sys/cpuvar.h>
527c478bd9Sstevel@tonic-gate #include <sys/copyops.h>
537c478bd9Sstevel@tonic-gate #include <sys/watchpoint.h>
547c478bd9Sstevel@tonic-gate 
557c478bd9Sstevel@tonic-gate #include <sys/fault.h>
567c478bd9Sstevel@tonic-gate #include <sys/syscall.h>
577c478bd9Sstevel@tonic-gate #include <sys/procfs.h>
587c478bd9Sstevel@tonic-gate #include <sys/archsystm.h>
597c478bd9Sstevel@tonic-gate #include <sys/cmn_err.h>
607c478bd9Sstevel@tonic-gate #include <sys/stack.h>
617c478bd9Sstevel@tonic-gate #include <sys/machpcb.h>
627c478bd9Sstevel@tonic-gate #include <sys/simulate.h>
637c478bd9Sstevel@tonic-gate #include <sys/fpu/fpusystm.h>
647c478bd9Sstevel@tonic-gate 
657c478bd9Sstevel@tonic-gate #include <sys/pte.h>
667c478bd9Sstevel@tonic-gate #include <sys/vmem.h>
677c478bd9Sstevel@tonic-gate #include <sys/mman.h>
687c478bd9Sstevel@tonic-gate #include <sys/vmparam.h>
697c478bd9Sstevel@tonic-gate #include <vm/hat.h>
707c478bd9Sstevel@tonic-gate #include <vm/as.h>
717c478bd9Sstevel@tonic-gate #include <vm/seg.h>
727c478bd9Sstevel@tonic-gate #include <vm/seg_kmem.h>
737c478bd9Sstevel@tonic-gate #include <vm/seg_kp.h>
747c478bd9Sstevel@tonic-gate #include <vm/page.h>
757c478bd9Sstevel@tonic-gate 
767c478bd9Sstevel@tonic-gate #include <fs/proc/prdata.h>
777c478bd9Sstevel@tonic-gate #include <v9/sys/psr_compat.h>
787c478bd9Sstevel@tonic-gate 
797c478bd9Sstevel@tonic-gate int	prnwatch = 10000;	/* maximum number of watched areas */
807c478bd9Sstevel@tonic-gate 
817c478bd9Sstevel@tonic-gate /*
827c478bd9Sstevel@tonic-gate  * Force a thread into the kernel if it is not already there.
837c478bd9Sstevel@tonic-gate  * This is a no-op on uniprocessors.
847c478bd9Sstevel@tonic-gate  */
857c478bd9Sstevel@tonic-gate /* ARGSUSED */
867c478bd9Sstevel@tonic-gate void
877c478bd9Sstevel@tonic-gate prpokethread(kthread_t *t)
887c478bd9Sstevel@tonic-gate {
897c478bd9Sstevel@tonic-gate 	if (t->t_state == TS_ONPROC && t->t_cpu != CPU)
907c478bd9Sstevel@tonic-gate 		poke_cpu(t->t_cpu->cpu_id);
917c478bd9Sstevel@tonic-gate }
927c478bd9Sstevel@tonic-gate 
937c478bd9Sstevel@tonic-gate /*
947c478bd9Sstevel@tonic-gate  * Return general registers.
957c478bd9Sstevel@tonic-gate  */
967c478bd9Sstevel@tonic-gate void
977c478bd9Sstevel@tonic-gate prgetprregs(klwp_t *lwp, prgregset_t prp)
987c478bd9Sstevel@tonic-gate {
997c478bd9Sstevel@tonic-gate 	gregset_t gr;
1007c478bd9Sstevel@tonic-gate 
1017c478bd9Sstevel@tonic-gate 	ASSERT(MUTEX_NOT_HELD(&lwptoproc(lwp)->p_lock));
1027c478bd9Sstevel@tonic-gate 
1037c478bd9Sstevel@tonic-gate 	getgregs(lwp, gr);
1047c478bd9Sstevel@tonic-gate 	bzero(prp, sizeof (prp));
1057c478bd9Sstevel@tonic-gate 
1067c478bd9Sstevel@tonic-gate 	/*
1077c478bd9Sstevel@tonic-gate 	 * Can't copy since prgregset_t and gregset_t
1087c478bd9Sstevel@tonic-gate 	 * use different defines.
1097c478bd9Sstevel@tonic-gate 	 */
1107c478bd9Sstevel@tonic-gate 	prp[R_G1] = gr[REG_G1];
1117c478bd9Sstevel@tonic-gate 	prp[R_G2] = gr[REG_G2];
1127c478bd9Sstevel@tonic-gate 	prp[R_G3] = gr[REG_G3];
1137c478bd9Sstevel@tonic-gate 	prp[R_G4] = gr[REG_G4];
1147c478bd9Sstevel@tonic-gate 	prp[R_G5] = gr[REG_G5];
1157c478bd9Sstevel@tonic-gate 	prp[R_G6] = gr[REG_G6];
1167c478bd9Sstevel@tonic-gate 	prp[R_G7] = gr[REG_G7];
1177c478bd9Sstevel@tonic-gate 
1187c478bd9Sstevel@tonic-gate 	prp[R_O0] = gr[REG_O0];
1197c478bd9Sstevel@tonic-gate 	prp[R_O1] = gr[REG_O1];
1207c478bd9Sstevel@tonic-gate 	prp[R_O2] = gr[REG_O2];
1217c478bd9Sstevel@tonic-gate 	prp[R_O3] = gr[REG_O3];
1227c478bd9Sstevel@tonic-gate 	prp[R_O4] = gr[REG_O4];
1237c478bd9Sstevel@tonic-gate 	prp[R_O5] = gr[REG_O5];
1247c478bd9Sstevel@tonic-gate 	prp[R_O6] = gr[REG_O6];
1257c478bd9Sstevel@tonic-gate 	prp[R_O7] = gr[REG_O7];
1267c478bd9Sstevel@tonic-gate 
1277c478bd9Sstevel@tonic-gate 	if (lwp->lwp_pcb.pcb_xregstat != XREGNONE) {
1287c478bd9Sstevel@tonic-gate 		prp[R_L0] = lwp->lwp_pcb.pcb_xregs.rw_local[0];
1297c478bd9Sstevel@tonic-gate 		prp[R_L1] = lwp->lwp_pcb.pcb_xregs.rw_local[1];
1307c478bd9Sstevel@tonic-gate 		prp[R_L2] = lwp->lwp_pcb.pcb_xregs.rw_local[2];
1317c478bd9Sstevel@tonic-gate 		prp[R_L3] = lwp->lwp_pcb.pcb_xregs.rw_local[3];
1327c478bd9Sstevel@tonic-gate 		prp[R_L4] = lwp->lwp_pcb.pcb_xregs.rw_local[4];
1337c478bd9Sstevel@tonic-gate 		prp[R_L5] = lwp->lwp_pcb.pcb_xregs.rw_local[5];
1347c478bd9Sstevel@tonic-gate 		prp[R_L6] = lwp->lwp_pcb.pcb_xregs.rw_local[6];
1357c478bd9Sstevel@tonic-gate 		prp[R_L7] = lwp->lwp_pcb.pcb_xregs.rw_local[7];
1367c478bd9Sstevel@tonic-gate 
1377c478bd9Sstevel@tonic-gate 		prp[R_I0] = lwp->lwp_pcb.pcb_xregs.rw_in[0];
1387c478bd9Sstevel@tonic-gate 		prp[R_I1] = lwp->lwp_pcb.pcb_xregs.rw_in[1];
1397c478bd9Sstevel@tonic-gate 		prp[R_I2] = lwp->lwp_pcb.pcb_xregs.rw_in[2];
1407c478bd9Sstevel@tonic-gate 		prp[R_I3] = lwp->lwp_pcb.pcb_xregs.rw_in[3];
1417c478bd9Sstevel@tonic-gate 		prp[R_I4] = lwp->lwp_pcb.pcb_xregs.rw_in[4];
1427c478bd9Sstevel@tonic-gate 		prp[R_I5] = lwp->lwp_pcb.pcb_xregs.rw_in[5];
1437c478bd9Sstevel@tonic-gate 		prp[R_I6] = lwp->lwp_pcb.pcb_xregs.rw_in[6];
1447c478bd9Sstevel@tonic-gate 		prp[R_I7] = lwp->lwp_pcb.pcb_xregs.rw_in[7];
1457c478bd9Sstevel@tonic-gate 	}
1467c478bd9Sstevel@tonic-gate 
1477c478bd9Sstevel@tonic-gate 	prp[R_CCR] = gr[REG_CCR];
1487c478bd9Sstevel@tonic-gate 	prp[R_ASI] = gr[REG_ASI];
1497c478bd9Sstevel@tonic-gate 	prp[R_FPRS] = gr[REG_FPRS];
1507c478bd9Sstevel@tonic-gate 	prp[R_PC]  = gr[REG_PC];
1517c478bd9Sstevel@tonic-gate 	prp[R_nPC] = gr[REG_nPC];
1527c478bd9Sstevel@tonic-gate 	prp[R_Y]   = gr[REG_Y];
1537c478bd9Sstevel@tonic-gate }
1547c478bd9Sstevel@tonic-gate 
1557c478bd9Sstevel@tonic-gate /*
1567c478bd9Sstevel@tonic-gate  * Set general registers.
1577c478bd9Sstevel@tonic-gate  */
1587c478bd9Sstevel@tonic-gate void
1597c478bd9Sstevel@tonic-gate prsetprregs(klwp_t *lwp, prgregset_t prp, int initial)
1607c478bd9Sstevel@tonic-gate {
1617c478bd9Sstevel@tonic-gate 	gregset_t gr;
1627c478bd9Sstevel@tonic-gate 
1637c478bd9Sstevel@tonic-gate 	gr[REG_G1] = prp[R_G1];
1647c478bd9Sstevel@tonic-gate 	gr[REG_G2] = prp[R_G2];
1657c478bd9Sstevel@tonic-gate 	gr[REG_G3] = prp[R_G3];
1667c478bd9Sstevel@tonic-gate 	gr[REG_G4] = prp[R_G4];
1677c478bd9Sstevel@tonic-gate 	gr[REG_G5] = prp[R_G5];
1687c478bd9Sstevel@tonic-gate 	gr[REG_G6] = prp[R_G6];
1697c478bd9Sstevel@tonic-gate 	gr[REG_G7] = prp[R_G7];
1707c478bd9Sstevel@tonic-gate 
1717c478bd9Sstevel@tonic-gate 	gr[REG_O0] = prp[R_O0];
1727c478bd9Sstevel@tonic-gate 	gr[REG_O1] = prp[R_O1];
1737c478bd9Sstevel@tonic-gate 	gr[REG_O2] = prp[R_O2];
1747c478bd9Sstevel@tonic-gate 	gr[REG_O3] = prp[R_O3];
1757c478bd9Sstevel@tonic-gate 	gr[REG_O4] = prp[R_O4];
1767c478bd9Sstevel@tonic-gate 	gr[REG_O5] = prp[R_O5];
1777c478bd9Sstevel@tonic-gate 	gr[REG_O6] = prp[R_O6];
1787c478bd9Sstevel@tonic-gate 	gr[REG_O7] = prp[R_O7];
1797c478bd9Sstevel@tonic-gate 
1807c478bd9Sstevel@tonic-gate 	lwp->lwp_pcb.pcb_xregs.rw_local[0] = prp[R_L0];
1817c478bd9Sstevel@tonic-gate 	lwp->lwp_pcb.pcb_xregs.rw_local[1] = prp[R_L1];
1827c478bd9Sstevel@tonic-gate 	lwp->lwp_pcb.pcb_xregs.rw_local[2] = prp[R_L2];
1837c478bd9Sstevel@tonic-gate 	lwp->lwp_pcb.pcb_xregs.rw_local[3] = prp[R_L3];
1847c478bd9Sstevel@tonic-gate 	lwp->lwp_pcb.pcb_xregs.rw_local[4] = prp[R_L4];
1857c478bd9Sstevel@tonic-gate 	lwp->lwp_pcb.pcb_xregs.rw_local[5] = prp[R_L5];
1867c478bd9Sstevel@tonic-gate 	lwp->lwp_pcb.pcb_xregs.rw_local[6] = prp[R_L6];
1877c478bd9Sstevel@tonic-gate 	lwp->lwp_pcb.pcb_xregs.rw_local[7] = prp[R_L7];
1887c478bd9Sstevel@tonic-gate 
1897c478bd9Sstevel@tonic-gate 	lwp->lwp_pcb.pcb_xregs.rw_in[0] = prp[R_I0];
1907c478bd9Sstevel@tonic-gate 	lwp->lwp_pcb.pcb_xregs.rw_in[1] = prp[R_I1];
1917c478bd9Sstevel@tonic-gate 	lwp->lwp_pcb.pcb_xregs.rw_in[2] = prp[R_I2];
1927c478bd9Sstevel@tonic-gate 	lwp->lwp_pcb.pcb_xregs.rw_in[3] = prp[R_I3];
1937c478bd9Sstevel@tonic-gate 	lwp->lwp_pcb.pcb_xregs.rw_in[4] = prp[R_I4];
1947c478bd9Sstevel@tonic-gate 	lwp->lwp_pcb.pcb_xregs.rw_in[5] = prp[R_I5];
1957c478bd9Sstevel@tonic-gate 	lwp->lwp_pcb.pcb_xregs.rw_in[6] = prp[R_I6];
1967c478bd9Sstevel@tonic-gate 	lwp->lwp_pcb.pcb_xregs.rw_in[7] = prp[R_I7];
1977c478bd9Sstevel@tonic-gate 
1987c478bd9Sstevel@tonic-gate 	lwp->lwp_pcb.pcb_xregstat = XREGMODIFIED;
1997c478bd9Sstevel@tonic-gate 	lwptot(lwp)->t_post_sys = 1;
2007c478bd9Sstevel@tonic-gate 
2017c478bd9Sstevel@tonic-gate 	/*
2027c478bd9Sstevel@tonic-gate 	 * setgregs will only allow the condition codes to be set.
2037c478bd9Sstevel@tonic-gate 	 */
2047c478bd9Sstevel@tonic-gate 	gr[REG_CCR] = prp[R_CCR];
2057c478bd9Sstevel@tonic-gate 	gr[REG_ASI] = prp[R_ASI];
2067c478bd9Sstevel@tonic-gate 	gr[REG_FPRS] = prp[R_FPRS];
2077c478bd9Sstevel@tonic-gate 	gr[REG_PC]  = prp[R_PC];
2087c478bd9Sstevel@tonic-gate 	gr[REG_nPC] = prp[R_nPC];
2097c478bd9Sstevel@tonic-gate 	gr[REG_Y]   = prp[R_Y];
2107c478bd9Sstevel@tonic-gate 
2117c478bd9Sstevel@tonic-gate 	if (initial) {		/* set initial values */
2127c478bd9Sstevel@tonic-gate 		if (lwptoproc(lwp)->p_model == DATAMODEL_LP64)
2137c478bd9Sstevel@tonic-gate 			lwptoregs(lwp)->r_tstate = TSTATE_USER64;
2147c478bd9Sstevel@tonic-gate 		else
2157c478bd9Sstevel@tonic-gate 			lwptoregs(lwp)->r_tstate = TSTATE_USER32;
2167c478bd9Sstevel@tonic-gate 		if (!fpu_exists)
2177c478bd9Sstevel@tonic-gate 			lwptoregs(lwp)->r_tstate &= ~TSTATE_PEF;
2187c478bd9Sstevel@tonic-gate 	}
2197c478bd9Sstevel@tonic-gate 
2207c478bd9Sstevel@tonic-gate 	setgregs(lwp, gr);
2217c478bd9Sstevel@tonic-gate }
2227c478bd9Sstevel@tonic-gate 
2237c478bd9Sstevel@tonic-gate #ifdef _SYSCALL32_IMPL
2247c478bd9Sstevel@tonic-gate 
2257c478bd9Sstevel@tonic-gate /*
2267c478bd9Sstevel@tonic-gate  * modify the lower 32bits of a uint64_t
2277c478bd9Sstevel@tonic-gate  */
2287c478bd9Sstevel@tonic-gate #define	SET_LOWER_32(all, lower)	\
2297c478bd9Sstevel@tonic-gate 	(((uint64_t)(all) & 0xffffffff00000000) | (uint32_t)(lower))
2307c478bd9Sstevel@tonic-gate 
2317c478bd9Sstevel@tonic-gate /*
2327c478bd9Sstevel@tonic-gate  * Convert prgregset32 to native prgregset.
2337c478bd9Sstevel@tonic-gate  */
2347c478bd9Sstevel@tonic-gate void
2357c478bd9Sstevel@tonic-gate prgregset_32ton(klwp_t *lwp, prgregset32_t src, prgregset_t dest)
2367c478bd9Sstevel@tonic-gate {
2377c478bd9Sstevel@tonic-gate 	struct regs *r = lwptoregs(lwp);
2387c478bd9Sstevel@tonic-gate 
2397c478bd9Sstevel@tonic-gate 	dest[R_G0] = SET_LOWER_32(0, src[R_G0]);
2407c478bd9Sstevel@tonic-gate 	dest[R_G1] = SET_LOWER_32(r->r_g1, src[R_G1]);
2417c478bd9Sstevel@tonic-gate 	dest[R_G2] = SET_LOWER_32(r->r_g2, src[R_G2]);
2427c478bd9Sstevel@tonic-gate 	dest[R_G3] = SET_LOWER_32(r->r_g3, src[R_G3]);
2437c478bd9Sstevel@tonic-gate 	dest[R_G4] = SET_LOWER_32(r->r_g4, src[R_G4]);
2447c478bd9Sstevel@tonic-gate 	dest[R_G5] = SET_LOWER_32(r->r_g5, src[R_G5]);
2457c478bd9Sstevel@tonic-gate 	dest[R_G6] = SET_LOWER_32(r->r_g6, src[R_G6]);
2467c478bd9Sstevel@tonic-gate 	dest[R_G7] = SET_LOWER_32(r->r_g7, src[R_G7]);
2477c478bd9Sstevel@tonic-gate 
2487c478bd9Sstevel@tonic-gate 	dest[R_O0] = SET_LOWER_32(r->r_o0, src[R_O0]);
2497c478bd9Sstevel@tonic-gate 	dest[R_O1] = SET_LOWER_32(r->r_o1, src[R_O1]);
2507c478bd9Sstevel@tonic-gate 	dest[R_O2] = SET_LOWER_32(r->r_o2, src[R_O2]);
2517c478bd9Sstevel@tonic-gate 	dest[R_O3] = SET_LOWER_32(r->r_o3, src[R_O3]);
2527c478bd9Sstevel@tonic-gate 	dest[R_O4] = SET_LOWER_32(r->r_o4, src[R_O4]);
2537c478bd9Sstevel@tonic-gate 	dest[R_O5] = SET_LOWER_32(r->r_o5, src[R_O5]);
2547c478bd9Sstevel@tonic-gate 	dest[R_O6] = SET_LOWER_32(r->r_o6, src[R_O6]);
2557c478bd9Sstevel@tonic-gate 	dest[R_O7] = SET_LOWER_32(r->r_o7, src[R_O7]);
2567c478bd9Sstevel@tonic-gate 
2577c478bd9Sstevel@tonic-gate 	if (lwp->lwp_pcb.pcb_xregstat != XREGNONE) {
2587c478bd9Sstevel@tonic-gate 		struct rwindow *rw = &lwp->lwp_pcb.pcb_xregs;
2597c478bd9Sstevel@tonic-gate 
2607c478bd9Sstevel@tonic-gate 		dest[R_L0] = SET_LOWER_32(rw->rw_local[0], src[R_L0]);
2617c478bd9Sstevel@tonic-gate 		dest[R_L1] = SET_LOWER_32(rw->rw_local[1], src[R_L1]);
2627c478bd9Sstevel@tonic-gate 		dest[R_L2] = SET_LOWER_32(rw->rw_local[2], src[R_L2]);
2637c478bd9Sstevel@tonic-gate 		dest[R_L3] = SET_LOWER_32(rw->rw_local[3], src[R_L3]);
2647c478bd9Sstevel@tonic-gate 		dest[R_L4] = SET_LOWER_32(rw->rw_local[4], src[R_L4]);
2657c478bd9Sstevel@tonic-gate 		dest[R_L5] = SET_LOWER_32(rw->rw_local[5], src[R_L5]);
2667c478bd9Sstevel@tonic-gate 		dest[R_L6] = SET_LOWER_32(rw->rw_local[6], src[R_L6]);
2677c478bd9Sstevel@tonic-gate 		dest[R_L7] = SET_LOWER_32(rw->rw_local[7], src[R_L7]);
2687c478bd9Sstevel@tonic-gate 
2697c478bd9Sstevel@tonic-gate 		dest[R_I0] = SET_LOWER_32(rw->rw_in[0], src[R_I0]);
2707c478bd9Sstevel@tonic-gate 		dest[R_I1] = SET_LOWER_32(rw->rw_in[1], src[R_I1]);
2717c478bd9Sstevel@tonic-gate 		dest[R_I2] = SET_LOWER_32(rw->rw_in[2], src[R_I2]);
2727c478bd9Sstevel@tonic-gate 		dest[R_I3] = SET_LOWER_32(rw->rw_in[3], src[R_I3]);
2737c478bd9Sstevel@tonic-gate 		dest[R_I4] = SET_LOWER_32(rw->rw_in[4], src[R_I4]);
2747c478bd9Sstevel@tonic-gate 		dest[R_I5] = SET_LOWER_32(rw->rw_in[5], src[R_I5]);
2757c478bd9Sstevel@tonic-gate 		dest[R_I6] = SET_LOWER_32(rw->rw_in[6], src[R_I6]);
2767c478bd9Sstevel@tonic-gate 		dest[R_I7] = SET_LOWER_32(rw->rw_in[7], src[R_I7]);
2777c478bd9Sstevel@tonic-gate 	} else {
2787c478bd9Sstevel@tonic-gate 		dest[R_L0] = (uint32_t)src[R_L0];
2797c478bd9Sstevel@tonic-gate 		dest[R_L1] = (uint32_t)src[R_L1];
2807c478bd9Sstevel@tonic-gate 		dest[R_L2] = (uint32_t)src[R_L2];
2817c478bd9Sstevel@tonic-gate 		dest[R_L3] = (uint32_t)src[R_L3];
2827c478bd9Sstevel@tonic-gate 		dest[R_L4] = (uint32_t)src[R_L4];
2837c478bd9Sstevel@tonic-gate 		dest[R_L5] = (uint32_t)src[R_L5];
2847c478bd9Sstevel@tonic-gate 		dest[R_L6] = (uint32_t)src[R_L6];
2857c478bd9Sstevel@tonic-gate 		dest[R_L7] = (uint32_t)src[R_L7];
2867c478bd9Sstevel@tonic-gate 
2877c478bd9Sstevel@tonic-gate 		dest[R_I0] = (uint32_t)src[R_I0];
2887c478bd9Sstevel@tonic-gate 		dest[R_I1] = (uint32_t)src[R_I1];
2897c478bd9Sstevel@tonic-gate 		dest[R_I2] = (uint32_t)src[R_I2];
2907c478bd9Sstevel@tonic-gate 		dest[R_I3] = (uint32_t)src[R_I3];
2917c478bd9Sstevel@tonic-gate 		dest[R_I4] = (uint32_t)src[R_I4];
2927c478bd9Sstevel@tonic-gate 		dest[R_I5] = (uint32_t)src[R_I5];
2937c478bd9Sstevel@tonic-gate 		dest[R_I6] = (uint32_t)src[R_I6];
2947c478bd9Sstevel@tonic-gate 		dest[R_I7] = (uint32_t)src[R_I7];
2957c478bd9Sstevel@tonic-gate 	}
2967c478bd9Sstevel@tonic-gate 
2977c478bd9Sstevel@tonic-gate 	dest[R_CCR] = ((r->r_tstate >> TSTATE_CCR_SHIFT) & CCR_XCC) |
2987c478bd9Sstevel@tonic-gate 	    ((src[R_PSR] >> (TSTATE_CCR_SHIFT-PSR_TSTATE_CC_SHIFT)) & CCR_ICC);
2997c478bd9Sstevel@tonic-gate 
3007c478bd9Sstevel@tonic-gate 	dest[R_PC] = SET_LOWER_32(r->r_pc, src[R_PC]);
3017c478bd9Sstevel@tonic-gate 	dest[R_nPC] = SET_LOWER_32(r->r_npc, src[R_nPC]);
3027c478bd9Sstevel@tonic-gate 	dest[R_Y] = (uint32_t)src[R_Y];
3037c478bd9Sstevel@tonic-gate 
3047c478bd9Sstevel@tonic-gate 	dest[R_ASI] = (r->r_tstate >> TSTATE_ASI_SHIFT) & TSTATE_ASI_MASK;
3057c478bd9Sstevel@tonic-gate 	dest[R_FPRS] = lwptofpu(lwp)->fpu_fprs;
3067c478bd9Sstevel@tonic-gate }
3077c478bd9Sstevel@tonic-gate 
3087c478bd9Sstevel@tonic-gate /*
3097c478bd9Sstevel@tonic-gate  * Return 32-bit general registers.
3107c478bd9Sstevel@tonic-gate  */
3117c478bd9Sstevel@tonic-gate 
3127c478bd9Sstevel@tonic-gate /* conversion from 64-bit register to 32-bit register */
3137c478bd9Sstevel@tonic-gate #define	R32(r)	(prgreg32_t)(uint32_t)(r)
3147c478bd9Sstevel@tonic-gate 
3157c478bd9Sstevel@tonic-gate void
3167c478bd9Sstevel@tonic-gate prgetprregs32(klwp_t *lwp, prgregset32_t prp)
3177c478bd9Sstevel@tonic-gate {
3187c478bd9Sstevel@tonic-gate 	gregset32_t gr;
3197c478bd9Sstevel@tonic-gate 
3207c478bd9Sstevel@tonic-gate 	extern void getgregs32(klwp_t *, gregset32_t);
3217c478bd9Sstevel@tonic-gate 
3227c478bd9Sstevel@tonic-gate 	ASSERT(MUTEX_NOT_HELD(&lwptoproc(lwp)->p_lock));
3237c478bd9Sstevel@tonic-gate 
3247c478bd9Sstevel@tonic-gate 	getgregs32(lwp, gr);
3257c478bd9Sstevel@tonic-gate 	bzero(prp, sizeof (prp));
3267c478bd9Sstevel@tonic-gate 
3277c478bd9Sstevel@tonic-gate 	/*
3287c478bd9Sstevel@tonic-gate 	 * Can't copy since prgregset_t and gregset_t
3297c478bd9Sstevel@tonic-gate 	 * use different defines.
3307c478bd9Sstevel@tonic-gate 	 */
3317c478bd9Sstevel@tonic-gate 	prp[R_G1] = gr[REG_G1];
3327c478bd9Sstevel@tonic-gate 	prp[R_G2] = gr[REG_G2];
3337c478bd9Sstevel@tonic-gate 	prp[R_G3] = gr[REG_G3];
3347c478bd9Sstevel@tonic-gate 	prp[R_G4] = gr[REG_G4];
3357c478bd9Sstevel@tonic-gate 	prp[R_G5] = gr[REG_G5];
3367c478bd9Sstevel@tonic-gate 	prp[R_G6] = gr[REG_G6];
3377c478bd9Sstevel@tonic-gate 	prp[R_G7] = gr[REG_G7];
3387c478bd9Sstevel@tonic-gate 
3397c478bd9Sstevel@tonic-gate 	prp[R_O0] = gr[REG_O0];
3407c478bd9Sstevel@tonic-gate 	prp[R_O1] = gr[REG_O1];
3417c478bd9Sstevel@tonic-gate 	prp[R_O2] = gr[REG_O2];
3427c478bd9Sstevel@tonic-gate 	prp[R_O3] = gr[REG_O3];
3437c478bd9Sstevel@tonic-gate 	prp[R_O4] = gr[REG_O4];
3447c478bd9Sstevel@tonic-gate 	prp[R_O5] = gr[REG_O5];
3457c478bd9Sstevel@tonic-gate 	prp[R_O6] = gr[REG_O6];
3467c478bd9Sstevel@tonic-gate 	prp[R_O7] = gr[REG_O7];
3477c478bd9Sstevel@tonic-gate 
3487c478bd9Sstevel@tonic-gate 	if (lwp->lwp_pcb.pcb_xregstat != XREGNONE) {
3497c478bd9Sstevel@tonic-gate 		prp[R_L0] = R32(lwp->lwp_pcb.pcb_xregs.rw_local[0]);
3507c478bd9Sstevel@tonic-gate 		prp[R_L1] = R32(lwp->lwp_pcb.pcb_xregs.rw_local[1]);
3517c478bd9Sstevel@tonic-gate 		prp[R_L2] = R32(lwp->lwp_pcb.pcb_xregs.rw_local[2]);
3527c478bd9Sstevel@tonic-gate 		prp[R_L3] = R32(lwp->lwp_pcb.pcb_xregs.rw_local[3]);
3537c478bd9Sstevel@tonic-gate 		prp[R_L4] = R32(lwp->lwp_pcb.pcb_xregs.rw_local[4]);
3547c478bd9Sstevel@tonic-gate 		prp[R_L5] = R32(lwp->lwp_pcb.pcb_xregs.rw_local[5]);
3557c478bd9Sstevel@tonic-gate 		prp[R_L6] = R32(lwp->lwp_pcb.pcb_xregs.rw_local[6]);
3567c478bd9Sstevel@tonic-gate 		prp[R_L7] = R32(lwp->lwp_pcb.pcb_xregs.rw_local[7]);
3577c478bd9Sstevel@tonic-gate 
3587c478bd9Sstevel@tonic-gate 		prp[R_I0] = R32(lwp->lwp_pcb.pcb_xregs.rw_in[0]);
3597c478bd9Sstevel@tonic-gate 		prp[R_I1] = R32(lwp->lwp_pcb.pcb_xregs.rw_in[1]);
3607c478bd9Sstevel@tonic-gate 		prp[R_I2] = R32(lwp->lwp_pcb.pcb_xregs.rw_in[2]);
3617c478bd9Sstevel@tonic-gate 		prp[R_I3] = R32(lwp->lwp_pcb.pcb_xregs.rw_in[3]);
3627c478bd9Sstevel@tonic-gate 		prp[R_I4] = R32(lwp->lwp_pcb.pcb_xregs.rw_in[4]);
3637c478bd9Sstevel@tonic-gate 		prp[R_I5] = R32(lwp->lwp_pcb.pcb_xregs.rw_in[5]);
3647c478bd9Sstevel@tonic-gate 		prp[R_I6] = R32(lwp->lwp_pcb.pcb_xregs.rw_in[6]);
3657c478bd9Sstevel@tonic-gate 		prp[R_I7] = R32(lwp->lwp_pcb.pcb_xregs.rw_in[7]);
3667c478bd9Sstevel@tonic-gate 	}
3677c478bd9Sstevel@tonic-gate 
3687c478bd9Sstevel@tonic-gate 	prp[R_PSR] = gr[REG_PSR];
3697c478bd9Sstevel@tonic-gate 	prp[R_PC]  = gr[REG_PC];
3707c478bd9Sstevel@tonic-gate 	prp[R_nPC] = gr[REG_nPC];
3717c478bd9Sstevel@tonic-gate 	prp[R_Y]   = gr[REG_Y];
3727c478bd9Sstevel@tonic-gate }
3737c478bd9Sstevel@tonic-gate 
3747c478bd9Sstevel@tonic-gate #endif	/* _SYSCALL32_IMPL */
3757c478bd9Sstevel@tonic-gate 
3767c478bd9Sstevel@tonic-gate /*
3777c478bd9Sstevel@tonic-gate  * Get the syscall return values for the lwp.
3787c478bd9Sstevel@tonic-gate  */
3797c478bd9Sstevel@tonic-gate int
3807c478bd9Sstevel@tonic-gate prgetrvals(klwp_t *lwp, long *rval1, long *rval2)
3817c478bd9Sstevel@tonic-gate {
3827c478bd9Sstevel@tonic-gate 	struct regs *r = lwptoregs(lwp);
3837c478bd9Sstevel@tonic-gate 
3847c478bd9Sstevel@tonic-gate 	if (r->r_tstate & TSTATE_IC)
3857c478bd9Sstevel@tonic-gate 		return ((int)r->r_o0);
3867c478bd9Sstevel@tonic-gate 	if (lwp->lwp_eosys == JUSTRETURN) {
3877c478bd9Sstevel@tonic-gate 		*rval1 = 0;
3887c478bd9Sstevel@tonic-gate 		*rval2 = 0;
3897c478bd9Sstevel@tonic-gate 	} else if (lwptoproc(lwp)->p_model == DATAMODEL_ILP32) {
3907c478bd9Sstevel@tonic-gate 		*rval1 = r->r_o0 & (uint32_t)0xffffffffU;
3917c478bd9Sstevel@tonic-gate 		*rval2 = r->r_o1 & (uint32_t)0xffffffffU;
3927c478bd9Sstevel@tonic-gate 	} else {
3937c478bd9Sstevel@tonic-gate 		*rval1 = r->r_o0;
3947c478bd9Sstevel@tonic-gate 		*rval2 = r->r_o1;
3957c478bd9Sstevel@tonic-gate 	}
3967c478bd9Sstevel@tonic-gate 	return (0);
3977c478bd9Sstevel@tonic-gate }
3987c478bd9Sstevel@tonic-gate 
3997c478bd9Sstevel@tonic-gate /*
4007c478bd9Sstevel@tonic-gate  * Does the system support floating-point, either through hardware
4017c478bd9Sstevel@tonic-gate  * or by trapping and emulating floating-point machine instructions?
4027c478bd9Sstevel@tonic-gate  */
4037c478bd9Sstevel@tonic-gate int
4047c478bd9Sstevel@tonic-gate prhasfp(void)
4057c478bd9Sstevel@tonic-gate {
4067c478bd9Sstevel@tonic-gate 	/*
4077c478bd9Sstevel@tonic-gate 	 * SunOS5.0 emulates floating-point if FP hardware is not present.
4087c478bd9Sstevel@tonic-gate 	 */
4097c478bd9Sstevel@tonic-gate 	return (1);
4107c478bd9Sstevel@tonic-gate }
4117c478bd9Sstevel@tonic-gate 
4127c478bd9Sstevel@tonic-gate /*
4137c478bd9Sstevel@tonic-gate  * Get floating-point registers.
4147c478bd9Sstevel@tonic-gate  */
4157c478bd9Sstevel@tonic-gate void
4167c478bd9Sstevel@tonic-gate prgetprfpregs(klwp_t *lwp, prfpregset_t *pfp)
4177c478bd9Sstevel@tonic-gate {
4187c478bd9Sstevel@tonic-gate 	bzero(pfp, sizeof (*pfp));
4197c478bd9Sstevel@tonic-gate 	/*
4207c478bd9Sstevel@tonic-gate 	 * This works only because prfpregset_t is intentionally
4217c478bd9Sstevel@tonic-gate 	 * constructed to be identical to fpregset_t, with additional
4227c478bd9Sstevel@tonic-gate 	 * space for the floating-point queue at the end.
4237c478bd9Sstevel@tonic-gate 	 */
4247c478bd9Sstevel@tonic-gate 	getfpregs(lwp, (fpregset_t *)pfp);
4257c478bd9Sstevel@tonic-gate 	/*
4267c478bd9Sstevel@tonic-gate 	 * This is supposed to be a pointer to the floating point queue.
4277c478bd9Sstevel@tonic-gate 	 * We can't provide such a thing through the /proc interface.
4287c478bd9Sstevel@tonic-gate 	 */
4297c478bd9Sstevel@tonic-gate 	pfp->pr_filler = NULL;
4307c478bd9Sstevel@tonic-gate 	/*
4317c478bd9Sstevel@tonic-gate 	 * XXX: to be done: fetch the FP queue if it is non-empty.
4327c478bd9Sstevel@tonic-gate 	 */
4337c478bd9Sstevel@tonic-gate }
4347c478bd9Sstevel@tonic-gate 
4357c478bd9Sstevel@tonic-gate #ifdef	_SYSCALL32_IMPL
4367c478bd9Sstevel@tonic-gate void
4377c478bd9Sstevel@tonic-gate prgetprfpregs32(klwp_t *lwp, prfpregset32_t *pfp)
4387c478bd9Sstevel@tonic-gate {
4397c478bd9Sstevel@tonic-gate 	bzero(pfp, sizeof (*pfp));
4407c478bd9Sstevel@tonic-gate 	/*
4417c478bd9Sstevel@tonic-gate 	 * This works only because prfpregset32_t is intentionally
4427c478bd9Sstevel@tonic-gate 	 * constructed to be identical to fpregset32_t, with additional
4437c478bd9Sstevel@tonic-gate 	 * space for the floating-point queue at the end.
4447c478bd9Sstevel@tonic-gate 	 */
4457c478bd9Sstevel@tonic-gate 	getfpregs32(lwp, (fpregset32_t *)pfp);
4467c478bd9Sstevel@tonic-gate 	/*
4477c478bd9Sstevel@tonic-gate 	 * This is supposed to be a pointer to the floating point queue.
4487c478bd9Sstevel@tonic-gate 	 * We can't provide such a thing through the /proc interface.
4497c478bd9Sstevel@tonic-gate 	 */
4507c478bd9Sstevel@tonic-gate 	pfp->pr_filler = NULL;
4517c478bd9Sstevel@tonic-gate 	/*
4527c478bd9Sstevel@tonic-gate 	 * XXX: to be done: fetch the FP queue if it is non-empty.
4537c478bd9Sstevel@tonic-gate 	 */
4547c478bd9Sstevel@tonic-gate }
4557c478bd9Sstevel@tonic-gate #endif	/* _SYSCALL32_IMPL */
4567c478bd9Sstevel@tonic-gate 
4577c478bd9Sstevel@tonic-gate /*
4587c478bd9Sstevel@tonic-gate  * Set floating-point registers.
4597c478bd9Sstevel@tonic-gate  */
4607c478bd9Sstevel@tonic-gate void
4617c478bd9Sstevel@tonic-gate prsetprfpregs(klwp_t *lwp, prfpregset_t *pfp)
4627c478bd9Sstevel@tonic-gate {
4637c478bd9Sstevel@tonic-gate 	/*
4647c478bd9Sstevel@tonic-gate 	 * XXX: to be done: store the FP queue if it is non-empty.
4657c478bd9Sstevel@tonic-gate 	 */
4667c478bd9Sstevel@tonic-gate 	pfp->pr_qcnt = 0;
4677c478bd9Sstevel@tonic-gate 	/*
4687c478bd9Sstevel@tonic-gate 	 * We set fpu_en before calling setfpregs() in order to
4697c478bd9Sstevel@tonic-gate 	 * retain the semantics of this operation from older
4707c478bd9Sstevel@tonic-gate 	 * versions of the system.  SunOS 5.4 and prior never
4717c478bd9Sstevel@tonic-gate 	 * queried fpu_en; they just set the registers.  The
4727c478bd9Sstevel@tonic-gate 	 * proper operation if fpu_en is zero is to disable
4737c478bd9Sstevel@tonic-gate 	 * floating point in the target process, but this can
4747c478bd9Sstevel@tonic-gate 	 * only change after a proper end-of-life period for
4757c478bd9Sstevel@tonic-gate 	 * the old semantics.
4767c478bd9Sstevel@tonic-gate 	 */
4777c478bd9Sstevel@tonic-gate 	pfp->pr_en = 1;
4787c478bd9Sstevel@tonic-gate 	/*
4797c478bd9Sstevel@tonic-gate 	 * This works only because prfpregset_t is intentionally
4807c478bd9Sstevel@tonic-gate 	 * constructed to be identical to fpregset_t, with additional
4817c478bd9Sstevel@tonic-gate 	 * space for the floating-point queue at the end.
4827c478bd9Sstevel@tonic-gate 	 */
4837c478bd9Sstevel@tonic-gate 	setfpregs(lwp, (fpregset_t *)pfp);
4847c478bd9Sstevel@tonic-gate }
4857c478bd9Sstevel@tonic-gate 
4867c478bd9Sstevel@tonic-gate #ifdef	_SYSCALL32_IMPL
4877c478bd9Sstevel@tonic-gate void
4887c478bd9Sstevel@tonic-gate prsetprfpregs32(klwp_t *lwp, prfpregset32_t *pfp)
4897c478bd9Sstevel@tonic-gate {
4907c478bd9Sstevel@tonic-gate 	/*
4917c478bd9Sstevel@tonic-gate 	 * XXX: to be done: store the FP queue if it is non-empty.
4927c478bd9Sstevel@tonic-gate 	 */
4937c478bd9Sstevel@tonic-gate 	pfp->pr_qcnt = 0;
4947c478bd9Sstevel@tonic-gate 	/*
4957c478bd9Sstevel@tonic-gate 	 * We set fpu_en before calling setfpregs() in order to
4967c478bd9Sstevel@tonic-gate 	 * retain the semantics of this operation from older
4977c478bd9Sstevel@tonic-gate 	 * versions of the system.  SunOS 5.4 and prior never
4987c478bd9Sstevel@tonic-gate 	 * queried fpu_en; they just set the registers.  The
4997c478bd9Sstevel@tonic-gate 	 * proper operation if fpu_en is zero is to disable
5007c478bd9Sstevel@tonic-gate 	 * floating point in the target process, but this can
5017c478bd9Sstevel@tonic-gate 	 * only change after a proper end-of-life period for
5027c478bd9Sstevel@tonic-gate 	 * the old semantics.
5037c478bd9Sstevel@tonic-gate 	 */
5047c478bd9Sstevel@tonic-gate 	pfp->pr_en = 1;
5057c478bd9Sstevel@tonic-gate 	/*
5067c478bd9Sstevel@tonic-gate 	 * This works only because prfpregset32_t is intentionally
5077c478bd9Sstevel@tonic-gate 	 * constructed to be identical to fpregset32_t, with additional
5087c478bd9Sstevel@tonic-gate 	 * space for the floating-point queue at the end.
5097c478bd9Sstevel@tonic-gate 	 */
5107c478bd9Sstevel@tonic-gate 	setfpregs32(lwp, (fpregset32_t *)pfp);
5117c478bd9Sstevel@tonic-gate }
5127c478bd9Sstevel@tonic-gate #endif	/* _SYSCALL32_IMPL */
5137c478bd9Sstevel@tonic-gate 
5147c478bd9Sstevel@tonic-gate /*
5157c478bd9Sstevel@tonic-gate  * Does the system support extra register state?
5167c478bd9Sstevel@tonic-gate  * In a kernel that supports both an _LP64 and an _ILP32 data model,
5177c478bd9Sstevel@tonic-gate  * the answer depends on the data model of the process.
5187c478bd9Sstevel@tonic-gate  * An _LP64 process does not have extra registers.
5197c478bd9Sstevel@tonic-gate  */
5207c478bd9Sstevel@tonic-gate int
5217c478bd9Sstevel@tonic-gate prhasx(proc_t *p)
5227c478bd9Sstevel@tonic-gate {
5237c478bd9Sstevel@tonic-gate 	extern int xregs_exists;
5247c478bd9Sstevel@tonic-gate 
5257c478bd9Sstevel@tonic-gate 	if (p->p_model == DATAMODEL_LP64)
5267c478bd9Sstevel@tonic-gate 		return (0);
5277c478bd9Sstevel@tonic-gate 	else
5287c478bd9Sstevel@tonic-gate 		return (xregs_exists);
5297c478bd9Sstevel@tonic-gate }
5307c478bd9Sstevel@tonic-gate 
5317c478bd9Sstevel@tonic-gate /*
5327c478bd9Sstevel@tonic-gate  * Get the size of the extra registers.
5337c478bd9Sstevel@tonic-gate  */
5347c478bd9Sstevel@tonic-gate int
5357c478bd9Sstevel@tonic-gate prgetprxregsize(proc_t *p)
5367c478bd9Sstevel@tonic-gate {
5377c478bd9Sstevel@tonic-gate 	return (xregs_getsize(p));
5387c478bd9Sstevel@tonic-gate }
5397c478bd9Sstevel@tonic-gate 
5407c478bd9Sstevel@tonic-gate /*
5417c478bd9Sstevel@tonic-gate  * Get extra registers.
5427c478bd9Sstevel@tonic-gate  */
5437c478bd9Sstevel@tonic-gate void
5447c478bd9Sstevel@tonic-gate prgetprxregs(klwp_t *lwp, caddr_t prx)
5457c478bd9Sstevel@tonic-gate {
5467c478bd9Sstevel@tonic-gate 	extern void xregs_get(struct _klwp *, caddr_t);
5477c478bd9Sstevel@tonic-gate 
5487c478bd9Sstevel@tonic-gate 	(void) xregs_get(lwp, prx);
5497c478bd9Sstevel@tonic-gate }
5507c478bd9Sstevel@tonic-gate 
5517c478bd9Sstevel@tonic-gate /*
5527c478bd9Sstevel@tonic-gate  * Set extra registers.
5537c478bd9Sstevel@tonic-gate  */
5547c478bd9Sstevel@tonic-gate void
5557c478bd9Sstevel@tonic-gate prsetprxregs(klwp_t *lwp, caddr_t prx)
5567c478bd9Sstevel@tonic-gate {
5577c478bd9Sstevel@tonic-gate 	extern void xregs_set(struct _klwp *, caddr_t);
5587c478bd9Sstevel@tonic-gate 
5597c478bd9Sstevel@tonic-gate 	(void) xregs_set(lwp, prx);
5607c478bd9Sstevel@tonic-gate }
5617c478bd9Sstevel@tonic-gate 
5627c478bd9Sstevel@tonic-gate /*
5637c478bd9Sstevel@tonic-gate  * Get the ancillary state registers.
5647c478bd9Sstevel@tonic-gate  */
5657c478bd9Sstevel@tonic-gate void
5667c478bd9Sstevel@tonic-gate prgetasregs(klwp_t *lwp, asrset_t asrset)
5677c478bd9Sstevel@tonic-gate {
5687c478bd9Sstevel@tonic-gate 	bzero(asrset, sizeof (asrset_t));
5697c478bd9Sstevel@tonic-gate 	getasrs(lwp, asrset);
5707c478bd9Sstevel@tonic-gate 	getfpasrs(lwp, asrset);
5717c478bd9Sstevel@tonic-gate }
5727c478bd9Sstevel@tonic-gate 
5737c478bd9Sstevel@tonic-gate /*
5747c478bd9Sstevel@tonic-gate  * Set the ancillary state registers.
5757c478bd9Sstevel@tonic-gate  */
5767c478bd9Sstevel@tonic-gate void
5777c478bd9Sstevel@tonic-gate prsetasregs(klwp_t *lwp, asrset_t asrset)
5787c478bd9Sstevel@tonic-gate {
5797c478bd9Sstevel@tonic-gate 	setasrs(lwp, asrset);
5807c478bd9Sstevel@tonic-gate 	setfpasrs(lwp, asrset);
5817c478bd9Sstevel@tonic-gate }
5827c478bd9Sstevel@tonic-gate 
5837c478bd9Sstevel@tonic-gate /*
5847c478bd9Sstevel@tonic-gate  * Return the base (lower limit) of the process stack.
5857c478bd9Sstevel@tonic-gate  */
5867c478bd9Sstevel@tonic-gate caddr_t
5877c478bd9Sstevel@tonic-gate prgetstackbase(proc_t *p)
5887c478bd9Sstevel@tonic-gate {
5897c478bd9Sstevel@tonic-gate 	return (p->p_usrstack - p->p_stksize);
5907c478bd9Sstevel@tonic-gate }
5917c478bd9Sstevel@tonic-gate 
5927c478bd9Sstevel@tonic-gate /*
5937c478bd9Sstevel@tonic-gate  * Return the "addr" field for pr_addr in prpsinfo_t.
5947c478bd9Sstevel@tonic-gate  * This is a vestige of the past, so whatever we return is OK.
5957c478bd9Sstevel@tonic-gate  */
5967c478bd9Sstevel@tonic-gate caddr_t
5977c478bd9Sstevel@tonic-gate prgetpsaddr(proc_t *p)
5987c478bd9Sstevel@tonic-gate {
5997c478bd9Sstevel@tonic-gate 	return ((caddr_t)p);
6007c478bd9Sstevel@tonic-gate }
6017c478bd9Sstevel@tonic-gate 
6027c478bd9Sstevel@tonic-gate /*
6037c478bd9Sstevel@tonic-gate  * Arrange to single-step the lwp.
6047c478bd9Sstevel@tonic-gate  */
6057c478bd9Sstevel@tonic-gate void
6067c478bd9Sstevel@tonic-gate prstep(klwp_t *lwp, int watchstep)
6077c478bd9Sstevel@tonic-gate {
6087c478bd9Sstevel@tonic-gate 	ASSERT(MUTEX_NOT_HELD(&lwptoproc(lwp)->p_lock));
6097c478bd9Sstevel@tonic-gate 
6107c478bd9Sstevel@tonic-gate 	lwp->lwp_pcb.pcb_step = STEP_REQUESTED;
6117c478bd9Sstevel@tonic-gate 	lwp->lwp_pcb.pcb_tracepc = NULL;
6127c478bd9Sstevel@tonic-gate 	if (watchstep)
6137c478bd9Sstevel@tonic-gate 		lwp->lwp_pcb.pcb_flags |= WATCH_STEP;
6147c478bd9Sstevel@tonic-gate 	else
6157c478bd9Sstevel@tonic-gate 		lwp->lwp_pcb.pcb_flags |= NORMAL_STEP;
6167c478bd9Sstevel@tonic-gate }
6177c478bd9Sstevel@tonic-gate 
6187c478bd9Sstevel@tonic-gate /*
6197c478bd9Sstevel@tonic-gate  * Undo prstep().
6207c478bd9Sstevel@tonic-gate  */
6217c478bd9Sstevel@tonic-gate void
6227c478bd9Sstevel@tonic-gate prnostep(klwp_t *lwp)
6237c478bd9Sstevel@tonic-gate {
6247c478bd9Sstevel@tonic-gate 	ASSERT(ttolwp(curthread) == lwp ||
6257c478bd9Sstevel@tonic-gate 	    MUTEX_NOT_HELD(&lwptoproc(lwp)->p_lock));
6267c478bd9Sstevel@tonic-gate 
6277c478bd9Sstevel@tonic-gate 	lwp->lwp_pcb.pcb_step = STEP_NONE;
6287c478bd9Sstevel@tonic-gate 	lwp->lwp_pcb.pcb_tracepc = NULL;
6297c478bd9Sstevel@tonic-gate 	lwp->lwp_pcb.pcb_flags &= ~(NORMAL_STEP|WATCH_STEP);
6307c478bd9Sstevel@tonic-gate }
6317c478bd9Sstevel@tonic-gate 
6327c478bd9Sstevel@tonic-gate /*
6337c478bd9Sstevel@tonic-gate  * Return non-zero if a single-step is in effect.
6347c478bd9Sstevel@tonic-gate  */
6357c478bd9Sstevel@tonic-gate int
6367c478bd9Sstevel@tonic-gate prisstep(klwp_t *lwp)
6377c478bd9Sstevel@tonic-gate {
6387c478bd9Sstevel@tonic-gate 	ASSERT(MUTEX_NOT_HELD(&lwptoproc(lwp)->p_lock));
6397c478bd9Sstevel@tonic-gate 
6407c478bd9Sstevel@tonic-gate 	return (lwp->lwp_pcb.pcb_step != STEP_NONE);
6417c478bd9Sstevel@tonic-gate }
6427c478bd9Sstevel@tonic-gate 
6437c478bd9Sstevel@tonic-gate /*
6447c478bd9Sstevel@tonic-gate  * Set the PC to the specified virtual address.
6457c478bd9Sstevel@tonic-gate  */
6467c478bd9Sstevel@tonic-gate void
6477c478bd9Sstevel@tonic-gate prsvaddr(klwp_t *lwp, caddr_t vaddr)
6487c478bd9Sstevel@tonic-gate {
6497c478bd9Sstevel@tonic-gate 	struct regs *r = lwptoregs(lwp);
6507c478bd9Sstevel@tonic-gate 
6517c478bd9Sstevel@tonic-gate 	ASSERT(MUTEX_NOT_HELD(&lwptoproc(lwp)->p_lock));
6527c478bd9Sstevel@tonic-gate 
6537c478bd9Sstevel@tonic-gate 	/*
6547c478bd9Sstevel@tonic-gate 	 * pc and npc must be word aligned on sparc.
6557c478bd9Sstevel@tonic-gate 	 * We silently make it so to avoid a watchdog reset.
6567c478bd9Sstevel@tonic-gate 	 */
6577c478bd9Sstevel@tonic-gate 	r->r_pc = (uintptr_t)vaddr & ~03L;
6587c478bd9Sstevel@tonic-gate 	r->r_npc = r->r_pc + 4;
6597c478bd9Sstevel@tonic-gate }
6607c478bd9Sstevel@tonic-gate 
6617c478bd9Sstevel@tonic-gate /*
6627c478bd9Sstevel@tonic-gate  * Map address "addr" in address space "as" into a kernel virtual address.
6637c478bd9Sstevel@tonic-gate  * The memory is guaranteed to be resident and locked down.
6647c478bd9Sstevel@tonic-gate  */
6657c478bd9Sstevel@tonic-gate caddr_t
6667c478bd9Sstevel@tonic-gate prmapin(struct as *as, caddr_t addr, int writing)
6677c478bd9Sstevel@tonic-gate {
6687c478bd9Sstevel@tonic-gate 	page_t *pp;
6697c478bd9Sstevel@tonic-gate 	caddr_t kaddr;
6707c478bd9Sstevel@tonic-gate 	pfn_t pfnum;
6717c478bd9Sstevel@tonic-gate 
6727c478bd9Sstevel@tonic-gate 	/*
6737c478bd9Sstevel@tonic-gate 	 * XXX - Because of past mistakes, we have bits being returned
6747c478bd9Sstevel@tonic-gate 	 * by getpfnum that are actually the page type bits of the pte.
6757c478bd9Sstevel@tonic-gate 	 * When the object we are trying to map is a memory page with
6767c478bd9Sstevel@tonic-gate 	 * a page structure everything is ok and we can use the optimal
6777c478bd9Sstevel@tonic-gate 	 * method, ppmapin.  Otherwise, we have to do something special.
6787c478bd9Sstevel@tonic-gate 	 */
6797c478bd9Sstevel@tonic-gate 	pfnum = hat_getpfnum(as->a_hat, addr);
6807c478bd9Sstevel@tonic-gate 	if (pf_is_memory(pfnum)) {
6817c478bd9Sstevel@tonic-gate 		pp = page_numtopp_nolock(pfnum);
6827c478bd9Sstevel@tonic-gate 		if (pp != NULL) {
6837c478bd9Sstevel@tonic-gate 			ASSERT(PAGE_LOCKED(pp));
6847c478bd9Sstevel@tonic-gate 			kaddr = ppmapin(pp, writing ?
6857c478bd9Sstevel@tonic-gate 				(PROT_READ | PROT_WRITE) : PROT_READ,
6867c478bd9Sstevel@tonic-gate 				(caddr_t)-1);
6877c478bd9Sstevel@tonic-gate 			return (kaddr + ((uintptr_t)addr & PAGEOFFSET));
6887c478bd9Sstevel@tonic-gate 		}
6897c478bd9Sstevel@tonic-gate 	}
6907c478bd9Sstevel@tonic-gate 
6917c478bd9Sstevel@tonic-gate 	/*
6927c478bd9Sstevel@tonic-gate 	 * Oh well, we didn't have a page struct for the object we were
6937c478bd9Sstevel@tonic-gate 	 * trying to map in; ppmapin doesn't handle devices, but allocating a
6947c478bd9Sstevel@tonic-gate 	 * heap address allows ppmapout to free virutal space when done.
6957c478bd9Sstevel@tonic-gate 	 */
6967c478bd9Sstevel@tonic-gate 	kaddr = vmem_alloc(heap_arena, PAGESIZE, VM_SLEEP);
6977c478bd9Sstevel@tonic-gate 
6987c478bd9Sstevel@tonic-gate 	hat_devload(kas.a_hat, kaddr, PAGESIZE, pfnum,
6997c478bd9Sstevel@tonic-gate 		writing ? (PROT_READ | PROT_WRITE) : PROT_READ, HAT_LOAD_LOCK);
7007c478bd9Sstevel@tonic-gate 
7017c478bd9Sstevel@tonic-gate 	return (kaddr + ((uintptr_t)addr & PAGEOFFSET));
7027c478bd9Sstevel@tonic-gate }
7037c478bd9Sstevel@tonic-gate 
7047c478bd9Sstevel@tonic-gate /*
7057c478bd9Sstevel@tonic-gate  * Unmap address "addr" in address space "as"; inverse of prmapin().
7067c478bd9Sstevel@tonic-gate  */
7077c478bd9Sstevel@tonic-gate /* ARGSUSED */
7087c478bd9Sstevel@tonic-gate void
7097c478bd9Sstevel@tonic-gate prmapout(struct as *as, caddr_t addr, caddr_t vaddr, int writing)
7107c478bd9Sstevel@tonic-gate {
7117c478bd9Sstevel@tonic-gate 	extern void ppmapout(caddr_t);
7127c478bd9Sstevel@tonic-gate 
7137c478bd9Sstevel@tonic-gate 	vaddr = (caddr_t)((uintptr_t)vaddr & PAGEMASK);
7147c478bd9Sstevel@tonic-gate 	ppmapout(vaddr);
7157c478bd9Sstevel@tonic-gate }
7167c478bd9Sstevel@tonic-gate 
7177c478bd9Sstevel@tonic-gate 
7187c478bd9Sstevel@tonic-gate #define	BAMASK22 0xffc00000	/* for masking out disp22 from ba,a */
7197c478bd9Sstevel@tonic-gate #define	BAA	0x30800000	/* ba,a without disp22 */
7207c478bd9Sstevel@tonic-gate #define	FBAA	0x31800000	/* fba,a without disp22 */
7217c478bd9Sstevel@tonic-gate #define	CBAA	0x31c00000	/* cba,a without disp22 */
7227c478bd9Sstevel@tonic-gate 
7237c478bd9Sstevel@tonic-gate #define	BAMASK19 0xfff80000	/* for masking out disp19 from ba,a %[ix]cc */
7247c478bd9Sstevel@tonic-gate #define	BAA_icc	0x30480000	/* ba,a %icc without disp19 */
7257c478bd9Sstevel@tonic-gate #define	BAA_xcc	0x30680000	/* ba,a %xcc without disp19 */
7267c478bd9Sstevel@tonic-gate 
7277c478bd9Sstevel@tonic-gate 
7287c478bd9Sstevel@tonic-gate /*
7297c478bd9Sstevel@tonic-gate  * Prepare to single-step the lwp if requested.
7307c478bd9Sstevel@tonic-gate  * This is called by the lwp itself just before returning to user level.
7317c478bd9Sstevel@tonic-gate  */
7327c478bd9Sstevel@tonic-gate void
7337c478bd9Sstevel@tonic-gate prdostep(void)
7347c478bd9Sstevel@tonic-gate {
7357c478bd9Sstevel@tonic-gate 	klwp_t *lwp = ttolwp(curthread);
7367c478bd9Sstevel@tonic-gate 	struct regs *r = lwptoregs(lwp);
7377c478bd9Sstevel@tonic-gate 	proc_t *p = lwptoproc(lwp);
7387c478bd9Sstevel@tonic-gate 	struct as *as = p->p_as;
7397c478bd9Sstevel@tonic-gate 	caddr_t pc;
7407c478bd9Sstevel@tonic-gate 	caddr_t npc;
7417c478bd9Sstevel@tonic-gate 
7427c478bd9Sstevel@tonic-gate 	ASSERT(lwp != NULL);
7437c478bd9Sstevel@tonic-gate 	ASSERT(r != NULL);
7447c478bd9Sstevel@tonic-gate 
7457c478bd9Sstevel@tonic-gate 	if (lwp->lwp_pcb.pcb_step == STEP_NONE ||
7467c478bd9Sstevel@tonic-gate 	    lwp->lwp_pcb.pcb_step == STEP_ACTIVE)
7477c478bd9Sstevel@tonic-gate 		return;
7487c478bd9Sstevel@tonic-gate 
7497c478bd9Sstevel@tonic-gate 	if (p->p_model == DATAMODEL_ILP32) {
750*75521904Sraf 		pc = (caddr_t)(uintptr_t)(caddr32_t)r->r_pc;
751*75521904Sraf 		npc = (caddr_t)(uintptr_t)(caddr32_t)r->r_npc;
7527c478bd9Sstevel@tonic-gate 	} else {
7537c478bd9Sstevel@tonic-gate 		pc = (caddr_t)r->r_pc;
7547c478bd9Sstevel@tonic-gate 		npc = (caddr_t)r->r_npc;
7557c478bd9Sstevel@tonic-gate 	}
7567c478bd9Sstevel@tonic-gate 
7577c478bd9Sstevel@tonic-gate 	if (lwp->lwp_pcb.pcb_step == STEP_WASACTIVE) {
7587c478bd9Sstevel@tonic-gate 		if (npc == (caddr_t)lwp->lwp_pcb.pcb_tracepc)
7597c478bd9Sstevel@tonic-gate 			r->r_npc = (greg_t)as->a_userlimit;
7607c478bd9Sstevel@tonic-gate 		else {
7617c478bd9Sstevel@tonic-gate 			lwp->lwp_pcb.pcb_tracepc = (void *)pc;
7627c478bd9Sstevel@tonic-gate 			r->r_pc = (greg_t)as->a_userlimit;
7637c478bd9Sstevel@tonic-gate 		}
7647c478bd9Sstevel@tonic-gate 	} else {
7657c478bd9Sstevel@tonic-gate 		/*
7667c478bd9Sstevel@tonic-gate 		 * Single-stepping on sparc is effected by setting nPC
7677c478bd9Sstevel@tonic-gate 		 * to an invalid address and expecting FLTBOUNDS to
7687c478bd9Sstevel@tonic-gate 		 * occur after the instruction at PC is executed.
7697c478bd9Sstevel@tonic-gate 		 * This is not the whole story, however; we must
7707c478bd9Sstevel@tonic-gate 		 * deal with branch-always instructions with the
7717c478bd9Sstevel@tonic-gate 		 * annul bit set as a special case here.
7727c478bd9Sstevel@tonic-gate 		 *
7737c478bd9Sstevel@tonic-gate 		 * fuword() returns -1 on error and we can't distinguish
7747c478bd9Sstevel@tonic-gate 		 * this from a legitimate instruction of all 1's.
7757c478bd9Sstevel@tonic-gate 		 * However 0xffffffff is not one of the branch-always
7767c478bd9Sstevel@tonic-gate 		 * instructions we are interested in.  No problem.
7777c478bd9Sstevel@tonic-gate 		 */
7787c478bd9Sstevel@tonic-gate 		int32_t instr;
7797c478bd9Sstevel@tonic-gate 		int32_t i;
7807c478bd9Sstevel@tonic-gate 
7817c478bd9Sstevel@tonic-gate 		if (fuword32_nowatch((void *)pc, (uint32_t *)&instr) != 0)
7827c478bd9Sstevel@tonic-gate 			instr = -1;
7837c478bd9Sstevel@tonic-gate 		if ((i = instr & BAMASK22) == BAA || i == FBAA || i == CBAA) {
7847c478bd9Sstevel@tonic-gate 			/*
7857c478bd9Sstevel@tonic-gate 			 * For ba,a and relatives, compute the
7867c478bd9Sstevel@tonic-gate 			 * new PC from the instruction.
7877c478bd9Sstevel@tonic-gate 			 */
7887c478bd9Sstevel@tonic-gate 			i = (instr << 10) >> 8;
7897c478bd9Sstevel@tonic-gate 			lwp->lwp_pcb.pcb_tracepc = (void *)(pc + i);
7907c478bd9Sstevel@tonic-gate 			r->r_pc = (greg_t)as->a_userlimit;
7917c478bd9Sstevel@tonic-gate 			r->r_npc = r->r_pc + 4;
7927c478bd9Sstevel@tonic-gate 		} else if ((i = instr & BAMASK19) == BAA_icc || i == BAA_xcc) {
7937c478bd9Sstevel@tonic-gate 			/*
7947c478bd9Sstevel@tonic-gate 			 * For ba,a %icc and ba,a %xcc, compute the
7957c478bd9Sstevel@tonic-gate 			 * new PC from the instruction.
7967c478bd9Sstevel@tonic-gate 			 */
7977c478bd9Sstevel@tonic-gate 			i = (instr << 13) >> 11;
7987c478bd9Sstevel@tonic-gate 			lwp->lwp_pcb.pcb_tracepc = (void *)(pc + i);
7997c478bd9Sstevel@tonic-gate 			r->r_pc = (greg_t)as->a_userlimit;
8007c478bd9Sstevel@tonic-gate 			r->r_npc = r->r_pc + 4;
8017c478bd9Sstevel@tonic-gate 		} else {
8027c478bd9Sstevel@tonic-gate 			lwp->lwp_pcb.pcb_tracepc = (void *)npc;
8037c478bd9Sstevel@tonic-gate 			r->r_npc = (greg_t)as->a_userlimit;
8047c478bd9Sstevel@tonic-gate 		}
8057c478bd9Sstevel@tonic-gate 	}
8067c478bd9Sstevel@tonic-gate 
8077c478bd9Sstevel@tonic-gate 	lwp->lwp_pcb.pcb_step = STEP_ACTIVE;
8087c478bd9Sstevel@tonic-gate }
8097c478bd9Sstevel@tonic-gate 
8107c478bd9Sstevel@tonic-gate /*
8117c478bd9Sstevel@tonic-gate  * Wrap up single stepping of the lwp.
8127c478bd9Sstevel@tonic-gate  * This is called by the lwp itself just after it has taken
8137c478bd9Sstevel@tonic-gate  * the FLTBOUNDS trap.  We fix up the PC and nPC to have their
8147c478bd9Sstevel@tonic-gate  * proper values after the step.  We return 1 to indicate that
8157c478bd9Sstevel@tonic-gate  * this fault really is the one we are expecting, else 0.
8167c478bd9Sstevel@tonic-gate  *
8177c478bd9Sstevel@tonic-gate  * This is also called from syscall() and stop() to reset PC
8187c478bd9Sstevel@tonic-gate  * and nPC to their proper values for debugger visibility.
8197c478bd9Sstevel@tonic-gate  */
8207c478bd9Sstevel@tonic-gate int
8217c478bd9Sstevel@tonic-gate prundostep(void)
8227c478bd9Sstevel@tonic-gate {
8237c478bd9Sstevel@tonic-gate 	klwp_t *lwp = ttolwp(curthread);
8247c478bd9Sstevel@tonic-gate 	proc_t *p = ttoproc(curthread);
8257c478bd9Sstevel@tonic-gate 	struct as *as = p->p_as;
8267c478bd9Sstevel@tonic-gate 	int rc = 0;
8277c478bd9Sstevel@tonic-gate 	caddr_t pc;
8287c478bd9Sstevel@tonic-gate 	caddr_t npc;
8297c478bd9Sstevel@tonic-gate 
8307c478bd9Sstevel@tonic-gate 	ASSERT(lwp != NULL);
8317c478bd9Sstevel@tonic-gate 
8327c478bd9Sstevel@tonic-gate 	if (lwp->lwp_pcb.pcb_step == STEP_ACTIVE) {
8337c478bd9Sstevel@tonic-gate 		struct regs *r = lwptoregs(lwp);
8347c478bd9Sstevel@tonic-gate 
8357c478bd9Sstevel@tonic-gate 		ASSERT(r != NULL);
8367c478bd9Sstevel@tonic-gate 
8377c478bd9Sstevel@tonic-gate 		if (p->p_model == DATAMODEL_ILP32) {
838*75521904Sraf 			pc = (caddr_t)(uintptr_t)(caddr32_t)r->r_pc;
839*75521904Sraf 			npc = (caddr_t)(uintptr_t)(caddr32_t)r->r_npc;
8407c478bd9Sstevel@tonic-gate 		} else {
8417c478bd9Sstevel@tonic-gate 			pc = (caddr_t)r->r_pc;
8427c478bd9Sstevel@tonic-gate 			npc = (caddr_t)r->r_npc;
8437c478bd9Sstevel@tonic-gate 		}
8447c478bd9Sstevel@tonic-gate 
8457c478bd9Sstevel@tonic-gate 		if (pc == (caddr_t)as->a_userlimit ||
8467c478bd9Sstevel@tonic-gate 		    pc == (caddr_t)as->a_userlimit + 4) {
8477c478bd9Sstevel@tonic-gate 			if (pc == (caddr_t)as->a_userlimit) {
8487c478bd9Sstevel@tonic-gate 				r->r_pc = (greg_t)lwp->lwp_pcb.pcb_tracepc;
8497c478bd9Sstevel@tonic-gate 				if (npc == (caddr_t)as->a_userlimit + 4)
8507c478bd9Sstevel@tonic-gate 					r->r_npc = r->r_pc + 4;
8517c478bd9Sstevel@tonic-gate 			} else {
8527c478bd9Sstevel@tonic-gate 				r->r_pc = (greg_t)lwp->lwp_pcb.pcb_tracepc + 4;
8537c478bd9Sstevel@tonic-gate 				r->r_npc = r->r_pc + 4;
8547c478bd9Sstevel@tonic-gate 			}
8557c478bd9Sstevel@tonic-gate 			rc = 1;
8567c478bd9Sstevel@tonic-gate 		} else {
8577c478bd9Sstevel@tonic-gate 			r->r_npc = (greg_t)lwp->lwp_pcb.pcb_tracepc;
8587c478bd9Sstevel@tonic-gate 		}
8597c478bd9Sstevel@tonic-gate 		lwp->lwp_pcb.pcb_step = STEP_WASACTIVE;
8607c478bd9Sstevel@tonic-gate 	}
8617c478bd9Sstevel@tonic-gate 
8627c478bd9Sstevel@tonic-gate 	return (rc);
8637c478bd9Sstevel@tonic-gate }
8647c478bd9Sstevel@tonic-gate 
8657c478bd9Sstevel@tonic-gate /*
8667c478bd9Sstevel@tonic-gate  * Make sure the lwp is in an orderly state
8677c478bd9Sstevel@tonic-gate  * for inspection by a debugger through /proc.
8687c478bd9Sstevel@tonic-gate  * Called from stop() and from syslwp_create().
8697c478bd9Sstevel@tonic-gate  */
8707c478bd9Sstevel@tonic-gate /* ARGSUSED */
8717c478bd9Sstevel@tonic-gate void
8727c478bd9Sstevel@tonic-gate prstop(int why, int what)
8737c478bd9Sstevel@tonic-gate {
8747c478bd9Sstevel@tonic-gate 	klwp_t *lwp = ttolwp(curthread);
8757c478bd9Sstevel@tonic-gate 	proc_t *p = lwptoproc(lwp);
8767c478bd9Sstevel@tonic-gate 	struct regs *r = lwptoregs(lwp);
8777c478bd9Sstevel@tonic-gate 	kfpu_t *pfp = lwptofpu(lwp);
8787c478bd9Sstevel@tonic-gate 	caddr_t sp;
8797c478bd9Sstevel@tonic-gate 	caddr_t pc;
8807c478bd9Sstevel@tonic-gate 	int watched;
8817c478bd9Sstevel@tonic-gate 	extern void fp_prsave(kfpu_t *);
8827c478bd9Sstevel@tonic-gate 
8837c478bd9Sstevel@tonic-gate 	/*
88416ade92dScwb 	 * Make sure we don't deadlock on a recursive call to prstop().
88516ade92dScwb 	 * stop() tests the lwp_nostop_r and lwp_nostop flags.
8867c478bd9Sstevel@tonic-gate 	 */
88716ade92dScwb 	lwp->lwp_nostop_r++;
88816ade92dScwb 	lwp->lwp_nostop++;
8897c478bd9Sstevel@tonic-gate 	(void) flush_user_windows_to_stack(NULL);
8907c478bd9Sstevel@tonic-gate 	if (lwp->lwp_pcb.pcb_step != STEP_NONE)
8917c478bd9Sstevel@tonic-gate 		(void) prundostep();
8927c478bd9Sstevel@tonic-gate 
8937c478bd9Sstevel@tonic-gate 	if (lwp->lwp_pcb.pcb_xregstat == XREGNONE) {
8947c478bd9Sstevel@tonic-gate 		/*
8957c478bd9Sstevel@tonic-gate 		 * Attempt to fetch the last register window from the stack.
8967c478bd9Sstevel@tonic-gate 		 * If that fails, look for it in the pcb.
8977c478bd9Sstevel@tonic-gate 		 * If that fails, give up.
8987c478bd9Sstevel@tonic-gate 		 */
8997c478bd9Sstevel@tonic-gate 		struct machpcb *mpcb = lwptompcb(lwp);
9007c478bd9Sstevel@tonic-gate 		struct rwindow32 rwindow32;
9017c478bd9Sstevel@tonic-gate 		size_t rw_size;
9027c478bd9Sstevel@tonic-gate 		caddr_t rwp;
9037c478bd9Sstevel@tonic-gate 		int is64;
9047c478bd9Sstevel@tonic-gate 
9057c478bd9Sstevel@tonic-gate 		if (mpcb->mpcb_wstate == WSTATE_USER32) {
9067c478bd9Sstevel@tonic-gate 			rw_size = sizeof (struct rwindow32);
907*75521904Sraf 			sp = (caddr_t)(uintptr_t)(caddr32_t)r->r_sp;
9087c478bd9Sstevel@tonic-gate 			rwp = sp;
9097c478bd9Sstevel@tonic-gate 			is64 = 0;
9107c478bd9Sstevel@tonic-gate 		} else {
9117c478bd9Sstevel@tonic-gate 			rw_size = sizeof (struct rwindow);
9127c478bd9Sstevel@tonic-gate 			sp = (caddr_t)r->r_sp;
9137c478bd9Sstevel@tonic-gate 			rwp = sp + V9BIAS64;
9147c478bd9Sstevel@tonic-gate 			is64 = 1;
9157c478bd9Sstevel@tonic-gate 		}
9167c478bd9Sstevel@tonic-gate 
9177c478bd9Sstevel@tonic-gate 		watched = watch_disable_addr(rwp, rw_size, S_READ);
9187c478bd9Sstevel@tonic-gate 		if (is64 &&
9197c478bd9Sstevel@tonic-gate 		    copyin(rwp, &lwp->lwp_pcb.pcb_xregs, rw_size) == 0)
9207c478bd9Sstevel@tonic-gate 			lwp->lwp_pcb.pcb_xregstat = XREGPRESENT;
9217c478bd9Sstevel@tonic-gate 		else if (!is64 &&
9227c478bd9Sstevel@tonic-gate 		    copyin(rwp, &rwindow32, rw_size) == 0) {
9237c478bd9Sstevel@tonic-gate 			rwindow_32ton(&rwindow32, &lwp->lwp_pcb.pcb_xregs);
9247c478bd9Sstevel@tonic-gate 			lwp->lwp_pcb.pcb_xregstat = XREGPRESENT;
9257c478bd9Sstevel@tonic-gate 		} else {
9267c478bd9Sstevel@tonic-gate 			int i;
9277c478bd9Sstevel@tonic-gate 
9287c478bd9Sstevel@tonic-gate 			for (i = 0; i < mpcb->mpcb_wbcnt; i++) {
9297c478bd9Sstevel@tonic-gate 				if (sp == mpcb->mpcb_spbuf[i]) {
9307c478bd9Sstevel@tonic-gate 					if (is64) {
9317c478bd9Sstevel@tonic-gate 						bcopy(mpcb->mpcb_wbuf +
9327c478bd9Sstevel@tonic-gate 						    (i * rw_size),
9337c478bd9Sstevel@tonic-gate 						    &lwp->lwp_pcb.pcb_xregs,
9347c478bd9Sstevel@tonic-gate 						    rw_size);
9357c478bd9Sstevel@tonic-gate 					} else {
9367c478bd9Sstevel@tonic-gate 						struct rwindow32 *rw32 =
9377c478bd9Sstevel@tonic-gate 						    (struct rwindow32 *)
9387c478bd9Sstevel@tonic-gate 						    (mpcb->mpcb_wbuf +
9397c478bd9Sstevel@tonic-gate 						    (i * rw_size));
9407c478bd9Sstevel@tonic-gate 						rwindow_32ton(rw32,
9417c478bd9Sstevel@tonic-gate 						    &lwp->lwp_pcb.pcb_xregs);
9427c478bd9Sstevel@tonic-gate 					}
9437c478bd9Sstevel@tonic-gate 					lwp->lwp_pcb.pcb_xregstat = XREGPRESENT;
9447c478bd9Sstevel@tonic-gate 					break;
9457c478bd9Sstevel@tonic-gate 				}
9467c478bd9Sstevel@tonic-gate 			}
9477c478bd9Sstevel@tonic-gate 		}
9487c478bd9Sstevel@tonic-gate 		if (watched)
9497c478bd9Sstevel@tonic-gate 			watch_enable_addr(rwp, rw_size, S_READ);
9507c478bd9Sstevel@tonic-gate 	}
9517c478bd9Sstevel@tonic-gate 
9527c478bd9Sstevel@tonic-gate 	/*
9537c478bd9Sstevel@tonic-gate 	 * Make sure the floating point state is saved.
9547c478bd9Sstevel@tonic-gate 	 */
9557c478bd9Sstevel@tonic-gate 	fp_prsave(pfp);
9567c478bd9Sstevel@tonic-gate 
9577c478bd9Sstevel@tonic-gate 	if (p->p_model == DATAMODEL_ILP32)
958*75521904Sraf 		pc = (caddr_t)(uintptr_t)(caddr32_t)r->r_pc;
9597c478bd9Sstevel@tonic-gate 	else
9607c478bd9Sstevel@tonic-gate 		pc = (caddr_t)r->r_pc;
9617c478bd9Sstevel@tonic-gate 
9627c478bd9Sstevel@tonic-gate 	if (copyin_nowatch(pc, &lwp->lwp_pcb.pcb_instr,
9637c478bd9Sstevel@tonic-gate 	    sizeof (lwp->lwp_pcb.pcb_instr)) == 0)
9647c478bd9Sstevel@tonic-gate 		lwp->lwp_pcb.pcb_flags |= INSTR_VALID;
9657c478bd9Sstevel@tonic-gate 	else {
9667c478bd9Sstevel@tonic-gate 		lwp->lwp_pcb.pcb_flags &= ~INSTR_VALID;
9677c478bd9Sstevel@tonic-gate 		lwp->lwp_pcb.pcb_instr = 0;
9687c478bd9Sstevel@tonic-gate 	}
9697c478bd9Sstevel@tonic-gate 
9707c478bd9Sstevel@tonic-gate 	(void) save_syscall_args();
97116ade92dScwb 	lwp->lwp_nostop--;
97216ade92dScwb 	lwp->lwp_nostop_r--;
9737c478bd9Sstevel@tonic-gate }
9747c478bd9Sstevel@tonic-gate 
9757c478bd9Sstevel@tonic-gate /*
9767c478bd9Sstevel@tonic-gate  * Fetch the user-level instruction on which the lwp is stopped.
9777c478bd9Sstevel@tonic-gate  * It was saved by the lwp itself, in prstop().
9787c478bd9Sstevel@tonic-gate  * Return non-zero if the instruction is valid.
9797c478bd9Sstevel@tonic-gate  */
9807c478bd9Sstevel@tonic-gate int
9817c478bd9Sstevel@tonic-gate prfetchinstr(klwp_t *lwp, ulong_t *ip)
9827c478bd9Sstevel@tonic-gate {
9837c478bd9Sstevel@tonic-gate 	*ip = (ulong_t)(instr_t)lwp->lwp_pcb.pcb_instr;
9847c478bd9Sstevel@tonic-gate 	return (lwp->lwp_pcb.pcb_flags & INSTR_VALID);
9857c478bd9Sstevel@tonic-gate }
9867c478bd9Sstevel@tonic-gate 
9877c478bd9Sstevel@tonic-gate int
9887c478bd9Sstevel@tonic-gate prnwindows(klwp_t *lwp)
9897c478bd9Sstevel@tonic-gate {
9907c478bd9Sstevel@tonic-gate 	struct machpcb *mpcb = lwptompcb(lwp);
9917c478bd9Sstevel@tonic-gate 
9927c478bd9Sstevel@tonic-gate 	return (mpcb->mpcb_wbcnt);
9937c478bd9Sstevel@tonic-gate }
9947c478bd9Sstevel@tonic-gate 
9957c478bd9Sstevel@tonic-gate void
9967c478bd9Sstevel@tonic-gate prgetwindows(klwp_t *lwp, gwindows_t *gwp)
9977c478bd9Sstevel@tonic-gate {
9987c478bd9Sstevel@tonic-gate 	getgwins(lwp, gwp);
9997c478bd9Sstevel@tonic-gate }
10007c478bd9Sstevel@tonic-gate 
10017c478bd9Sstevel@tonic-gate #ifdef	_SYSCALL32_IMPL
10027c478bd9Sstevel@tonic-gate void
10037c478bd9Sstevel@tonic-gate prgetwindows32(klwp_t *lwp, gwindows32_t *gwp)
10047c478bd9Sstevel@tonic-gate {
10057c478bd9Sstevel@tonic-gate 	getgwins32(lwp, gwp);
10067c478bd9Sstevel@tonic-gate }
10077c478bd9Sstevel@tonic-gate #endif	/* _SYSCALL32_IMPL */
10087c478bd9Sstevel@tonic-gate 
10097c478bd9Sstevel@tonic-gate /*
10107c478bd9Sstevel@tonic-gate  * Called from trap() when a load or store instruction
10117c478bd9Sstevel@tonic-gate  * falls in a watched page but is not a watchpoint.
10127c478bd9Sstevel@tonic-gate  * We emulate the instruction in the kernel.
10137c478bd9Sstevel@tonic-gate  */
10147c478bd9Sstevel@tonic-gate int
10157c478bd9Sstevel@tonic-gate pr_watch_emul(struct regs *rp, caddr_t addr, enum seg_rw rw)
10167c478bd9Sstevel@tonic-gate {
10177c478bd9Sstevel@tonic-gate 	char *badaddr = (caddr_t)(-1);
10187c478bd9Sstevel@tonic-gate 	int res;
10197c478bd9Sstevel@tonic-gate 	int watched;
10207c478bd9Sstevel@tonic-gate 
10217c478bd9Sstevel@tonic-gate 	/* prevent recursive calls to pr_watch_emul() */
10227c478bd9Sstevel@tonic-gate 	ASSERT(!(curthread->t_flag & T_WATCHPT));
10237c478bd9Sstevel@tonic-gate 	curthread->t_flag |= T_WATCHPT;
10247c478bd9Sstevel@tonic-gate 
10257c478bd9Sstevel@tonic-gate 	watched = watch_disable_addr(addr, 16, rw);
10267c478bd9Sstevel@tonic-gate 	res = do_unaligned(rp, &badaddr);
10277c478bd9Sstevel@tonic-gate 	if (watched)
10287c478bd9Sstevel@tonic-gate 		watch_enable_addr(addr, 16, rw);
10297c478bd9Sstevel@tonic-gate 
10307c478bd9Sstevel@tonic-gate 	curthread->t_flag &= ~T_WATCHPT;
10317c478bd9Sstevel@tonic-gate 	if (res == SIMU_SUCCESS) {
10327c478bd9Sstevel@tonic-gate 		rp->r_pc = rp->r_npc;
10337c478bd9Sstevel@tonic-gate 		rp->r_npc += 4;
10347c478bd9Sstevel@tonic-gate 		return (1);
10357c478bd9Sstevel@tonic-gate 	}
10367c478bd9Sstevel@tonic-gate 	return (0);
10377c478bd9Sstevel@tonic-gate }
1038