xref: /titanic_51/usr/src/cmd/mdb/sparc/kmdb/kaif.c (revision 186d582bd9dbcd38e0aeea49036d47d3426a3536)
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
5a35baf17Shyw  * Common Development and Distribution License (the "License").
6a35baf17Shyw  * You may not use this file except in compliance with the License.
77c478bd9Sstevel@tonic-gate  *
87c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
97c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
107c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
117c478bd9Sstevel@tonic-gate  * and limitations under the License.
127c478bd9Sstevel@tonic-gate  *
137c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
147c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
157c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
167c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
177c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
187c478bd9Sstevel@tonic-gate  *
197c478bd9Sstevel@tonic-gate  * CDDL HEADER END
207c478bd9Sstevel@tonic-gate  */
21*186d582bSSurya Prakki 
227c478bd9Sstevel@tonic-gate /*
23*186d582bSSurya Prakki  * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
247c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
257c478bd9Sstevel@tonic-gate  */
267c478bd9Sstevel@tonic-gate 
277c478bd9Sstevel@tonic-gate /*
287c478bd9Sstevel@tonic-gate  * The debugger/PROM interface
297c478bd9Sstevel@tonic-gate  */
307c478bd9Sstevel@tonic-gate 
317c478bd9Sstevel@tonic-gate #include <sys/types.h>
327c478bd9Sstevel@tonic-gate #include <sys/mmu.h>
337c478bd9Sstevel@tonic-gate 
347c478bd9Sstevel@tonic-gate #ifndef	sun4v
357c478bd9Sstevel@tonic-gate #include <sys/spitregs.h>
367c478bd9Sstevel@tonic-gate #endif	/* sun4v */
377c478bd9Sstevel@tonic-gate 
387c478bd9Sstevel@tonic-gate #include <sys/machasi.h>
397c478bd9Sstevel@tonic-gate #include <sys/machtrap.h>
407c478bd9Sstevel@tonic-gate #include <sys/trap.h>
417c478bd9Sstevel@tonic-gate #include <sys/privregs.h>
427c478bd9Sstevel@tonic-gate 
437c478bd9Sstevel@tonic-gate #include <kmdb/kaif.h>
447c478bd9Sstevel@tonic-gate #include <kmdb/kaif_regs.h>
457c478bd9Sstevel@tonic-gate #include <kmdb/kmdb_asmutil.h>
467c478bd9Sstevel@tonic-gate #include <kmdb/kmdb_kdi.h>
477c478bd9Sstevel@tonic-gate #include <kmdb/kmdb_promif_isadep.h>
487c478bd9Sstevel@tonic-gate #include <kmdb/kmdb_dpi_impl.h>
497c478bd9Sstevel@tonic-gate #include <mdb/mdb_debug.h>
507c478bd9Sstevel@tonic-gate #include <mdb/mdb_err.h>
517c478bd9Sstevel@tonic-gate #include <mdb/mdb_modapi.h>
527c478bd9Sstevel@tonic-gate #include <mdb/mdb_nv.h>
537c478bd9Sstevel@tonic-gate #include <mdb/mdb_kreg_impl.h>
547c478bd9Sstevel@tonic-gate #include <mdb/mdb_v9util.h>
557c478bd9Sstevel@tonic-gate #include <mdb/mdb.h>
567c478bd9Sstevel@tonic-gate 
577c478bd9Sstevel@tonic-gate #define	KAIF_PREGNO_PSTATE	0x6		/* %pstate is priv reg 6 */
587c478bd9Sstevel@tonic-gate #define	KAIF_BRKPT_INSTR	0x91d0207e	/* ta 0x7e */
597c478bd9Sstevel@tonic-gate 
607c478bd9Sstevel@tonic-gate 
617c478bd9Sstevel@tonic-gate #define	OP(x)		((x) >> 30)
627c478bd9Sstevel@tonic-gate #define	OP2(x)		(((x) >> 22) & 0x07)
637c478bd9Sstevel@tonic-gate #define	OP3(x)		(((x) >> 19) & 0x3f)
647c478bd9Sstevel@tonic-gate #define	COND(x)		(((x) >> 25) & 0x0f)
657c478bd9Sstevel@tonic-gate #define	RD(x)		(((x) >> 25) & 0x1f)
667c478bd9Sstevel@tonic-gate #define	RS1(x)		(((x) >> 14) & 0x1f)
677c478bd9Sstevel@tonic-gate #define	RS2(x)		((x) & 0x1f)
687c478bd9Sstevel@tonic-gate 
697c478bd9Sstevel@tonic-gate #define	OP_BRANCH	0x0
707c478bd9Sstevel@tonic-gate #define	OP_ARITH	0x2
717c478bd9Sstevel@tonic-gate 
727c478bd9Sstevel@tonic-gate #define	OP2_BPcc	0x1
737c478bd9Sstevel@tonic-gate #define	OP2_Bicc	0x2
747c478bd9Sstevel@tonic-gate #define	OP2_BPr		0x3
757c478bd9Sstevel@tonic-gate #define	OP2_FBPfcc	0x5
767c478bd9Sstevel@tonic-gate #define	OP2_FBfcc	0x6
777c478bd9Sstevel@tonic-gate 
787c478bd9Sstevel@tonic-gate #define	OP3_RDPR	0x2a
797c478bd9Sstevel@tonic-gate #define	OP3_WRPR	0x32
807c478bd9Sstevel@tonic-gate 
817c478bd9Sstevel@tonic-gate #define	A(x)		(((x) >> 29) & 0x01)
827c478bd9Sstevel@tonic-gate #define	I(x)		(((x) >> 13) & 0x01)
837c478bd9Sstevel@tonic-gate #define	DISP16(x)	((((x) >> 6) & 0xc000) | ((x) & 0x3fff))
847c478bd9Sstevel@tonic-gate #define	DISP22(x)	((x) & 0x3fffff)
857c478bd9Sstevel@tonic-gate #define	DISP19(x)	((x) & 0x7ffff)
867c478bd9Sstevel@tonic-gate #define	SIMM13(x)	((x) & 0x1fff)
877c478bd9Sstevel@tonic-gate 
887c478bd9Sstevel@tonic-gate static uint64_t		kaif_vwapt_addr;
897c478bd9Sstevel@tonic-gate static uint64_t		kaif_pwapt_addr;
907c478bd9Sstevel@tonic-gate 
917c478bd9Sstevel@tonic-gate #ifndef	sun4v
927c478bd9Sstevel@tonic-gate static uint64_t		kaif_lsuctl;
937c478bd9Sstevel@tonic-gate #endif	/* sun4v */
947c478bd9Sstevel@tonic-gate 
957c478bd9Sstevel@tonic-gate kaif_cpusave_t		*kaif_cpusave;
967c478bd9Sstevel@tonic-gate int			kaif_ncpusave;
977c478bd9Sstevel@tonic-gate caddr_t			kaif_dseg;
987c478bd9Sstevel@tonic-gate caddr_t			kaif_dseg_lim;
997c478bd9Sstevel@tonic-gate caddr_t			kaif_tba;		/* table currently in use */
1007c478bd9Sstevel@tonic-gate caddr_t			kaif_tba_obp;		/* obp's trap table */
1017c478bd9Sstevel@tonic-gate caddr_t			kaif_tba_native;	/* our table; needs khat */
1027c478bd9Sstevel@tonic-gate #ifdef	sun4v
1037c478bd9Sstevel@tonic-gate caddr_t			kaif_tba_kernel;	/* kernel's trap table */
1047c478bd9Sstevel@tonic-gate #endif	/* sun4v */
1057c478bd9Sstevel@tonic-gate size_t			kaif_tba_native_sz;
1067c478bd9Sstevel@tonic-gate int			*kaif_promexitarmp;
1077c478bd9Sstevel@tonic-gate int			kaif_trap_switch;
1087c478bd9Sstevel@tonic-gate 
1097c478bd9Sstevel@tonic-gate void (*kaif_modchg_cb)(struct modctl *, int);
1107c478bd9Sstevel@tonic-gate void (*kaif_ktrap_install)(int, void (*)(void));
1117c478bd9Sstevel@tonic-gate void (*kaif_ktrap_restore)(void);
1127c478bd9Sstevel@tonic-gate 
1137c478bd9Sstevel@tonic-gate static int
1147c478bd9Sstevel@tonic-gate kaif_get_master_cpuid(void)
1157c478bd9Sstevel@tonic-gate {
1167c478bd9Sstevel@tonic-gate 	return (kaif_master_cpuid);
1177c478bd9Sstevel@tonic-gate }
1187c478bd9Sstevel@tonic-gate 
1197c478bd9Sstevel@tonic-gate /*ARGSUSED*/
1207c478bd9Sstevel@tonic-gate static int
1217c478bd9Sstevel@tonic-gate kaif_get_nwin(int cpuid)
1227c478bd9Sstevel@tonic-gate {
1237c478bd9Sstevel@tonic-gate 	return (get_nwin());
1247c478bd9Sstevel@tonic-gate }
1257c478bd9Sstevel@tonic-gate 
126acbc304dSjohnlev static kaif_cpusave_t *
127acbc304dSjohnlev kaif_cpuid2save(int cpuid)
128acbc304dSjohnlev {
129acbc304dSjohnlev 	kaif_cpusave_t *save;
130acbc304dSjohnlev 
131acbc304dSjohnlev 	if (cpuid == DPI_MASTER_CPUID)
132acbc304dSjohnlev 		return (&kaif_cpusave[kaif_master_cpuid]);
133acbc304dSjohnlev 
134acbc304dSjohnlev 	if (cpuid < 0 || cpuid >= kaif_ncpusave) {
135acbc304dSjohnlev 		(void) set_errno(EINVAL);
136acbc304dSjohnlev 		return (NULL);
137acbc304dSjohnlev 	}
138acbc304dSjohnlev 
139acbc304dSjohnlev 	save = &kaif_cpusave[cpuid];
140acbc304dSjohnlev 
141acbc304dSjohnlev 	if (save->krs_cpu_state != KAIF_CPU_STATE_MASTER &&
142acbc304dSjohnlev 	    save->krs_cpu_state != KAIF_CPU_STATE_SLAVE) {
143acbc304dSjohnlev 		(void) set_errno(EINVAL);
144acbc304dSjohnlev 		return (NULL);
145acbc304dSjohnlev 	}
146acbc304dSjohnlev 
147acbc304dSjohnlev 	return (save);
148acbc304dSjohnlev }
149acbc304dSjohnlev 
1507c478bd9Sstevel@tonic-gate static int
1517c478bd9Sstevel@tonic-gate kaif_get_cpu_state(int cpuid)
1527c478bd9Sstevel@tonic-gate {
153acbc304dSjohnlev 	kaif_cpusave_t *save;
1547c478bd9Sstevel@tonic-gate 
155acbc304dSjohnlev 	if ((save = kaif_cpuid2save(cpuid)) == NULL)
156acbc304dSjohnlev 		return (-1); /* errno is set for us */
1577c478bd9Sstevel@tonic-gate 
158acbc304dSjohnlev 	switch (save->krs_cpu_state) {
1597c478bd9Sstevel@tonic-gate 	case KAIF_CPU_STATE_MASTER:
1607c478bd9Sstevel@tonic-gate 		return (DPI_CPU_STATE_MASTER);
1617c478bd9Sstevel@tonic-gate 	case KAIF_CPU_STATE_SLAVE:
1627c478bd9Sstevel@tonic-gate 		return (DPI_CPU_STATE_SLAVE);
1637c478bd9Sstevel@tonic-gate 	default:
1647c478bd9Sstevel@tonic-gate 		return (set_errno(EINVAL));
1657c478bd9Sstevel@tonic-gate 	}
1667c478bd9Sstevel@tonic-gate }
1677c478bd9Sstevel@tonic-gate 
1687c478bd9Sstevel@tonic-gate static const mdb_tgt_gregset_t *
1697c478bd9Sstevel@tonic-gate kaif_get_gregs(int cpuid)
1707c478bd9Sstevel@tonic-gate {
171acbc304dSjohnlev 	kaif_cpusave_t *save;
1727c478bd9Sstevel@tonic-gate 	mdb_tgt_gregset_t *gregs;
1737c478bd9Sstevel@tonic-gate 	int wp, i;
1747c478bd9Sstevel@tonic-gate 
175acbc304dSjohnlev 	if ((save = kaif_cpuid2save(cpuid)) == NULL)
176acbc304dSjohnlev 		return (NULL); /* errno is set for us */
1777c478bd9Sstevel@tonic-gate 
178acbc304dSjohnlev 	gregs = &save->krs_gregs;
1797c478bd9Sstevel@tonic-gate 
1807c478bd9Sstevel@tonic-gate 	/*
1817c478bd9Sstevel@tonic-gate 	 * The DPI startup routine populates the register window portions of
1827c478bd9Sstevel@tonic-gate 	 * the kaif_cpusave_t.  We copy the current set of ins, outs, and
1837c478bd9Sstevel@tonic-gate 	 * locals to the gregs.  We also extract %pstate from %tstate.
1847c478bd9Sstevel@tonic-gate 	 */
1857c478bd9Sstevel@tonic-gate 	wp = gregs->kregs[KREG_CWP];
1867c478bd9Sstevel@tonic-gate 	for (i = 0; i < 8; i++) {
187acbc304dSjohnlev 		gregs->kregs[KREG_L0 + i] = save->krs_rwins[wp].rw_local[i];
188acbc304dSjohnlev 		gregs->kregs[KREG_I0 + i] = save->krs_rwins[wp].rw_in[i];
1897c478bd9Sstevel@tonic-gate 	}
1907c478bd9Sstevel@tonic-gate 
191acbc304dSjohnlev 	gregs->kregs[KREG_PSTATE] = KREG_TSTATE_PSTATE(save->krs_tstate);
1927c478bd9Sstevel@tonic-gate 
1937c478bd9Sstevel@tonic-gate 	if (++wp == kaif_get_nwin(cpuid))
1947c478bd9Sstevel@tonic-gate 		wp = 0;
1957c478bd9Sstevel@tonic-gate 
1967c478bd9Sstevel@tonic-gate 	for (i = 0; i < 8; i++)
197acbc304dSjohnlev 		gregs->kregs[KREG_O0 + i] = save->krs_rwins[wp].rw_in[i];
1987c478bd9Sstevel@tonic-gate 
1997c478bd9Sstevel@tonic-gate 	return (gregs);
2007c478bd9Sstevel@tonic-gate }
2017c478bd9Sstevel@tonic-gate 
2027c478bd9Sstevel@tonic-gate static kreg_t *
203acbc304dSjohnlev kaif_find_regp(kaif_cpusave_t *save, const char *regname)
2047c478bd9Sstevel@tonic-gate {
2057c478bd9Sstevel@tonic-gate 	mdb_tgt_gregset_t *gregs;
2067c478bd9Sstevel@tonic-gate 	int nwin, i;
207acbc304dSjohnlev 	int win;
2087c478bd9Sstevel@tonic-gate 
209acbc304dSjohnlev 	nwin = kaif_get_nwin(DPI_MASTER_CPUID);
2107c478bd9Sstevel@tonic-gate 
211acbc304dSjohnlev 	gregs = &save->krs_gregs;
2127c478bd9Sstevel@tonic-gate 
2137c478bd9Sstevel@tonic-gate 	win = gregs->kregs[KREG_CWP];
2147c478bd9Sstevel@tonic-gate 
2157c478bd9Sstevel@tonic-gate 	if (strcmp(regname, "sp") == 0)
2167c478bd9Sstevel@tonic-gate 		regname = "o6";
2177c478bd9Sstevel@tonic-gate 	else if (strcmp(regname, "fp") == 0)
2187c478bd9Sstevel@tonic-gate 		regname = "i6";
2197c478bd9Sstevel@tonic-gate 
2207c478bd9Sstevel@tonic-gate 	if (strlen(regname) == 2 && regname[1] >= '0' && regname[1] <= '7') {
2217c478bd9Sstevel@tonic-gate 		int idx = regname[1] - '0';
2227c478bd9Sstevel@tonic-gate 
2237c478bd9Sstevel@tonic-gate 		switch (regname[0]) {
2247c478bd9Sstevel@tonic-gate 		case 'o':
2257c478bd9Sstevel@tonic-gate 			if (++win == nwin)
2267c478bd9Sstevel@tonic-gate 				win = 0;
2277c478bd9Sstevel@tonic-gate 			/*FALLTHROUGH*/
2287c478bd9Sstevel@tonic-gate 		case 'i':
229acbc304dSjohnlev 			return ((kreg_t *)&save->krs_rwins[win].rw_in[idx]);
2307c478bd9Sstevel@tonic-gate 		case 'l':
231acbc304dSjohnlev 			return ((kreg_t *)&save->krs_rwins[win].rw_local[idx]);
2327c478bd9Sstevel@tonic-gate 		}
2337c478bd9Sstevel@tonic-gate 	}
2347c478bd9Sstevel@tonic-gate 
2357c478bd9Sstevel@tonic-gate 	for (i = 0; mdb_sparcv9_kregs[i].rd_name != NULL; i++) {
2367c478bd9Sstevel@tonic-gate 		const mdb_tgt_regdesc_t *rd = &mdb_sparcv9_kregs[i];
2377c478bd9Sstevel@tonic-gate 
2387c478bd9Sstevel@tonic-gate 		if (strcmp(rd->rd_name, regname) == 0)
2397c478bd9Sstevel@tonic-gate 			return (&gregs->kregs[rd->rd_num]);
2407c478bd9Sstevel@tonic-gate 	}
2417c478bd9Sstevel@tonic-gate 
2427c478bd9Sstevel@tonic-gate 	(void) set_errno(ENOENT);
2437c478bd9Sstevel@tonic-gate 	return (NULL);
2447c478bd9Sstevel@tonic-gate }
2457c478bd9Sstevel@tonic-gate 
2467c478bd9Sstevel@tonic-gate static int
247acbc304dSjohnlev kaif_get_register(const char *regname, kreg_t *valp)
2487c478bd9Sstevel@tonic-gate {
249acbc304dSjohnlev 	kaif_cpusave_t *save;
2507c478bd9Sstevel@tonic-gate 	kreg_t *regp;
2517c478bd9Sstevel@tonic-gate 
252acbc304dSjohnlev 	save = kaif_cpuid2save(DPI_MASTER_CPUID);
2537c478bd9Sstevel@tonic-gate 
2547c478bd9Sstevel@tonic-gate 	if (strcmp(regname, "pstate") == 0) {
255acbc304dSjohnlev 		*valp = KREG_TSTATE_PSTATE(save->krs_tstate);
2567c478bd9Sstevel@tonic-gate 		return (0);
2577c478bd9Sstevel@tonic-gate 	}
2587c478bd9Sstevel@tonic-gate 
259acbc304dSjohnlev 	if ((regp = kaif_find_regp(save, regname)) == NULL)
2607c478bd9Sstevel@tonic-gate 		return (-1);
2617c478bd9Sstevel@tonic-gate 
2627c478bd9Sstevel@tonic-gate 	*valp = *regp;
2637c478bd9Sstevel@tonic-gate 
2647c478bd9Sstevel@tonic-gate 	return (0);
2657c478bd9Sstevel@tonic-gate }
2667c478bd9Sstevel@tonic-gate 
2677c478bd9Sstevel@tonic-gate static int
268acbc304dSjohnlev kaif_set_register(const char *regname, kreg_t val)
2697c478bd9Sstevel@tonic-gate {
270acbc304dSjohnlev 	kaif_cpusave_t *save;
2717c478bd9Sstevel@tonic-gate 	kreg_t *regp;
2727c478bd9Sstevel@tonic-gate 
273acbc304dSjohnlev 	save = kaif_cpuid2save(DPI_MASTER_CPUID);
2747c478bd9Sstevel@tonic-gate 
2757c478bd9Sstevel@tonic-gate 	if (strcmp(regname, "g0") == 0) {
2767c478bd9Sstevel@tonic-gate 		return (0);
2777c478bd9Sstevel@tonic-gate 
2787c478bd9Sstevel@tonic-gate 	} else if (strcmp(regname, "pstate") == 0) {
279acbc304dSjohnlev 		save->krs_tstate &= ~KREG_TSTATE_PSTATE_MASK;
280acbc304dSjohnlev 		save->krs_tstate |= (val & KREG_PSTATE_MASK) <<
281acbc304dSjohnlev 		    KREG_TSTATE_PSTATE_SHIFT;
2827c478bd9Sstevel@tonic-gate 		return (0);
2837c478bd9Sstevel@tonic-gate 	}
2847c478bd9Sstevel@tonic-gate 
285acbc304dSjohnlev 	if ((regp = kaif_find_regp(save, regname)) == NULL)
2867c478bd9Sstevel@tonic-gate 		return (-1);
2877c478bd9Sstevel@tonic-gate 
2887c478bd9Sstevel@tonic-gate 	*regp = val;
2897c478bd9Sstevel@tonic-gate 
2907c478bd9Sstevel@tonic-gate 	return (0);
2917c478bd9Sstevel@tonic-gate }
2927c478bd9Sstevel@tonic-gate 
2937c478bd9Sstevel@tonic-gate static int
2947c478bd9Sstevel@tonic-gate kaif_brkpt_arm(uintptr_t addr, mdb_instr_t *instrp)
2957c478bd9Sstevel@tonic-gate {
2967c478bd9Sstevel@tonic-gate 	mdb_instr_t bkpt = KAIF_BRKPT_INSTR;
2977c478bd9Sstevel@tonic-gate 
2987c478bd9Sstevel@tonic-gate 	if (mdb_tgt_vread(mdb.m_target, instrp, sizeof (mdb_instr_t), addr) !=
2997c478bd9Sstevel@tonic-gate 	    sizeof (mdb_instr_t))
3007c478bd9Sstevel@tonic-gate 		return (-1); /* errno is set for us */
3017c478bd9Sstevel@tonic-gate 
3027c478bd9Sstevel@tonic-gate 	if (mdb_tgt_vwrite(mdb.m_target, &bkpt, sizeof (mdb_instr_t), addr) !=
3037c478bd9Sstevel@tonic-gate 	    sizeof (mdb_instr_t))
3047c478bd9Sstevel@tonic-gate 		return (-1); /* errno is set for us */
3057c478bd9Sstevel@tonic-gate 
3067c478bd9Sstevel@tonic-gate 	return (0);
3077c478bd9Sstevel@tonic-gate }
3087c478bd9Sstevel@tonic-gate 
3097c478bd9Sstevel@tonic-gate static int
3107c478bd9Sstevel@tonic-gate kaif_brkpt_disarm(uintptr_t addr, mdb_instr_t instrp)
3117c478bd9Sstevel@tonic-gate {
3127c478bd9Sstevel@tonic-gate 	if (mdb_tgt_vwrite(mdb.m_target, &instrp, sizeof (mdb_instr_t), addr) !=
3137c478bd9Sstevel@tonic-gate 	    sizeof (mdb_instr_t))
3147c478bd9Sstevel@tonic-gate 		return (-1); /* errno is set for us */
3157c478bd9Sstevel@tonic-gate 
3167c478bd9Sstevel@tonic-gate 	return (0);
3177c478bd9Sstevel@tonic-gate }
3187c478bd9Sstevel@tonic-gate 
3197c478bd9Sstevel@tonic-gate /*
3207c478bd9Sstevel@tonic-gate  * Calculate the watchpoint mask byte (VM or PM, as appropriate).  A 1 bit in
3217c478bd9Sstevel@tonic-gate  * the mask indicates that the corresponding byte in the watchpoint address
3227c478bd9Sstevel@tonic-gate  * should be used for activation comparison.
3237c478bd9Sstevel@tonic-gate  */
3247c478bd9Sstevel@tonic-gate /*
325acbc304dSjohnlev  * Sun4v doesn't have watchpoint regs
3267c478bd9Sstevel@tonic-gate  */
3277c478bd9Sstevel@tonic-gate #ifndef	sun4v
3287c478bd9Sstevel@tonic-gate static uchar_t
3297c478bd9Sstevel@tonic-gate kaif_wapt_calc_mask(size_t len)
3307c478bd9Sstevel@tonic-gate {
3317c478bd9Sstevel@tonic-gate 	int pow;
3327c478bd9Sstevel@tonic-gate 
3337c478bd9Sstevel@tonic-gate 	if (len == 8)
3347c478bd9Sstevel@tonic-gate 		return (0xff);
3357c478bd9Sstevel@tonic-gate 
336*186d582bSSurya Prakki 	for (pow = 0; len > 1; len /= 256, pow++)
337*186d582bSSurya Prakki 		;
3387c478bd9Sstevel@tonic-gate 
3397c478bd9Sstevel@tonic-gate 	return (~((1 << pow) - 1));
3407c478bd9Sstevel@tonic-gate }
3417c478bd9Sstevel@tonic-gate #endif
3427c478bd9Sstevel@tonic-gate 
3437c478bd9Sstevel@tonic-gate /*
3447c478bd9Sstevel@tonic-gate  * UltraSPARC processors have one physical and one virtual watchpoint.  These
3457c478bd9Sstevel@tonic-gate  * watchpoints are specified by setting the address in a register, and by
3467c478bd9Sstevel@tonic-gate  * setting a selector byte in another register to determine which bytes of the
3477c478bd9Sstevel@tonic-gate  * address are to be used for comparison.  For simplicity, we only support
3487c478bd9Sstevel@tonic-gate  * selector byte values whose bit patterns match the regexp "1+0*".  Watchpoint
3497c478bd9Sstevel@tonic-gate  * addresses must be 8-byte aligned on these chips, so a selector byte of 0xff
3507c478bd9Sstevel@tonic-gate  * indicates an 8-byte watchpoint.  Successive valid sizes are powers of 256,
3517c478bd9Sstevel@tonic-gate  * starting with 256.
3527c478bd9Sstevel@tonic-gate  */
3537c478bd9Sstevel@tonic-gate static int
3547c478bd9Sstevel@tonic-gate kaif_wapt_validate(kmdb_wapt_t *wp)
3557c478bd9Sstevel@tonic-gate {
3567c478bd9Sstevel@tonic-gate 	if (wp->wp_wflags & MDB_TGT_WA_X) {
3577c478bd9Sstevel@tonic-gate 		warn("execute watchpoints are not supported on this "
3587c478bd9Sstevel@tonic-gate 		    "platform\n");
3597c478bd9Sstevel@tonic-gate 		return (set_errno(EMDB_TGTNOTSUP));
3607c478bd9Sstevel@tonic-gate 	}
3617c478bd9Sstevel@tonic-gate 
3627c478bd9Sstevel@tonic-gate 	if (wp->wp_size % 0xff != 0 && wp->wp_size != 8) {
3637c478bd9Sstevel@tonic-gate 		warn("watchpoint size must be 8 or a power of 256 bytes\n");
3647c478bd9Sstevel@tonic-gate 		return (set_errno(EINVAL));
3657c478bd9Sstevel@tonic-gate 	}
3667c478bd9Sstevel@tonic-gate 
3677c478bd9Sstevel@tonic-gate 	if (wp->wp_addr & (wp->wp_size - 1)) {
3687c478bd9Sstevel@tonic-gate 		warn("%lu-byte watchpoints must be %lu-byte aligned\n",
3697c478bd9Sstevel@tonic-gate 		    wp->wp_size, wp->wp_size);
3707c478bd9Sstevel@tonic-gate 		return (set_errno(EINVAL));
3717c478bd9Sstevel@tonic-gate 	}
3727c478bd9Sstevel@tonic-gate 
3737c478bd9Sstevel@tonic-gate 	if (wp->wp_type != DPI_WAPT_TYPE_PHYS &&
3747c478bd9Sstevel@tonic-gate 	    wp->wp_type != DPI_WAPT_TYPE_VIRT) {
3757c478bd9Sstevel@tonic-gate 		warn("requested watchpoint type not supported on this "
3767c478bd9Sstevel@tonic-gate 		    "platform\n");
3777c478bd9Sstevel@tonic-gate 		return (set_errno(EMDB_TGTHWNOTSUP));
3787c478bd9Sstevel@tonic-gate 	}
3797c478bd9Sstevel@tonic-gate 
3807c478bd9Sstevel@tonic-gate 	return (0);
3817c478bd9Sstevel@tonic-gate }
3827c478bd9Sstevel@tonic-gate 
3837c478bd9Sstevel@tonic-gate static int
3847c478bd9Sstevel@tonic-gate kaif_wapt_reserve(kmdb_wapt_t *wp)
3857c478bd9Sstevel@tonic-gate {
3867c478bd9Sstevel@tonic-gate #ifdef	sun4v
3877c478bd9Sstevel@tonic-gate #ifdef	lint
3887c478bd9Sstevel@tonic-gate 	ASSERT(wp == (kmdb_wapt_t *)wp);
3897c478bd9Sstevel@tonic-gate #endif	/* !lint */
3907c478bd9Sstevel@tonic-gate 	/* Watchpoints not supported */
3917c478bd9Sstevel@tonic-gate 	return (set_errno(EMDB_TGTHWNOTSUP));
3927c478bd9Sstevel@tonic-gate #else
3937c478bd9Sstevel@tonic-gate 	uint64_t *addrp;
3947c478bd9Sstevel@tonic-gate 
3957c478bd9Sstevel@tonic-gate 	if (wp->wp_type == DPI_WAPT_TYPE_PHYS)
3967c478bd9Sstevel@tonic-gate 		addrp = &kaif_pwapt_addr;
3977c478bd9Sstevel@tonic-gate 	else
3987c478bd9Sstevel@tonic-gate 		addrp = &kaif_vwapt_addr;
3997c478bd9Sstevel@tonic-gate 
4007c478bd9Sstevel@tonic-gate 	if (*addrp != NULL)
4017c478bd9Sstevel@tonic-gate 		return (set_errno(EMDB_WPTOOMANY));
4027c478bd9Sstevel@tonic-gate 
4037c478bd9Sstevel@tonic-gate 	*addrp = wp->wp_addr;
4047c478bd9Sstevel@tonic-gate 
4057c478bd9Sstevel@tonic-gate 	return (0);
4067c478bd9Sstevel@tonic-gate #endif
4077c478bd9Sstevel@tonic-gate }
4087c478bd9Sstevel@tonic-gate 
4097c478bd9Sstevel@tonic-gate static void
4107c478bd9Sstevel@tonic-gate kaif_wapt_release(kmdb_wapt_t *wp)
4117c478bd9Sstevel@tonic-gate {
4127c478bd9Sstevel@tonic-gate 	uint64_t *addrp = (wp->wp_type == DPI_WAPT_TYPE_PHYS ?
4137c478bd9Sstevel@tonic-gate 	    &kaif_pwapt_addr : &kaif_vwapt_addr);
4147c478bd9Sstevel@tonic-gate 
4157c478bd9Sstevel@tonic-gate 	ASSERT(*addrp != NULL);
4167c478bd9Sstevel@tonic-gate 	*addrp = NULL;
4177c478bd9Sstevel@tonic-gate }
4187c478bd9Sstevel@tonic-gate 
4197c478bd9Sstevel@tonic-gate /*ARGSUSED*/
4207c478bd9Sstevel@tonic-gate static void
4217c478bd9Sstevel@tonic-gate kaif_wapt_arm(kmdb_wapt_t *wp)
4227c478bd9Sstevel@tonic-gate {
4237c478bd9Sstevel@tonic-gate 	/*
424acbc304dSjohnlev 	 * Sun4v doesn't have watch point regs
4257c478bd9Sstevel@tonic-gate 	 */
4267c478bd9Sstevel@tonic-gate #ifndef	sun4v
4277c478bd9Sstevel@tonic-gate 	uint64_t mask = kaif_wapt_calc_mask(wp->wp_size);
4287c478bd9Sstevel@tonic-gate 
4297c478bd9Sstevel@tonic-gate 	if (wp->wp_type == DPI_WAPT_TYPE_PHYS) {
4307c478bd9Sstevel@tonic-gate 		kaif_lsuctl &= ~KAIF_LSUCTL_PWAPT_MASK;
4317c478bd9Sstevel@tonic-gate 
4327c478bd9Sstevel@tonic-gate 		if (wp->wp_wflags & MDB_TGT_WA_R)
4337c478bd9Sstevel@tonic-gate 			kaif_lsuctl |= LSU_PR;
4347c478bd9Sstevel@tonic-gate 		if (wp->wp_wflags & MDB_TGT_WA_W)
4357c478bd9Sstevel@tonic-gate 			kaif_lsuctl |= LSU_PW;
4367c478bd9Sstevel@tonic-gate 		kaif_lsuctl |= ((mask << LSU_PM_SHIFT) & LSU_PM);
4377c478bd9Sstevel@tonic-gate 
4387c478bd9Sstevel@tonic-gate 	} else if (wp->wp_type == DPI_WAPT_TYPE_VIRT) {
4397c478bd9Sstevel@tonic-gate 		kaif_lsuctl &= ~KAIF_LSUCTL_VWAPT_MASK;
4407c478bd9Sstevel@tonic-gate 
4417c478bd9Sstevel@tonic-gate 		if (wp->wp_wflags & MDB_TGT_WA_R)
4427c478bd9Sstevel@tonic-gate 			kaif_lsuctl |= LSU_VR;
4437c478bd9Sstevel@tonic-gate 		if (wp->wp_wflags & MDB_TGT_WA_W)
4447c478bd9Sstevel@tonic-gate 			kaif_lsuctl |= LSU_VW;
4457c478bd9Sstevel@tonic-gate 		kaif_lsuctl |= ((mask << LSU_VM_SHIFT) & LSU_VM);
4467c478bd9Sstevel@tonic-gate 	}
4477c478bd9Sstevel@tonic-gate #endif	/* sun4v */
4487c478bd9Sstevel@tonic-gate }
4497c478bd9Sstevel@tonic-gate 
4507c478bd9Sstevel@tonic-gate /*ARGSUSED*/
4517c478bd9Sstevel@tonic-gate static void
4527c478bd9Sstevel@tonic-gate kaif_wapt_disarm(kmdb_wapt_t *wp)
4537c478bd9Sstevel@tonic-gate {
4547c478bd9Sstevel@tonic-gate 	/*
455acbc304dSjohnlev 	 * Sun4v doesn't have watch point regs
4567c478bd9Sstevel@tonic-gate 	 */
4577c478bd9Sstevel@tonic-gate #ifndef	sun4v
4587c478bd9Sstevel@tonic-gate 	if (wp->wp_type == DPI_WAPT_TYPE_PHYS) {
4597c478bd9Sstevel@tonic-gate 		ASSERT(kaif_pwapt_addr != NULL);
4607c478bd9Sstevel@tonic-gate 		kaif_lsuctl &= ~(LSU_PR|LSU_PW);
4617c478bd9Sstevel@tonic-gate 	} else {
4627c478bd9Sstevel@tonic-gate 		ASSERT(kaif_vwapt_addr != NULL);
4637c478bd9Sstevel@tonic-gate 		kaif_lsuctl &= ~(LSU_VR|LSU_VW);
4647c478bd9Sstevel@tonic-gate 	}
4657c478bd9Sstevel@tonic-gate #endif
4667c478bd9Sstevel@tonic-gate }
4677c478bd9Sstevel@tonic-gate 
4687c478bd9Sstevel@tonic-gate /*
4697c478bd9Sstevel@tonic-gate  * `kaif_wapt_arm' and `kaif_wapt_disarm' modify the global state we keep that
4707c478bd9Sstevel@tonic-gate  * indicates what the values of the wapt control registers should be.  These
4717c478bd9Sstevel@tonic-gate  * values must be individually set and cleared on each active CPU, a task which
4727c478bd9Sstevel@tonic-gate  * is performed by `kaif_wapt_clear_regs' and `kaif_wapt_set_regs', invoked as
4737c478bd9Sstevel@tonic-gate  * the world is stopped and resumed, respectively.  `kaif_wapt_set_regs' is also
4747c478bd9Sstevel@tonic-gate  * used for CPU initialization.
4757c478bd9Sstevel@tonic-gate  */
4767c478bd9Sstevel@tonic-gate void
4777c478bd9Sstevel@tonic-gate kaif_wapt_set_regs(void)
4787c478bd9Sstevel@tonic-gate {
4797c478bd9Sstevel@tonic-gate 	/*
480acbc304dSjohnlev 	 * Sun4v doesn't have watch point regs
4817c478bd9Sstevel@tonic-gate 	 */
4827c478bd9Sstevel@tonic-gate #ifndef sun4v
4837c478bd9Sstevel@tonic-gate 	uint64_t lsu;
4847c478bd9Sstevel@tonic-gate 
4857c478bd9Sstevel@tonic-gate 	wrasi(ASI_DMMU, MMU_VAW, kaif_vwapt_addr);
4867c478bd9Sstevel@tonic-gate 	wrasi(ASI_DMMU, MMU_PAW, kaif_pwapt_addr);
4877c478bd9Sstevel@tonic-gate 
4887c478bd9Sstevel@tonic-gate 	ASSERT((kaif_lsuctl & ~KAIF_LSUCTL_WAPT_MASK) == NULL);
4897c478bd9Sstevel@tonic-gate 
4907c478bd9Sstevel@tonic-gate 	lsu = rdasi(ASI_LSU, NULL);
4917c478bd9Sstevel@tonic-gate 	lsu &= ~KAIF_LSUCTL_WAPT_MASK;
4927c478bd9Sstevel@tonic-gate 	lsu |= kaif_lsuctl;
4937c478bd9Sstevel@tonic-gate 	wrasi(ASI_LSU, NULL, lsu);
4947c478bd9Sstevel@tonic-gate #endif /* sun4v */
4957c478bd9Sstevel@tonic-gate }
4967c478bd9Sstevel@tonic-gate 
4977c478bd9Sstevel@tonic-gate void
4987c478bd9Sstevel@tonic-gate kaif_wapt_clear_regs(void)
4997c478bd9Sstevel@tonic-gate {
5007c478bd9Sstevel@tonic-gate 	/*
501acbc304dSjohnlev 	 * Sun4v doesn't have watch point regs
5027c478bd9Sstevel@tonic-gate 	 */
5037c478bd9Sstevel@tonic-gate #ifndef sun4v
5047c478bd9Sstevel@tonic-gate 	uint64_t lsu = rdasi(ASI_LSU, NULL);
5057c478bd9Sstevel@tonic-gate 	lsu &= ~KAIF_LSUCTL_WAPT_MASK;
5067c478bd9Sstevel@tonic-gate 	wrasi(ASI_LSU, NULL, lsu);
5077c478bd9Sstevel@tonic-gate #endif /* sun4v */
5087c478bd9Sstevel@tonic-gate }
5097c478bd9Sstevel@tonic-gate 
5107c478bd9Sstevel@tonic-gate /*
5117c478bd9Sstevel@tonic-gate  * UltraSPARC has one PA watchpoint and one VA watchpoint.  The trap we get will
5127c478bd9Sstevel@tonic-gate  * tell us which one we hit, but it won't tell us where.  We could attempt to
5137c478bd9Sstevel@tonic-gate  * dissect the instruction at %pc to see where it was reading from or writing
5147c478bd9Sstevel@tonic-gate  * to, but that gets messy in a hurry.  We can, however, make a couple of
5157c478bd9Sstevel@tonic-gate  * assumptions:
5167c478bd9Sstevel@tonic-gate  *
5177c478bd9Sstevel@tonic-gate  * - kaif_set_watchpoint and kaif_delete_watchpoint will enforce the limits as
5187c478bd9Sstevel@tonic-gate  *   to the number of watch points.  As such, at most one VA watchpoint and one
5197c478bd9Sstevel@tonic-gate  *   PA watchpoint will be on the active list.
5207c478bd9Sstevel@tonic-gate  *
5217c478bd9Sstevel@tonic-gate  * - We'll only be called on watchpoints that are on the active list.
5227c478bd9Sstevel@tonic-gate  *
5237c478bd9Sstevel@tonic-gate  * Taking these two assumptions, we can conclude that, if we're stopped due to
5247c478bd9Sstevel@tonic-gate  * a watchpoint and we're asked to match against a watchpoint, we must have
5257c478bd9Sstevel@tonic-gate  * stopped due to the watchpoint.  This is all very terrifying, but the
5267c478bd9Sstevel@tonic-gate  * alternative (taking instructions apart) is worse.
5277c478bd9Sstevel@tonic-gate  */
5287c478bd9Sstevel@tonic-gate /*ARGSUSED*/
5297c478bd9Sstevel@tonic-gate static int
5307c478bd9Sstevel@tonic-gate kaif_wapt_match(kmdb_wapt_t *wp)
5317c478bd9Sstevel@tonic-gate {
5327c478bd9Sstevel@tonic-gate 	int state, why, deswhy;
5337c478bd9Sstevel@tonic-gate 
5347c478bd9Sstevel@tonic-gate 	state = kmdb_dpi_get_state(&why);
5357c478bd9Sstevel@tonic-gate 
5367c478bd9Sstevel@tonic-gate 	if (wp->wp_type == DPI_WAPT_TYPE_PHYS)
5377c478bd9Sstevel@tonic-gate 		deswhy = DPI_STATE_WHY_P_WAPT;
5387c478bd9Sstevel@tonic-gate 	else
5397c478bd9Sstevel@tonic-gate 		deswhy = DPI_STATE_WHY_V_WAPT;
5407c478bd9Sstevel@tonic-gate 
5417c478bd9Sstevel@tonic-gate 	return (state == DPI_STATE_FAULTED && why == deswhy);
5427c478bd9Sstevel@tonic-gate }
5437c478bd9Sstevel@tonic-gate 
5447c478bd9Sstevel@tonic-gate static const char *
5457c478bd9Sstevel@tonic-gate regno2name(int idx)
5467c478bd9Sstevel@tonic-gate {
5477c478bd9Sstevel@tonic-gate 	const mdb_tgt_regdesc_t *rd;
5487c478bd9Sstevel@tonic-gate 
5497c478bd9Sstevel@tonic-gate 	for (rd = mdb_sparcv9_kregs; rd->rd_name != NULL; rd++) {
5507c478bd9Sstevel@tonic-gate 		if (idx == rd->rd_num)
5517c478bd9Sstevel@tonic-gate 			return (rd->rd_name);
5527c478bd9Sstevel@tonic-gate 	}
5537c478bd9Sstevel@tonic-gate 
5547c478bd9Sstevel@tonic-gate 	ASSERT(rd->rd_name != NULL);
5557c478bd9Sstevel@tonic-gate 
5567c478bd9Sstevel@tonic-gate 	return ("unknown");
5577c478bd9Sstevel@tonic-gate }
5587c478bd9Sstevel@tonic-gate 
5597c478bd9Sstevel@tonic-gate /*
5607c478bd9Sstevel@tonic-gate  * UltraSPARC doesn't support single-step natively, so we have to do it
5617c478bd9Sstevel@tonic-gate  * ourselves, by placing breakpoints at the instruction after the current one.
5627c478bd9Sstevel@tonic-gate  * Note that "after" will be %npc in the simple case, but can be one of
5637c478bd9Sstevel@tonic-gate  * several places if %pc is a branch.
5647c478bd9Sstevel@tonic-gate  *
5657c478bd9Sstevel@tonic-gate  * If %pc is an unconditional annulled branch, we put a breakpoint at the branch
5667c478bd9Sstevel@tonic-gate  * target.  If it is a conditional annulled branch, we put breakpoints at %pc +
5677c478bd9Sstevel@tonic-gate  * 8 and the branch target.  For all other branches, %npc will be set correctly
5687c478bd9Sstevel@tonic-gate  * as determined by the branch condition, and thus we can step through the
5697c478bd9Sstevel@tonic-gate  * branch by putting a breakpoint at %npc.  If %pc contains a non-branch
5707c478bd9Sstevel@tonic-gate  * instruction (with the exception of certain rdpr and wrpr instructions,
5717c478bd9Sstevel@tonic-gate  * described more below), we step over it by placing a breakpoint at %npc.
5727c478bd9Sstevel@tonic-gate  */
5737c478bd9Sstevel@tonic-gate static int
5747c478bd9Sstevel@tonic-gate kaif_step(void)
5757c478bd9Sstevel@tonic-gate {
5767c478bd9Sstevel@tonic-gate 	kreg_t pc, npc, brtgt, pstate, tt;
5777c478bd9Sstevel@tonic-gate 	int bptgt = 0, bpnpc = 0, bppc8 = 0;
5787c478bd9Sstevel@tonic-gate 	mdb_instr_t svtgt = 0, svnpc = 0, svpc8 = 0;
5797c478bd9Sstevel@tonic-gate 	mdb_instr_t instr;
5807c478bd9Sstevel@tonic-gate 	int ie, err;
5817c478bd9Sstevel@tonic-gate 
5827c478bd9Sstevel@tonic-gate 	(void) kmdb_dpi_get_register("pc", &pc);
5837c478bd9Sstevel@tonic-gate 	(void) kmdb_dpi_get_register("npc", &npc);
5847c478bd9Sstevel@tonic-gate 
5857c478bd9Sstevel@tonic-gate 	if (mdb_tgt_vread(mdb.m_target, &instr, sizeof (instr), pc) !=
5867c478bd9Sstevel@tonic-gate 	    sizeof (instr)) {
5877c478bd9Sstevel@tonic-gate 		warn("failed to read %%pc at %p for step", (void *)pc);
5887c478bd9Sstevel@tonic-gate 		return (-1);
5897c478bd9Sstevel@tonic-gate 	}
5907c478bd9Sstevel@tonic-gate 
5917c478bd9Sstevel@tonic-gate 	/*
5927c478bd9Sstevel@tonic-gate 	 * If the current instruction is a read or write of PSTATE we need
5937c478bd9Sstevel@tonic-gate 	 * to emulate it because we've taken over management of PSTATE and
5947c478bd9Sstevel@tonic-gate 	 * we need keep interrupts disabled. If it's a branch, we may need
5957c478bd9Sstevel@tonic-gate 	 * to set two breakpoints -- one at the target and one at the
5967c478bd9Sstevel@tonic-gate 	 * subsequent instruction.
5977c478bd9Sstevel@tonic-gate 	 */
5987c478bd9Sstevel@tonic-gate 	if (OP(instr) == OP_ARITH) {
5997c478bd9Sstevel@tonic-gate 		if (OP3(instr) == OP3_RDPR &&
6007c478bd9Sstevel@tonic-gate 		    RS1(instr) == KAIF_PREGNO_PSTATE) {
6017c478bd9Sstevel@tonic-gate 			const char *tgtreg =
6027c478bd9Sstevel@tonic-gate 			    mdb_sparcv9_kregs[RD(instr)].rd_name;
6037c478bd9Sstevel@tonic-gate 			kreg_t pstate;
6047c478bd9Sstevel@tonic-gate 
6057c478bd9Sstevel@tonic-gate 			(void) kmdb_dpi_get_register("pstate", &pstate);
6067c478bd9Sstevel@tonic-gate 			(void) kmdb_dpi_set_register(tgtreg, pstate);
6077c478bd9Sstevel@tonic-gate 
6087c478bd9Sstevel@tonic-gate 			(void) kmdb_dpi_set_register("pc", npc);
6097c478bd9Sstevel@tonic-gate 			(void) kmdb_dpi_set_register("npc", npc + 4);
6107c478bd9Sstevel@tonic-gate 			return (0);
6117c478bd9Sstevel@tonic-gate 
6127c478bd9Sstevel@tonic-gate 		} else if (OP3(instr) == OP3_WRPR &&
6137c478bd9Sstevel@tonic-gate 		    RD(instr) == KAIF_PREGNO_PSTATE) {
6147c478bd9Sstevel@tonic-gate 			kreg_t rs1, rs2, val;
6157c478bd9Sstevel@tonic-gate 
6167c478bd9Sstevel@tonic-gate 			(void) kmdb_dpi_get_register(regno2name(RS1(instr)),
6177c478bd9Sstevel@tonic-gate 			    &rs1);
6187c478bd9Sstevel@tonic-gate 
6197c478bd9Sstevel@tonic-gate 			if (I(instr)) {
6207c478bd9Sstevel@tonic-gate 				int imm = SIMM13(instr);
6217c478bd9Sstevel@tonic-gate 				imm <<= 19;
6227c478bd9Sstevel@tonic-gate 				imm >>= 19;
6237c478bd9Sstevel@tonic-gate 				rs2 = imm;
6247c478bd9Sstevel@tonic-gate 			} else {
6257c478bd9Sstevel@tonic-gate 				(void) kmdb_dpi_get_register(
6267c478bd9Sstevel@tonic-gate 				    regno2name(RS2(instr)), &rs2);
6277c478bd9Sstevel@tonic-gate 			}
6287c478bd9Sstevel@tonic-gate 
6297c478bd9Sstevel@tonic-gate 			val = rs1 ^ rs2;
6307c478bd9Sstevel@tonic-gate 
6317c478bd9Sstevel@tonic-gate 			(void) kmdb_dpi_set_register("pstate", val);
6327c478bd9Sstevel@tonic-gate 
6337c478bd9Sstevel@tonic-gate 			(void) kmdb_dpi_set_register("pc", npc);
6347c478bd9Sstevel@tonic-gate 			(void) kmdb_dpi_set_register("npc", npc + 4);
6357c478bd9Sstevel@tonic-gate 			return (0);
6367c478bd9Sstevel@tonic-gate 
6377c478bd9Sstevel@tonic-gate 		}
6387c478bd9Sstevel@tonic-gate 
6397c478bd9Sstevel@tonic-gate 		bpnpc = 1;
6407c478bd9Sstevel@tonic-gate 
6417c478bd9Sstevel@tonic-gate 	} else if (OP(instr) == OP_BRANCH) {
6427c478bd9Sstevel@tonic-gate 		int disp, cond, annul;
6437c478bd9Sstevel@tonic-gate 
6447c478bd9Sstevel@tonic-gate 		switch (OP2(instr)) {
6457c478bd9Sstevel@tonic-gate 		case OP2_BPcc:
6467c478bd9Sstevel@tonic-gate 		case OP2_FBPfcc:
6477c478bd9Sstevel@tonic-gate 			cond = (COND(instr) != 8);
6487c478bd9Sstevel@tonic-gate 
6497c478bd9Sstevel@tonic-gate 			disp = DISP19(instr);
6507c478bd9Sstevel@tonic-gate 			disp <<= 13;
6517c478bd9Sstevel@tonic-gate 			disp >>= 11;
6527c478bd9Sstevel@tonic-gate 			break;
6537c478bd9Sstevel@tonic-gate 
6547c478bd9Sstevel@tonic-gate 		case OP2_Bicc:
6557c478bd9Sstevel@tonic-gate 		case OP2_FBfcc:
6567c478bd9Sstevel@tonic-gate 			cond = (COND(instr) != 8);
6577c478bd9Sstevel@tonic-gate 
6587c478bd9Sstevel@tonic-gate 			disp = DISP22(instr);
6597c478bd9Sstevel@tonic-gate 			disp <<= 10;
6607c478bd9Sstevel@tonic-gate 			disp >>= 8;
6617c478bd9Sstevel@tonic-gate 			break;
6627c478bd9Sstevel@tonic-gate 
6637c478bd9Sstevel@tonic-gate 		case OP2_BPr:
6647c478bd9Sstevel@tonic-gate 			cond = 1;
6657c478bd9Sstevel@tonic-gate 
6667c478bd9Sstevel@tonic-gate 			disp = DISP16(instr);
6677c478bd9Sstevel@tonic-gate 			disp <<= 16;
6687c478bd9Sstevel@tonic-gate 			disp >>= 14;
6697c478bd9Sstevel@tonic-gate 			break;
6707c478bd9Sstevel@tonic-gate 
6717c478bd9Sstevel@tonic-gate 		default:
6727c478bd9Sstevel@tonic-gate 			bpnpc = 1;
6737c478bd9Sstevel@tonic-gate 		}
6747c478bd9Sstevel@tonic-gate 
6757c478bd9Sstevel@tonic-gate 		if (!bpnpc) {
6767c478bd9Sstevel@tonic-gate 			annul = A(instr);
6777c478bd9Sstevel@tonic-gate 
6787c478bd9Sstevel@tonic-gate 			if (!cond && annul) {
6797c478bd9Sstevel@tonic-gate 				brtgt = pc + disp;
6807c478bd9Sstevel@tonic-gate 				bptgt = 1;
6817c478bd9Sstevel@tonic-gate 			} else {
6827c478bd9Sstevel@tonic-gate 				bpnpc = 1;
6837c478bd9Sstevel@tonic-gate 
6847c478bd9Sstevel@tonic-gate 				if (cond && annul)
6857c478bd9Sstevel@tonic-gate 					bppc8 = 1;
6867c478bd9Sstevel@tonic-gate 			}
6877c478bd9Sstevel@tonic-gate 		}
6887c478bd9Sstevel@tonic-gate 
6897c478bd9Sstevel@tonic-gate 	} else {
6907c478bd9Sstevel@tonic-gate 		bpnpc = 1;
6917c478bd9Sstevel@tonic-gate 	}
6927c478bd9Sstevel@tonic-gate 
6937c478bd9Sstevel@tonic-gate 	/*
6947c478bd9Sstevel@tonic-gate 	 * Place the breakpoints and resume this CPU with IE off.  We'll come
6957c478bd9Sstevel@tonic-gate 	 * back after having encountered either one of the breakpoints we placed
6967c478bd9Sstevel@tonic-gate 	 * or a trap.
6977c478bd9Sstevel@tonic-gate 	 */
6987c478bd9Sstevel@tonic-gate 	err = 0;
6997c478bd9Sstevel@tonic-gate 	if ((bpnpc && kaif_brkpt_arm(npc, &svnpc) != 0) ||
7007c478bd9Sstevel@tonic-gate 	    (bppc8 && kaif_brkpt_arm(pc + 8, &svpc8) != 0) ||
7017c478bd9Sstevel@tonic-gate 	    (bptgt && kaif_brkpt_arm(brtgt, &svtgt) != 0)) {
7027c478bd9Sstevel@tonic-gate 		err = errno;
7037c478bd9Sstevel@tonic-gate 		goto step_done;
7047c478bd9Sstevel@tonic-gate 	}
7057c478bd9Sstevel@tonic-gate 
7067c478bd9Sstevel@tonic-gate 	(void) kmdb_dpi_get_register("pstate", &pstate);
7077c478bd9Sstevel@tonic-gate 	ie = pstate & KREG_PSTATE_IE_MASK;
7087c478bd9Sstevel@tonic-gate 	(void) kmdb_dpi_set_register("pstate", (pstate & ~KREG_PSTATE_IE_MASK));
7097c478bd9Sstevel@tonic-gate 
7107c478bd9Sstevel@tonic-gate 	kmdb_dpi_resume_master(); /* ... there and back again ... */
7117c478bd9Sstevel@tonic-gate 
7127c478bd9Sstevel@tonic-gate 	(void) kmdb_dpi_get_register("pstate", &pstate);
7137c478bd9Sstevel@tonic-gate 	(void) kmdb_dpi_set_register("pstate",
7147c478bd9Sstevel@tonic-gate 	    ((pstate & ~KREG_PSTATE_IE_MASK) | ie));
7157c478bd9Sstevel@tonic-gate 
7167c478bd9Sstevel@tonic-gate 	(void) kmdb_dpi_get_register("tt", &tt);
7177c478bd9Sstevel@tonic-gate 
7187c478bd9Sstevel@tonic-gate step_done:
7197c478bd9Sstevel@tonic-gate 	if (svnpc)
7207c478bd9Sstevel@tonic-gate 		(void) kaif_brkpt_disarm(npc, svnpc);
7217c478bd9Sstevel@tonic-gate 	if (svpc8)
7227c478bd9Sstevel@tonic-gate 		(void) kaif_brkpt_disarm(pc + 8, svpc8);
7237c478bd9Sstevel@tonic-gate 	if (svtgt)
7247c478bd9Sstevel@tonic-gate 		(void) kaif_brkpt_disarm(brtgt, svtgt);
7257c478bd9Sstevel@tonic-gate 
7267c478bd9Sstevel@tonic-gate 	return (err == 0 ? 0 : set_errno(err));
7277c478bd9Sstevel@tonic-gate }
7287c478bd9Sstevel@tonic-gate 
7297c478bd9Sstevel@tonic-gate static uintptr_t
7307c478bd9Sstevel@tonic-gate kaif_call(uintptr_t funcva, uint_t argc, const uintptr_t *argv)
7317c478bd9Sstevel@tonic-gate {
7327c478bd9Sstevel@tonic-gate 	kreg_t g6, g7;
7337c478bd9Sstevel@tonic-gate 
7347c478bd9Sstevel@tonic-gate 	(void) kmdb_dpi_get_register("g6", &g6);
7357c478bd9Sstevel@tonic-gate 	(void) kmdb_dpi_get_register("g7", &g7);
7367c478bd9Sstevel@tonic-gate 
7377c478bd9Sstevel@tonic-gate 	return (kaif_invoke(funcva, argc, argv, g6, g7));
7387c478bd9Sstevel@tonic-gate }
7397c478bd9Sstevel@tonic-gate 
7407c478bd9Sstevel@tonic-gate static const mdb_bitmask_t krm_flag_bits[] = {
7417c478bd9Sstevel@tonic-gate 	{ "M_W",	KAIF_CRUMB_F_MAIN_OBPWAPT, KAIF_CRUMB_F_MAIN_OBPWAPT },
7427c478bd9Sstevel@tonic-gate 	{ "M_PE",	KAIF_CRUMB_F_MAIN_OBPPENT, KAIF_CRUMB_F_MAIN_OBPPENT },
7437c478bd9Sstevel@tonic-gate 	{ "M_NRM",	KAIF_CRUMB_F_MAIN_NORMAL, KAIF_CRUMB_F_MAIN_NORMAL },
7447c478bd9Sstevel@tonic-gate 	{ "I_RE",	KAIF_CRUMB_F_IVEC_REENTER, KAIF_CRUMB_F_IVEC_REENTER },
7457c478bd9Sstevel@tonic-gate 	{ "I_OBP", 	KAIF_CRUMB_F_IVEC_INOBP, KAIF_CRUMB_F_IVEC_INOBP },
7467c478bd9Sstevel@tonic-gate 	{ "I_NRM",	KAIF_CRUMB_F_IVEC_NORMAL, KAIF_CRUMB_F_IVEC_NORMAL },
7477c478bd9Sstevel@tonic-gate 	{ "O_NRM",	KAIF_CRUMB_F_OBP_NORMAL, KAIF_CRUMB_F_OBP_NORMAL },
7487c478bd9Sstevel@tonic-gate 	{ "O_REVEC",	KAIF_CRUMB_F_OBP_REVECT, KAIF_CRUMB_F_OBP_REVECT },
7497c478bd9Sstevel@tonic-gate 	{ NULL }
7507c478bd9Sstevel@tonic-gate };
7517c478bd9Sstevel@tonic-gate 
7527c478bd9Sstevel@tonic-gate static void
753acbc304dSjohnlev dump_crumb(kaif_crumb_t *krmp)
7547c478bd9Sstevel@tonic-gate {
755acbc304dSjohnlev 	kaif_crumb_t krm;
756acbc304dSjohnlev 
757acbc304dSjohnlev 	if (mdb_vread(&krm, sizeof (kaif_crumb_t), (uintptr_t)krmp) !=
758acbc304dSjohnlev 	    sizeof (kaif_crumb_t)) {
759acbc304dSjohnlev 		warn("failed to read crumb at %p", krmp);
760acbc304dSjohnlev 		return;
761acbc304dSjohnlev 	}
762acbc304dSjohnlev 
7637c478bd9Sstevel@tonic-gate 	mdb_printf(" src: ");
764acbc304dSjohnlev 	switch (krm.krm_src) {
7657c478bd9Sstevel@tonic-gate 	case KAIF_CRUMB_SRC_OBP:
7667c478bd9Sstevel@tonic-gate 		mdb_printf("O");
7677c478bd9Sstevel@tonic-gate 		break;
7687c478bd9Sstevel@tonic-gate 	case KAIF_CRUMB_SRC_IVEC:
7697c478bd9Sstevel@tonic-gate 		mdb_printf("I");
7707c478bd9Sstevel@tonic-gate 		break;
7717c478bd9Sstevel@tonic-gate 	case KAIF_CRUMB_SRC_MAIN:
7727c478bd9Sstevel@tonic-gate 		mdb_printf("M");
7737c478bd9Sstevel@tonic-gate 		break;
7747c478bd9Sstevel@tonic-gate 	case 0:
7757c478bd9Sstevel@tonic-gate 		mdb_printf("-");
7767c478bd9Sstevel@tonic-gate 		break;
7777c478bd9Sstevel@tonic-gate 	default:
778acbc304dSjohnlev 		mdb_printf("%d", krm.krm_src);
7797c478bd9Sstevel@tonic-gate 	}
7807c478bd9Sstevel@tonic-gate 
7817c478bd9Sstevel@tonic-gate 	mdb_printf(" tt %3x pc %8p %-20A <%b>\n",
782acbc304dSjohnlev 	    krm.krm_tt, krm.krm_pc, krm.krm_pc, krm.krm_flag, krm_flag_bits);
7837c478bd9Sstevel@tonic-gate }
7847c478bd9Sstevel@tonic-gate 
7857c478bd9Sstevel@tonic-gate static void
7867c478bd9Sstevel@tonic-gate dump_crumbs(kaif_cpusave_t *save)
7877c478bd9Sstevel@tonic-gate {
7887c478bd9Sstevel@tonic-gate 	int i;
7897c478bd9Sstevel@tonic-gate 
7907c478bd9Sstevel@tonic-gate 	for (i = KAIF_NCRUMBS; i > 0; i--) {
7917c478bd9Sstevel@tonic-gate 		uint_t idx = (save->krs_curcrumbidx + i) % KAIF_NCRUMBS;
7927c478bd9Sstevel@tonic-gate 		dump_crumb(&save->krs_crumbs[idx]);
7937c478bd9Sstevel@tonic-gate 	}
7947c478bd9Sstevel@tonic-gate }
7957c478bd9Sstevel@tonic-gate 
7967c478bd9Sstevel@tonic-gate static void
7977c478bd9Sstevel@tonic-gate kaif_dump_crumbs(uintptr_t addr, int cpuid)
7987c478bd9Sstevel@tonic-gate {
7997c478bd9Sstevel@tonic-gate 	int i;
8007c478bd9Sstevel@tonic-gate 
8017c478bd9Sstevel@tonic-gate 	if (addr != NULL) {
802acbc304dSjohnlev 		/* dump_crumb will protect us from bogus addresses */
8037c478bd9Sstevel@tonic-gate 		dump_crumb((kaif_crumb_t *)addr);
8047c478bd9Sstevel@tonic-gate 
8057c478bd9Sstevel@tonic-gate 	} else if (cpuid != -1) {
8067c478bd9Sstevel@tonic-gate 		if (cpuid >= kaif_ncpusave)
8077c478bd9Sstevel@tonic-gate 			return;
8087c478bd9Sstevel@tonic-gate 
8097c478bd9Sstevel@tonic-gate 		dump_crumbs(&kaif_cpusave[cpuid]);
8107c478bd9Sstevel@tonic-gate 
8117c478bd9Sstevel@tonic-gate 	} else {
8127c478bd9Sstevel@tonic-gate 		for (i = 0; i < kaif_ncpusave; i++) {
8137c478bd9Sstevel@tonic-gate 			kaif_cpusave_t *save = &kaif_cpusave[i];
8147c478bd9Sstevel@tonic-gate 
8157c478bd9Sstevel@tonic-gate 			if (save->krs_cpu_state == KAIF_CPU_STATE_NONE)
8167c478bd9Sstevel@tonic-gate 				continue;
8177c478bd9Sstevel@tonic-gate 
8187c478bd9Sstevel@tonic-gate 			mdb_printf("%sCPU %d crumbs: (curidx %d)\n",
8197c478bd9Sstevel@tonic-gate 			    (i == 0 ? "" : "\n"), i, save->krs_curcrumbidx);
8207c478bd9Sstevel@tonic-gate 
8217c478bd9Sstevel@tonic-gate 			dump_crumbs(save);
8227c478bd9Sstevel@tonic-gate 		}
8237c478bd9Sstevel@tonic-gate 	}
8247c478bd9Sstevel@tonic-gate }
8257c478bd9Sstevel@tonic-gate 
8267c478bd9Sstevel@tonic-gate static int
8277c478bd9Sstevel@tonic-gate kaif_get_rwin(int cpuid, int win, struct rwindow *rwin)
8287c478bd9Sstevel@tonic-gate {
829acbc304dSjohnlev 	kaif_cpusave_t *save;
830acbc304dSjohnlev 
831acbc304dSjohnlev 	if ((save = kaif_cpuid2save(cpuid)) == NULL)
832acbc304dSjohnlev 		return (-1); /* errno is set for us */
8337c478bd9Sstevel@tonic-gate 
8347c478bd9Sstevel@tonic-gate 	if (win < 0 || win >= kaif_get_nwin(cpuid))
8357c478bd9Sstevel@tonic-gate 		return (-1);
8367c478bd9Sstevel@tonic-gate 
837acbc304dSjohnlev 	bcopy(&save->krs_rwins[win], rwin, sizeof (struct rwindow));
8387c478bd9Sstevel@tonic-gate 
8397c478bd9Sstevel@tonic-gate 	return (0);
8407c478bd9Sstevel@tonic-gate }
8417c478bd9Sstevel@tonic-gate 
8427c478bd9Sstevel@tonic-gate static void
8437c478bd9Sstevel@tonic-gate kaif_enter_mon(void)
8447c478bd9Sstevel@tonic-gate {
8457c478bd9Sstevel@tonic-gate 	kmdb_prom_enter_mon();
8467c478bd9Sstevel@tonic-gate 	kaif_prom_rearm();
847a35baf17Shyw 	kaif_slave_loop_barrier();
8487c478bd9Sstevel@tonic-gate }
8497c478bd9Sstevel@tonic-gate 
8507c478bd9Sstevel@tonic-gate static void
8517c478bd9Sstevel@tonic-gate kaif_modchg_register(void (*func)(struct modctl *, int))
8527c478bd9Sstevel@tonic-gate {
8537c478bd9Sstevel@tonic-gate 	kaif_modchg_cb = func;
8547c478bd9Sstevel@tonic-gate }
8557c478bd9Sstevel@tonic-gate 
8567c478bd9Sstevel@tonic-gate static void
8577c478bd9Sstevel@tonic-gate kaif_modchg_cancel(void)
8587c478bd9Sstevel@tonic-gate {
8597c478bd9Sstevel@tonic-gate 	ASSERT(kaif_modchg_cb != NULL);
8607c478bd9Sstevel@tonic-gate 
8617c478bd9Sstevel@tonic-gate 	kaif_modchg_cb = NULL;
8627c478bd9Sstevel@tonic-gate }
8637c478bd9Sstevel@tonic-gate 
8647c478bd9Sstevel@tonic-gate void
8657c478bd9Sstevel@tonic-gate kaif_mod_loaded(struct modctl *modp)
8667c478bd9Sstevel@tonic-gate {
8677c478bd9Sstevel@tonic-gate 	if (kaif_modchg_cb != NULL)
8687c478bd9Sstevel@tonic-gate 		kaif_modchg_cb(modp, 1);
8697c478bd9Sstevel@tonic-gate }
8707c478bd9Sstevel@tonic-gate 
8717c478bd9Sstevel@tonic-gate void
8727c478bd9Sstevel@tonic-gate kaif_mod_unloading(struct modctl *modp)
8737c478bd9Sstevel@tonic-gate {
8747c478bd9Sstevel@tonic-gate 	if (kaif_modchg_cb != NULL)
8757c478bd9Sstevel@tonic-gate 		kaif_modchg_cb(modp, 0);
8767c478bd9Sstevel@tonic-gate }
8777c478bd9Sstevel@tonic-gate 
8787c478bd9Sstevel@tonic-gate void
8797c478bd9Sstevel@tonic-gate kaif_trap_set_debugger(void)
8807c478bd9Sstevel@tonic-gate {
881*186d582bSSurya Prakki 	(void) set_tba((void *)kaif_tba);
8827c478bd9Sstevel@tonic-gate }
8837c478bd9Sstevel@tonic-gate 
8847c478bd9Sstevel@tonic-gate void
885acbc304dSjohnlev kaif_trap_set_saved(kaif_cpusave_t *save)
8867c478bd9Sstevel@tonic-gate {
887*186d582bSSurya Prakki 	(void) set_tba((void *)save->krs_gregs.kregs[KREG_TBA]);
8887c478bd9Sstevel@tonic-gate }
8897c478bd9Sstevel@tonic-gate 
8907c478bd9Sstevel@tonic-gate static void
8917c478bd9Sstevel@tonic-gate kaif_kernpanic(int cpuid)
8927c478bd9Sstevel@tonic-gate {
8937c478bd9Sstevel@tonic-gate 	struct regs regs;
8947c478bd9Sstevel@tonic-gate 
8957c478bd9Sstevel@tonic-gate 	/*
8967c478bd9Sstevel@tonic-gate 	 * We're going to try to panic the system by using the same entry point
8977c478bd9Sstevel@tonic-gate 	 * used by the PROM when told to `sync'.  The kernel wants a
8987c478bd9Sstevel@tonic-gate 	 * fully-populated struct regs, which we're going to build using the
8997c478bd9Sstevel@tonic-gate 	 * state captured at the time of the debugger fault.  Said state lives
9007c478bd9Sstevel@tonic-gate 	 * in kaif_cb_save, since we haven't yet copied it over to the cpusave
9017c478bd9Sstevel@tonic-gate 	 * structure for the current master.
9027c478bd9Sstevel@tonic-gate 	 */
9037c478bd9Sstevel@tonic-gate 
9047c478bd9Sstevel@tonic-gate 	regs.r_tstate = kaif_cb_save.krs_tstate;
9057c478bd9Sstevel@tonic-gate 
9067c478bd9Sstevel@tonic-gate 	regs.r_g1 = kaif_cb_save.krs_gregs.kregs[KREG_G1];
9077c478bd9Sstevel@tonic-gate 	regs.r_g2 = kaif_cb_save.krs_gregs.kregs[KREG_G2];
9087c478bd9Sstevel@tonic-gate 	regs.r_g3 = kaif_cb_save.krs_gregs.kregs[KREG_G3];
9097c478bd9Sstevel@tonic-gate 	regs.r_g4 = kaif_cb_save.krs_gregs.kregs[KREG_G4];
9107c478bd9Sstevel@tonic-gate 	regs.r_g5 = kaif_cb_save.krs_gregs.kregs[KREG_G5];
9117c478bd9Sstevel@tonic-gate 	regs.r_g6 = kaif_cb_save.krs_gregs.kregs[KREG_G6];
9127c478bd9Sstevel@tonic-gate 	regs.r_g7 = kaif_cb_save.krs_gregs.kregs[KREG_G7];
9137c478bd9Sstevel@tonic-gate 
9147c478bd9Sstevel@tonic-gate 	regs.r_o0 = kaif_cb_save.krs_gregs.kregs[KREG_O0];
9157c478bd9Sstevel@tonic-gate 	regs.r_o1 = kaif_cb_save.krs_gregs.kregs[KREG_O1];
9167c478bd9Sstevel@tonic-gate 	regs.r_o2 = kaif_cb_save.krs_gregs.kregs[KREG_O2];
9177c478bd9Sstevel@tonic-gate 	regs.r_o3 = kaif_cb_save.krs_gregs.kregs[KREG_O3];
9187c478bd9Sstevel@tonic-gate 	regs.r_o4 = kaif_cb_save.krs_gregs.kregs[KREG_O4];
9197c478bd9Sstevel@tonic-gate 	regs.r_o5 = kaif_cb_save.krs_gregs.kregs[KREG_O5];
9207c478bd9Sstevel@tonic-gate 	regs.r_o6 = kaif_cb_save.krs_gregs.kregs[KREG_O6];
9217c478bd9Sstevel@tonic-gate 	regs.r_o7 = kaif_cb_save.krs_gregs.kregs[KREG_O7];
9227c478bd9Sstevel@tonic-gate 
9237c478bd9Sstevel@tonic-gate 	regs.r_pc = kaif_cb_save.krs_gregs.kregs[KREG_PC];
9247c478bd9Sstevel@tonic-gate 	regs.r_npc = kaif_cb_save.krs_gregs.kregs[KREG_NPC];
9257c478bd9Sstevel@tonic-gate 	regs.r_y = kaif_cb_save.krs_gregs.kregs[KREG_Y];
9267c478bd9Sstevel@tonic-gate 
9277c478bd9Sstevel@tonic-gate 	/*
9287c478bd9Sstevel@tonic-gate 	 * The %tba is, as ever, different.  We don't want the %tba from the
9297c478bd9Sstevel@tonic-gate 	 * time of the fault -- that'll be the debugger's.  We want the %tba
9307c478bd9Sstevel@tonic-gate 	 * saved when the debugger was initially entered.  It'll be saved in
9317c478bd9Sstevel@tonic-gate 	 * the cpusave area for the current CPU.
9327c478bd9Sstevel@tonic-gate 	 */
933*186d582bSSurya Prakki 	(void) set_tba((void *)kaif_cpusave[cpuid].krs_gregs.kregs[KREG_TBA]);
9347c478bd9Sstevel@tonic-gate 
9357c478bd9Sstevel@tonic-gate 	kmdb_kdi_kernpanic(&regs, kaif_cb_save.krs_gregs.kregs[KREG_TT]);
9367c478bd9Sstevel@tonic-gate }
9377c478bd9Sstevel@tonic-gate 
9387c478bd9Sstevel@tonic-gate static int
9397c478bd9Sstevel@tonic-gate kaif_init(kmdb_auxv_t *kav)
9407c478bd9Sstevel@tonic-gate {
9417c478bd9Sstevel@tonic-gate 	struct rwindow *rwins;
9427c478bd9Sstevel@tonic-gate 	int nwin = get_nwin();
9437c478bd9Sstevel@tonic-gate 	int i;
9447c478bd9Sstevel@tonic-gate 
9457c478bd9Sstevel@tonic-gate 	kaif_vwapt_addr = kaif_pwapt_addr = 0;
9467c478bd9Sstevel@tonic-gate 
9477c478bd9Sstevel@tonic-gate 	kaif_tba = kav->kav_tba_active;
9487c478bd9Sstevel@tonic-gate 	kaif_tba_obp = kav->kav_tba_obp;
9497c478bd9Sstevel@tonic-gate 	kaif_tba_native = kav->kav_tba_native;
9507c478bd9Sstevel@tonic-gate 	kaif_tba_native_sz = kav->kav_tba_native_sz;
9517c478bd9Sstevel@tonic-gate #ifdef	sun4v
9527c478bd9Sstevel@tonic-gate 	kaif_tba_kernel = kav->kav_tba_kernel;
9537c478bd9Sstevel@tonic-gate #endif
9547c478bd9Sstevel@tonic-gate 
9557c478bd9Sstevel@tonic-gate 	/* Allocate the per-CPU save areas */
9567c478bd9Sstevel@tonic-gate 	kaif_cpusave = mdb_zalloc(sizeof (kaif_cpusave_t) * kav->kav_ncpu,
9577c478bd9Sstevel@tonic-gate 	    UM_SLEEP);
9587c478bd9Sstevel@tonic-gate 	kaif_ncpusave = kav->kav_ncpu;
9597c478bd9Sstevel@tonic-gate 
9607c478bd9Sstevel@tonic-gate 	rwins = mdb_zalloc(sizeof (struct rwindow) * nwin * kav->kav_ncpu,
9617c478bd9Sstevel@tonic-gate 	    UM_SLEEP);
9627c478bd9Sstevel@tonic-gate 
9637c478bd9Sstevel@tonic-gate 	for (i = 0; i < kaif_ncpusave; i++) {
964acbc304dSjohnlev 		kaif_cpusave_t *save = &kaif_cpusave[i];
9657c478bd9Sstevel@tonic-gate 
966acbc304dSjohnlev 		save->krs_cpu_id = i;
967acbc304dSjohnlev 		save->krs_rwins = &rwins[nwin * i];
968acbc304dSjohnlev 		save->krs_curcrumbidx = KAIF_NCRUMBS - 1;
969acbc304dSjohnlev 		save->krs_curcrumb = &save->krs_crumbs[save->krs_curcrumbidx];
9707c478bd9Sstevel@tonic-gate 	}
9717c478bd9Sstevel@tonic-gate 
9727c478bd9Sstevel@tonic-gate 	kaif_dseg = kav->kav_dseg;
9737c478bd9Sstevel@tonic-gate 	kaif_dseg_lim = kav->kav_dseg + kav->kav_dseg_size;
9747c478bd9Sstevel@tonic-gate 
9757c478bd9Sstevel@tonic-gate 	kaif_promexitarmp = kav->kav_promexitarmp;
9767c478bd9Sstevel@tonic-gate 
9777c478bd9Sstevel@tonic-gate 	kaif_ktrap_install = kav->kav_ktrap_install;
9787c478bd9Sstevel@tonic-gate 	kaif_ktrap_restore = kav->kav_ktrap_restore;
9797c478bd9Sstevel@tonic-gate 
9807c478bd9Sstevel@tonic-gate 	kaif_modchg_cb = NULL;
9817c478bd9Sstevel@tonic-gate 
9827c478bd9Sstevel@tonic-gate 	kaif_trap_switch = (kav->kav_flags & KMDB_AUXV_FL_NOTRPSWTCH) == 0;
9837c478bd9Sstevel@tonic-gate 
9847c478bd9Sstevel@tonic-gate 	return (0);
9857c478bd9Sstevel@tonic-gate }
9867c478bd9Sstevel@tonic-gate 
9877c478bd9Sstevel@tonic-gate dpi_ops_t kmdb_dpi_ops = {
9887c478bd9Sstevel@tonic-gate 	kaif_init,
9897c478bd9Sstevel@tonic-gate 	kaif_activate,
9907c478bd9Sstevel@tonic-gate 	kaif_deactivate,
9917c478bd9Sstevel@tonic-gate 	kaif_enter_mon,
9927c478bd9Sstevel@tonic-gate 	kaif_modchg_register,
9937c478bd9Sstevel@tonic-gate 	kaif_modchg_cancel,
9947c478bd9Sstevel@tonic-gate 	kaif_get_cpu_state,
9957c478bd9Sstevel@tonic-gate 	kaif_get_master_cpuid,
9967c478bd9Sstevel@tonic-gate 	kaif_get_gregs,
997acbc304dSjohnlev 	kaif_get_register,
998acbc304dSjohnlev 	kaif_set_register,
9997c478bd9Sstevel@tonic-gate 	kaif_get_rwin,
10007c478bd9Sstevel@tonic-gate 	kaif_get_nwin,
10017c478bd9Sstevel@tonic-gate 	kaif_brkpt_arm,
10027c478bd9Sstevel@tonic-gate 	kaif_brkpt_disarm,
10037c478bd9Sstevel@tonic-gate 	kaif_wapt_validate,
10047c478bd9Sstevel@tonic-gate 	kaif_wapt_reserve,
10057c478bd9Sstevel@tonic-gate 	kaif_wapt_release,
10067c478bd9Sstevel@tonic-gate 	kaif_wapt_arm,
10077c478bd9Sstevel@tonic-gate 	kaif_wapt_disarm,
10087c478bd9Sstevel@tonic-gate 	kaif_wapt_match,
10097c478bd9Sstevel@tonic-gate 	kaif_step,
10107c478bd9Sstevel@tonic-gate 	kaif_call,
10117c478bd9Sstevel@tonic-gate 	kaif_dump_crumbs,
10127c478bd9Sstevel@tonic-gate 	kaif_kernpanic
10137c478bd9Sstevel@tonic-gate };
1014