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