xref: /onnv-gate/usr/src/cmd/mdb/intel/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 layer
31*0Sstevel@tonic-gate  *
32*0Sstevel@tonic-gate  * (it makes more sense on SPARC)
33*0Sstevel@tonic-gate  */
34*0Sstevel@tonic-gate 
35*0Sstevel@tonic-gate #include <kmdb/kmdb_dpi_impl.h>
36*0Sstevel@tonic-gate #include <kmdb/kmdb_kdi.h>
37*0Sstevel@tonic-gate #include <kmdb/kmdb_umemglue.h>
38*0Sstevel@tonic-gate #include <kmdb/kaif.h>
39*0Sstevel@tonic-gate #include <kmdb/kaif_asmutil.h>
40*0Sstevel@tonic-gate #include <mdb/mdb_err.h>
41*0Sstevel@tonic-gate #include <mdb/mdb_debug.h>
42*0Sstevel@tonic-gate #include <mdb/mdb_isautil.h>
43*0Sstevel@tonic-gate #include <mdb/mdb_io_impl.h>
44*0Sstevel@tonic-gate #include <mdb/mdb_kreg.h>
45*0Sstevel@tonic-gate #include <mdb/mdb.h>
46*0Sstevel@tonic-gate 
47*0Sstevel@tonic-gate #include <sys/types.h>
48*0Sstevel@tonic-gate #include <sys/segments.h>
49*0Sstevel@tonic-gate #include <sys/bitmap.h>
50*0Sstevel@tonic-gate 
51*0Sstevel@tonic-gate kaif_cpusave_t	*kaif_cpusave;
52*0Sstevel@tonic-gate int		kaif_ncpusave;
53*0Sstevel@tonic-gate 
54*0Sstevel@tonic-gate kaif_drreg_t	kaif_drreg;
55*0Sstevel@tonic-gate 
56*0Sstevel@tonic-gate uint32_t	kaif_waptmap;
57*0Sstevel@tonic-gate 
58*0Sstevel@tonic-gate #ifndef __amd64
59*0Sstevel@tonic-gate /* Used to track the current set of valid kernel selectors. */
60*0Sstevel@tonic-gate uint32_t	kaif_cs;
61*0Sstevel@tonic-gate uint32_t	kaif_ds;
62*0Sstevel@tonic-gate uint32_t	kaif_fs;
63*0Sstevel@tonic-gate uint32_t	kaif_gs;
64*0Sstevel@tonic-gate #endif
65*0Sstevel@tonic-gate 
66*0Sstevel@tonic-gate uint_t		kaif_msr_wrexit_msr;
67*0Sstevel@tonic-gate uint64_t	*kaif_msr_wrexit_valp;
68*0Sstevel@tonic-gate 
69*0Sstevel@tonic-gate uintptr_t	kaif_kernel_handler;
70*0Sstevel@tonic-gate uintptr_t	kaif_sys_sysenter;
71*0Sstevel@tonic-gate 
72*0Sstevel@tonic-gate int		kaif_trap_switch;
73*0Sstevel@tonic-gate 
74*0Sstevel@tonic-gate void (*kaif_modchg_cb)(struct modctl *, int);
75*0Sstevel@tonic-gate 
76*0Sstevel@tonic-gate #define	KAIF_MEMRANGES_MAX	2
77*0Sstevel@tonic-gate 
78*0Sstevel@tonic-gate kaif_memrange_t	kaif_memranges[KAIF_MEMRANGES_MAX];
79*0Sstevel@tonic-gate int		kaif_nmemranges;
80*0Sstevel@tonic-gate 
81*0Sstevel@tonic-gate enum {
82*0Sstevel@tonic-gate 	M_SYSRET	= 0x07, /* after M_ESC */
83*0Sstevel@tonic-gate 	M_ESC		= 0x0f,
84*0Sstevel@tonic-gate 	M_SYSEXIT	= 0x35, /* after M_ESC */
85*0Sstevel@tonic-gate 	M_REX_LO	= 0x40, /* first REX prefix */
86*0Sstevel@tonic-gate 	M_REX_HI	= 0x4f, /* last REX prefix */
87*0Sstevel@tonic-gate 	M_PUSHF		= 0x9c,	/* pushfl and pushfq */
88*0Sstevel@tonic-gate 	M_POPF		= 0x9d,	/* popfl and popfq */
89*0Sstevel@tonic-gate 	M_INT3		= 0xcc,
90*0Sstevel@tonic-gate 	M_INTX		= 0xcd,
91*0Sstevel@tonic-gate 	M_INTO		= 0xce,
92*0Sstevel@tonic-gate 	M_IRET		= 0xcf,
93*0Sstevel@tonic-gate 	M_CLI		= 0xfa,
94*0Sstevel@tonic-gate 	M_STI		= 0xfb
95*0Sstevel@tonic-gate };
96*0Sstevel@tonic-gate 
97*0Sstevel@tonic-gate #define	KAIF_BREAKPOINT_INSTR	M_INT3
98*0Sstevel@tonic-gate 
99*0Sstevel@tonic-gate #define	KAIF_WPPRIV2ID(wp)	(int)(uintptr_t)((wp)->wp_priv)
100*0Sstevel@tonic-gate 
101*0Sstevel@tonic-gate #ifdef __amd64
102*0Sstevel@tonic-gate #define	FLAGS_REG_NAME		"rflags"
103*0Sstevel@tonic-gate #else
104*0Sstevel@tonic-gate #define	FLAGS_REG_NAME		"eflags"
105*0Sstevel@tonic-gate #endif
106*0Sstevel@tonic-gate 
107*0Sstevel@tonic-gate /*
108*0Sstevel@tonic-gate  * Called during normal debugger operation and during debugger faults.
109*0Sstevel@tonic-gate  */
110*0Sstevel@tonic-gate static void
111*0Sstevel@tonic-gate kaif_enter_mon(void)
112*0Sstevel@tonic-gate {
113*0Sstevel@tonic-gate 	char c;
114*0Sstevel@tonic-gate 
115*0Sstevel@tonic-gate 	for (;;) {
116*0Sstevel@tonic-gate 		mdb_iob_printf(mdb.m_out,
117*0Sstevel@tonic-gate 		    "%s: Do you really want to reboot? (y/n) ",
118*0Sstevel@tonic-gate 		    mdb.m_pname);
119*0Sstevel@tonic-gate 		mdb_iob_flush(mdb.m_out);
120*0Sstevel@tonic-gate 
121*0Sstevel@tonic-gate 		while (IOP_READ(mdb.m_term, &c, 1) != 1)
122*0Sstevel@tonic-gate 			continue;
123*0Sstevel@tonic-gate 		mdb_iob_printf(mdb.m_out, "%c%s", c, (c == '\n' ? "" : "\n"));
124*0Sstevel@tonic-gate 
125*0Sstevel@tonic-gate 		if (c == 'n' || c == 'N')
126*0Sstevel@tonic-gate 			return;
127*0Sstevel@tonic-gate 		else if (c == 'y' || c == 'Y') {
128*0Sstevel@tonic-gate 			mdb_iob_printf(mdb.m_out, "Rebooting...\n");
129*0Sstevel@tonic-gate 
130*0Sstevel@tonic-gate 			kmdb_dpi_reboot();
131*0Sstevel@tonic-gate 		}
132*0Sstevel@tonic-gate 	}
133*0Sstevel@tonic-gate }
134*0Sstevel@tonic-gate 
135*0Sstevel@tonic-gate static int
136*0Sstevel@tonic-gate kaif_get_cpu_state(int cpuid)
137*0Sstevel@tonic-gate {
138*0Sstevel@tonic-gate 	if (cpuid == DPI_MASTER_CPUID)
139*0Sstevel@tonic-gate 		return (DPI_CPU_STATE_MASTER);
140*0Sstevel@tonic-gate 
141*0Sstevel@tonic-gate 	if (cpuid < 0 || cpuid >= kaif_ncpusave)
142*0Sstevel@tonic-gate 		return (set_errno(EINVAL));
143*0Sstevel@tonic-gate 
144*0Sstevel@tonic-gate 	switch (kaif_cpusave[cpuid].krs_cpu_state) {
145*0Sstevel@tonic-gate 	case KAIF_CPU_STATE_MASTER:
146*0Sstevel@tonic-gate 		return (DPI_CPU_STATE_MASTER);
147*0Sstevel@tonic-gate 	case KAIF_CPU_STATE_SLAVE:
148*0Sstevel@tonic-gate 		return (DPI_CPU_STATE_SLAVE);
149*0Sstevel@tonic-gate 	default:
150*0Sstevel@tonic-gate 		return (set_errno(EINVAL));
151*0Sstevel@tonic-gate 	}
152*0Sstevel@tonic-gate }
153*0Sstevel@tonic-gate 
154*0Sstevel@tonic-gate static int
155*0Sstevel@tonic-gate kaif_get_master_cpuid(void)
156*0Sstevel@tonic-gate {
157*0Sstevel@tonic-gate 	return (kaif_master_cpuid);
158*0Sstevel@tonic-gate }
159*0Sstevel@tonic-gate 
160*0Sstevel@tonic-gate static const mdb_tgt_gregset_t *
161*0Sstevel@tonic-gate kaif_get_gregs(int cpuid)
162*0Sstevel@tonic-gate {
163*0Sstevel@tonic-gate 	if (cpuid == DPI_MASTER_CPUID)
164*0Sstevel@tonic-gate 		cpuid = kaif_master_cpuid;
165*0Sstevel@tonic-gate 
166*0Sstevel@tonic-gate 	if (cpuid < 0 || cpuid >= kaif_ncpusave) {
167*0Sstevel@tonic-gate 		(void) set_errno(EINVAL);
168*0Sstevel@tonic-gate 		return (NULL);
169*0Sstevel@tonic-gate 	}
170*0Sstevel@tonic-gate 
171*0Sstevel@tonic-gate 	return (kaif_cpusave[cpuid].krs_gregs);
172*0Sstevel@tonic-gate }
173*0Sstevel@tonic-gate 
174*0Sstevel@tonic-gate typedef struct kaif_reg_synonyms {
175*0Sstevel@tonic-gate 	const char *rs_syn;
176*0Sstevel@tonic-gate 	const char *rs_name;
177*0Sstevel@tonic-gate } kaif_reg_synonyms_t;
178*0Sstevel@tonic-gate 
179*0Sstevel@tonic-gate static kreg_t *
180*0Sstevel@tonic-gate kaif_find_regp(int cpuid, const char *regname)
181*0Sstevel@tonic-gate {
182*0Sstevel@tonic-gate 	static const kaif_reg_synonyms_t synonyms[] = {
183*0Sstevel@tonic-gate #ifdef __amd64
184*0Sstevel@tonic-gate 	    { "pc", "rip" },
185*0Sstevel@tonic-gate 	    { "sp", "rsp" },
186*0Sstevel@tonic-gate 	    { "fp", "rbp" },
187*0Sstevel@tonic-gate #else
188*0Sstevel@tonic-gate 	    { "pc", "eip" },
189*0Sstevel@tonic-gate 	    { "sp", "esp" },
190*0Sstevel@tonic-gate 	    { "fp", "ebp" },
191*0Sstevel@tonic-gate #endif
192*0Sstevel@tonic-gate 	    { "tt", "trapno" }
193*0Sstevel@tonic-gate 	};
194*0Sstevel@tonic-gate 	int i;
195*0Sstevel@tonic-gate 
196*0Sstevel@tonic-gate 	if (cpuid == DPI_MASTER_CPUID)
197*0Sstevel@tonic-gate 		cpuid = kaif_master_cpuid;
198*0Sstevel@tonic-gate 
199*0Sstevel@tonic-gate 	if (cpuid < 0 || cpuid >= kaif_ncpusave) {
200*0Sstevel@tonic-gate 		(void) set_errno(EINVAL);
201*0Sstevel@tonic-gate 		return (NULL);
202*0Sstevel@tonic-gate 	}
203*0Sstevel@tonic-gate 
204*0Sstevel@tonic-gate 	for (i = 0; i < sizeof (synonyms) / sizeof (synonyms[0]); i++) {
205*0Sstevel@tonic-gate 		if (strcmp(synonyms[i].rs_syn, regname) == 0)
206*0Sstevel@tonic-gate 			regname = synonyms[i].rs_name;
207*0Sstevel@tonic-gate 	}
208*0Sstevel@tonic-gate 
209*0Sstevel@tonic-gate 	for (i = 0; mdb_isa_kregs[i].rd_name != NULL; i++) {
210*0Sstevel@tonic-gate 		const mdb_tgt_regdesc_t *rd = &mdb_isa_kregs[i];
211*0Sstevel@tonic-gate 
212*0Sstevel@tonic-gate 		if (strcmp(rd->rd_name, regname) == 0)
213*0Sstevel@tonic-gate 			return (&kaif_cpusave[cpuid].krs_gregs->
214*0Sstevel@tonic-gate 			    kregs[rd->rd_num]);
215*0Sstevel@tonic-gate 	}
216*0Sstevel@tonic-gate 
217*0Sstevel@tonic-gate 	(void) set_errno(ENOENT);
218*0Sstevel@tonic-gate 	return (NULL);
219*0Sstevel@tonic-gate }
220*0Sstevel@tonic-gate 
221*0Sstevel@tonic-gate /*ARGSUSED*/
222*0Sstevel@tonic-gate static int
223*0Sstevel@tonic-gate kaif_get_cpu_register(int cpuid, const char *regname, kreg_t *valp)
224*0Sstevel@tonic-gate {
225*0Sstevel@tonic-gate 	kreg_t *regp;
226*0Sstevel@tonic-gate 
227*0Sstevel@tonic-gate 	if ((regp = kaif_find_regp(cpuid, regname)) == NULL)
228*0Sstevel@tonic-gate 		return (-1);
229*0Sstevel@tonic-gate 
230*0Sstevel@tonic-gate 	*valp = *regp;
231*0Sstevel@tonic-gate 
232*0Sstevel@tonic-gate 	return (0);
233*0Sstevel@tonic-gate }
234*0Sstevel@tonic-gate 
235*0Sstevel@tonic-gate static int
236*0Sstevel@tonic-gate kaif_set_cpu_register(int cpuid, const char *regname, kreg_t val)
237*0Sstevel@tonic-gate {
238*0Sstevel@tonic-gate 	kreg_t *regp;
239*0Sstevel@tonic-gate 
240*0Sstevel@tonic-gate 	if ((regp = kaif_find_regp(cpuid, regname)) == NULL)
241*0Sstevel@tonic-gate 		return (-1);
242*0Sstevel@tonic-gate 
243*0Sstevel@tonic-gate 	*regp = val;
244*0Sstevel@tonic-gate 
245*0Sstevel@tonic-gate 	return (0);
246*0Sstevel@tonic-gate }
247*0Sstevel@tonic-gate 
248*0Sstevel@tonic-gate static int
249*0Sstevel@tonic-gate kaif_brkpt_arm(uintptr_t addr, mdb_instr_t *instrp)
250*0Sstevel@tonic-gate {
251*0Sstevel@tonic-gate 	mdb_instr_t bkpt = KAIF_BREAKPOINT_INSTR;
252*0Sstevel@tonic-gate 
253*0Sstevel@tonic-gate 	if (mdb_tgt_vread(mdb.m_target, instrp, sizeof (mdb_instr_t), addr) !=
254*0Sstevel@tonic-gate 	    sizeof (mdb_instr_t))
255*0Sstevel@tonic-gate 		return (-1); /* errno is set for us */
256*0Sstevel@tonic-gate 
257*0Sstevel@tonic-gate 	if (mdb_tgt_vwrite(mdb.m_target, &bkpt, sizeof (mdb_instr_t), addr) !=
258*0Sstevel@tonic-gate 	    sizeof (mdb_instr_t))
259*0Sstevel@tonic-gate 		return (-1); /* errno is set for us */
260*0Sstevel@tonic-gate 
261*0Sstevel@tonic-gate 	return (0);
262*0Sstevel@tonic-gate }
263*0Sstevel@tonic-gate 
264*0Sstevel@tonic-gate static int
265*0Sstevel@tonic-gate kaif_brkpt_disarm(uintptr_t addr, mdb_instr_t instrp)
266*0Sstevel@tonic-gate {
267*0Sstevel@tonic-gate 	if (mdb_tgt_vwrite(mdb.m_target, &instrp, sizeof (mdb_instr_t), addr) !=
268*0Sstevel@tonic-gate 	    sizeof (mdb_instr_t))
269*0Sstevel@tonic-gate 		return (-1); /* errno is set for us */
270*0Sstevel@tonic-gate 
271*0Sstevel@tonic-gate 	return (0);
272*0Sstevel@tonic-gate }
273*0Sstevel@tonic-gate 
274*0Sstevel@tonic-gate /*
275*0Sstevel@tonic-gate  * Intel watchpoints are even more fun than SPARC ones.  The Intel architecture
276*0Sstevel@tonic-gate  * manuals refer to watchpoints as breakpoints.  For consistency  with the
277*0Sstevel@tonic-gate  * terminology used in other portions of kmdb, we will, however, refer to them
278*0Sstevel@tonic-gate  * as watchpoints.
279*0Sstevel@tonic-gate  *
280*0Sstevel@tonic-gate  * Execute, data write, I/O read/write, and data read/write watchpoints are
281*0Sstevel@tonic-gate  * supported by the hardware.  Execute watchpoints must be one byte in length,
282*0Sstevel@tonic-gate  * and must be placed on the first byte of the instruction to be watched.
283*0Sstevel@tonic-gate  * Lengths of other watchpoints are more varied.
284*0Sstevel@tonic-gate  *
285*0Sstevel@tonic-gate  * Given that we already have a breakpoint facility, and given the restrictions
286*0Sstevel@tonic-gate  * placed on execute watchpoints, we're going to disallow the creation of
287*0Sstevel@tonic-gate  * execute watchpoints.  The others will be fully supported.  See the Debugging
288*0Sstevel@tonic-gate  * chapter in both the IA32 and AMD64 System Programming books for more details.
289*0Sstevel@tonic-gate  */
290*0Sstevel@tonic-gate 
291*0Sstevel@tonic-gate #ifdef __amd64
292*0Sstevel@tonic-gate #define	WAPT_DATA_MAX_SIZE	8
293*0Sstevel@tonic-gate #define	WAPT_DATA_SIZES_MSG	"1, 2, 4, or 8"
294*0Sstevel@tonic-gate #else
295*0Sstevel@tonic-gate #define	WAPT_DATA_MAX_SIZE	4
296*0Sstevel@tonic-gate #define	WAPT_DATA_SIZES_MSG	"1, 2, or 4"
297*0Sstevel@tonic-gate #endif
298*0Sstevel@tonic-gate 
299*0Sstevel@tonic-gate static int
300*0Sstevel@tonic-gate kaif_wapt_validate(kmdb_wapt_t *wp)
301*0Sstevel@tonic-gate {
302*0Sstevel@tonic-gate 	if (wp->wp_type == DPI_WAPT_TYPE_IO) {
303*0Sstevel@tonic-gate 		if (wp->wp_wflags != (MDB_TGT_WA_R | MDB_TGT_WA_W)) {
304*0Sstevel@tonic-gate 			warn("I/O port watchpoints must be read/write\n");
305*0Sstevel@tonic-gate 			return (set_errno(EINVAL));
306*0Sstevel@tonic-gate 		}
307*0Sstevel@tonic-gate 
308*0Sstevel@tonic-gate 		if (wp->wp_size != 1 && wp->wp_size != 2 && wp->wp_size != 4) {
309*0Sstevel@tonic-gate 			warn("I/O watchpoint size must be 1, 2, or 4 bytes\n");
310*0Sstevel@tonic-gate 			return (set_errno(EINVAL));
311*0Sstevel@tonic-gate 		}
312*0Sstevel@tonic-gate 
313*0Sstevel@tonic-gate 	} else if (wp->wp_type == DPI_WAPT_TYPE_PHYS) {
314*0Sstevel@tonic-gate 		warn("physical address watchpoints are not supported on this "
315*0Sstevel@tonic-gate 		    "platform\n");
316*0Sstevel@tonic-gate 		return (set_errno(EMDB_TGTHWNOTSUP));
317*0Sstevel@tonic-gate 
318*0Sstevel@tonic-gate 	} else {
319*0Sstevel@tonic-gate 		if (wp->wp_wflags != (MDB_TGT_WA_R | MDB_TGT_WA_W) &&
320*0Sstevel@tonic-gate 		    wp->wp_wflags != MDB_TGT_WA_W) {
321*0Sstevel@tonic-gate 			warn("watchpoints must be read/write or write-only\n");
322*0Sstevel@tonic-gate 			return (set_errno(EINVAL));
323*0Sstevel@tonic-gate 		}
324*0Sstevel@tonic-gate 
325*0Sstevel@tonic-gate 		if ((wp->wp_size & -(wp->wp_size)) != wp->wp_size ||
326*0Sstevel@tonic-gate 		    wp->wp_size > WAPT_DATA_MAX_SIZE) {
327*0Sstevel@tonic-gate 			warn("data watchpoint size must be " WAPT_DATA_SIZES_MSG
328*0Sstevel@tonic-gate 			    " bytes\n");
329*0Sstevel@tonic-gate 			return (set_errno(EINVAL));
330*0Sstevel@tonic-gate 		}
331*0Sstevel@tonic-gate 
332*0Sstevel@tonic-gate 	}
333*0Sstevel@tonic-gate 
334*0Sstevel@tonic-gate 	if (wp->wp_addr & (wp->wp_size - 1)) {
335*0Sstevel@tonic-gate 		warn("%lu-byte watchpoints must be %lu-byte aligned\n",
336*0Sstevel@tonic-gate 		    (ulong_t)wp->wp_size, (ulong_t)wp->wp_size);
337*0Sstevel@tonic-gate 		return (set_errno(EINVAL));
338*0Sstevel@tonic-gate 	}
339*0Sstevel@tonic-gate 
340*0Sstevel@tonic-gate 	return (0);
341*0Sstevel@tonic-gate }
342*0Sstevel@tonic-gate 
343*0Sstevel@tonic-gate static int
344*0Sstevel@tonic-gate kaif_wapt_reserve(kmdb_wapt_t *wp)
345*0Sstevel@tonic-gate {
346*0Sstevel@tonic-gate 	int id;
347*0Sstevel@tonic-gate 
348*0Sstevel@tonic-gate 	for (id = 0; id <= KREG_MAXWPIDX; id++) {
349*0Sstevel@tonic-gate 		if (!BT_TEST(&kaif_waptmap, id)) {
350*0Sstevel@tonic-gate 			/* found one */
351*0Sstevel@tonic-gate 			BT_SET(&kaif_waptmap, id);
352*0Sstevel@tonic-gate 			wp->wp_priv = (void *)(uintptr_t)id;
353*0Sstevel@tonic-gate 			return (0);
354*0Sstevel@tonic-gate 		}
355*0Sstevel@tonic-gate 	}
356*0Sstevel@tonic-gate 
357*0Sstevel@tonic-gate 	return (set_errno(EMDB_WPTOOMANY));
358*0Sstevel@tonic-gate }
359*0Sstevel@tonic-gate 
360*0Sstevel@tonic-gate static void
361*0Sstevel@tonic-gate kaif_wapt_release(kmdb_wapt_t *wp)
362*0Sstevel@tonic-gate {
363*0Sstevel@tonic-gate 	int id = KAIF_WPPRIV2ID(wp);
364*0Sstevel@tonic-gate 
365*0Sstevel@tonic-gate 	ASSERT(BT_TEST(&kaif_waptmap, id));
366*0Sstevel@tonic-gate 	BT_CLEAR(&kaif_waptmap, id);
367*0Sstevel@tonic-gate }
368*0Sstevel@tonic-gate 
369*0Sstevel@tonic-gate /*ARGSUSED*/
370*0Sstevel@tonic-gate static void
371*0Sstevel@tonic-gate kaif_wapt_arm(kmdb_wapt_t *wp)
372*0Sstevel@tonic-gate {
373*0Sstevel@tonic-gate 	uint_t rw;
374*0Sstevel@tonic-gate 	int hwid = KAIF_WPPRIV2ID(wp);
375*0Sstevel@tonic-gate 
376*0Sstevel@tonic-gate 	ASSERT(BT_TEST(&kaif_waptmap, hwid));
377*0Sstevel@tonic-gate 
378*0Sstevel@tonic-gate 	if (wp->wp_type == DPI_WAPT_TYPE_IO)
379*0Sstevel@tonic-gate 		rw = KREG_DRCTL_WP_IORW;
380*0Sstevel@tonic-gate 	else if (wp->wp_wflags & MDB_TGT_WA_R)
381*0Sstevel@tonic-gate 		rw = KREG_DRCTL_WP_RW;
382*0Sstevel@tonic-gate 	else if (wp->wp_wflags & MDB_TGT_WA_X)
383*0Sstevel@tonic-gate 		rw = KREG_DRCTL_WP_EXEC;
384*0Sstevel@tonic-gate 	else
385*0Sstevel@tonic-gate 		rw = KREG_DRCTL_WP_WONLY;
386*0Sstevel@tonic-gate 
387*0Sstevel@tonic-gate 	kaif_drreg.dr_addr[hwid] = wp->wp_addr;
388*0Sstevel@tonic-gate 
389*0Sstevel@tonic-gate 	kaif_drreg.dr_ctl &= ~KREG_DRCTL_WP_MASK(hwid);
390*0Sstevel@tonic-gate 	kaif_drreg.dr_ctl |= KREG_DRCTL_WP_LENRW(hwid, wp->wp_size - 1, rw);
391*0Sstevel@tonic-gate 	kaif_drreg.dr_ctl |= KREG_DRCTL_WPEN(hwid);
392*0Sstevel@tonic-gate }
393*0Sstevel@tonic-gate 
394*0Sstevel@tonic-gate /*ARGSUSED*/
395*0Sstevel@tonic-gate static void
396*0Sstevel@tonic-gate kaif_wapt_disarm(kmdb_wapt_t *wp)
397*0Sstevel@tonic-gate {
398*0Sstevel@tonic-gate 	int hwid = KAIF_WPPRIV2ID(wp);
399*0Sstevel@tonic-gate 
400*0Sstevel@tonic-gate 	ASSERT(BT_TEST(&kaif_waptmap, hwid));
401*0Sstevel@tonic-gate 
402*0Sstevel@tonic-gate 	kaif_drreg.dr_addr[hwid] = 0;
403*0Sstevel@tonic-gate 	kaif_drreg.dr_ctl &= ~(KREG_DRCTL_WP_MASK(hwid) |
404*0Sstevel@tonic-gate 	    KREG_DRCTL_WPEN_MASK(hwid));
405*0Sstevel@tonic-gate }
406*0Sstevel@tonic-gate 
407*0Sstevel@tonic-gate /*ARGSUSED*/
408*0Sstevel@tonic-gate static int
409*0Sstevel@tonic-gate kaif_wapt_match(kmdb_wapt_t *wp)
410*0Sstevel@tonic-gate {
411*0Sstevel@tonic-gate 	int hwid = KAIF_WPPRIV2ID(wp);
412*0Sstevel@tonic-gate 	uint32_t mask = KREG_DRSTAT_WP_MASK(hwid);
413*0Sstevel@tonic-gate 	int n = 0;
414*0Sstevel@tonic-gate 	int i;
415*0Sstevel@tonic-gate 
416*0Sstevel@tonic-gate 	ASSERT(BT_TEST(&kaif_waptmap, hwid));
417*0Sstevel@tonic-gate 
418*0Sstevel@tonic-gate 	for (i = 0; i < kaif_ncpusave; i++)
419*0Sstevel@tonic-gate 		n += (kaif_cpusave[i].krs_dr.dr_stat & mask) != 0;
420*0Sstevel@tonic-gate 
421*0Sstevel@tonic-gate 	return (n);
422*0Sstevel@tonic-gate }
423*0Sstevel@tonic-gate 
424*0Sstevel@tonic-gate static int
425*0Sstevel@tonic-gate kaif_step(void)
426*0Sstevel@tonic-gate {
427*0Sstevel@tonic-gate 	kreg_t pc, fl, oldfl, newfl, sp;
428*0Sstevel@tonic-gate 	mdb_tgt_addr_t npc;
429*0Sstevel@tonic-gate 	mdb_instr_t instr;
430*0Sstevel@tonic-gate 	int emulated = 0, rchk = 0;
431*0Sstevel@tonic-gate 	size_t pcoff = 0;
432*0Sstevel@tonic-gate 
433*0Sstevel@tonic-gate 	(void) kmdb_dpi_get_register("pc", &pc);
434*0Sstevel@tonic-gate 
435*0Sstevel@tonic-gate 	if ((npc = mdb_dis_nextins(mdb.m_disasm, mdb.m_target,
436*0Sstevel@tonic-gate 	    MDB_TGT_AS_VIRT, pc)) == pc) {
437*0Sstevel@tonic-gate 		warn("failed to decode instruction at %a for step\n", pc);
438*0Sstevel@tonic-gate 		return (set_errno(EINVAL));
439*0Sstevel@tonic-gate 	}
440*0Sstevel@tonic-gate 
441*0Sstevel@tonic-gate 	/*
442*0Sstevel@tonic-gate 	 * Stepping behavior depends on the type of instruction.  It does not
443*0Sstevel@tonic-gate 	 * depend on the presence of a REX prefix, as the action we take for a
444*0Sstevel@tonic-gate 	 * given instruction doesn't currently vary for 32-bit instructions
445*0Sstevel@tonic-gate 	 * versus their 64-bit counterparts.
446*0Sstevel@tonic-gate 	 */
447*0Sstevel@tonic-gate 	do {
448*0Sstevel@tonic-gate 		if (mdb_tgt_vread(mdb.m_target, &instr, sizeof (mdb_instr_t),
449*0Sstevel@tonic-gate 		    pc + pcoff) != sizeof (mdb_instr_t)) {
450*0Sstevel@tonic-gate 			warn("failed to read at %p for step",
451*0Sstevel@tonic-gate 			    (void *)(pc + pcoff));
452*0Sstevel@tonic-gate 			return (-1);
453*0Sstevel@tonic-gate 		}
454*0Sstevel@tonic-gate 	} while (pcoff++, (instr >= M_REX_LO && instr <= M_REX_HI && !rchk++));
455*0Sstevel@tonic-gate 
456*0Sstevel@tonic-gate 	switch (instr) {
457*0Sstevel@tonic-gate 	case M_IRET:
458*0Sstevel@tonic-gate 		warn("iret cannot be stepped\n");
459*0Sstevel@tonic-gate 		return (set_errno(EMDB_TGTNOTSUP));
460*0Sstevel@tonic-gate 
461*0Sstevel@tonic-gate 	case M_INT3:
462*0Sstevel@tonic-gate 	case M_INTX:
463*0Sstevel@tonic-gate 	case M_INTO:
464*0Sstevel@tonic-gate 		warn("int cannot be stepped\n");
465*0Sstevel@tonic-gate 		return (set_errno(EMDB_TGTNOTSUP));
466*0Sstevel@tonic-gate 
467*0Sstevel@tonic-gate 	case M_ESC:
468*0Sstevel@tonic-gate 		if (mdb_tgt_vread(mdb.m_target, &instr, sizeof (mdb_instr_t),
469*0Sstevel@tonic-gate 		    pc + pcoff) != sizeof (mdb_instr_t)) {
470*0Sstevel@tonic-gate 			warn("failed to read at %p for step",
471*0Sstevel@tonic-gate 			    (void *)(pc + pcoff));
472*0Sstevel@tonic-gate 			return (-1);
473*0Sstevel@tonic-gate 		}
474*0Sstevel@tonic-gate 
475*0Sstevel@tonic-gate 		switch (instr) {
476*0Sstevel@tonic-gate 		case M_SYSRET:
477*0Sstevel@tonic-gate 			warn("sysret cannot be stepped\n");
478*0Sstevel@tonic-gate 			return (set_errno(EMDB_TGTNOTSUP));
479*0Sstevel@tonic-gate 		case M_SYSEXIT:
480*0Sstevel@tonic-gate 			warn("sysexit cannot be stepped\n");
481*0Sstevel@tonic-gate 			return (set_errno(EMDB_TGTNOTSUP));
482*0Sstevel@tonic-gate 		}
483*0Sstevel@tonic-gate 		break;
484*0Sstevel@tonic-gate 
485*0Sstevel@tonic-gate 	/*
486*0Sstevel@tonic-gate 	 * Some instructions need to be emulated.  We need to prevent direct
487*0Sstevel@tonic-gate 	 * manipulations of EFLAGS, so we'll emulate cli, sti.  pushfl and
488*0Sstevel@tonic-gate 	 * popfl also receive special handling, as they manipulate both EFLAGS
489*0Sstevel@tonic-gate 	 * and %esp.
490*0Sstevel@tonic-gate 	 */
491*0Sstevel@tonic-gate 	case M_CLI:
492*0Sstevel@tonic-gate 		(void) kmdb_dpi_get_register(FLAGS_REG_NAME, &fl);
493*0Sstevel@tonic-gate 		fl &= ~KREG_EFLAGS_IF_MASK;
494*0Sstevel@tonic-gate 		(void) kmdb_dpi_set_register(FLAGS_REG_NAME, fl);
495*0Sstevel@tonic-gate 
496*0Sstevel@tonic-gate 		emulated = 1;
497*0Sstevel@tonic-gate 		break;
498*0Sstevel@tonic-gate 
499*0Sstevel@tonic-gate 	case M_STI:
500*0Sstevel@tonic-gate 		(void) kmdb_dpi_get_register(FLAGS_REG_NAME, &fl);
501*0Sstevel@tonic-gate 		fl |= (1 << KREG_EFLAGS_IF_SHIFT);
502*0Sstevel@tonic-gate 		(void) kmdb_dpi_set_register(FLAGS_REG_NAME, fl);
503*0Sstevel@tonic-gate 
504*0Sstevel@tonic-gate 		emulated = 1;
505*0Sstevel@tonic-gate 		break;
506*0Sstevel@tonic-gate 
507*0Sstevel@tonic-gate 	case M_POPF:
508*0Sstevel@tonic-gate 		/*
509*0Sstevel@tonic-gate 		 * popfl will restore a pushed EFLAGS from the stack, and could
510*0Sstevel@tonic-gate 		 * in so doing cause IF to be turned on, if only for a a brief
511*0Sstevel@tonic-gate 		 * period.  To avoid this, we'll secretly replace the stack's
512*0Sstevel@tonic-gate 		 * EFLAGS with our decaffeinated brand.  We'll then manually
513*0Sstevel@tonic-gate 		 * load our EFLAGS copy with the real verion after the step.
514*0Sstevel@tonic-gate 		 */
515*0Sstevel@tonic-gate 		(void) kmdb_dpi_get_register("sp", &sp);
516*0Sstevel@tonic-gate 		(void) kmdb_dpi_get_register(FLAGS_REG_NAME, &fl);
517*0Sstevel@tonic-gate 
518*0Sstevel@tonic-gate 		if (mdb_tgt_vread(mdb.m_target, &newfl, sizeof (kreg_t),
519*0Sstevel@tonic-gate 		    sp) != sizeof (kreg_t)) {
520*0Sstevel@tonic-gate 			warn("failed to read " FLAGS_REG_NAME
521*0Sstevel@tonic-gate 			    " at %p for popfl step\n", (void *)sp);
522*0Sstevel@tonic-gate 			return (set_errno(EMDB_TGTNOTSUP)); /* XXX ? */
523*0Sstevel@tonic-gate 		}
524*0Sstevel@tonic-gate 
525*0Sstevel@tonic-gate 		fl = (fl & ~KREG_EFLAGS_IF_MASK) | KREG_EFLAGS_TF_MASK;
526*0Sstevel@tonic-gate 
527*0Sstevel@tonic-gate 		if (mdb_tgt_vwrite(mdb.m_target, &fl, sizeof (kreg_t),
528*0Sstevel@tonic-gate 		    sp) != sizeof (kreg_t)) {
529*0Sstevel@tonic-gate 			warn("failed to update " FLAGS_REG_NAME
530*0Sstevel@tonic-gate 			    " at %p for popfl step\n", (void *)sp);
531*0Sstevel@tonic-gate 			return (set_errno(EMDB_TGTNOTSUP)); /* XXX ? */
532*0Sstevel@tonic-gate 		}
533*0Sstevel@tonic-gate 		break;
534*0Sstevel@tonic-gate 	}
535*0Sstevel@tonic-gate 
536*0Sstevel@tonic-gate 	if (emulated) {
537*0Sstevel@tonic-gate 		(void) kmdb_dpi_set_register("pc", npc);
538*0Sstevel@tonic-gate 		return (0);
539*0Sstevel@tonic-gate 	}
540*0Sstevel@tonic-gate 
541*0Sstevel@tonic-gate 	/* Do the step with IF off, and TF (step) on */
542*0Sstevel@tonic-gate 	(void) kmdb_dpi_get_register(FLAGS_REG_NAME, &oldfl);
543*0Sstevel@tonic-gate 	(void) kmdb_dpi_set_register(FLAGS_REG_NAME,
544*0Sstevel@tonic-gate 	    ((oldfl | (1 << KREG_EFLAGS_TF_SHIFT)) & ~KREG_EFLAGS_IF_MASK));
545*0Sstevel@tonic-gate 
546*0Sstevel@tonic-gate 	kmdb_dpi_resume_master(); /* ... there and back again ... */
547*0Sstevel@tonic-gate 
548*0Sstevel@tonic-gate 	/* EFLAGS has now changed, and may require tuning */
549*0Sstevel@tonic-gate 
550*0Sstevel@tonic-gate 	switch (instr) {
551*0Sstevel@tonic-gate 	case M_POPF:
552*0Sstevel@tonic-gate 		/*
553*0Sstevel@tonic-gate 		 * Use the EFLAGS we grabbed before the pop - see the pre-step
554*0Sstevel@tonic-gate 		 * M_POPFL comment.
555*0Sstevel@tonic-gate 		 */
556*0Sstevel@tonic-gate 		(void) kmdb_dpi_set_register(FLAGS_REG_NAME, newfl);
557*0Sstevel@tonic-gate 		return (0);
558*0Sstevel@tonic-gate 
559*0Sstevel@tonic-gate 	case M_PUSHF:
560*0Sstevel@tonic-gate 		/*
561*0Sstevel@tonic-gate 		 * We pushed our modified EFLAGS (with IF and TF turned off)
562*0Sstevel@tonic-gate 		 * onto the stack.  Replace the pushed version with our
563*0Sstevel@tonic-gate 		 * unmodified one.
564*0Sstevel@tonic-gate 		 */
565*0Sstevel@tonic-gate 		(void) kmdb_dpi_get_register("sp", &sp);
566*0Sstevel@tonic-gate 
567*0Sstevel@tonic-gate 		if (mdb_tgt_vwrite(mdb.m_target, &oldfl, sizeof (kreg_t),
568*0Sstevel@tonic-gate 		    sp) != sizeof (kreg_t)) {
569*0Sstevel@tonic-gate 			warn("failed to update pushed " FLAGS_REG_NAME
570*0Sstevel@tonic-gate 			    " at %p after pushfl step\n", (void *)sp);
571*0Sstevel@tonic-gate 			return (set_errno(EMDB_TGTNOTSUP)); /* XXX ? */
572*0Sstevel@tonic-gate 		}
573*0Sstevel@tonic-gate 
574*0Sstevel@tonic-gate 		/* Go back to using the EFLAGS we were using before the step */
575*0Sstevel@tonic-gate 		(void) kmdb_dpi_set_register(FLAGS_REG_NAME, oldfl);
576*0Sstevel@tonic-gate 		return (0);
577*0Sstevel@tonic-gate 
578*0Sstevel@tonic-gate 	default:
579*0Sstevel@tonic-gate 		/*
580*0Sstevel@tonic-gate 		 * The stepped instruction may have altered EFLAGS.  We only
581*0Sstevel@tonic-gate 		 * really care about the value of IF, and we know the stepped
582*0Sstevel@tonic-gate 		 * instruction didn't alter it, so we can simply copy the
583*0Sstevel@tonic-gate 		 * pre-step value.  We'll also need to turn TF back off.
584*0Sstevel@tonic-gate 		 */
585*0Sstevel@tonic-gate 		(void) kmdb_dpi_get_register(FLAGS_REG_NAME, &fl);
586*0Sstevel@tonic-gate 		(void) kmdb_dpi_set_register(FLAGS_REG_NAME,
587*0Sstevel@tonic-gate 		    ((fl & ~(KREG_EFLAGS_TF_MASK|KREG_EFLAGS_IF_MASK)) |
588*0Sstevel@tonic-gate 		    (oldfl & KREG_EFLAGS_IF_MASK)));
589*0Sstevel@tonic-gate 		return (0);
590*0Sstevel@tonic-gate 	}
591*0Sstevel@tonic-gate }
592*0Sstevel@tonic-gate 
593*0Sstevel@tonic-gate /*
594*0Sstevel@tonic-gate  * The target has already configured the chip for branch step, leaving us to
595*0Sstevel@tonic-gate  * actually make the machine go.  Due to a number of issues involving
596*0Sstevel@tonic-gate  * the potential alteration of system state via instructions like sti, cli,
597*0Sstevel@tonic-gate  * pushfl, and popfl, we're going to treat this like a normal system resume.
598*0Sstevel@tonic-gate  * All CPUs will be released, on the kernel's IDT.  Our primary concern is
599*0Sstevel@tonic-gate  * the alteration/storage of our TF'd EFLAGS via pushfl and popfl.  There's no
600*0Sstevel@tonic-gate  * real workaround - we don't have opcode breakpoints - so the best we can do is
601*0Sstevel@tonic-gate  * to ensure that the world won't end if someone does bad things to EFLAGS.
602*0Sstevel@tonic-gate  *
603*0Sstevel@tonic-gate  * Two things can happen:
604*0Sstevel@tonic-gate  *  1. EFLAGS.TF may be cleared, either maliciously or via a popfl from saved
605*0Sstevel@tonic-gate  *     state.  The CPU will continue execution beyond the branch, and will not
606*0Sstevel@tonic-gate  *     reenter the debugger unless brought/sent in by other means.
607*0Sstevel@tonic-gate  *  2. Someone may pushlf the TF'd EFLAGS, and may stash a copy of it somewhere.
608*0Sstevel@tonic-gate  *     When the saved version is popfl'd back into place, the debugger will be
609*0Sstevel@tonic-gate  *     re-entered on a single-step trap.
610*0Sstevel@tonic-gate  */
611*0Sstevel@tonic-gate static void
612*0Sstevel@tonic-gate kaif_step_branch(void)
613*0Sstevel@tonic-gate {
614*0Sstevel@tonic-gate 	kreg_t fl;
615*0Sstevel@tonic-gate 
616*0Sstevel@tonic-gate 	(void) kmdb_dpi_get_register(FLAGS_REG_NAME, &fl);
617*0Sstevel@tonic-gate 	(void) kmdb_dpi_set_register(FLAGS_REG_NAME,
618*0Sstevel@tonic-gate 	    (fl | (1 << KREG_EFLAGS_TF_SHIFT)));
619*0Sstevel@tonic-gate 
620*0Sstevel@tonic-gate 	kmdb_dpi_resume_master();
621*0Sstevel@tonic-gate 
622*0Sstevel@tonic-gate 	(void) kmdb_dpi_set_register(FLAGS_REG_NAME, fl);
623*0Sstevel@tonic-gate }
624*0Sstevel@tonic-gate 
625*0Sstevel@tonic-gate /*ARGSUSED*/
626*0Sstevel@tonic-gate static uintptr_t
627*0Sstevel@tonic-gate kaif_call(uintptr_t funcva, uint_t argc, const uintptr_t argv[])
628*0Sstevel@tonic-gate {
629*0Sstevel@tonic-gate 	return (kaif_invoke(funcva, argc, argv));
630*0Sstevel@tonic-gate }
631*0Sstevel@tonic-gate 
632*0Sstevel@tonic-gate static void
633*0Sstevel@tonic-gate dump_crumb(kaif_crumb_t *crumb)
634*0Sstevel@tonic-gate {
635*0Sstevel@tonic-gate 	mdb_printf("state: ");
636*0Sstevel@tonic-gate 	switch (crumb->krm_cpu_state) {
637*0Sstevel@tonic-gate 	case KAIF_CPU_STATE_MASTER:
638*0Sstevel@tonic-gate 		mdb_printf("M");
639*0Sstevel@tonic-gate 		break;
640*0Sstevel@tonic-gate 	case KAIF_CPU_STATE_SLAVE:
641*0Sstevel@tonic-gate 		mdb_printf("S");
642*0Sstevel@tonic-gate 		break;
643*0Sstevel@tonic-gate 	default:
644*0Sstevel@tonic-gate 		mdb_printf("%d", crumb->krm_cpu_state);
645*0Sstevel@tonic-gate 	}
646*0Sstevel@tonic-gate 
647*0Sstevel@tonic-gate 	mdb_printf(" trapno %3d sp %08x flag %d pc %p %A\n",
648*0Sstevel@tonic-gate 	    crumb->krm_trapno, crumb->krm_sp, crumb->krm_flag,
649*0Sstevel@tonic-gate 	    crumb->krm_pc, crumb->krm_pc);
650*0Sstevel@tonic-gate }
651*0Sstevel@tonic-gate 
652*0Sstevel@tonic-gate static void
653*0Sstevel@tonic-gate dump_crumbs(kaif_cpusave_t *save)
654*0Sstevel@tonic-gate {
655*0Sstevel@tonic-gate 	int i;
656*0Sstevel@tonic-gate 
657*0Sstevel@tonic-gate 	for (i = KAIF_NCRUMBS; i > 0; i--) {
658*0Sstevel@tonic-gate 		uint_t idx = (save->krs_curcrumbidx + i) % KAIF_NCRUMBS;
659*0Sstevel@tonic-gate 
660*0Sstevel@tonic-gate 		dump_crumb(&save->krs_crumbs[idx]);
661*0Sstevel@tonic-gate 	}
662*0Sstevel@tonic-gate }
663*0Sstevel@tonic-gate 
664*0Sstevel@tonic-gate static void
665*0Sstevel@tonic-gate kaif_dump_crumbs(uintptr_t addr, int cpuid)
666*0Sstevel@tonic-gate {
667*0Sstevel@tonic-gate 	int i;
668*0Sstevel@tonic-gate 
669*0Sstevel@tonic-gate 	if (addr != NULL) {
670*0Sstevel@tonic-gate 		dump_crumb((kaif_crumb_t *)addr);
671*0Sstevel@tonic-gate 
672*0Sstevel@tonic-gate 	} else if (cpuid != -1) {
673*0Sstevel@tonic-gate 		if (cpuid >= kaif_ncpusave)
674*0Sstevel@tonic-gate 			return;
675*0Sstevel@tonic-gate 
676*0Sstevel@tonic-gate 		dump_crumbs(&kaif_cpusave[cpuid]);
677*0Sstevel@tonic-gate 
678*0Sstevel@tonic-gate 	} else {
679*0Sstevel@tonic-gate 		for (i = 0; i < kaif_ncpusave; i++) {
680*0Sstevel@tonic-gate 			kaif_cpusave_t *save = &kaif_cpusave[i];
681*0Sstevel@tonic-gate 
682*0Sstevel@tonic-gate 			if (save->krs_cpu_state == KAIF_CPU_STATE_NONE)
683*0Sstevel@tonic-gate 				continue;
684*0Sstevel@tonic-gate 
685*0Sstevel@tonic-gate 			mdb_printf("%sCPU %d crumbs: (curidx %d)\n",
686*0Sstevel@tonic-gate 			    (i == 0 ? "" : "\n"), i, save->krs_curcrumbidx);
687*0Sstevel@tonic-gate 
688*0Sstevel@tonic-gate 			dump_crumbs(save);
689*0Sstevel@tonic-gate 		}
690*0Sstevel@tonic-gate 	}
691*0Sstevel@tonic-gate }
692*0Sstevel@tonic-gate 
693*0Sstevel@tonic-gate static void
694*0Sstevel@tonic-gate kaif_modchg_register(void (*func)(struct modctl *, int))
695*0Sstevel@tonic-gate {
696*0Sstevel@tonic-gate 	kaif_modchg_cb = func;
697*0Sstevel@tonic-gate }
698*0Sstevel@tonic-gate 
699*0Sstevel@tonic-gate static void
700*0Sstevel@tonic-gate kaif_modchg_cancel(void)
701*0Sstevel@tonic-gate {
702*0Sstevel@tonic-gate 	ASSERT(kaif_modchg_cb != NULL);
703*0Sstevel@tonic-gate 
704*0Sstevel@tonic-gate 	kaif_modchg_cb = NULL;
705*0Sstevel@tonic-gate }
706*0Sstevel@tonic-gate 
707*0Sstevel@tonic-gate void
708*0Sstevel@tonic-gate kaif_mod_loaded(struct modctl *modp)
709*0Sstevel@tonic-gate {
710*0Sstevel@tonic-gate 	if (kaif_modchg_cb != NULL)
711*0Sstevel@tonic-gate 		kaif_modchg_cb(modp, 1);
712*0Sstevel@tonic-gate }
713*0Sstevel@tonic-gate 
714*0Sstevel@tonic-gate void
715*0Sstevel@tonic-gate kaif_mod_unloading(struct modctl *modp)
716*0Sstevel@tonic-gate {
717*0Sstevel@tonic-gate 	if (kaif_modchg_cb != NULL)
718*0Sstevel@tonic-gate 		kaif_modchg_cb(modp, 0);
719*0Sstevel@tonic-gate }
720*0Sstevel@tonic-gate 
721*0Sstevel@tonic-gate /*
722*0Sstevel@tonic-gate  * On some processors, we'll need to clear a certain MSR before proceeding into
723*0Sstevel@tonic-gate  * the debugger.  Complicating matters, this MSR must be cleared before we take
724*0Sstevel@tonic-gate  * any branches.  We have patch points in every trap handler, which will cover
725*0Sstevel@tonic-gate  * all entry paths for master CPUs.  We also have a patch point in the slave
726*0Sstevel@tonic-gate  * entry code.
727*0Sstevel@tonic-gate  */
728*0Sstevel@tonic-gate static void
729*0Sstevel@tonic-gate kaif_msr_add_clrentry(uint_t msr)
730*0Sstevel@tonic-gate {
731*0Sstevel@tonic-gate #ifdef __amd64
732*0Sstevel@tonic-gate 	uchar_t code[] = {
733*0Sstevel@tonic-gate 		0x51, 0x50, 0x52,		/* pushq %rcx, %rax, %rdx */
734*0Sstevel@tonic-gate 		0xb9, 0x00, 0x00, 0x00, 0x00,	/* movl $MSRNUM, %ecx */
735*0Sstevel@tonic-gate 		0x31, 0xc0,			/* clr %eax */
736*0Sstevel@tonic-gate 		0x31, 0xd2,			/* clr %edx */
737*0Sstevel@tonic-gate 		0x0f, 0x30,			/* wrmsr */
738*0Sstevel@tonic-gate 		0x5a, 0x58, 0x59		/* popq %rdx, %rax, %rcx */
739*0Sstevel@tonic-gate 	};
740*0Sstevel@tonic-gate 	uchar_t *patch = &code[4];
741*0Sstevel@tonic-gate #else
742*0Sstevel@tonic-gate 	uchar_t code[] = {
743*0Sstevel@tonic-gate 		0x60,				/* pushal */
744*0Sstevel@tonic-gate 		0xb9, 0x00, 0x00, 0x00, 0x00,	/* movl $MSRNUM, %ecx */
745*0Sstevel@tonic-gate 		0x31, 0xc0,			/* clr %eax */
746*0Sstevel@tonic-gate 		0x31, 0xd2,			/* clr %edx */
747*0Sstevel@tonic-gate 		0x0f, 0x30,			/* wrmsr */
748*0Sstevel@tonic-gate 		0x61				/* popal */
749*0Sstevel@tonic-gate 	};
750*0Sstevel@tonic-gate 	uchar_t *patch = &code[2];
751*0Sstevel@tonic-gate #endif
752*0Sstevel@tonic-gate 
753*0Sstevel@tonic-gate 	bcopy(&msr, patch, sizeof (uint32_t));
754*0Sstevel@tonic-gate 
755*0Sstevel@tonic-gate 	kaif_idt_patch((caddr_t)code, sizeof (code));
756*0Sstevel@tonic-gate 
757*0Sstevel@tonic-gate 	bcopy(code, &kaif_slave_entry_patch, sizeof (code));
758*0Sstevel@tonic-gate }
759*0Sstevel@tonic-gate 
760*0Sstevel@tonic-gate static void
761*0Sstevel@tonic-gate kaif_msr_add_wrexit(uint_t msr, uint64_t *valp)
762*0Sstevel@tonic-gate {
763*0Sstevel@tonic-gate 	kaif_msr_wrexit_msr = msr;
764*0Sstevel@tonic-gate 	kaif_msr_wrexit_valp = valp;
765*0Sstevel@tonic-gate }
766*0Sstevel@tonic-gate 
767*0Sstevel@tonic-gate static void
768*0Sstevel@tonic-gate kaif_msr_add(const kmdb_msr_t *msrs)
769*0Sstevel@tonic-gate {
770*0Sstevel@tonic-gate 	kmdb_msr_t *save;
771*0Sstevel@tonic-gate 	int nmsrs, i;
772*0Sstevel@tonic-gate 
773*0Sstevel@tonic-gate 	ASSERT(kaif_cpusave[0].krs_msr == NULL);
774*0Sstevel@tonic-gate 
775*0Sstevel@tonic-gate 	for (i = 0; msrs[i].msr_num != 0; i++) {
776*0Sstevel@tonic-gate 		switch (msrs[i].msr_type) {
777*0Sstevel@tonic-gate 		case KMDB_MSR_CLEARENTRY:
778*0Sstevel@tonic-gate 			kaif_msr_add_clrentry(msrs[i].msr_num);
779*0Sstevel@tonic-gate 			break;
780*0Sstevel@tonic-gate 
781*0Sstevel@tonic-gate 		case KMDB_MSR_WRITEDELAY:
782*0Sstevel@tonic-gate 			kaif_msr_add_wrexit(msrs[i].msr_num, msrs[i].msr_valp);
783*0Sstevel@tonic-gate 			break;
784*0Sstevel@tonic-gate 		}
785*0Sstevel@tonic-gate 	}
786*0Sstevel@tonic-gate 	nmsrs = i + 1; /* we want to copy the terminating kmdb_msr_t too */
787*0Sstevel@tonic-gate 
788*0Sstevel@tonic-gate 	save = mdb_zalloc(sizeof (kmdb_msr_t) * nmsrs * kaif_ncpusave,
789*0Sstevel@tonic-gate 	    UM_SLEEP);
790*0Sstevel@tonic-gate 
791*0Sstevel@tonic-gate 	for (i = 0; i < kaif_ncpusave; i++) {
792*0Sstevel@tonic-gate 		bcopy(msrs, &save[nmsrs * i], sizeof (kmdb_msr_t) * nmsrs);
793*0Sstevel@tonic-gate 		kaif_cpusave[i].krs_msr = &save[nmsrs * i];
794*0Sstevel@tonic-gate 	}
795*0Sstevel@tonic-gate }
796*0Sstevel@tonic-gate 
797*0Sstevel@tonic-gate static uint64_t
798*0Sstevel@tonic-gate kaif_msr_get(int cpuid, uint_t num)
799*0Sstevel@tonic-gate {
800*0Sstevel@tonic-gate 	kmdb_msr_t *msr;
801*0Sstevel@tonic-gate 	int i;
802*0Sstevel@tonic-gate 
803*0Sstevel@tonic-gate 	if (cpuid == DPI_MASTER_CPUID)
804*0Sstevel@tonic-gate 		cpuid = kaif_master_cpuid;
805*0Sstevel@tonic-gate 	msr = kaif_cpusave[cpuid].krs_msr;
806*0Sstevel@tonic-gate 
807*0Sstevel@tonic-gate 	for (i = 0; msr[i].msr_num != 0; i++) {
808*0Sstevel@tonic-gate 		if (msr[i].msr_num == num &&
809*0Sstevel@tonic-gate 		    (msr[i].msr_type & KMDB_MSR_READ))
810*0Sstevel@tonic-gate 			return (msr[i].msr_val);
811*0Sstevel@tonic-gate 	}
812*0Sstevel@tonic-gate 
813*0Sstevel@tonic-gate 	return (0);
814*0Sstevel@tonic-gate }
815*0Sstevel@tonic-gate 
816*0Sstevel@tonic-gate int
817*0Sstevel@tonic-gate kaif_memrange_add(caddr_t base, size_t len)
818*0Sstevel@tonic-gate {
819*0Sstevel@tonic-gate 	kaif_memrange_t *mr = &kaif_memranges[kaif_nmemranges];
820*0Sstevel@tonic-gate 
821*0Sstevel@tonic-gate 	if (kaif_nmemranges == KAIF_MEMRANGES_MAX)
822*0Sstevel@tonic-gate 		return (set_errno(ENOSPC));
823*0Sstevel@tonic-gate 
824*0Sstevel@tonic-gate 	/*
825*0Sstevel@tonic-gate 	 * In the unlikely event that someone is stepping through this routine,
826*0Sstevel@tonic-gate 	 * we need to make sure that kaif_memranges knows about the new range
827*0Sstevel@tonic-gate 	 * before umem gets it.  That way the entry code can recognize stacks
828*0Sstevel@tonic-gate 	 * allocated from the new region.
829*0Sstevel@tonic-gate 	 */
830*0Sstevel@tonic-gate 	mr->mr_base = base;
831*0Sstevel@tonic-gate 	mr->mr_lim = base + len - 1;
832*0Sstevel@tonic-gate 	kaif_nmemranges++;
833*0Sstevel@tonic-gate 
834*0Sstevel@tonic-gate 	if (mdb_umem_add(base, len) < 0) {
835*0Sstevel@tonic-gate 		kaif_nmemranges--;
836*0Sstevel@tonic-gate 		return (-1); /* errno is set for us */
837*0Sstevel@tonic-gate 	}
838*0Sstevel@tonic-gate 
839*0Sstevel@tonic-gate 	return (0);
840*0Sstevel@tonic-gate }
841*0Sstevel@tonic-gate 
842*0Sstevel@tonic-gate void
843*0Sstevel@tonic-gate kaif_trap_set_debugger(void)
844*0Sstevel@tonic-gate {
845*0Sstevel@tonic-gate 	set_idt(&kaif_idtr);
846*0Sstevel@tonic-gate }
847*0Sstevel@tonic-gate 
848*0Sstevel@tonic-gate void
849*0Sstevel@tonic-gate kaif_trap_set_saved(kaif_cpusave_t *cpusave)
850*0Sstevel@tonic-gate {
851*0Sstevel@tonic-gate 	set_idt(&cpusave->krs_idtr);
852*0Sstevel@tonic-gate }
853*0Sstevel@tonic-gate 
854*0Sstevel@tonic-gate static int
855*0Sstevel@tonic-gate kaif_init(kmdb_auxv_t *kav)
856*0Sstevel@tonic-gate {
857*0Sstevel@tonic-gate 	int i;
858*0Sstevel@tonic-gate 
859*0Sstevel@tonic-gate 	/* Allocate the per-CPU save areas */
860*0Sstevel@tonic-gate 	kaif_cpusave = mdb_zalloc(sizeof (kaif_cpusave_t) * kav->kav_ncpu,
861*0Sstevel@tonic-gate 	    UM_SLEEP);
862*0Sstevel@tonic-gate 	kaif_ncpusave = kav->kav_ncpu;
863*0Sstevel@tonic-gate 
864*0Sstevel@tonic-gate 	for (i = 0; i < kaif_ncpusave; i++) {
865*0Sstevel@tonic-gate 		kaif_cpusave[i].krs_cpu_id = i;
866*0Sstevel@tonic-gate 
867*0Sstevel@tonic-gate 		kaif_cpusave[i].krs_curcrumb =
868*0Sstevel@tonic-gate 		    &kaif_cpusave[i].krs_crumbs[KAIF_NCRUMBS - 1];
869*0Sstevel@tonic-gate 		kaif_cpusave[i].krs_curcrumbidx = KAIF_NCRUMBS - 1;
870*0Sstevel@tonic-gate 	}
871*0Sstevel@tonic-gate 
872*0Sstevel@tonic-gate 	kaif_idt_init();
873*0Sstevel@tonic-gate 
874*0Sstevel@tonic-gate 	/* The initial selector set.  Updated by the debugger-entry code */
875*0Sstevel@tonic-gate #ifndef __amd64
876*0Sstevel@tonic-gate 	kaif_cs = BOOTCODE_SEL;
877*0Sstevel@tonic-gate 	kaif_ds = kaif_fs = kaif_gs = BOOTFLAT_SEL;
878*0Sstevel@tonic-gate #endif
879*0Sstevel@tonic-gate 
880*0Sstevel@tonic-gate 	kaif_memranges[0].mr_base = kav->kav_dseg;
881*0Sstevel@tonic-gate 	kaif_memranges[0].mr_lim = kav->kav_dseg + kav->kav_dseg_size - 1;
882*0Sstevel@tonic-gate 	kaif_nmemranges = 1;
883*0Sstevel@tonic-gate 
884*0Sstevel@tonic-gate 	kaif_modchg_cb = NULL;
885*0Sstevel@tonic-gate 
886*0Sstevel@tonic-gate 	kaif_waptmap = 0;
887*0Sstevel@tonic-gate 
888*0Sstevel@tonic-gate 	kaif_drreg.dr_ctl = KREG_DRCTL_RESERVED;
889*0Sstevel@tonic-gate 	kaif_drreg.dr_stat = KREG_DRSTAT_RESERVED;
890*0Sstevel@tonic-gate 
891*0Sstevel@tonic-gate 	kaif_msr_wrexit_msr = 0;
892*0Sstevel@tonic-gate 	kaif_msr_wrexit_valp = NULL;
893*0Sstevel@tonic-gate 
894*0Sstevel@tonic-gate 	kaif_trap_switch = (kav->kav_flags & KMDB_AUXV_FL_NOTRPSWTCH) == 0;
895*0Sstevel@tonic-gate 
896*0Sstevel@tonic-gate 	if ((kaif_sys_sysenter = kmdb_kdi_lookup_by_name("unix",
897*0Sstevel@tonic-gate 	    "sys_sysenter")) == NULL)
898*0Sstevel@tonic-gate 		return (set_errno(ENOENT));
899*0Sstevel@tonic-gate 
900*0Sstevel@tonic-gate 	return (0);
901*0Sstevel@tonic-gate }
902*0Sstevel@tonic-gate 
903*0Sstevel@tonic-gate dpi_ops_t kmdb_dpi_ops = {
904*0Sstevel@tonic-gate 	kaif_init,
905*0Sstevel@tonic-gate 	kaif_activate,
906*0Sstevel@tonic-gate 	kaif_deactivate,
907*0Sstevel@tonic-gate 	kaif_enter_mon,
908*0Sstevel@tonic-gate 	kaif_modchg_register,
909*0Sstevel@tonic-gate 	kaif_modchg_cancel,
910*0Sstevel@tonic-gate 	kaif_get_cpu_state,
911*0Sstevel@tonic-gate 	kaif_get_master_cpuid,
912*0Sstevel@tonic-gate 	kaif_get_gregs,
913*0Sstevel@tonic-gate 	kaif_get_cpu_register,
914*0Sstevel@tonic-gate 	kaif_set_cpu_register,
915*0Sstevel@tonic-gate 	kaif_brkpt_arm,
916*0Sstevel@tonic-gate 	kaif_brkpt_disarm,
917*0Sstevel@tonic-gate 	kaif_wapt_validate,
918*0Sstevel@tonic-gate 	kaif_wapt_reserve,
919*0Sstevel@tonic-gate 	kaif_wapt_release,
920*0Sstevel@tonic-gate 	kaif_wapt_arm,
921*0Sstevel@tonic-gate 	kaif_wapt_disarm,
922*0Sstevel@tonic-gate 	kaif_wapt_match,
923*0Sstevel@tonic-gate 	kaif_step,
924*0Sstevel@tonic-gate 	kaif_step_branch,
925*0Sstevel@tonic-gate 	kaif_call,
926*0Sstevel@tonic-gate 	kaif_dump_crumbs,
927*0Sstevel@tonic-gate 	kaif_memrange_add,
928*0Sstevel@tonic-gate 	kaif_msr_add,
929*0Sstevel@tonic-gate 	kaif_msr_get,
930*0Sstevel@tonic-gate };
931