xref: /onnv-gate/usr/src/cmd/mdb/sparc/kmdb/kaif.c (revision 0:68f95e015346)
1*0Sstevel@tonic-gate /*
2*0Sstevel@tonic-gate  * CDDL HEADER START
3*0Sstevel@tonic-gate  *
4*0Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5*0Sstevel@tonic-gate  * Common Development and Distribution License, Version 1.0 only
6*0Sstevel@tonic-gate  * (the "License").  You may not use this file except in compliance
7*0Sstevel@tonic-gate  * with the License.
8*0Sstevel@tonic-gate  *
9*0Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10*0Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
11*0Sstevel@tonic-gate  * See the License for the specific language governing permissions
12*0Sstevel@tonic-gate  * and limitations under the License.
13*0Sstevel@tonic-gate  *
14*0Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
15*0Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16*0Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
17*0Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
18*0Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
19*0Sstevel@tonic-gate  *
20*0Sstevel@tonic-gate  * CDDL HEADER END
21*0Sstevel@tonic-gate  */
22*0Sstevel@tonic-gate /*
23*0Sstevel@tonic-gate  * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
24*0Sstevel@tonic-gate  * Use is subject to license terms.
25*0Sstevel@tonic-gate  */
26*0Sstevel@tonic-gate 
27*0Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
28*0Sstevel@tonic-gate 
29*0Sstevel@tonic-gate /*
30*0Sstevel@tonic-gate  * The debugger/PROM interface
31*0Sstevel@tonic-gate  */
32*0Sstevel@tonic-gate 
33*0Sstevel@tonic-gate #include <sys/types.h>
34*0Sstevel@tonic-gate #include <sys/mmu.h>
35*0Sstevel@tonic-gate 
36*0Sstevel@tonic-gate #ifndef	sun4v
37*0Sstevel@tonic-gate #include <sys/spitregs.h>
38*0Sstevel@tonic-gate #endif	/* sun4v */
39*0Sstevel@tonic-gate 
40*0Sstevel@tonic-gate #include <sys/machasi.h>
41*0Sstevel@tonic-gate #include <sys/machtrap.h>
42*0Sstevel@tonic-gate #include <sys/trap.h>
43*0Sstevel@tonic-gate #include <sys/privregs.h>
44*0Sstevel@tonic-gate 
45*0Sstevel@tonic-gate #include <kmdb/kaif.h>
46*0Sstevel@tonic-gate #include <kmdb/kaif_regs.h>
47*0Sstevel@tonic-gate #include <kmdb/kmdb_asmutil.h>
48*0Sstevel@tonic-gate #include <kmdb/kmdb_kdi.h>
49*0Sstevel@tonic-gate #include <kmdb/kmdb_promif_isadep.h>
50*0Sstevel@tonic-gate #include <kmdb/kmdb_dpi_impl.h>
51*0Sstevel@tonic-gate #include <mdb/mdb_debug.h>
52*0Sstevel@tonic-gate #include <mdb/mdb_err.h>
53*0Sstevel@tonic-gate #include <mdb/mdb_modapi.h>
54*0Sstevel@tonic-gate #include <mdb/mdb_nv.h>
55*0Sstevel@tonic-gate #include <mdb/mdb_kreg_impl.h>
56*0Sstevel@tonic-gate #include <mdb/mdb_v9util.h>
57*0Sstevel@tonic-gate #include <mdb/mdb.h>
58*0Sstevel@tonic-gate 
59*0Sstevel@tonic-gate #define	KAIF_PREGNO_PSTATE	0x6		/* %pstate is priv reg 6 */
60*0Sstevel@tonic-gate #define	KAIF_BRKPT_INSTR	0x91d0207e	/* ta 0x7e */
61*0Sstevel@tonic-gate 
62*0Sstevel@tonic-gate 
63*0Sstevel@tonic-gate #define	OP(x)		((x) >> 30)
64*0Sstevel@tonic-gate #define	OP2(x)		(((x) >> 22) & 0x07)
65*0Sstevel@tonic-gate #define	OP3(x)		(((x) >> 19) & 0x3f)
66*0Sstevel@tonic-gate #define	COND(x)		(((x) >> 25) & 0x0f)
67*0Sstevel@tonic-gate #define	RD(x)		(((x) >> 25) & 0x1f)
68*0Sstevel@tonic-gate #define	RS1(x)		(((x) >> 14) & 0x1f)
69*0Sstevel@tonic-gate #define	RS2(x)		((x) & 0x1f)
70*0Sstevel@tonic-gate 
71*0Sstevel@tonic-gate #define	OP_BRANCH	0x0
72*0Sstevel@tonic-gate #define	OP_ARITH	0x2
73*0Sstevel@tonic-gate 
74*0Sstevel@tonic-gate #define	OP2_BPcc	0x1
75*0Sstevel@tonic-gate #define	OP2_Bicc	0x2
76*0Sstevel@tonic-gate #define	OP2_BPr		0x3
77*0Sstevel@tonic-gate #define	OP2_FBPfcc	0x5
78*0Sstevel@tonic-gate #define	OP2_FBfcc	0x6
79*0Sstevel@tonic-gate 
80*0Sstevel@tonic-gate #define	OP3_RDPR	0x2a
81*0Sstevel@tonic-gate #define	OP3_WRPR	0x32
82*0Sstevel@tonic-gate 
83*0Sstevel@tonic-gate #define	A(x)		(((x) >> 29) & 0x01)
84*0Sstevel@tonic-gate #define	I(x)		(((x) >> 13) & 0x01)
85*0Sstevel@tonic-gate #define	DISP16(x)	((((x) >> 6) & 0xc000) | ((x) & 0x3fff))
86*0Sstevel@tonic-gate #define	DISP22(x)	((x) & 0x3fffff)
87*0Sstevel@tonic-gate #define	DISP19(x)	((x) & 0x7ffff)
88*0Sstevel@tonic-gate #define	SIMM13(x)	((x) & 0x1fff)
89*0Sstevel@tonic-gate 
90*0Sstevel@tonic-gate static uint64_t		kaif_vwapt_addr;
91*0Sstevel@tonic-gate static uint64_t		kaif_pwapt_addr;
92*0Sstevel@tonic-gate 
93*0Sstevel@tonic-gate #ifndef	sun4v
94*0Sstevel@tonic-gate static uint64_t		kaif_lsuctl;
95*0Sstevel@tonic-gate #endif	/* sun4v */
96*0Sstevel@tonic-gate 
97*0Sstevel@tonic-gate kaif_cpusave_t		*kaif_cpusave;
98*0Sstevel@tonic-gate int			kaif_ncpusave;
99*0Sstevel@tonic-gate caddr_t			kaif_dseg;
100*0Sstevel@tonic-gate caddr_t			kaif_dseg_lim;
101*0Sstevel@tonic-gate caddr_t			kaif_tba;		/* table currently in use */
102*0Sstevel@tonic-gate caddr_t			kaif_tba_obp;		/* obp's trap table */
103*0Sstevel@tonic-gate caddr_t			kaif_tba_native;	/* our table; needs khat */
104*0Sstevel@tonic-gate #ifdef	sun4v
105*0Sstevel@tonic-gate caddr_t			kaif_tba_kernel;	/* kernel's trap table */
106*0Sstevel@tonic-gate #endif	/* sun4v */
107*0Sstevel@tonic-gate size_t			kaif_tba_native_sz;
108*0Sstevel@tonic-gate int			*kaif_promexitarmp;
109*0Sstevel@tonic-gate int			kaif_trap_switch;
110*0Sstevel@tonic-gate 
111*0Sstevel@tonic-gate void (*kaif_modchg_cb)(struct modctl *, int);
112*0Sstevel@tonic-gate void (*kaif_ktrap_install)(int, void (*)(void));
113*0Sstevel@tonic-gate void (*kaif_ktrap_restore)(void);
114*0Sstevel@tonic-gate 
115*0Sstevel@tonic-gate static int
116*0Sstevel@tonic-gate kaif_get_master_cpuid(void)
117*0Sstevel@tonic-gate {
118*0Sstevel@tonic-gate 	return (kaif_master_cpuid);
119*0Sstevel@tonic-gate }
120*0Sstevel@tonic-gate 
121*0Sstevel@tonic-gate /*ARGSUSED*/
122*0Sstevel@tonic-gate static int
123*0Sstevel@tonic-gate kaif_get_nwin(int cpuid)
124*0Sstevel@tonic-gate {
125*0Sstevel@tonic-gate 	return (get_nwin());
126*0Sstevel@tonic-gate }
127*0Sstevel@tonic-gate 
128*0Sstevel@tonic-gate static int
129*0Sstevel@tonic-gate kaif_get_cpu_state(int cpuid)
130*0Sstevel@tonic-gate {
131*0Sstevel@tonic-gate 	if (cpuid == DPI_MASTER_CPUID)
132*0Sstevel@tonic-gate 		return (DPI_CPU_STATE_MASTER);
133*0Sstevel@tonic-gate 
134*0Sstevel@tonic-gate 	if (cpuid < 0 || cpuid >= kaif_ncpusave)
135*0Sstevel@tonic-gate 		return (set_errno(EINVAL));
136*0Sstevel@tonic-gate 
137*0Sstevel@tonic-gate 	switch (kaif_cpusave[cpuid].krs_cpu_state) {
138*0Sstevel@tonic-gate 	case KAIF_CPU_STATE_MASTER:
139*0Sstevel@tonic-gate 		return (DPI_CPU_STATE_MASTER);
140*0Sstevel@tonic-gate 	case KAIF_CPU_STATE_SLAVE:
141*0Sstevel@tonic-gate 		return (DPI_CPU_STATE_SLAVE);
142*0Sstevel@tonic-gate 	default:
143*0Sstevel@tonic-gate 		return (set_errno(EINVAL));
144*0Sstevel@tonic-gate 	}
145*0Sstevel@tonic-gate }
146*0Sstevel@tonic-gate 
147*0Sstevel@tonic-gate static const mdb_tgt_gregset_t *
148*0Sstevel@tonic-gate kaif_get_gregs(int cpuid)
149*0Sstevel@tonic-gate {
150*0Sstevel@tonic-gate 	kaif_cpusave_t *cpusave;
151*0Sstevel@tonic-gate 	mdb_tgt_gregset_t *gregs;
152*0Sstevel@tonic-gate 	int wp, i;
153*0Sstevel@tonic-gate 
154*0Sstevel@tonic-gate 	if (cpuid == DPI_MASTER_CPUID)
155*0Sstevel@tonic-gate 		cpuid = kaif_master_cpuid;
156*0Sstevel@tonic-gate 
157*0Sstevel@tonic-gate 	if (cpuid < 0 || cpuid >= kaif_ncpusave) {
158*0Sstevel@tonic-gate 		(void) set_errno(EINVAL);
159*0Sstevel@tonic-gate 		return (NULL);
160*0Sstevel@tonic-gate 	}
161*0Sstevel@tonic-gate 
162*0Sstevel@tonic-gate 	cpusave = &kaif_cpusave[cpuid];
163*0Sstevel@tonic-gate 	gregs = &cpusave->krs_gregs;
164*0Sstevel@tonic-gate 
165*0Sstevel@tonic-gate 	/*
166*0Sstevel@tonic-gate 	 * The DPI startup routine populates the register window portions of
167*0Sstevel@tonic-gate 	 * the kaif_cpusave_t.  We copy the current set of ins, outs, and
168*0Sstevel@tonic-gate 	 * locals to the gregs.  We also extract %pstate from %tstate.
169*0Sstevel@tonic-gate 	 */
170*0Sstevel@tonic-gate 	wp = gregs->kregs[KREG_CWP];
171*0Sstevel@tonic-gate 	for (i = 0; i < 8; i++) {
172*0Sstevel@tonic-gate 		gregs->kregs[KREG_L0 + i] = cpusave->krs_rwins[wp].rw_local[i];
173*0Sstevel@tonic-gate 		gregs->kregs[KREG_I0 + i] = cpusave->krs_rwins[wp].rw_in[i];
174*0Sstevel@tonic-gate 	}
175*0Sstevel@tonic-gate 
176*0Sstevel@tonic-gate 	gregs->kregs[KREG_PSTATE] = KREG_TSTATE_PSTATE(cpusave->krs_tstate);
177*0Sstevel@tonic-gate 
178*0Sstevel@tonic-gate 	if (++wp == kaif_get_nwin(cpuid))
179*0Sstevel@tonic-gate 		wp = 0;
180*0Sstevel@tonic-gate 
181*0Sstevel@tonic-gate 	for (i = 0; i < 8; i++)
182*0Sstevel@tonic-gate 		gregs->kregs[KREG_O0 + i] = cpusave->krs_rwins[wp].rw_in[i];
183*0Sstevel@tonic-gate 
184*0Sstevel@tonic-gate 	return (gregs);
185*0Sstevel@tonic-gate }
186*0Sstevel@tonic-gate 
187*0Sstevel@tonic-gate static kreg_t *
188*0Sstevel@tonic-gate kaif_find_regp(int cpuid, int win, const char *regname)
189*0Sstevel@tonic-gate {
190*0Sstevel@tonic-gate 	kaif_cpusave_t *cpusave;
191*0Sstevel@tonic-gate 	mdb_tgt_gregset_t *gregs;
192*0Sstevel@tonic-gate 	int nwin, i;
193*0Sstevel@tonic-gate 
194*0Sstevel@tonic-gate 	ASSERT(cpuid != DPI_MASTER_CPUID);
195*0Sstevel@tonic-gate 
196*0Sstevel@tonic-gate 	if (cpuid < 0 || cpuid >= kaif_ncpusave) {
197*0Sstevel@tonic-gate 		(void) set_errno(EINVAL);
198*0Sstevel@tonic-gate 		return (NULL);
199*0Sstevel@tonic-gate 	}
200*0Sstevel@tonic-gate 
201*0Sstevel@tonic-gate 	nwin = kaif_get_nwin(cpuid);
202*0Sstevel@tonic-gate 
203*0Sstevel@tonic-gate 	if (win < -1 || win >= nwin) {
204*0Sstevel@tonic-gate 		(void) set_errno(EINVAL);
205*0Sstevel@tonic-gate 		return (NULL);
206*0Sstevel@tonic-gate 	}
207*0Sstevel@tonic-gate 
208*0Sstevel@tonic-gate 	cpusave = &kaif_cpusave[cpuid];
209*0Sstevel@tonic-gate 	gregs = &cpusave->krs_gregs;
210*0Sstevel@tonic-gate 
211*0Sstevel@tonic-gate 	if (win == DPI_TOP_WINDOW)
212*0Sstevel@tonic-gate 		win = gregs->kregs[KREG_CWP];
213*0Sstevel@tonic-gate 
214*0Sstevel@tonic-gate 	if (strcmp(regname, "sp") == 0)
215*0Sstevel@tonic-gate 		regname = "o6";
216*0Sstevel@tonic-gate 	else if (strcmp(regname, "fp") == 0)
217*0Sstevel@tonic-gate 		regname = "i6";
218*0Sstevel@tonic-gate 
219*0Sstevel@tonic-gate 	if (strlen(regname) == 2 && regname[1] >= '0' && regname[1] <= '7') {
220*0Sstevel@tonic-gate 		int idx = regname[1] - '0';
221*0Sstevel@tonic-gate 
222*0Sstevel@tonic-gate 		switch (regname[0]) {
223*0Sstevel@tonic-gate 		case 'o':
224*0Sstevel@tonic-gate 			if (++win == nwin)
225*0Sstevel@tonic-gate 				win = 0;
226*0Sstevel@tonic-gate 			/*FALLTHROUGH*/
227*0Sstevel@tonic-gate 		case 'i':
228*0Sstevel@tonic-gate 			return ((kreg_t *)&cpusave->krs_rwins[win].rw_in[idx]);
229*0Sstevel@tonic-gate 		case 'l':
230*0Sstevel@tonic-gate 			return ((kreg_t *)
231*0Sstevel@tonic-gate 			    &cpusave->krs_rwins[win].rw_local[idx]);
232*0Sstevel@tonic-gate 		}
233*0Sstevel@tonic-gate 	}
234*0Sstevel@tonic-gate 
235*0Sstevel@tonic-gate 	for (i = 0; mdb_sparcv9_kregs[i].rd_name != NULL; i++) {
236*0Sstevel@tonic-gate 		const mdb_tgt_regdesc_t *rd = &mdb_sparcv9_kregs[i];
237*0Sstevel@tonic-gate 
238*0Sstevel@tonic-gate 		if (strcmp(rd->rd_name, regname) == 0)
239*0Sstevel@tonic-gate 			return (&gregs->kregs[rd->rd_num]);
240*0Sstevel@tonic-gate 	}
241*0Sstevel@tonic-gate 
242*0Sstevel@tonic-gate 	(void) set_errno(ENOENT);
243*0Sstevel@tonic-gate 	return (NULL);
244*0Sstevel@tonic-gate }
245*0Sstevel@tonic-gate 
246*0Sstevel@tonic-gate static int
247*0Sstevel@tonic-gate kaif_get_cpu_register(int cpuid, int win, const char *regname, kreg_t *valp)
248*0Sstevel@tonic-gate {
249*0Sstevel@tonic-gate 	kreg_t *regp;
250*0Sstevel@tonic-gate 
251*0Sstevel@tonic-gate 	if (cpuid == DPI_MASTER_CPUID)
252*0Sstevel@tonic-gate 		cpuid = kaif_master_cpuid;
253*0Sstevel@tonic-gate 
254*0Sstevel@tonic-gate 	if (cpuid < 0 || cpuid >= kaif_ncpusave)
255*0Sstevel@tonic-gate 		return (set_errno(EINVAL));
256*0Sstevel@tonic-gate 
257*0Sstevel@tonic-gate 	if (strcmp(regname, "pstate") == 0) {
258*0Sstevel@tonic-gate 		*valp = KREG_TSTATE_PSTATE(kaif_cpusave[cpuid].krs_tstate);
259*0Sstevel@tonic-gate 		return (0);
260*0Sstevel@tonic-gate 	}
261*0Sstevel@tonic-gate 
262*0Sstevel@tonic-gate 	if ((regp = kaif_find_regp(cpuid, win, regname)) == NULL)
263*0Sstevel@tonic-gate 		return (-1);
264*0Sstevel@tonic-gate 
265*0Sstevel@tonic-gate 	*valp = *regp;
266*0Sstevel@tonic-gate 
267*0Sstevel@tonic-gate 	return (0);
268*0Sstevel@tonic-gate }
269*0Sstevel@tonic-gate 
270*0Sstevel@tonic-gate static int
271*0Sstevel@tonic-gate kaif_set_cpu_register(int cpuid, int win, const char *regname, kreg_t val)
272*0Sstevel@tonic-gate {
273*0Sstevel@tonic-gate 	kreg_t *regp;
274*0Sstevel@tonic-gate 
275*0Sstevel@tonic-gate 	if (cpuid == DPI_MASTER_CPUID)
276*0Sstevel@tonic-gate 		cpuid = kaif_master_cpuid;
277*0Sstevel@tonic-gate 
278*0Sstevel@tonic-gate 	if (cpuid < 0 || cpuid >= kaif_ncpusave)
279*0Sstevel@tonic-gate 		return (set_errno(EINVAL));
280*0Sstevel@tonic-gate 
281*0Sstevel@tonic-gate 	if (strcmp(regname, "g0") == 0) {
282*0Sstevel@tonic-gate 		return (0);
283*0Sstevel@tonic-gate 
284*0Sstevel@tonic-gate 	} else if (strcmp(regname, "pstate") == 0) {
285*0Sstevel@tonic-gate 		kaif_cpusave[cpuid].krs_tstate &= ~KREG_TSTATE_PSTATE_MASK;
286*0Sstevel@tonic-gate 		kaif_cpusave[cpuid].krs_tstate |=
287*0Sstevel@tonic-gate 		    (val & KREG_PSTATE_MASK) << KREG_TSTATE_PSTATE_SHIFT;
288*0Sstevel@tonic-gate 		return (0);
289*0Sstevel@tonic-gate 	}
290*0Sstevel@tonic-gate 
291*0Sstevel@tonic-gate 	if ((regp = kaif_find_regp(cpuid, win, regname)) == NULL)
292*0Sstevel@tonic-gate 		return (-1);
293*0Sstevel@tonic-gate 
294*0Sstevel@tonic-gate 	*regp = val;
295*0Sstevel@tonic-gate 
296*0Sstevel@tonic-gate 	return (0);
297*0Sstevel@tonic-gate }
298*0Sstevel@tonic-gate 
299*0Sstevel@tonic-gate static int
300*0Sstevel@tonic-gate kaif_brkpt_arm(uintptr_t addr, mdb_instr_t *instrp)
301*0Sstevel@tonic-gate {
302*0Sstevel@tonic-gate 	mdb_instr_t bkpt = KAIF_BRKPT_INSTR;
303*0Sstevel@tonic-gate 
304*0Sstevel@tonic-gate 	if (mdb_tgt_vread(mdb.m_target, instrp, sizeof (mdb_instr_t), addr) !=
305*0Sstevel@tonic-gate 	    sizeof (mdb_instr_t))
306*0Sstevel@tonic-gate 		return (-1); /* errno is set for us */
307*0Sstevel@tonic-gate 
308*0Sstevel@tonic-gate 	if (mdb_tgt_vwrite(mdb.m_target, &bkpt, sizeof (mdb_instr_t), addr) !=
309*0Sstevel@tonic-gate 	    sizeof (mdb_instr_t))
310*0Sstevel@tonic-gate 		return (-1); /* errno is set for us */
311*0Sstevel@tonic-gate 
312*0Sstevel@tonic-gate 	return (0);
313*0Sstevel@tonic-gate }
314*0Sstevel@tonic-gate 
315*0Sstevel@tonic-gate static int
316*0Sstevel@tonic-gate kaif_brkpt_disarm(uintptr_t addr, mdb_instr_t instrp)
317*0Sstevel@tonic-gate {
318*0Sstevel@tonic-gate 	if (mdb_tgt_vwrite(mdb.m_target, &instrp, sizeof (mdb_instr_t), addr) !=
319*0Sstevel@tonic-gate 	    sizeof (mdb_instr_t))
320*0Sstevel@tonic-gate 		return (-1); /* errno is set for us */
321*0Sstevel@tonic-gate 
322*0Sstevel@tonic-gate 	return (0);
323*0Sstevel@tonic-gate }
324*0Sstevel@tonic-gate 
325*0Sstevel@tonic-gate /*
326*0Sstevel@tonic-gate  * Calculate the watchpoint mask byte (VM or PM, as appropriate).  A 1 bit in
327*0Sstevel@tonic-gate  * the mask indicates that the corresponding byte in the watchpoint address
328*0Sstevel@tonic-gate  * should be used for activation comparison.
329*0Sstevel@tonic-gate  */
330*0Sstevel@tonic-gate /*
331*0Sstevel@tonic-gate  * Sun4v dosen't have watchpoint regs
332*0Sstevel@tonic-gate  */
333*0Sstevel@tonic-gate #ifndef	sun4v
334*0Sstevel@tonic-gate static uchar_t
335*0Sstevel@tonic-gate kaif_wapt_calc_mask(size_t len)
336*0Sstevel@tonic-gate {
337*0Sstevel@tonic-gate 	int pow;
338*0Sstevel@tonic-gate 
339*0Sstevel@tonic-gate 	if (len == 8)
340*0Sstevel@tonic-gate 		return (0xff);
341*0Sstevel@tonic-gate 
342*0Sstevel@tonic-gate 	for (pow = 0; len > 1; len /= 256, pow++);
343*0Sstevel@tonic-gate 
344*0Sstevel@tonic-gate 	return (~((1 << pow) - 1));
345*0Sstevel@tonic-gate }
346*0Sstevel@tonic-gate #endif
347*0Sstevel@tonic-gate 
348*0Sstevel@tonic-gate /*
349*0Sstevel@tonic-gate  * UltraSPARC processors have one physical and one virtual watchpoint.  These
350*0Sstevel@tonic-gate  * watchpoints are specified by setting the address in a register, and by
351*0Sstevel@tonic-gate  * setting a selector byte in another register to determine which bytes of the
352*0Sstevel@tonic-gate  * address are to be used for comparison.  For simplicity, we only support
353*0Sstevel@tonic-gate  * selector byte values whose bit patterns match the regexp "1+0*".  Watchpoint
354*0Sstevel@tonic-gate  * addresses must be 8-byte aligned on these chips, so a selector byte of 0xff
355*0Sstevel@tonic-gate  * indicates an 8-byte watchpoint.  Successive valid sizes are powers of 256,
356*0Sstevel@tonic-gate  * starting with 256.
357*0Sstevel@tonic-gate  */
358*0Sstevel@tonic-gate static int
359*0Sstevel@tonic-gate kaif_wapt_validate(kmdb_wapt_t *wp)
360*0Sstevel@tonic-gate {
361*0Sstevel@tonic-gate 	if (wp->wp_wflags & MDB_TGT_WA_X) {
362*0Sstevel@tonic-gate 		warn("execute watchpoints are not supported on this "
363*0Sstevel@tonic-gate 		    "platform\n");
364*0Sstevel@tonic-gate 		return (set_errno(EMDB_TGTNOTSUP));
365*0Sstevel@tonic-gate 	}
366*0Sstevel@tonic-gate 
367*0Sstevel@tonic-gate 	if (wp->wp_size % 0xff != 0 && wp->wp_size != 8) {
368*0Sstevel@tonic-gate 		warn("watchpoint size must be 8 or a power of 256 bytes\n");
369*0Sstevel@tonic-gate 		return (set_errno(EINVAL));
370*0Sstevel@tonic-gate 	}
371*0Sstevel@tonic-gate 
372*0Sstevel@tonic-gate 	if (wp->wp_addr & (wp->wp_size - 1)) {
373*0Sstevel@tonic-gate 		warn("%lu-byte watchpoints must be %lu-byte aligned\n",
374*0Sstevel@tonic-gate 		    wp->wp_size, wp->wp_size);
375*0Sstevel@tonic-gate 		return (set_errno(EINVAL));
376*0Sstevel@tonic-gate 	}
377*0Sstevel@tonic-gate 
378*0Sstevel@tonic-gate 	if (wp->wp_type != DPI_WAPT_TYPE_PHYS &&
379*0Sstevel@tonic-gate 	    wp->wp_type != DPI_WAPT_TYPE_VIRT) {
380*0Sstevel@tonic-gate 		warn("requested watchpoint type not supported on this "
381*0Sstevel@tonic-gate 		    "platform\n");
382*0Sstevel@tonic-gate 		return (set_errno(EMDB_TGTHWNOTSUP));
383*0Sstevel@tonic-gate 	}
384*0Sstevel@tonic-gate 
385*0Sstevel@tonic-gate 	return (0);
386*0Sstevel@tonic-gate }
387*0Sstevel@tonic-gate 
388*0Sstevel@tonic-gate static int
389*0Sstevel@tonic-gate kaif_wapt_reserve(kmdb_wapt_t *wp)
390*0Sstevel@tonic-gate {
391*0Sstevel@tonic-gate #ifdef	sun4v
392*0Sstevel@tonic-gate #ifdef	lint
393*0Sstevel@tonic-gate 	ASSERT(wp == (kmdb_wapt_t *)wp);
394*0Sstevel@tonic-gate #endif	/* !lint */
395*0Sstevel@tonic-gate 	/* Watchpoints not supported */
396*0Sstevel@tonic-gate 	return (set_errno(EMDB_TGTHWNOTSUP));
397*0Sstevel@tonic-gate #else
398*0Sstevel@tonic-gate 	uint64_t *addrp;
399*0Sstevel@tonic-gate 
400*0Sstevel@tonic-gate 	if (wp->wp_type == DPI_WAPT_TYPE_PHYS)
401*0Sstevel@tonic-gate 		addrp = &kaif_pwapt_addr;
402*0Sstevel@tonic-gate 	else
403*0Sstevel@tonic-gate 		addrp = &kaif_vwapt_addr;
404*0Sstevel@tonic-gate 
405*0Sstevel@tonic-gate 	if (*addrp != NULL)
406*0Sstevel@tonic-gate 		return (set_errno(EMDB_WPTOOMANY));
407*0Sstevel@tonic-gate 
408*0Sstevel@tonic-gate 	*addrp = wp->wp_addr;
409*0Sstevel@tonic-gate 
410*0Sstevel@tonic-gate 	return (0);
411*0Sstevel@tonic-gate #endif
412*0Sstevel@tonic-gate }
413*0Sstevel@tonic-gate 
414*0Sstevel@tonic-gate static void
415*0Sstevel@tonic-gate kaif_wapt_release(kmdb_wapt_t *wp)
416*0Sstevel@tonic-gate {
417*0Sstevel@tonic-gate 	uint64_t *addrp = (wp->wp_type == DPI_WAPT_TYPE_PHYS ?
418*0Sstevel@tonic-gate 	    &kaif_pwapt_addr : &kaif_vwapt_addr);
419*0Sstevel@tonic-gate 
420*0Sstevel@tonic-gate 	ASSERT(*addrp != NULL);
421*0Sstevel@tonic-gate 	*addrp = NULL;
422*0Sstevel@tonic-gate }
423*0Sstevel@tonic-gate 
424*0Sstevel@tonic-gate /*ARGSUSED*/
425*0Sstevel@tonic-gate static void
426*0Sstevel@tonic-gate kaif_wapt_arm(kmdb_wapt_t *wp)
427*0Sstevel@tonic-gate {
428*0Sstevel@tonic-gate 	/*
429*0Sstevel@tonic-gate 	 * Sun4v dosen't have watch point regs
430*0Sstevel@tonic-gate 	 */
431*0Sstevel@tonic-gate #ifndef	sun4v
432*0Sstevel@tonic-gate 	uint64_t mask = kaif_wapt_calc_mask(wp->wp_size);
433*0Sstevel@tonic-gate 
434*0Sstevel@tonic-gate 	if (wp->wp_type == DPI_WAPT_TYPE_PHYS) {
435*0Sstevel@tonic-gate 		kaif_lsuctl &= ~KAIF_LSUCTL_PWAPT_MASK;
436*0Sstevel@tonic-gate 
437*0Sstevel@tonic-gate 		if (wp->wp_wflags & MDB_TGT_WA_R)
438*0Sstevel@tonic-gate 			kaif_lsuctl |= LSU_PR;
439*0Sstevel@tonic-gate 		if (wp->wp_wflags & MDB_TGT_WA_W)
440*0Sstevel@tonic-gate 			kaif_lsuctl |= LSU_PW;
441*0Sstevel@tonic-gate 		kaif_lsuctl |= ((mask << LSU_PM_SHIFT) & LSU_PM);
442*0Sstevel@tonic-gate 
443*0Sstevel@tonic-gate 	} else if (wp->wp_type == DPI_WAPT_TYPE_VIRT) {
444*0Sstevel@tonic-gate 		kaif_lsuctl &= ~KAIF_LSUCTL_VWAPT_MASK;
445*0Sstevel@tonic-gate 
446*0Sstevel@tonic-gate 		if (wp->wp_wflags & MDB_TGT_WA_R)
447*0Sstevel@tonic-gate 			kaif_lsuctl |= LSU_VR;
448*0Sstevel@tonic-gate 		if (wp->wp_wflags & MDB_TGT_WA_W)
449*0Sstevel@tonic-gate 			kaif_lsuctl |= LSU_VW;
450*0Sstevel@tonic-gate 		kaif_lsuctl |= ((mask << LSU_VM_SHIFT) & LSU_VM);
451*0Sstevel@tonic-gate 	}
452*0Sstevel@tonic-gate #endif	/* sun4v */
453*0Sstevel@tonic-gate }
454*0Sstevel@tonic-gate 
455*0Sstevel@tonic-gate /*ARGSUSED*/
456*0Sstevel@tonic-gate static void
457*0Sstevel@tonic-gate kaif_wapt_disarm(kmdb_wapt_t *wp)
458*0Sstevel@tonic-gate {
459*0Sstevel@tonic-gate 	/*
460*0Sstevel@tonic-gate 	 * Sun4v dosen't have watch point regs
461*0Sstevel@tonic-gate 	 */
462*0Sstevel@tonic-gate #ifndef	sun4v
463*0Sstevel@tonic-gate 	if (wp->wp_type == DPI_WAPT_TYPE_PHYS) {
464*0Sstevel@tonic-gate 		ASSERT(kaif_pwapt_addr != NULL);
465*0Sstevel@tonic-gate 		kaif_lsuctl &= ~(LSU_PR|LSU_PW);
466*0Sstevel@tonic-gate 	} else {
467*0Sstevel@tonic-gate 		ASSERT(kaif_vwapt_addr != NULL);
468*0Sstevel@tonic-gate 		kaif_lsuctl &= ~(LSU_VR|LSU_VW);
469*0Sstevel@tonic-gate 	}
470*0Sstevel@tonic-gate #endif
471*0Sstevel@tonic-gate }
472*0Sstevel@tonic-gate 
473*0Sstevel@tonic-gate /*
474*0Sstevel@tonic-gate  * `kaif_wapt_arm' and `kaif_wapt_disarm' modify the global state we keep that
475*0Sstevel@tonic-gate  * indicates what the values of the wapt control registers should be.  These
476*0Sstevel@tonic-gate  * values must be individually set and cleared on each active CPU, a task which
477*0Sstevel@tonic-gate  * is performed by `kaif_wapt_clear_regs' and `kaif_wapt_set_regs', invoked as
478*0Sstevel@tonic-gate  * the world is stopped and resumed, respectively.  `kaif_wapt_set_regs' is also
479*0Sstevel@tonic-gate  * used for CPU initialization.
480*0Sstevel@tonic-gate  */
481*0Sstevel@tonic-gate void
482*0Sstevel@tonic-gate kaif_wapt_set_regs(void)
483*0Sstevel@tonic-gate {
484*0Sstevel@tonic-gate 	/*
485*0Sstevel@tonic-gate 	 * Sun4v dosen't have watch point regs
486*0Sstevel@tonic-gate 	 */
487*0Sstevel@tonic-gate #ifndef sun4v
488*0Sstevel@tonic-gate 	uint64_t lsu;
489*0Sstevel@tonic-gate 
490*0Sstevel@tonic-gate 	wrasi(ASI_DMMU, MMU_VAW, kaif_vwapt_addr);
491*0Sstevel@tonic-gate 	wrasi(ASI_DMMU, MMU_PAW, kaif_pwapt_addr);
492*0Sstevel@tonic-gate 
493*0Sstevel@tonic-gate 	ASSERT((kaif_lsuctl & ~KAIF_LSUCTL_WAPT_MASK) == NULL);
494*0Sstevel@tonic-gate 
495*0Sstevel@tonic-gate 	lsu = rdasi(ASI_LSU, NULL);
496*0Sstevel@tonic-gate 	lsu &= ~KAIF_LSUCTL_WAPT_MASK;
497*0Sstevel@tonic-gate 	lsu |= kaif_lsuctl;
498*0Sstevel@tonic-gate 	wrasi(ASI_LSU, NULL, lsu);
499*0Sstevel@tonic-gate #endif /* sun4v */
500*0Sstevel@tonic-gate }
501*0Sstevel@tonic-gate 
502*0Sstevel@tonic-gate void
503*0Sstevel@tonic-gate kaif_wapt_clear_regs(void)
504*0Sstevel@tonic-gate {
505*0Sstevel@tonic-gate 	/*
506*0Sstevel@tonic-gate 	 * Sun4v dosen't have watch point regs
507*0Sstevel@tonic-gate 	 */
508*0Sstevel@tonic-gate #ifndef sun4v
509*0Sstevel@tonic-gate 	uint64_t lsu = rdasi(ASI_LSU, NULL);
510*0Sstevel@tonic-gate 	lsu &= ~KAIF_LSUCTL_WAPT_MASK;
511*0Sstevel@tonic-gate 	wrasi(ASI_LSU, NULL, lsu);
512*0Sstevel@tonic-gate #endif /* sun4v */
513*0Sstevel@tonic-gate }
514*0Sstevel@tonic-gate 
515*0Sstevel@tonic-gate /*
516*0Sstevel@tonic-gate  * UltraSPARC has one PA watchpoint and one VA watchpoint.  The trap we get will
517*0Sstevel@tonic-gate  * tell us which one we hit, but it won't tell us where.  We could attempt to
518*0Sstevel@tonic-gate  * dissect the instruction at %pc to see where it was reading from or writing
519*0Sstevel@tonic-gate  * to, but that gets messy in a hurry.  We can, however, make a couple of
520*0Sstevel@tonic-gate  * assumptions:
521*0Sstevel@tonic-gate  *
522*0Sstevel@tonic-gate  * - kaif_set_watchpoint and kaif_delete_watchpoint will enforce the limits as
523*0Sstevel@tonic-gate  *   to the number of watch points.  As such, at most one VA watchpoint and one
524*0Sstevel@tonic-gate  *   PA watchpoint will be on the active list.
525*0Sstevel@tonic-gate  *
526*0Sstevel@tonic-gate  * - We'll only be called on watchpoints that are on the active list.
527*0Sstevel@tonic-gate  *
528*0Sstevel@tonic-gate  * Taking these two assumptions, we can conclude that, if we're stopped due to
529*0Sstevel@tonic-gate  * a watchpoint and we're asked to match against a watchpoint, we must have
530*0Sstevel@tonic-gate  * stopped due to the watchpoint.  This is all very terrifying, but the
531*0Sstevel@tonic-gate  * alternative (taking instructions apart) is worse.
532*0Sstevel@tonic-gate  */
533*0Sstevel@tonic-gate /*ARGSUSED*/
534*0Sstevel@tonic-gate static int
535*0Sstevel@tonic-gate kaif_wapt_match(kmdb_wapt_t *wp)
536*0Sstevel@tonic-gate {
537*0Sstevel@tonic-gate 	int state, why, deswhy;
538*0Sstevel@tonic-gate 
539*0Sstevel@tonic-gate 	state = kmdb_dpi_get_state(&why);
540*0Sstevel@tonic-gate 
541*0Sstevel@tonic-gate 	if (wp->wp_type == DPI_WAPT_TYPE_PHYS)
542*0Sstevel@tonic-gate 		deswhy = DPI_STATE_WHY_P_WAPT;
543*0Sstevel@tonic-gate 	else
544*0Sstevel@tonic-gate 		deswhy = DPI_STATE_WHY_V_WAPT;
545*0Sstevel@tonic-gate 
546*0Sstevel@tonic-gate 	return (state == DPI_STATE_FAULTED && why == deswhy);
547*0Sstevel@tonic-gate }
548*0Sstevel@tonic-gate 
549*0Sstevel@tonic-gate static const char *
550*0Sstevel@tonic-gate regno2name(int idx)
551*0Sstevel@tonic-gate {
552*0Sstevel@tonic-gate 	const mdb_tgt_regdesc_t *rd;
553*0Sstevel@tonic-gate 
554*0Sstevel@tonic-gate 	for (rd = mdb_sparcv9_kregs; rd->rd_name != NULL; rd++) {
555*0Sstevel@tonic-gate 		if (idx == rd->rd_num)
556*0Sstevel@tonic-gate 			return (rd->rd_name);
557*0Sstevel@tonic-gate 	}
558*0Sstevel@tonic-gate 
559*0Sstevel@tonic-gate 	ASSERT(rd->rd_name != NULL);
560*0Sstevel@tonic-gate 
561*0Sstevel@tonic-gate 	return ("unknown");
562*0Sstevel@tonic-gate }
563*0Sstevel@tonic-gate 
564*0Sstevel@tonic-gate /*
565*0Sstevel@tonic-gate  * UltraSPARC doesn't support single-step natively, so we have to do it
566*0Sstevel@tonic-gate  * ourselves, by placing breakpoints at the instruction after the current one.
567*0Sstevel@tonic-gate  * Note that "after" will be %npc in the simple case, but can be one of
568*0Sstevel@tonic-gate  * several places if %pc is a branch.
569*0Sstevel@tonic-gate  *
570*0Sstevel@tonic-gate  * If %pc is an unconditional annulled branch, we put a breakpoint at the branch
571*0Sstevel@tonic-gate  * target.  If it is a conditional annulled branch, we put breakpoints at %pc +
572*0Sstevel@tonic-gate  * 8 and the branch target.  For all other branches, %npc will be set correctly
573*0Sstevel@tonic-gate  * as determined by the branch condition, and thus we can step through the
574*0Sstevel@tonic-gate  * branch by putting a breakpoint at %npc.  If %pc contains a non-branch
575*0Sstevel@tonic-gate  * instruction (with the exception of certain rdpr and wrpr instructions,
576*0Sstevel@tonic-gate  * described more below), we step over it by placing a breakpoint at %npc.
577*0Sstevel@tonic-gate  */
578*0Sstevel@tonic-gate static int
579*0Sstevel@tonic-gate kaif_step(void)
580*0Sstevel@tonic-gate {
581*0Sstevel@tonic-gate 	kreg_t pc, npc, brtgt, pstate, tt;
582*0Sstevel@tonic-gate 	int bptgt = 0, bpnpc = 0, bppc8 = 0;
583*0Sstevel@tonic-gate 	mdb_instr_t svtgt = 0, svnpc = 0, svpc8 = 0;
584*0Sstevel@tonic-gate 	mdb_instr_t instr;
585*0Sstevel@tonic-gate 	int ie, err;
586*0Sstevel@tonic-gate 
587*0Sstevel@tonic-gate 	(void) kmdb_dpi_get_register("pc", &pc);
588*0Sstevel@tonic-gate 	(void) kmdb_dpi_get_register("npc", &npc);
589*0Sstevel@tonic-gate 
590*0Sstevel@tonic-gate 	if (mdb_tgt_vread(mdb.m_target, &instr, sizeof (instr), pc) !=
591*0Sstevel@tonic-gate 	    sizeof (instr)) {
592*0Sstevel@tonic-gate 		warn("failed to read %%pc at %p for step", (void *)pc);
593*0Sstevel@tonic-gate 		return (-1);
594*0Sstevel@tonic-gate 	}
595*0Sstevel@tonic-gate 
596*0Sstevel@tonic-gate 	/*
597*0Sstevel@tonic-gate 	 * If the current instruction is a read or write of PSTATE we need
598*0Sstevel@tonic-gate 	 * to emulate it because we've taken over management of PSTATE and
599*0Sstevel@tonic-gate 	 * we need keep interrupts disabled. If it's a branch, we may need
600*0Sstevel@tonic-gate 	 * to set two breakpoints -- one at the target and one at the
601*0Sstevel@tonic-gate 	 * subsequent instruction.
602*0Sstevel@tonic-gate 	 */
603*0Sstevel@tonic-gate 	if (OP(instr) == OP_ARITH) {
604*0Sstevel@tonic-gate 		if (OP3(instr) == OP3_RDPR &&
605*0Sstevel@tonic-gate 		    RS1(instr) == KAIF_PREGNO_PSTATE) {
606*0Sstevel@tonic-gate 			const char *tgtreg =
607*0Sstevel@tonic-gate 			    mdb_sparcv9_kregs[RD(instr)].rd_name;
608*0Sstevel@tonic-gate 			kreg_t pstate;
609*0Sstevel@tonic-gate 
610*0Sstevel@tonic-gate 			(void) kmdb_dpi_get_register("pstate", &pstate);
611*0Sstevel@tonic-gate 			(void) kmdb_dpi_set_register(tgtreg, pstate);
612*0Sstevel@tonic-gate 
613*0Sstevel@tonic-gate 			(void) kmdb_dpi_set_register("pc", npc);
614*0Sstevel@tonic-gate 			(void) kmdb_dpi_set_register("npc", npc + 4);
615*0Sstevel@tonic-gate 			return (0);
616*0Sstevel@tonic-gate 
617*0Sstevel@tonic-gate 		} else if (OP3(instr) == OP3_WRPR &&
618*0Sstevel@tonic-gate 		    RD(instr) == KAIF_PREGNO_PSTATE) {
619*0Sstevel@tonic-gate 			kreg_t rs1, rs2, val;
620*0Sstevel@tonic-gate 
621*0Sstevel@tonic-gate 			(void) kmdb_dpi_get_register(regno2name(RS1(instr)),
622*0Sstevel@tonic-gate 			    &rs1);
623*0Sstevel@tonic-gate 
624*0Sstevel@tonic-gate 			if (I(instr)) {
625*0Sstevel@tonic-gate 				int imm = SIMM13(instr);
626*0Sstevel@tonic-gate 				imm <<= 19;
627*0Sstevel@tonic-gate 				imm >>= 19;
628*0Sstevel@tonic-gate 				rs2 = imm;
629*0Sstevel@tonic-gate 			} else {
630*0Sstevel@tonic-gate 				(void) kmdb_dpi_get_register(
631*0Sstevel@tonic-gate 				    regno2name(RS2(instr)), &rs2);
632*0Sstevel@tonic-gate 			}
633*0Sstevel@tonic-gate 
634*0Sstevel@tonic-gate 			val = rs1 ^ rs2;
635*0Sstevel@tonic-gate 
636*0Sstevel@tonic-gate 			(void) kmdb_dpi_set_register("pstate", val);
637*0Sstevel@tonic-gate 
638*0Sstevel@tonic-gate 			(void) kmdb_dpi_set_register("pc", npc);
639*0Sstevel@tonic-gate 			(void) kmdb_dpi_set_register("npc", npc + 4);
640*0Sstevel@tonic-gate 			return (0);
641*0Sstevel@tonic-gate 
642*0Sstevel@tonic-gate 		}
643*0Sstevel@tonic-gate 
644*0Sstevel@tonic-gate 		bpnpc = 1;
645*0Sstevel@tonic-gate 
646*0Sstevel@tonic-gate 	} else if (OP(instr) == OP_BRANCH) {
647*0Sstevel@tonic-gate 		int disp, cond, annul;
648*0Sstevel@tonic-gate 
649*0Sstevel@tonic-gate 		switch (OP2(instr)) {
650*0Sstevel@tonic-gate 		case OP2_BPcc:
651*0Sstevel@tonic-gate 		case OP2_FBPfcc:
652*0Sstevel@tonic-gate 			cond = (COND(instr) != 8);
653*0Sstevel@tonic-gate 
654*0Sstevel@tonic-gate 			disp = DISP19(instr);
655*0Sstevel@tonic-gate 			disp <<= 13;
656*0Sstevel@tonic-gate 			disp >>= 11;
657*0Sstevel@tonic-gate 			break;
658*0Sstevel@tonic-gate 
659*0Sstevel@tonic-gate 		case OP2_Bicc:
660*0Sstevel@tonic-gate 		case OP2_FBfcc:
661*0Sstevel@tonic-gate 			cond = (COND(instr) != 8);
662*0Sstevel@tonic-gate 
663*0Sstevel@tonic-gate 			disp = DISP22(instr);
664*0Sstevel@tonic-gate 			disp <<= 10;
665*0Sstevel@tonic-gate 			disp >>= 8;
666*0Sstevel@tonic-gate 			break;
667*0Sstevel@tonic-gate 
668*0Sstevel@tonic-gate 		case OP2_BPr:
669*0Sstevel@tonic-gate 			cond = 1;
670*0Sstevel@tonic-gate 
671*0Sstevel@tonic-gate 			disp = DISP16(instr);
672*0Sstevel@tonic-gate 			disp <<= 16;
673*0Sstevel@tonic-gate 			disp >>= 14;
674*0Sstevel@tonic-gate 			break;
675*0Sstevel@tonic-gate 
676*0Sstevel@tonic-gate 		default:
677*0Sstevel@tonic-gate 			bpnpc = 1;
678*0Sstevel@tonic-gate 		}
679*0Sstevel@tonic-gate 
680*0Sstevel@tonic-gate 		if (!bpnpc) {
681*0Sstevel@tonic-gate 			annul = A(instr);
682*0Sstevel@tonic-gate 
683*0Sstevel@tonic-gate 			if (!cond && annul) {
684*0Sstevel@tonic-gate 				brtgt = pc + disp;
685*0Sstevel@tonic-gate 				bptgt = 1;
686*0Sstevel@tonic-gate 			} else {
687*0Sstevel@tonic-gate 				bpnpc = 1;
688*0Sstevel@tonic-gate 
689*0Sstevel@tonic-gate 				if (cond && annul)
690*0Sstevel@tonic-gate 					bppc8 = 1;
691*0Sstevel@tonic-gate 			}
692*0Sstevel@tonic-gate 		}
693*0Sstevel@tonic-gate 
694*0Sstevel@tonic-gate 	} else {
695*0Sstevel@tonic-gate 		bpnpc = 1;
696*0Sstevel@tonic-gate 	}
697*0Sstevel@tonic-gate 
698*0Sstevel@tonic-gate 	/*
699*0Sstevel@tonic-gate 	 * Place the breakpoints and resume this CPU with IE off.  We'll come
700*0Sstevel@tonic-gate 	 * back after having encountered either one of the breakpoints we placed
701*0Sstevel@tonic-gate 	 * or a trap.
702*0Sstevel@tonic-gate 	 */
703*0Sstevel@tonic-gate 	err = 0;
704*0Sstevel@tonic-gate 	if ((bpnpc && kaif_brkpt_arm(npc, &svnpc) != 0) ||
705*0Sstevel@tonic-gate 	    (bppc8 && kaif_brkpt_arm(pc + 8, &svpc8) != 0) ||
706*0Sstevel@tonic-gate 	    (bptgt && kaif_brkpt_arm(brtgt, &svtgt) != 0)) {
707*0Sstevel@tonic-gate 		err = errno;
708*0Sstevel@tonic-gate 		goto step_done;
709*0Sstevel@tonic-gate 	}
710*0Sstevel@tonic-gate 
711*0Sstevel@tonic-gate 	(void) kmdb_dpi_get_register("pstate", &pstate);
712*0Sstevel@tonic-gate 	ie = pstate & KREG_PSTATE_IE_MASK;
713*0Sstevel@tonic-gate 	(void) kmdb_dpi_set_register("pstate", (pstate & ~KREG_PSTATE_IE_MASK));
714*0Sstevel@tonic-gate 
715*0Sstevel@tonic-gate 	kmdb_dpi_resume_master(); /* ... there and back again ... */
716*0Sstevel@tonic-gate 
717*0Sstevel@tonic-gate 	(void) kmdb_dpi_get_register("pstate", &pstate);
718*0Sstevel@tonic-gate 	(void) kmdb_dpi_set_register("pstate",
719*0Sstevel@tonic-gate 	    ((pstate & ~KREG_PSTATE_IE_MASK) | ie));
720*0Sstevel@tonic-gate 
721*0Sstevel@tonic-gate 	(void) kmdb_dpi_get_register("tt", &tt);
722*0Sstevel@tonic-gate 
723*0Sstevel@tonic-gate step_done:
724*0Sstevel@tonic-gate 	if (svnpc)
725*0Sstevel@tonic-gate 		(void) kaif_brkpt_disarm(npc, svnpc);
726*0Sstevel@tonic-gate 	if (svpc8)
727*0Sstevel@tonic-gate 		(void) kaif_brkpt_disarm(pc + 8, svpc8);
728*0Sstevel@tonic-gate 	if (svtgt)
729*0Sstevel@tonic-gate 		(void) kaif_brkpt_disarm(brtgt, svtgt);
730*0Sstevel@tonic-gate 
731*0Sstevel@tonic-gate 	return (err == 0 ? 0 : set_errno(err));
732*0Sstevel@tonic-gate }
733*0Sstevel@tonic-gate 
734*0Sstevel@tonic-gate static uintptr_t
735*0Sstevel@tonic-gate kaif_call(uintptr_t funcva, uint_t argc, const uintptr_t *argv)
736*0Sstevel@tonic-gate {
737*0Sstevel@tonic-gate 	kreg_t g6, g7;
738*0Sstevel@tonic-gate 
739*0Sstevel@tonic-gate 	(void) kmdb_dpi_get_register("g6", &g6);
740*0Sstevel@tonic-gate 	(void) kmdb_dpi_get_register("g7", &g7);
741*0Sstevel@tonic-gate 
742*0Sstevel@tonic-gate 	return (kaif_invoke(funcva, argc, argv, g6, g7));
743*0Sstevel@tonic-gate }
744*0Sstevel@tonic-gate 
745*0Sstevel@tonic-gate static const mdb_bitmask_t krm_flag_bits[] = {
746*0Sstevel@tonic-gate 	{ "M_W",	KAIF_CRUMB_F_MAIN_OBPWAPT, KAIF_CRUMB_F_MAIN_OBPWAPT },
747*0Sstevel@tonic-gate 	{ "M_PE",	KAIF_CRUMB_F_MAIN_OBPPENT, KAIF_CRUMB_F_MAIN_OBPPENT },
748*0Sstevel@tonic-gate 	{ "M_NRM",	KAIF_CRUMB_F_MAIN_NORMAL, KAIF_CRUMB_F_MAIN_NORMAL },
749*0Sstevel@tonic-gate 	{ "I_RE",	KAIF_CRUMB_F_IVEC_REENTER, KAIF_CRUMB_F_IVEC_REENTER },
750*0Sstevel@tonic-gate 	{ "I_OBP", 	KAIF_CRUMB_F_IVEC_INOBP, KAIF_CRUMB_F_IVEC_INOBP },
751*0Sstevel@tonic-gate 	{ "I_NRM",	KAIF_CRUMB_F_IVEC_NORMAL, KAIF_CRUMB_F_IVEC_NORMAL },
752*0Sstevel@tonic-gate 	{ "O_NRM",	KAIF_CRUMB_F_OBP_NORMAL, KAIF_CRUMB_F_OBP_NORMAL },
753*0Sstevel@tonic-gate 	{ "O_REVEC",	KAIF_CRUMB_F_OBP_REVECT, KAIF_CRUMB_F_OBP_REVECT },
754*0Sstevel@tonic-gate 	{ NULL }
755*0Sstevel@tonic-gate };
756*0Sstevel@tonic-gate 
757*0Sstevel@tonic-gate static void
758*0Sstevel@tonic-gate dump_crumb(kaif_crumb_t *crumb)
759*0Sstevel@tonic-gate {
760*0Sstevel@tonic-gate 	mdb_printf(" src: ");
761*0Sstevel@tonic-gate 	switch (crumb->krm_src) {
762*0Sstevel@tonic-gate 	case KAIF_CRUMB_SRC_OBP:
763*0Sstevel@tonic-gate 		mdb_printf("O");
764*0Sstevel@tonic-gate 		break;
765*0Sstevel@tonic-gate 	case KAIF_CRUMB_SRC_IVEC:
766*0Sstevel@tonic-gate 		mdb_printf("I");
767*0Sstevel@tonic-gate 		break;
768*0Sstevel@tonic-gate 	case KAIF_CRUMB_SRC_MAIN:
769*0Sstevel@tonic-gate 		mdb_printf("M");
770*0Sstevel@tonic-gate 		break;
771*0Sstevel@tonic-gate 	case 0:
772*0Sstevel@tonic-gate 		mdb_printf("-");
773*0Sstevel@tonic-gate 		break;
774*0Sstevel@tonic-gate 	default:
775*0Sstevel@tonic-gate 		mdb_printf("%d", crumb->krm_src);
776*0Sstevel@tonic-gate 	}
777*0Sstevel@tonic-gate 
778*0Sstevel@tonic-gate 	mdb_printf(" tt %3x pc %8p %-20A <%b>\n",
779*0Sstevel@tonic-gate 	    crumb->krm_tt, crumb->krm_pc, crumb->krm_pc,
780*0Sstevel@tonic-gate 	    crumb->krm_flag, krm_flag_bits);
781*0Sstevel@tonic-gate }
782*0Sstevel@tonic-gate 
783*0Sstevel@tonic-gate static void
784*0Sstevel@tonic-gate dump_crumbs(kaif_cpusave_t *save)
785*0Sstevel@tonic-gate {
786*0Sstevel@tonic-gate 	int i;
787*0Sstevel@tonic-gate 
788*0Sstevel@tonic-gate 	for (i = KAIF_NCRUMBS; i > 0; i--) {
789*0Sstevel@tonic-gate 		uint_t idx = (save->krs_curcrumbidx + i) % KAIF_NCRUMBS;
790*0Sstevel@tonic-gate 
791*0Sstevel@tonic-gate 		dump_crumb(&save->krs_crumbs[idx]);
792*0Sstevel@tonic-gate 	}
793*0Sstevel@tonic-gate }
794*0Sstevel@tonic-gate 
795*0Sstevel@tonic-gate static void
796*0Sstevel@tonic-gate kaif_dump_crumbs(uintptr_t addr, int cpuid)
797*0Sstevel@tonic-gate {
798*0Sstevel@tonic-gate 	int i;
799*0Sstevel@tonic-gate 
800*0Sstevel@tonic-gate 	if (addr != NULL) {
801*0Sstevel@tonic-gate 		dump_crumb((kaif_crumb_t *)addr);
802*0Sstevel@tonic-gate 
803*0Sstevel@tonic-gate 	} else if (cpuid != -1) {
804*0Sstevel@tonic-gate 		if (cpuid >= kaif_ncpusave)
805*0Sstevel@tonic-gate 			return;
806*0Sstevel@tonic-gate 
807*0Sstevel@tonic-gate 		dump_crumbs(&kaif_cpusave[cpuid]);
808*0Sstevel@tonic-gate 
809*0Sstevel@tonic-gate 	} else {
810*0Sstevel@tonic-gate 		for (i = 0; i < kaif_ncpusave; i++) {
811*0Sstevel@tonic-gate 			kaif_cpusave_t *save = &kaif_cpusave[i];
812*0Sstevel@tonic-gate 
813*0Sstevel@tonic-gate 			if (save->krs_cpu_state == KAIF_CPU_STATE_NONE)
814*0Sstevel@tonic-gate 				continue;
815*0Sstevel@tonic-gate 
816*0Sstevel@tonic-gate 			mdb_printf("%sCPU %d crumbs: (curidx %d)\n",
817*0Sstevel@tonic-gate 			    (i == 0 ? "" : "\n"), i, save->krs_curcrumbidx);
818*0Sstevel@tonic-gate 
819*0Sstevel@tonic-gate 			dump_crumbs(save);
820*0Sstevel@tonic-gate 		}
821*0Sstevel@tonic-gate 	}
822*0Sstevel@tonic-gate }
823*0Sstevel@tonic-gate 
824*0Sstevel@tonic-gate static int
825*0Sstevel@tonic-gate kaif_get_rwin(int cpuid, int win, struct rwindow *rwin)
826*0Sstevel@tonic-gate {
827*0Sstevel@tonic-gate 	if (cpuid == DPI_MASTER_CPUID)
828*0Sstevel@tonic-gate 		cpuid = kaif_master_cpuid;
829*0Sstevel@tonic-gate 	if (win == DPI_TOP_WINDOW)
830*0Sstevel@tonic-gate 		win = kaif_cpusave[cpuid].krs_gregs.kregs[KREG_CWP];
831*0Sstevel@tonic-gate 
832*0Sstevel@tonic-gate 	if (win < 0 || win >= kaif_get_nwin(cpuid))
833*0Sstevel@tonic-gate 		return (-1);
834*0Sstevel@tonic-gate 
835*0Sstevel@tonic-gate 	bcopy(&kaif_cpusave[cpuid].krs_rwins[win], rwin,
836*0Sstevel@tonic-gate 	    sizeof (struct rwindow));
837*0Sstevel@tonic-gate 
838*0Sstevel@tonic-gate 	return (0);
839*0Sstevel@tonic-gate }
840*0Sstevel@tonic-gate 
841*0Sstevel@tonic-gate static void
842*0Sstevel@tonic-gate kaif_enter_mon(void)
843*0Sstevel@tonic-gate {
844*0Sstevel@tonic-gate 	kmdb_prom_enter_mon();
845*0Sstevel@tonic-gate 	kaif_prom_rearm();
846*0Sstevel@tonic-gate }
847*0Sstevel@tonic-gate 
848*0Sstevel@tonic-gate static void
849*0Sstevel@tonic-gate kaif_modchg_register(void (*func)(struct modctl *, int))
850*0Sstevel@tonic-gate {
851*0Sstevel@tonic-gate 	kaif_modchg_cb = func;
852*0Sstevel@tonic-gate }
853*0Sstevel@tonic-gate 
854*0Sstevel@tonic-gate static void
855*0Sstevel@tonic-gate kaif_modchg_cancel(void)
856*0Sstevel@tonic-gate {
857*0Sstevel@tonic-gate 	ASSERT(kaif_modchg_cb != NULL);
858*0Sstevel@tonic-gate 
859*0Sstevel@tonic-gate 	kaif_modchg_cb = NULL;
860*0Sstevel@tonic-gate }
861*0Sstevel@tonic-gate 
862*0Sstevel@tonic-gate void
863*0Sstevel@tonic-gate kaif_mod_loaded(struct modctl *modp)
864*0Sstevel@tonic-gate {
865*0Sstevel@tonic-gate 	if (kaif_modchg_cb != NULL)
866*0Sstevel@tonic-gate 		kaif_modchg_cb(modp, 1);
867*0Sstevel@tonic-gate }
868*0Sstevel@tonic-gate 
869*0Sstevel@tonic-gate void
870*0Sstevel@tonic-gate kaif_mod_unloading(struct modctl *modp)
871*0Sstevel@tonic-gate {
872*0Sstevel@tonic-gate 	if (kaif_modchg_cb != NULL)
873*0Sstevel@tonic-gate 		kaif_modchg_cb(modp, 0);
874*0Sstevel@tonic-gate }
875*0Sstevel@tonic-gate 
876*0Sstevel@tonic-gate /*ARGSUSED*/
877*0Sstevel@tonic-gate int
878*0Sstevel@tonic-gate kaif_memrange_add(caddr_t base, size_t len)
879*0Sstevel@tonic-gate {
880*0Sstevel@tonic-gate 	/* We don't support multiple memory ranges on SPARC */
881*0Sstevel@tonic-gate 	return (set_errno(ENOTSUP));
882*0Sstevel@tonic-gate }
883*0Sstevel@tonic-gate 
884*0Sstevel@tonic-gate void
885*0Sstevel@tonic-gate kaif_trap_set_debugger(void)
886*0Sstevel@tonic-gate {
887*0Sstevel@tonic-gate 	set_tba(kaif_tba);
888*0Sstevel@tonic-gate }
889*0Sstevel@tonic-gate 
890*0Sstevel@tonic-gate void
891*0Sstevel@tonic-gate kaif_trap_set_saved(kaif_cpusave_t *cpusave)
892*0Sstevel@tonic-gate {
893*0Sstevel@tonic-gate 	set_tba((caddr_t)cpusave->krs_gregs.kregs[KREG_TBA]);
894*0Sstevel@tonic-gate }
895*0Sstevel@tonic-gate 
896*0Sstevel@tonic-gate static void
897*0Sstevel@tonic-gate kaif_kernpanic(int cpuid)
898*0Sstevel@tonic-gate {
899*0Sstevel@tonic-gate 	struct regs regs;
900*0Sstevel@tonic-gate 
901*0Sstevel@tonic-gate 	/*
902*0Sstevel@tonic-gate 	 * We're going to try to panic the system by using the same entry point
903*0Sstevel@tonic-gate 	 * used by the PROM when told to `sync'.  The kernel wants a
904*0Sstevel@tonic-gate 	 * fully-populated struct regs, which we're going to build using the
905*0Sstevel@tonic-gate 	 * state captured at the time of the debugger fault.  Said state lives
906*0Sstevel@tonic-gate 	 * in kaif_cb_save, since we haven't yet copied it over to the cpusave
907*0Sstevel@tonic-gate 	 * structure for the current master.
908*0Sstevel@tonic-gate 	 */
909*0Sstevel@tonic-gate 
910*0Sstevel@tonic-gate 	regs.r_tstate = kaif_cb_save.krs_tstate;
911*0Sstevel@tonic-gate 
912*0Sstevel@tonic-gate 	regs.r_g1 = kaif_cb_save.krs_gregs.kregs[KREG_G1];
913*0Sstevel@tonic-gate 	regs.r_g2 = kaif_cb_save.krs_gregs.kregs[KREG_G2];
914*0Sstevel@tonic-gate 	regs.r_g3 = kaif_cb_save.krs_gregs.kregs[KREG_G3];
915*0Sstevel@tonic-gate 	regs.r_g4 = kaif_cb_save.krs_gregs.kregs[KREG_G4];
916*0Sstevel@tonic-gate 	regs.r_g5 = kaif_cb_save.krs_gregs.kregs[KREG_G5];
917*0Sstevel@tonic-gate 	regs.r_g6 = kaif_cb_save.krs_gregs.kregs[KREG_G6];
918*0Sstevel@tonic-gate 	regs.r_g7 = kaif_cb_save.krs_gregs.kregs[KREG_G7];
919*0Sstevel@tonic-gate 
920*0Sstevel@tonic-gate 	regs.r_o0 = kaif_cb_save.krs_gregs.kregs[KREG_O0];
921*0Sstevel@tonic-gate 	regs.r_o1 = kaif_cb_save.krs_gregs.kregs[KREG_O1];
922*0Sstevel@tonic-gate 	regs.r_o2 = kaif_cb_save.krs_gregs.kregs[KREG_O2];
923*0Sstevel@tonic-gate 	regs.r_o3 = kaif_cb_save.krs_gregs.kregs[KREG_O3];
924*0Sstevel@tonic-gate 	regs.r_o4 = kaif_cb_save.krs_gregs.kregs[KREG_O4];
925*0Sstevel@tonic-gate 	regs.r_o5 = kaif_cb_save.krs_gregs.kregs[KREG_O5];
926*0Sstevel@tonic-gate 	regs.r_o6 = kaif_cb_save.krs_gregs.kregs[KREG_O6];
927*0Sstevel@tonic-gate 	regs.r_o7 = kaif_cb_save.krs_gregs.kregs[KREG_O7];
928*0Sstevel@tonic-gate 
929*0Sstevel@tonic-gate 	regs.r_pc = kaif_cb_save.krs_gregs.kregs[KREG_PC];
930*0Sstevel@tonic-gate 	regs.r_npc = kaif_cb_save.krs_gregs.kregs[KREG_NPC];
931*0Sstevel@tonic-gate 	regs.r_y = kaif_cb_save.krs_gregs.kregs[KREG_Y];
932*0Sstevel@tonic-gate 
933*0Sstevel@tonic-gate 	/*
934*0Sstevel@tonic-gate 	 * The %tba is, as ever, different.  We don't want the %tba from the
935*0Sstevel@tonic-gate 	 * time of the fault -- that'll be the debugger's.  We want the %tba
936*0Sstevel@tonic-gate 	 * saved when the debugger was initially entered.  It'll be saved in
937*0Sstevel@tonic-gate 	 * the cpusave area for the current CPU.
938*0Sstevel@tonic-gate 	 */
939*0Sstevel@tonic-gate 	set_tba((caddr_t)kaif_cpusave[cpuid].krs_gregs.kregs[KREG_TBA]);
940*0Sstevel@tonic-gate 
941*0Sstevel@tonic-gate 	kmdb_kdi_kernpanic(&regs, kaif_cb_save.krs_gregs.kregs[KREG_TT]);
942*0Sstevel@tonic-gate }
943*0Sstevel@tonic-gate 
944*0Sstevel@tonic-gate static int
945*0Sstevel@tonic-gate kaif_init(kmdb_auxv_t *kav)
946*0Sstevel@tonic-gate {
947*0Sstevel@tonic-gate 	struct rwindow *rwins;
948*0Sstevel@tonic-gate 	int nwin = get_nwin();
949*0Sstevel@tonic-gate 	int i;
950*0Sstevel@tonic-gate 
951*0Sstevel@tonic-gate 	kaif_vwapt_addr = kaif_pwapt_addr = 0;
952*0Sstevel@tonic-gate 
953*0Sstevel@tonic-gate 	kaif_tba = kav->kav_tba_active;
954*0Sstevel@tonic-gate 	kaif_tba_obp = kav->kav_tba_obp;
955*0Sstevel@tonic-gate 	kaif_tba_native = kav->kav_tba_native;
956*0Sstevel@tonic-gate 	kaif_tba_native_sz = kav->kav_tba_native_sz;
957*0Sstevel@tonic-gate #ifdef	sun4v
958*0Sstevel@tonic-gate 	kaif_tba_kernel = kav->kav_tba_kernel;
959*0Sstevel@tonic-gate #endif
960*0Sstevel@tonic-gate 
961*0Sstevel@tonic-gate 	/* Allocate the per-CPU save areas */
962*0Sstevel@tonic-gate 	kaif_cpusave = mdb_zalloc(sizeof (kaif_cpusave_t) * kav->kav_ncpu,
963*0Sstevel@tonic-gate 	    UM_SLEEP);
964*0Sstevel@tonic-gate 	kaif_ncpusave = kav->kav_ncpu;
965*0Sstevel@tonic-gate 
966*0Sstevel@tonic-gate 	rwins = mdb_zalloc(sizeof (struct rwindow) * nwin * kav->kav_ncpu,
967*0Sstevel@tonic-gate 	    UM_SLEEP);
968*0Sstevel@tonic-gate 
969*0Sstevel@tonic-gate 	for (i = 0; i < kaif_ncpusave; i++) {
970*0Sstevel@tonic-gate 		kaif_cpusave[i].krs_rwins = &rwins[nwin * i];
971*0Sstevel@tonic-gate 		kaif_cpusave[i].krs_cpu_id = i;
972*0Sstevel@tonic-gate 
973*0Sstevel@tonic-gate 		kaif_cpusave[i].krs_curcrumb =
974*0Sstevel@tonic-gate 		    &kaif_cpusave[i].krs_crumbs[KAIF_NCRUMBS - 1];
975*0Sstevel@tonic-gate 		kaif_cpusave[i].krs_curcrumbidx = KAIF_NCRUMBS - 1;
976*0Sstevel@tonic-gate 	}
977*0Sstevel@tonic-gate 
978*0Sstevel@tonic-gate 	kaif_dseg = kav->kav_dseg;
979*0Sstevel@tonic-gate 	kaif_dseg_lim = kav->kav_dseg + kav->kav_dseg_size;
980*0Sstevel@tonic-gate 
981*0Sstevel@tonic-gate 	kaif_promexitarmp = kav->kav_promexitarmp;
982*0Sstevel@tonic-gate 
983*0Sstevel@tonic-gate 	kaif_ktrap_install = kav->kav_ktrap_install;
984*0Sstevel@tonic-gate 	kaif_ktrap_restore = kav->kav_ktrap_restore;
985*0Sstevel@tonic-gate 
986*0Sstevel@tonic-gate 	kaif_modchg_cb = NULL;
987*0Sstevel@tonic-gate 
988*0Sstevel@tonic-gate 	kaif_trap_switch = (kav->kav_flags & KMDB_AUXV_FL_NOTRPSWTCH) == 0;
989*0Sstevel@tonic-gate 
990*0Sstevel@tonic-gate 	return (0);
991*0Sstevel@tonic-gate }
992*0Sstevel@tonic-gate 
993*0Sstevel@tonic-gate dpi_ops_t kmdb_dpi_ops = {
994*0Sstevel@tonic-gate 	kaif_init,
995*0Sstevel@tonic-gate 	kaif_activate,
996*0Sstevel@tonic-gate 	kaif_deactivate,
997*0Sstevel@tonic-gate 	kaif_enter_mon,
998*0Sstevel@tonic-gate 	kaif_modchg_register,
999*0Sstevel@tonic-gate 	kaif_modchg_cancel,
1000*0Sstevel@tonic-gate 	kaif_get_cpu_state,
1001*0Sstevel@tonic-gate 	kaif_get_master_cpuid,
1002*0Sstevel@tonic-gate 	kaif_get_gregs,
1003*0Sstevel@tonic-gate 	kaif_get_cpu_register,
1004*0Sstevel@tonic-gate 	kaif_set_cpu_register,
1005*0Sstevel@tonic-gate 	kaif_get_rwin,
1006*0Sstevel@tonic-gate 	kaif_get_nwin,
1007*0Sstevel@tonic-gate 	kaif_brkpt_arm,
1008*0Sstevel@tonic-gate 	kaif_brkpt_disarm,
1009*0Sstevel@tonic-gate 	kaif_wapt_validate,
1010*0Sstevel@tonic-gate 	kaif_wapt_reserve,
1011*0Sstevel@tonic-gate 	kaif_wapt_release,
1012*0Sstevel@tonic-gate 	kaif_wapt_arm,
1013*0Sstevel@tonic-gate 	kaif_wapt_disarm,
1014*0Sstevel@tonic-gate 	kaif_wapt_match,
1015*0Sstevel@tonic-gate 	kaif_step,
1016*0Sstevel@tonic-gate 	kaif_call,
1017*0Sstevel@tonic-gate 	kaif_dump_crumbs,
1018*0Sstevel@tonic-gate 	kaif_memrange_add,
1019*0Sstevel@tonic-gate 	kaif_kernpanic
1020*0Sstevel@tonic-gate };
1021