xref: /illumos-gate/usr/src/cmd/mdb/intel/kmdb/kaif.c (revision c7bf320592a8c4a952d9855186d4b38524c7484d)
17c478bd9Sstevel@tonic-gate /*
27c478bd9Sstevel@tonic-gate  * CDDL HEADER START
37c478bd9Sstevel@tonic-gate  *
47c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5*c7bf3205Sjohnlev  * Common Development and Distribution License (the "License").
6*c7bf3205Sjohnlev  * You may not use this file except in compliance with the License.
77c478bd9Sstevel@tonic-gate  *
87c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
97c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
107c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
117c478bd9Sstevel@tonic-gate  * and limitations under the License.
127c478bd9Sstevel@tonic-gate  *
137c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
147c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
157c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
167c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
177c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
187c478bd9Sstevel@tonic-gate  *
197c478bd9Sstevel@tonic-gate  * CDDL HEADER END
207c478bd9Sstevel@tonic-gate  */
217c478bd9Sstevel@tonic-gate /*
22acbc304dSjohnlev  * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
237c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
247c478bd9Sstevel@tonic-gate  */
257c478bd9Sstevel@tonic-gate 
267c478bd9Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
277c478bd9Sstevel@tonic-gate 
287c478bd9Sstevel@tonic-gate /*
297c478bd9Sstevel@tonic-gate  * The debugger/"PROM" interface layer
307c478bd9Sstevel@tonic-gate  *
317c478bd9Sstevel@tonic-gate  * (it makes more sense on SPARC)
327c478bd9Sstevel@tonic-gate  */
337c478bd9Sstevel@tonic-gate 
347c478bd9Sstevel@tonic-gate #include <kmdb/kmdb_dpi_impl.h>
357c478bd9Sstevel@tonic-gate #include <kmdb/kmdb_kdi.h>
367c478bd9Sstevel@tonic-gate #include <kmdb/kmdb_umemglue.h>
377c478bd9Sstevel@tonic-gate #include <kmdb/kaif.h>
387c478bd9Sstevel@tonic-gate #include <kmdb/kaif_asmutil.h>
39*c7bf3205Sjohnlev #include <kmdb/kmdb_io.h>
407c478bd9Sstevel@tonic-gate #include <mdb/mdb_err.h>
417c478bd9Sstevel@tonic-gate #include <mdb/mdb_debug.h>
427c478bd9Sstevel@tonic-gate #include <mdb/mdb_isautil.h>
437c478bd9Sstevel@tonic-gate #include <mdb/mdb_io_impl.h>
447c478bd9Sstevel@tonic-gate #include <mdb/mdb_kreg.h>
457c478bd9Sstevel@tonic-gate #include <mdb/mdb.h>
467c478bd9Sstevel@tonic-gate 
477c478bd9Sstevel@tonic-gate #include <sys/types.h>
487c478bd9Sstevel@tonic-gate #include <sys/segments.h>
497c478bd9Sstevel@tonic-gate #include <sys/bitmap.h>
50*c7bf3205Sjohnlev #include <sys/termios.h>
517c478bd9Sstevel@tonic-gate 
527c478bd9Sstevel@tonic-gate kaif_cpusave_t	*kaif_cpusave;
537c478bd9Sstevel@tonic-gate int		kaif_ncpusave;
547c478bd9Sstevel@tonic-gate 
557c478bd9Sstevel@tonic-gate kaif_drreg_t	kaif_drreg;
567c478bd9Sstevel@tonic-gate 
577c478bd9Sstevel@tonic-gate uint32_t	kaif_waptmap;
587c478bd9Sstevel@tonic-gate 
597c478bd9Sstevel@tonic-gate #ifndef __amd64
607c478bd9Sstevel@tonic-gate /* Used to track the current set of valid kernel selectors. */
617c478bd9Sstevel@tonic-gate uint32_t	kaif_cs;
627c478bd9Sstevel@tonic-gate uint32_t	kaif_ds;
637c478bd9Sstevel@tonic-gate uint32_t	kaif_fs;
647c478bd9Sstevel@tonic-gate uint32_t	kaif_gs;
657c478bd9Sstevel@tonic-gate #endif
667c478bd9Sstevel@tonic-gate 
677c478bd9Sstevel@tonic-gate uint_t		kaif_msr_wrexit_msr;
687c478bd9Sstevel@tonic-gate uint64_t	*kaif_msr_wrexit_valp;
697c478bd9Sstevel@tonic-gate 
707c478bd9Sstevel@tonic-gate uintptr_t	kaif_kernel_handler;
717c478bd9Sstevel@tonic-gate uintptr_t	kaif_sys_sysenter;
727c478bd9Sstevel@tonic-gate 
737c478bd9Sstevel@tonic-gate int		kaif_trap_switch;
747c478bd9Sstevel@tonic-gate 
757c478bd9Sstevel@tonic-gate void (*kaif_modchg_cb)(struct modctl *, int);
767c478bd9Sstevel@tonic-gate 
777c478bd9Sstevel@tonic-gate #define	KAIF_MEMRANGES_MAX	2
787c478bd9Sstevel@tonic-gate 
797c478bd9Sstevel@tonic-gate kaif_memrange_t	kaif_memranges[KAIF_MEMRANGES_MAX];
807c478bd9Sstevel@tonic-gate int		kaif_nmemranges;
817c478bd9Sstevel@tonic-gate 
827c478bd9Sstevel@tonic-gate enum {
837c478bd9Sstevel@tonic-gate 	M_SYSRET	= 0x07, /* after M_ESC */
847c478bd9Sstevel@tonic-gate 	M_ESC		= 0x0f,
857c478bd9Sstevel@tonic-gate 	M_SYSEXIT	= 0x35, /* after M_ESC */
867c478bd9Sstevel@tonic-gate 	M_REX_LO	= 0x40, /* first REX prefix */
877c478bd9Sstevel@tonic-gate 	M_REX_HI	= 0x4f, /* last REX prefix */
887c478bd9Sstevel@tonic-gate 	M_PUSHF		= 0x9c,	/* pushfl and pushfq */
897c478bd9Sstevel@tonic-gate 	M_POPF		= 0x9d,	/* popfl and popfq */
907c478bd9Sstevel@tonic-gate 	M_INT3		= 0xcc,
917c478bd9Sstevel@tonic-gate 	M_INTX		= 0xcd,
927c478bd9Sstevel@tonic-gate 	M_INTO		= 0xce,
937c478bd9Sstevel@tonic-gate 	M_IRET		= 0xcf,
947c478bd9Sstevel@tonic-gate 	M_CLI		= 0xfa,
957c478bd9Sstevel@tonic-gate 	M_STI		= 0xfb
967c478bd9Sstevel@tonic-gate };
977c478bd9Sstevel@tonic-gate 
987c478bd9Sstevel@tonic-gate #define	KAIF_BREAKPOINT_INSTR	M_INT3
997c478bd9Sstevel@tonic-gate 
1007c478bd9Sstevel@tonic-gate #define	KAIF_WPPRIV2ID(wp)	(int)(uintptr_t)((wp)->wp_priv)
1017c478bd9Sstevel@tonic-gate 
1027c478bd9Sstevel@tonic-gate #ifdef __amd64
1037c478bd9Sstevel@tonic-gate #define	FLAGS_REG_NAME		"rflags"
1047c478bd9Sstevel@tonic-gate #else
1057c478bd9Sstevel@tonic-gate #define	FLAGS_REG_NAME		"eflags"
1067c478bd9Sstevel@tonic-gate #endif
1077c478bd9Sstevel@tonic-gate 
1087c478bd9Sstevel@tonic-gate /*
1097c478bd9Sstevel@tonic-gate  * Called during normal debugger operation and during debugger faults.
1107c478bd9Sstevel@tonic-gate  */
1117c478bd9Sstevel@tonic-gate static void
1127c478bd9Sstevel@tonic-gate kaif_enter_mon(void)
1137c478bd9Sstevel@tonic-gate {
1147c478bd9Sstevel@tonic-gate 	char c;
1157c478bd9Sstevel@tonic-gate 
1167c478bd9Sstevel@tonic-gate 	for (;;) {
1177c478bd9Sstevel@tonic-gate 		mdb_iob_printf(mdb.m_out,
1187c478bd9Sstevel@tonic-gate 		    "%s: Do you really want to reboot? (y/n) ",
1197c478bd9Sstevel@tonic-gate 		    mdb.m_pname);
1207c478bd9Sstevel@tonic-gate 		mdb_iob_flush(mdb.m_out);
121*c7bf3205Sjohnlev 		mdb_iob_clearlines(mdb.m_out);
1227c478bd9Sstevel@tonic-gate 
123*c7bf3205Sjohnlev 		c = kmdb_getchar();
1247c478bd9Sstevel@tonic-gate 
125*c7bf3205Sjohnlev 		if (c == 'n' || c == 'N' || c == CTRL('c'))
1267c478bd9Sstevel@tonic-gate 			return;
1277c478bd9Sstevel@tonic-gate 		else if (c == 'y' || c == 'Y') {
1287c478bd9Sstevel@tonic-gate 			mdb_iob_printf(mdb.m_out, "Rebooting...\n");
1297c478bd9Sstevel@tonic-gate 
1307c478bd9Sstevel@tonic-gate 			kmdb_dpi_reboot();
1317c478bd9Sstevel@tonic-gate 		}
1327c478bd9Sstevel@tonic-gate 	}
1337c478bd9Sstevel@tonic-gate }
1347c478bd9Sstevel@tonic-gate 
135acbc304dSjohnlev static kaif_cpusave_t *
136acbc304dSjohnlev kaif_cpuid2save(int cpuid)
137acbc304dSjohnlev {
138acbc304dSjohnlev 	kaif_cpusave_t *save;
139acbc304dSjohnlev 
140acbc304dSjohnlev 	if (cpuid == DPI_MASTER_CPUID)
141acbc304dSjohnlev 		return (&kaif_cpusave[kaif_master_cpuid]);
142acbc304dSjohnlev 
143acbc304dSjohnlev 	if (cpuid < 0 || cpuid >= kaif_ncpusave) {
144acbc304dSjohnlev 		(void) set_errno(EINVAL);
145acbc304dSjohnlev 		return (NULL);
146acbc304dSjohnlev 	}
147acbc304dSjohnlev 
148acbc304dSjohnlev 	save = &kaif_cpusave[cpuid];
149acbc304dSjohnlev 
150acbc304dSjohnlev 	if (save->krs_cpu_state != KAIF_CPU_STATE_MASTER &&
151acbc304dSjohnlev 	    save->krs_cpu_state != KAIF_CPU_STATE_SLAVE) {
152acbc304dSjohnlev 		(void) set_errno(EINVAL);
153acbc304dSjohnlev 		return (NULL);
154acbc304dSjohnlev 	}
155acbc304dSjohnlev 
156acbc304dSjohnlev 	return (save);
157acbc304dSjohnlev }
158acbc304dSjohnlev 
1597c478bd9Sstevel@tonic-gate static int
1607c478bd9Sstevel@tonic-gate kaif_get_cpu_state(int cpuid)
1617c478bd9Sstevel@tonic-gate {
162acbc304dSjohnlev 	kaif_cpusave_t *save;
1637c478bd9Sstevel@tonic-gate 
164acbc304dSjohnlev 	if ((save = kaif_cpuid2save(cpuid)) == NULL)
165acbc304dSjohnlev 		return (-1); /* errno is set for us */
1667c478bd9Sstevel@tonic-gate 
167acbc304dSjohnlev 	switch (save->krs_cpu_state) {
1687c478bd9Sstevel@tonic-gate 	case KAIF_CPU_STATE_MASTER:
1697c478bd9Sstevel@tonic-gate 		return (DPI_CPU_STATE_MASTER);
1707c478bd9Sstevel@tonic-gate 	case KAIF_CPU_STATE_SLAVE:
1717c478bd9Sstevel@tonic-gate 		return (DPI_CPU_STATE_SLAVE);
1727c478bd9Sstevel@tonic-gate 	default:
1737c478bd9Sstevel@tonic-gate 		return (set_errno(EINVAL));
1747c478bd9Sstevel@tonic-gate 	}
1757c478bd9Sstevel@tonic-gate }
1767c478bd9Sstevel@tonic-gate 
1777c478bd9Sstevel@tonic-gate static int
1787c478bd9Sstevel@tonic-gate kaif_get_master_cpuid(void)
1797c478bd9Sstevel@tonic-gate {
1807c478bd9Sstevel@tonic-gate 	return (kaif_master_cpuid);
1817c478bd9Sstevel@tonic-gate }
1827c478bd9Sstevel@tonic-gate 
1837c478bd9Sstevel@tonic-gate static const mdb_tgt_gregset_t *
1847c478bd9Sstevel@tonic-gate kaif_get_gregs(int cpuid)
1857c478bd9Sstevel@tonic-gate {
186acbc304dSjohnlev 	kaif_cpusave_t *save;
1877c478bd9Sstevel@tonic-gate 
188acbc304dSjohnlev 	if ((save = kaif_cpuid2save(cpuid)) == NULL)
189acbc304dSjohnlev 		return (NULL); /* errno is set for us */
1907c478bd9Sstevel@tonic-gate 
191acbc304dSjohnlev 	return (save->krs_gregs);
1927c478bd9Sstevel@tonic-gate }
1937c478bd9Sstevel@tonic-gate 
1947c478bd9Sstevel@tonic-gate typedef struct kaif_reg_synonyms {
1957c478bd9Sstevel@tonic-gate 	const char *rs_syn;
1967c478bd9Sstevel@tonic-gate 	const char *rs_name;
1977c478bd9Sstevel@tonic-gate } kaif_reg_synonyms_t;
1987c478bd9Sstevel@tonic-gate 
1997c478bd9Sstevel@tonic-gate static kreg_t *
200acbc304dSjohnlev kaif_find_regp(const char *regname)
2017c478bd9Sstevel@tonic-gate {
2027c478bd9Sstevel@tonic-gate 	static const kaif_reg_synonyms_t synonyms[] = {
2037c478bd9Sstevel@tonic-gate #ifdef __amd64
2047c478bd9Sstevel@tonic-gate 	    { "pc", "rip" },
2057c478bd9Sstevel@tonic-gate 	    { "sp", "rsp" },
2067c478bd9Sstevel@tonic-gate 	    { "fp", "rbp" },
2077c478bd9Sstevel@tonic-gate #else
2087c478bd9Sstevel@tonic-gate 	    { "pc", "eip" },
2097c478bd9Sstevel@tonic-gate 	    { "sp", "esp" },
2107c478bd9Sstevel@tonic-gate 	    { "fp", "ebp" },
2117c478bd9Sstevel@tonic-gate #endif
2127c478bd9Sstevel@tonic-gate 	    { "tt", "trapno" }
2137c478bd9Sstevel@tonic-gate 	};
214acbc304dSjohnlev 
215acbc304dSjohnlev 	kaif_cpusave_t *save;
2167c478bd9Sstevel@tonic-gate 	int i;
2177c478bd9Sstevel@tonic-gate 
218acbc304dSjohnlev 	save = kaif_cpuid2save(DPI_MASTER_CPUID);
2197c478bd9Sstevel@tonic-gate 
2207c478bd9Sstevel@tonic-gate 	for (i = 0; i < sizeof (synonyms) / sizeof (synonyms[0]); i++) {
2217c478bd9Sstevel@tonic-gate 		if (strcmp(synonyms[i].rs_syn, regname) == 0)
2227c478bd9Sstevel@tonic-gate 			regname = synonyms[i].rs_name;
2237c478bd9Sstevel@tonic-gate 	}
2247c478bd9Sstevel@tonic-gate 
2257c478bd9Sstevel@tonic-gate 	for (i = 0; mdb_isa_kregs[i].rd_name != NULL; i++) {
2267c478bd9Sstevel@tonic-gate 		const mdb_tgt_regdesc_t *rd = &mdb_isa_kregs[i];
2277c478bd9Sstevel@tonic-gate 
2287c478bd9Sstevel@tonic-gate 		if (strcmp(rd->rd_name, regname) == 0)
229acbc304dSjohnlev 			return (&save->krs_gregs->kregs[rd->rd_num]);
2307c478bd9Sstevel@tonic-gate 	}
2317c478bd9Sstevel@tonic-gate 
2327c478bd9Sstevel@tonic-gate 	(void) set_errno(ENOENT);
2337c478bd9Sstevel@tonic-gate 	return (NULL);
2347c478bd9Sstevel@tonic-gate }
2357c478bd9Sstevel@tonic-gate 
2367c478bd9Sstevel@tonic-gate /*ARGSUSED*/
2377c478bd9Sstevel@tonic-gate static int
238acbc304dSjohnlev kaif_get_register(const char *regname, kreg_t *valp)
2397c478bd9Sstevel@tonic-gate {
2407c478bd9Sstevel@tonic-gate 	kreg_t *regp;
2417c478bd9Sstevel@tonic-gate 
242acbc304dSjohnlev 	if ((regp = kaif_find_regp(regname)) == NULL)
2437c478bd9Sstevel@tonic-gate 		return (-1);
2447c478bd9Sstevel@tonic-gate 
2457c478bd9Sstevel@tonic-gate 	*valp = *regp;
2467c478bd9Sstevel@tonic-gate 
2477c478bd9Sstevel@tonic-gate 	return (0);
2487c478bd9Sstevel@tonic-gate }
2497c478bd9Sstevel@tonic-gate 
2507c478bd9Sstevel@tonic-gate static int
251acbc304dSjohnlev kaif_set_register(const char *regname, kreg_t val)
2527c478bd9Sstevel@tonic-gate {
2537c478bd9Sstevel@tonic-gate 	kreg_t *regp;
2547c478bd9Sstevel@tonic-gate 
255acbc304dSjohnlev 	if ((regp = kaif_find_regp(regname)) == NULL)
2567c478bd9Sstevel@tonic-gate 		return (-1);
2577c478bd9Sstevel@tonic-gate 
2587c478bd9Sstevel@tonic-gate 	*regp = val;
2597c478bd9Sstevel@tonic-gate 
2607c478bd9Sstevel@tonic-gate 	return (0);
2617c478bd9Sstevel@tonic-gate }
2627c478bd9Sstevel@tonic-gate 
2637c478bd9Sstevel@tonic-gate static int
2647c478bd9Sstevel@tonic-gate kaif_brkpt_arm(uintptr_t addr, mdb_instr_t *instrp)
2657c478bd9Sstevel@tonic-gate {
2667c478bd9Sstevel@tonic-gate 	mdb_instr_t bkpt = KAIF_BREAKPOINT_INSTR;
2677c478bd9Sstevel@tonic-gate 
2687c478bd9Sstevel@tonic-gate 	if (mdb_tgt_vread(mdb.m_target, instrp, sizeof (mdb_instr_t), addr) !=
2697c478bd9Sstevel@tonic-gate 	    sizeof (mdb_instr_t))
2707c478bd9Sstevel@tonic-gate 		return (-1); /* errno is set for us */
2717c478bd9Sstevel@tonic-gate 
2727c478bd9Sstevel@tonic-gate 	if (mdb_tgt_vwrite(mdb.m_target, &bkpt, sizeof (mdb_instr_t), addr) !=
2737c478bd9Sstevel@tonic-gate 	    sizeof (mdb_instr_t))
2747c478bd9Sstevel@tonic-gate 		return (-1); /* errno is set for us */
2757c478bd9Sstevel@tonic-gate 
2767c478bd9Sstevel@tonic-gate 	return (0);
2777c478bd9Sstevel@tonic-gate }
2787c478bd9Sstevel@tonic-gate 
2797c478bd9Sstevel@tonic-gate static int
2807c478bd9Sstevel@tonic-gate kaif_brkpt_disarm(uintptr_t addr, mdb_instr_t instrp)
2817c478bd9Sstevel@tonic-gate {
2827c478bd9Sstevel@tonic-gate 	if (mdb_tgt_vwrite(mdb.m_target, &instrp, sizeof (mdb_instr_t), addr) !=
2837c478bd9Sstevel@tonic-gate 	    sizeof (mdb_instr_t))
2847c478bd9Sstevel@tonic-gate 		return (-1); /* errno is set for us */
2857c478bd9Sstevel@tonic-gate 
2867c478bd9Sstevel@tonic-gate 	return (0);
2877c478bd9Sstevel@tonic-gate }
2887c478bd9Sstevel@tonic-gate 
2897c478bd9Sstevel@tonic-gate /*
2907c478bd9Sstevel@tonic-gate  * Intel watchpoints are even more fun than SPARC ones.  The Intel architecture
2917c478bd9Sstevel@tonic-gate  * manuals refer to watchpoints as breakpoints.  For consistency  with the
2927c478bd9Sstevel@tonic-gate  * terminology used in other portions of kmdb, we will, however, refer to them
2937c478bd9Sstevel@tonic-gate  * as watchpoints.
2947c478bd9Sstevel@tonic-gate  *
2957c478bd9Sstevel@tonic-gate  * Execute, data write, I/O read/write, and data read/write watchpoints are
2967c478bd9Sstevel@tonic-gate  * supported by the hardware.  Execute watchpoints must be one byte in length,
2977c478bd9Sstevel@tonic-gate  * and must be placed on the first byte of the instruction to be watched.
2987c478bd9Sstevel@tonic-gate  * Lengths of other watchpoints are more varied.
2997c478bd9Sstevel@tonic-gate  *
3007c478bd9Sstevel@tonic-gate  * Given that we already have a breakpoint facility, and given the restrictions
3017c478bd9Sstevel@tonic-gate  * placed on execute watchpoints, we're going to disallow the creation of
3027c478bd9Sstevel@tonic-gate  * execute watchpoints.  The others will be fully supported.  See the Debugging
3037c478bd9Sstevel@tonic-gate  * chapter in both the IA32 and AMD64 System Programming books for more details.
3047c478bd9Sstevel@tonic-gate  */
3057c478bd9Sstevel@tonic-gate 
3067c478bd9Sstevel@tonic-gate #ifdef __amd64
3077c478bd9Sstevel@tonic-gate #define	WAPT_DATA_MAX_SIZE	8
3087c478bd9Sstevel@tonic-gate #define	WAPT_DATA_SIZES_MSG	"1, 2, 4, or 8"
3097c478bd9Sstevel@tonic-gate #else
3107c478bd9Sstevel@tonic-gate #define	WAPT_DATA_MAX_SIZE	4
3117c478bd9Sstevel@tonic-gate #define	WAPT_DATA_SIZES_MSG	"1, 2, or 4"
3127c478bd9Sstevel@tonic-gate #endif
3137c478bd9Sstevel@tonic-gate 
3147c478bd9Sstevel@tonic-gate static int
3157c478bd9Sstevel@tonic-gate kaif_wapt_validate(kmdb_wapt_t *wp)
3167c478bd9Sstevel@tonic-gate {
3177c478bd9Sstevel@tonic-gate 	if (wp->wp_type == DPI_WAPT_TYPE_IO) {
3187c478bd9Sstevel@tonic-gate 		if (wp->wp_wflags != (MDB_TGT_WA_R | MDB_TGT_WA_W)) {
3197c478bd9Sstevel@tonic-gate 			warn("I/O port watchpoints must be read/write\n");
3207c478bd9Sstevel@tonic-gate 			return (set_errno(EINVAL));
3217c478bd9Sstevel@tonic-gate 		}
3227c478bd9Sstevel@tonic-gate 
3237c478bd9Sstevel@tonic-gate 		if (wp->wp_size != 1 && wp->wp_size != 2 && wp->wp_size != 4) {
3247c478bd9Sstevel@tonic-gate 			warn("I/O watchpoint size must be 1, 2, or 4 bytes\n");
3257c478bd9Sstevel@tonic-gate 			return (set_errno(EINVAL));
3267c478bd9Sstevel@tonic-gate 		}
3277c478bd9Sstevel@tonic-gate 
3287c478bd9Sstevel@tonic-gate 	} else if (wp->wp_type == DPI_WAPT_TYPE_PHYS) {
3297c478bd9Sstevel@tonic-gate 		warn("physical address watchpoints are not supported on this "
3307c478bd9Sstevel@tonic-gate 		    "platform\n");
3317c478bd9Sstevel@tonic-gate 		return (set_errno(EMDB_TGTHWNOTSUP));
3327c478bd9Sstevel@tonic-gate 
3337c478bd9Sstevel@tonic-gate 	} else {
3347c478bd9Sstevel@tonic-gate 		if (wp->wp_wflags != (MDB_TGT_WA_R | MDB_TGT_WA_W) &&
3357c478bd9Sstevel@tonic-gate 		    wp->wp_wflags != MDB_TGT_WA_W) {
3367c478bd9Sstevel@tonic-gate 			warn("watchpoints must be read/write or write-only\n");
3377c478bd9Sstevel@tonic-gate 			return (set_errno(EINVAL));
3387c478bd9Sstevel@tonic-gate 		}
3397c478bd9Sstevel@tonic-gate 
3407c478bd9Sstevel@tonic-gate 		if ((wp->wp_size & -(wp->wp_size)) != wp->wp_size ||
3417c478bd9Sstevel@tonic-gate 		    wp->wp_size > WAPT_DATA_MAX_SIZE) {
3427c478bd9Sstevel@tonic-gate 			warn("data watchpoint size must be " WAPT_DATA_SIZES_MSG
3437c478bd9Sstevel@tonic-gate 			    " bytes\n");
3447c478bd9Sstevel@tonic-gate 			return (set_errno(EINVAL));
3457c478bd9Sstevel@tonic-gate 		}
3467c478bd9Sstevel@tonic-gate 
3477c478bd9Sstevel@tonic-gate 	}
3487c478bd9Sstevel@tonic-gate 
3497c478bd9Sstevel@tonic-gate 	if (wp->wp_addr & (wp->wp_size - 1)) {
3507c478bd9Sstevel@tonic-gate 		warn("%lu-byte watchpoints must be %lu-byte aligned\n",
3517c478bd9Sstevel@tonic-gate 		    (ulong_t)wp->wp_size, (ulong_t)wp->wp_size);
3527c478bd9Sstevel@tonic-gate 		return (set_errno(EINVAL));
3537c478bd9Sstevel@tonic-gate 	}
3547c478bd9Sstevel@tonic-gate 
3557c478bd9Sstevel@tonic-gate 	return (0);
3567c478bd9Sstevel@tonic-gate }
3577c478bd9Sstevel@tonic-gate 
3587c478bd9Sstevel@tonic-gate static int
3597c478bd9Sstevel@tonic-gate kaif_wapt_reserve(kmdb_wapt_t *wp)
3607c478bd9Sstevel@tonic-gate {
3617c478bd9Sstevel@tonic-gate 	int id;
3627c478bd9Sstevel@tonic-gate 
3637c478bd9Sstevel@tonic-gate 	for (id = 0; id <= KREG_MAXWPIDX; id++) {
3647c478bd9Sstevel@tonic-gate 		if (!BT_TEST(&kaif_waptmap, id)) {
3657c478bd9Sstevel@tonic-gate 			/* found one */
3667c478bd9Sstevel@tonic-gate 			BT_SET(&kaif_waptmap, id);
3677c478bd9Sstevel@tonic-gate 			wp->wp_priv = (void *)(uintptr_t)id;
3687c478bd9Sstevel@tonic-gate 			return (0);
3697c478bd9Sstevel@tonic-gate 		}
3707c478bd9Sstevel@tonic-gate 	}
3717c478bd9Sstevel@tonic-gate 
3727c478bd9Sstevel@tonic-gate 	return (set_errno(EMDB_WPTOOMANY));
3737c478bd9Sstevel@tonic-gate }
3747c478bd9Sstevel@tonic-gate 
3757c478bd9Sstevel@tonic-gate static void
3767c478bd9Sstevel@tonic-gate kaif_wapt_release(kmdb_wapt_t *wp)
3777c478bd9Sstevel@tonic-gate {
3787c478bd9Sstevel@tonic-gate 	int id = KAIF_WPPRIV2ID(wp);
3797c478bd9Sstevel@tonic-gate 
3807c478bd9Sstevel@tonic-gate 	ASSERT(BT_TEST(&kaif_waptmap, id));
3817c478bd9Sstevel@tonic-gate 	BT_CLEAR(&kaif_waptmap, id);
3827c478bd9Sstevel@tonic-gate }
3837c478bd9Sstevel@tonic-gate 
3847c478bd9Sstevel@tonic-gate /*ARGSUSED*/
3857c478bd9Sstevel@tonic-gate static void
3867c478bd9Sstevel@tonic-gate kaif_wapt_arm(kmdb_wapt_t *wp)
3877c478bd9Sstevel@tonic-gate {
3887c478bd9Sstevel@tonic-gate 	uint_t rw;
3897c478bd9Sstevel@tonic-gate 	int hwid = KAIF_WPPRIV2ID(wp);
3907c478bd9Sstevel@tonic-gate 
3917c478bd9Sstevel@tonic-gate 	ASSERT(BT_TEST(&kaif_waptmap, hwid));
3927c478bd9Sstevel@tonic-gate 
3937c478bd9Sstevel@tonic-gate 	if (wp->wp_type == DPI_WAPT_TYPE_IO)
3947c478bd9Sstevel@tonic-gate 		rw = KREG_DRCTL_WP_IORW;
3957c478bd9Sstevel@tonic-gate 	else if (wp->wp_wflags & MDB_TGT_WA_R)
3967c478bd9Sstevel@tonic-gate 		rw = KREG_DRCTL_WP_RW;
3977c478bd9Sstevel@tonic-gate 	else if (wp->wp_wflags & MDB_TGT_WA_X)
3987c478bd9Sstevel@tonic-gate 		rw = KREG_DRCTL_WP_EXEC;
3997c478bd9Sstevel@tonic-gate 	else
4007c478bd9Sstevel@tonic-gate 		rw = KREG_DRCTL_WP_WONLY;
4017c478bd9Sstevel@tonic-gate 
4027c478bd9Sstevel@tonic-gate 	kaif_drreg.dr_addr[hwid] = wp->wp_addr;
4037c478bd9Sstevel@tonic-gate 
4047c478bd9Sstevel@tonic-gate 	kaif_drreg.dr_ctl &= ~KREG_DRCTL_WP_MASK(hwid);
4057c478bd9Sstevel@tonic-gate 	kaif_drreg.dr_ctl |= KREG_DRCTL_WP_LENRW(hwid, wp->wp_size - 1, rw);
4067c478bd9Sstevel@tonic-gate 	kaif_drreg.dr_ctl |= KREG_DRCTL_WPEN(hwid);
4077c478bd9Sstevel@tonic-gate }
4087c478bd9Sstevel@tonic-gate 
4097c478bd9Sstevel@tonic-gate /*ARGSUSED*/
4107c478bd9Sstevel@tonic-gate static void
4117c478bd9Sstevel@tonic-gate kaif_wapt_disarm(kmdb_wapt_t *wp)
4127c478bd9Sstevel@tonic-gate {
4137c478bd9Sstevel@tonic-gate 	int hwid = KAIF_WPPRIV2ID(wp);
4147c478bd9Sstevel@tonic-gate 
4157c478bd9Sstevel@tonic-gate 	ASSERT(BT_TEST(&kaif_waptmap, hwid));
4167c478bd9Sstevel@tonic-gate 
4177c478bd9Sstevel@tonic-gate 	kaif_drreg.dr_addr[hwid] = 0;
4187c478bd9Sstevel@tonic-gate 	kaif_drreg.dr_ctl &= ~(KREG_DRCTL_WP_MASK(hwid) |
4197c478bd9Sstevel@tonic-gate 	    KREG_DRCTL_WPEN_MASK(hwid));
4207c478bd9Sstevel@tonic-gate }
4217c478bd9Sstevel@tonic-gate 
4227c478bd9Sstevel@tonic-gate /*ARGSUSED*/
4237c478bd9Sstevel@tonic-gate static int
4247c478bd9Sstevel@tonic-gate kaif_wapt_match(kmdb_wapt_t *wp)
4257c478bd9Sstevel@tonic-gate {
4267c478bd9Sstevel@tonic-gate 	int hwid = KAIF_WPPRIV2ID(wp);
4277c478bd9Sstevel@tonic-gate 	uint32_t mask = KREG_DRSTAT_WP_MASK(hwid);
4287c478bd9Sstevel@tonic-gate 	int n = 0;
4297c478bd9Sstevel@tonic-gate 	int i;
4307c478bd9Sstevel@tonic-gate 
4317c478bd9Sstevel@tonic-gate 	ASSERT(BT_TEST(&kaif_waptmap, hwid));
4327c478bd9Sstevel@tonic-gate 
4337c478bd9Sstevel@tonic-gate 	for (i = 0; i < kaif_ncpusave; i++)
4347c478bd9Sstevel@tonic-gate 		n += (kaif_cpusave[i].krs_dr.dr_stat & mask) != 0;
4357c478bd9Sstevel@tonic-gate 
4367c478bd9Sstevel@tonic-gate 	return (n);
4377c478bd9Sstevel@tonic-gate }
4387c478bd9Sstevel@tonic-gate 
4397c478bd9Sstevel@tonic-gate static int
4407c478bd9Sstevel@tonic-gate kaif_step(void)
4417c478bd9Sstevel@tonic-gate {
4427c478bd9Sstevel@tonic-gate 	kreg_t pc, fl, oldfl, newfl, sp;
4437c478bd9Sstevel@tonic-gate 	mdb_tgt_addr_t npc;
4447c478bd9Sstevel@tonic-gate 	mdb_instr_t instr;
4457c478bd9Sstevel@tonic-gate 	int emulated = 0, rchk = 0;
4467c478bd9Sstevel@tonic-gate 	size_t pcoff = 0;
4477c478bd9Sstevel@tonic-gate 
4487c478bd9Sstevel@tonic-gate 	(void) kmdb_dpi_get_register("pc", &pc);
4497c478bd9Sstevel@tonic-gate 
4507c478bd9Sstevel@tonic-gate 	if ((npc = mdb_dis_nextins(mdb.m_disasm, mdb.m_target,
4517c478bd9Sstevel@tonic-gate 	    MDB_TGT_AS_VIRT, pc)) == pc) {
4527c478bd9Sstevel@tonic-gate 		warn("failed to decode instruction at %a for step\n", pc);
4537c478bd9Sstevel@tonic-gate 		return (set_errno(EINVAL));
4547c478bd9Sstevel@tonic-gate 	}
4557c478bd9Sstevel@tonic-gate 
4567c478bd9Sstevel@tonic-gate 	/*
4577c478bd9Sstevel@tonic-gate 	 * Stepping behavior depends on the type of instruction.  It does not
4587c478bd9Sstevel@tonic-gate 	 * depend on the presence of a REX prefix, as the action we take for a
4597c478bd9Sstevel@tonic-gate 	 * given instruction doesn't currently vary for 32-bit instructions
4607c478bd9Sstevel@tonic-gate 	 * versus their 64-bit counterparts.
4617c478bd9Sstevel@tonic-gate 	 */
4627c478bd9Sstevel@tonic-gate 	do {
4637c478bd9Sstevel@tonic-gate 		if (mdb_tgt_vread(mdb.m_target, &instr, sizeof (mdb_instr_t),
4647c478bd9Sstevel@tonic-gate 		    pc + pcoff) != sizeof (mdb_instr_t)) {
4657c478bd9Sstevel@tonic-gate 			warn("failed to read at %p for step",
4667c478bd9Sstevel@tonic-gate 			    (void *)(pc + pcoff));
4677c478bd9Sstevel@tonic-gate 			return (-1);
4687c478bd9Sstevel@tonic-gate 		}
4697c478bd9Sstevel@tonic-gate 	} while (pcoff++, (instr >= M_REX_LO && instr <= M_REX_HI && !rchk++));
4707c478bd9Sstevel@tonic-gate 
4717c478bd9Sstevel@tonic-gate 	switch (instr) {
4727c478bd9Sstevel@tonic-gate 	case M_IRET:
4737c478bd9Sstevel@tonic-gate 		warn("iret cannot be stepped\n");
4747c478bd9Sstevel@tonic-gate 		return (set_errno(EMDB_TGTNOTSUP));
4757c478bd9Sstevel@tonic-gate 
4767c478bd9Sstevel@tonic-gate 	case M_INT3:
4777c478bd9Sstevel@tonic-gate 	case M_INTX:
4787c478bd9Sstevel@tonic-gate 	case M_INTO:
4797c478bd9Sstevel@tonic-gate 		warn("int cannot be stepped\n");
4807c478bd9Sstevel@tonic-gate 		return (set_errno(EMDB_TGTNOTSUP));
4817c478bd9Sstevel@tonic-gate 
4827c478bd9Sstevel@tonic-gate 	case M_ESC:
4837c478bd9Sstevel@tonic-gate 		if (mdb_tgt_vread(mdb.m_target, &instr, sizeof (mdb_instr_t),
4847c478bd9Sstevel@tonic-gate 		    pc + pcoff) != sizeof (mdb_instr_t)) {
4857c478bd9Sstevel@tonic-gate 			warn("failed to read at %p for step",
4867c478bd9Sstevel@tonic-gate 			    (void *)(pc + pcoff));
4877c478bd9Sstevel@tonic-gate 			return (-1);
4887c478bd9Sstevel@tonic-gate 		}
4897c478bd9Sstevel@tonic-gate 
4907c478bd9Sstevel@tonic-gate 		switch (instr) {
4917c478bd9Sstevel@tonic-gate 		case M_SYSRET:
4927c478bd9Sstevel@tonic-gate 			warn("sysret cannot be stepped\n");
4937c478bd9Sstevel@tonic-gate 			return (set_errno(EMDB_TGTNOTSUP));
4947c478bd9Sstevel@tonic-gate 		case M_SYSEXIT:
4957c478bd9Sstevel@tonic-gate 			warn("sysexit cannot be stepped\n");
4967c478bd9Sstevel@tonic-gate 			return (set_errno(EMDB_TGTNOTSUP));
4977c478bd9Sstevel@tonic-gate 		}
4987c478bd9Sstevel@tonic-gate 		break;
4997c478bd9Sstevel@tonic-gate 
5007c478bd9Sstevel@tonic-gate 	/*
5017c478bd9Sstevel@tonic-gate 	 * Some instructions need to be emulated.  We need to prevent direct
5027c478bd9Sstevel@tonic-gate 	 * manipulations of EFLAGS, so we'll emulate cli, sti.  pushfl and
5037c478bd9Sstevel@tonic-gate 	 * popfl also receive special handling, as they manipulate both EFLAGS
5047c478bd9Sstevel@tonic-gate 	 * and %esp.
5057c478bd9Sstevel@tonic-gate 	 */
5067c478bd9Sstevel@tonic-gate 	case M_CLI:
5077c478bd9Sstevel@tonic-gate 		(void) kmdb_dpi_get_register(FLAGS_REG_NAME, &fl);
5087c478bd9Sstevel@tonic-gate 		fl &= ~KREG_EFLAGS_IF_MASK;
5097c478bd9Sstevel@tonic-gate 		(void) kmdb_dpi_set_register(FLAGS_REG_NAME, fl);
5107c478bd9Sstevel@tonic-gate 
5117c478bd9Sstevel@tonic-gate 		emulated = 1;
5127c478bd9Sstevel@tonic-gate 		break;
5137c478bd9Sstevel@tonic-gate 
5147c478bd9Sstevel@tonic-gate 	case M_STI:
5157c478bd9Sstevel@tonic-gate 		(void) kmdb_dpi_get_register(FLAGS_REG_NAME, &fl);
5167c478bd9Sstevel@tonic-gate 		fl |= (1 << KREG_EFLAGS_IF_SHIFT);
5177c478bd9Sstevel@tonic-gate 		(void) kmdb_dpi_set_register(FLAGS_REG_NAME, fl);
5187c478bd9Sstevel@tonic-gate 
5197c478bd9Sstevel@tonic-gate 		emulated = 1;
5207c478bd9Sstevel@tonic-gate 		break;
5217c478bd9Sstevel@tonic-gate 
5227c478bd9Sstevel@tonic-gate 	case M_POPF:
5237c478bd9Sstevel@tonic-gate 		/*
5247c478bd9Sstevel@tonic-gate 		 * popfl will restore a pushed EFLAGS from the stack, and could
5257c478bd9Sstevel@tonic-gate 		 * in so doing cause IF to be turned on, if only for a a brief
5267c478bd9Sstevel@tonic-gate 		 * period.  To avoid this, we'll secretly replace the stack's
5277c478bd9Sstevel@tonic-gate 		 * EFLAGS with our decaffeinated brand.  We'll then manually
5287c478bd9Sstevel@tonic-gate 		 * load our EFLAGS copy with the real verion after the step.
5297c478bd9Sstevel@tonic-gate 		 */
5307c478bd9Sstevel@tonic-gate 		(void) kmdb_dpi_get_register("sp", &sp);
5317c478bd9Sstevel@tonic-gate 		(void) kmdb_dpi_get_register(FLAGS_REG_NAME, &fl);
5327c478bd9Sstevel@tonic-gate 
5337c478bd9Sstevel@tonic-gate 		if (mdb_tgt_vread(mdb.m_target, &newfl, sizeof (kreg_t),
5347c478bd9Sstevel@tonic-gate 		    sp) != sizeof (kreg_t)) {
5357c478bd9Sstevel@tonic-gate 			warn("failed to read " FLAGS_REG_NAME
5367c478bd9Sstevel@tonic-gate 			    " at %p for popfl step\n", (void *)sp);
5377c478bd9Sstevel@tonic-gate 			return (set_errno(EMDB_TGTNOTSUP)); /* XXX ? */
5387c478bd9Sstevel@tonic-gate 		}
5397c478bd9Sstevel@tonic-gate 
5407c478bd9Sstevel@tonic-gate 		fl = (fl & ~KREG_EFLAGS_IF_MASK) | KREG_EFLAGS_TF_MASK;
5417c478bd9Sstevel@tonic-gate 
5427c478bd9Sstevel@tonic-gate 		if (mdb_tgt_vwrite(mdb.m_target, &fl, sizeof (kreg_t),
5437c478bd9Sstevel@tonic-gate 		    sp) != sizeof (kreg_t)) {
5447c478bd9Sstevel@tonic-gate 			warn("failed to update " FLAGS_REG_NAME
5457c478bd9Sstevel@tonic-gate 			    " at %p for popfl step\n", (void *)sp);
5467c478bd9Sstevel@tonic-gate 			return (set_errno(EMDB_TGTNOTSUP)); /* XXX ? */
5477c478bd9Sstevel@tonic-gate 		}
5487c478bd9Sstevel@tonic-gate 		break;
5497c478bd9Sstevel@tonic-gate 	}
5507c478bd9Sstevel@tonic-gate 
5517c478bd9Sstevel@tonic-gate 	if (emulated) {
5527c478bd9Sstevel@tonic-gate 		(void) kmdb_dpi_set_register("pc", npc);
5537c478bd9Sstevel@tonic-gate 		return (0);
5547c478bd9Sstevel@tonic-gate 	}
5557c478bd9Sstevel@tonic-gate 
5567c478bd9Sstevel@tonic-gate 	/* Do the step with IF off, and TF (step) on */
5577c478bd9Sstevel@tonic-gate 	(void) kmdb_dpi_get_register(FLAGS_REG_NAME, &oldfl);
5587c478bd9Sstevel@tonic-gate 	(void) kmdb_dpi_set_register(FLAGS_REG_NAME,
5597c478bd9Sstevel@tonic-gate 	    ((oldfl | (1 << KREG_EFLAGS_TF_SHIFT)) & ~KREG_EFLAGS_IF_MASK));
5607c478bd9Sstevel@tonic-gate 
5617c478bd9Sstevel@tonic-gate 	kmdb_dpi_resume_master(); /* ... there and back again ... */
5627c478bd9Sstevel@tonic-gate 
5637c478bd9Sstevel@tonic-gate 	/* EFLAGS has now changed, and may require tuning */
5647c478bd9Sstevel@tonic-gate 
5657c478bd9Sstevel@tonic-gate 	switch (instr) {
5667c478bd9Sstevel@tonic-gate 	case M_POPF:
5677c478bd9Sstevel@tonic-gate 		/*
5687c478bd9Sstevel@tonic-gate 		 * Use the EFLAGS we grabbed before the pop - see the pre-step
5697c478bd9Sstevel@tonic-gate 		 * M_POPFL comment.
5707c478bd9Sstevel@tonic-gate 		 */
5717c478bd9Sstevel@tonic-gate 		(void) kmdb_dpi_set_register(FLAGS_REG_NAME, newfl);
5727c478bd9Sstevel@tonic-gate 		return (0);
5737c478bd9Sstevel@tonic-gate 
5747c478bd9Sstevel@tonic-gate 	case M_PUSHF:
5757c478bd9Sstevel@tonic-gate 		/*
5767c478bd9Sstevel@tonic-gate 		 * We pushed our modified EFLAGS (with IF and TF turned off)
5777c478bd9Sstevel@tonic-gate 		 * onto the stack.  Replace the pushed version with our
5787c478bd9Sstevel@tonic-gate 		 * unmodified one.
5797c478bd9Sstevel@tonic-gate 		 */
5807c478bd9Sstevel@tonic-gate 		(void) kmdb_dpi_get_register("sp", &sp);
5817c478bd9Sstevel@tonic-gate 
5827c478bd9Sstevel@tonic-gate 		if (mdb_tgt_vwrite(mdb.m_target, &oldfl, sizeof (kreg_t),
5837c478bd9Sstevel@tonic-gate 		    sp) != sizeof (kreg_t)) {
5847c478bd9Sstevel@tonic-gate 			warn("failed to update pushed " FLAGS_REG_NAME
5857c478bd9Sstevel@tonic-gate 			    " at %p after pushfl step\n", (void *)sp);
5867c478bd9Sstevel@tonic-gate 			return (set_errno(EMDB_TGTNOTSUP)); /* XXX ? */
5877c478bd9Sstevel@tonic-gate 		}
5887c478bd9Sstevel@tonic-gate 
5897c478bd9Sstevel@tonic-gate 		/* Go back to using the EFLAGS we were using before the step */
5907c478bd9Sstevel@tonic-gate 		(void) kmdb_dpi_set_register(FLAGS_REG_NAME, oldfl);
5917c478bd9Sstevel@tonic-gate 		return (0);
5927c478bd9Sstevel@tonic-gate 
5937c478bd9Sstevel@tonic-gate 	default:
5947c478bd9Sstevel@tonic-gate 		/*
5957c478bd9Sstevel@tonic-gate 		 * The stepped instruction may have altered EFLAGS.  We only
5967c478bd9Sstevel@tonic-gate 		 * really care about the value of IF, and we know the stepped
5977c478bd9Sstevel@tonic-gate 		 * instruction didn't alter it, so we can simply copy the
5987c478bd9Sstevel@tonic-gate 		 * pre-step value.  We'll also need to turn TF back off.
5997c478bd9Sstevel@tonic-gate 		 */
6007c478bd9Sstevel@tonic-gate 		(void) kmdb_dpi_get_register(FLAGS_REG_NAME, &fl);
6017c478bd9Sstevel@tonic-gate 		(void) kmdb_dpi_set_register(FLAGS_REG_NAME,
6027c478bd9Sstevel@tonic-gate 		    ((fl & ~(KREG_EFLAGS_TF_MASK|KREG_EFLAGS_IF_MASK)) |
6037c478bd9Sstevel@tonic-gate 		    (oldfl & KREG_EFLAGS_IF_MASK)));
6047c478bd9Sstevel@tonic-gate 		return (0);
6057c478bd9Sstevel@tonic-gate 	}
6067c478bd9Sstevel@tonic-gate }
6077c478bd9Sstevel@tonic-gate 
6087c478bd9Sstevel@tonic-gate /*
6097c478bd9Sstevel@tonic-gate  * The target has already configured the chip for branch step, leaving us to
6107c478bd9Sstevel@tonic-gate  * actually make the machine go.  Due to a number of issues involving
6117c478bd9Sstevel@tonic-gate  * the potential alteration of system state via instructions like sti, cli,
6127c478bd9Sstevel@tonic-gate  * pushfl, and popfl, we're going to treat this like a normal system resume.
6137c478bd9Sstevel@tonic-gate  * All CPUs will be released, on the kernel's IDT.  Our primary concern is
6147c478bd9Sstevel@tonic-gate  * the alteration/storage of our TF'd EFLAGS via pushfl and popfl.  There's no
6157c478bd9Sstevel@tonic-gate  * real workaround - we don't have opcode breakpoints - so the best we can do is
6167c478bd9Sstevel@tonic-gate  * to ensure that the world won't end if someone does bad things to EFLAGS.
6177c478bd9Sstevel@tonic-gate  *
6187c478bd9Sstevel@tonic-gate  * Two things can happen:
6197c478bd9Sstevel@tonic-gate  *  1. EFLAGS.TF may be cleared, either maliciously or via a popfl from saved
6207c478bd9Sstevel@tonic-gate  *     state.  The CPU will continue execution beyond the branch, and will not
6217c478bd9Sstevel@tonic-gate  *     reenter the debugger unless brought/sent in by other means.
6227c478bd9Sstevel@tonic-gate  *  2. Someone may pushlf the TF'd EFLAGS, and may stash a copy of it somewhere.
6237c478bd9Sstevel@tonic-gate  *     When the saved version is popfl'd back into place, the debugger will be
6247c478bd9Sstevel@tonic-gate  *     re-entered on a single-step trap.
6257c478bd9Sstevel@tonic-gate  */
6267c478bd9Sstevel@tonic-gate static void
6277c478bd9Sstevel@tonic-gate kaif_step_branch(void)
6287c478bd9Sstevel@tonic-gate {
6297c478bd9Sstevel@tonic-gate 	kreg_t fl;
6307c478bd9Sstevel@tonic-gate 
6317c478bd9Sstevel@tonic-gate 	(void) kmdb_dpi_get_register(FLAGS_REG_NAME, &fl);
6327c478bd9Sstevel@tonic-gate 	(void) kmdb_dpi_set_register(FLAGS_REG_NAME,
6337c478bd9Sstevel@tonic-gate 	    (fl | (1 << KREG_EFLAGS_TF_SHIFT)));
6347c478bd9Sstevel@tonic-gate 
6357c478bd9Sstevel@tonic-gate 	kmdb_dpi_resume_master();
6367c478bd9Sstevel@tonic-gate 
6377c478bd9Sstevel@tonic-gate 	(void) kmdb_dpi_set_register(FLAGS_REG_NAME, fl);
6387c478bd9Sstevel@tonic-gate }
6397c478bd9Sstevel@tonic-gate 
6407c478bd9Sstevel@tonic-gate /*ARGSUSED*/
6417c478bd9Sstevel@tonic-gate static uintptr_t
6427c478bd9Sstevel@tonic-gate kaif_call(uintptr_t funcva, uint_t argc, const uintptr_t argv[])
6437c478bd9Sstevel@tonic-gate {
6447c478bd9Sstevel@tonic-gate 	return (kaif_invoke(funcva, argc, argv));
6457c478bd9Sstevel@tonic-gate }
6467c478bd9Sstevel@tonic-gate 
6477c478bd9Sstevel@tonic-gate static void
648acbc304dSjohnlev dump_crumb(kaif_crumb_t *krmp)
6497c478bd9Sstevel@tonic-gate {
650acbc304dSjohnlev 	kaif_crumb_t krm;
651acbc304dSjohnlev 
652acbc304dSjohnlev 	if (mdb_vread(&krm, sizeof (kaif_crumb_t), (uintptr_t)krmp) !=
653acbc304dSjohnlev 	    sizeof (kaif_crumb_t)) {
654acbc304dSjohnlev 		warn("failed to read crumb at %p", krmp);
655acbc304dSjohnlev 		return;
656acbc304dSjohnlev 	}
657acbc304dSjohnlev 
6587c478bd9Sstevel@tonic-gate 	mdb_printf("state: ");
659acbc304dSjohnlev 	switch (krm.krm_cpu_state) {
6607c478bd9Sstevel@tonic-gate 	case KAIF_CPU_STATE_MASTER:
6617c478bd9Sstevel@tonic-gate 		mdb_printf("M");
6627c478bd9Sstevel@tonic-gate 		break;
6637c478bd9Sstevel@tonic-gate 	case KAIF_CPU_STATE_SLAVE:
6647c478bd9Sstevel@tonic-gate 		mdb_printf("S");
6657c478bd9Sstevel@tonic-gate 		break;
6667c478bd9Sstevel@tonic-gate 	default:
667acbc304dSjohnlev 		mdb_printf("%d", krm.krm_cpu_state);
6687c478bd9Sstevel@tonic-gate 	}
6697c478bd9Sstevel@tonic-gate 
6707c478bd9Sstevel@tonic-gate 	mdb_printf(" trapno %3d sp %08x flag %d pc %p %A\n",
671acbc304dSjohnlev 	    krm.krm_trapno, krm.krm_sp, krm.krm_flag, krm.krm_pc, krm.krm_pc);
6727c478bd9Sstevel@tonic-gate }
6737c478bd9Sstevel@tonic-gate 
6747c478bd9Sstevel@tonic-gate static void
6757c478bd9Sstevel@tonic-gate dump_crumbs(kaif_cpusave_t *save)
6767c478bd9Sstevel@tonic-gate {
6777c478bd9Sstevel@tonic-gate 	int i;
6787c478bd9Sstevel@tonic-gate 
6797c478bd9Sstevel@tonic-gate 	for (i = KAIF_NCRUMBS; i > 0; i--) {
6807c478bd9Sstevel@tonic-gate 		uint_t idx = (save->krs_curcrumbidx + i) % KAIF_NCRUMBS;
6817c478bd9Sstevel@tonic-gate 		dump_crumb(&save->krs_crumbs[idx]);
6827c478bd9Sstevel@tonic-gate 	}
6837c478bd9Sstevel@tonic-gate }
6847c478bd9Sstevel@tonic-gate 
6857c478bd9Sstevel@tonic-gate static void
6867c478bd9Sstevel@tonic-gate kaif_dump_crumbs(uintptr_t addr, int cpuid)
6877c478bd9Sstevel@tonic-gate {
6887c478bd9Sstevel@tonic-gate 	int i;
6897c478bd9Sstevel@tonic-gate 
6907c478bd9Sstevel@tonic-gate 	if (addr != NULL) {
691acbc304dSjohnlev 		/* dump_crumb will protect us against bogus addresses */
6927c478bd9Sstevel@tonic-gate 		dump_crumb((kaif_crumb_t *)addr);
6937c478bd9Sstevel@tonic-gate 
6947c478bd9Sstevel@tonic-gate 	} else if (cpuid != -1) {
695acbc304dSjohnlev 		if (cpuid < 0 || cpuid >= kaif_ncpusave)
6967c478bd9Sstevel@tonic-gate 			return;
6977c478bd9Sstevel@tonic-gate 
6987c478bd9Sstevel@tonic-gate 		dump_crumbs(&kaif_cpusave[cpuid]);
6997c478bd9Sstevel@tonic-gate 
7007c478bd9Sstevel@tonic-gate 	} else {
7017c478bd9Sstevel@tonic-gate 		for (i = 0; i < kaif_ncpusave; i++) {
7027c478bd9Sstevel@tonic-gate 			kaif_cpusave_t *save = &kaif_cpusave[i];
7037c478bd9Sstevel@tonic-gate 
7047c478bd9Sstevel@tonic-gate 			if (save->krs_cpu_state == KAIF_CPU_STATE_NONE)
7057c478bd9Sstevel@tonic-gate 				continue;
7067c478bd9Sstevel@tonic-gate 
7077c478bd9Sstevel@tonic-gate 			mdb_printf("%sCPU %d crumbs: (curidx %d)\n",
7087c478bd9Sstevel@tonic-gate 			    (i == 0 ? "" : "\n"), i, save->krs_curcrumbidx);
7097c478bd9Sstevel@tonic-gate 
7107c478bd9Sstevel@tonic-gate 			dump_crumbs(save);
7117c478bd9Sstevel@tonic-gate 		}
7127c478bd9Sstevel@tonic-gate 	}
7137c478bd9Sstevel@tonic-gate }
7147c478bd9Sstevel@tonic-gate 
7157c478bd9Sstevel@tonic-gate static void
7167c478bd9Sstevel@tonic-gate kaif_modchg_register(void (*func)(struct modctl *, int))
7177c478bd9Sstevel@tonic-gate {
7187c478bd9Sstevel@tonic-gate 	kaif_modchg_cb = func;
7197c478bd9Sstevel@tonic-gate }
7207c478bd9Sstevel@tonic-gate 
7217c478bd9Sstevel@tonic-gate static void
7227c478bd9Sstevel@tonic-gate kaif_modchg_cancel(void)
7237c478bd9Sstevel@tonic-gate {
7247c478bd9Sstevel@tonic-gate 	ASSERT(kaif_modchg_cb != NULL);
7257c478bd9Sstevel@tonic-gate 
7267c478bd9Sstevel@tonic-gate 	kaif_modchg_cb = NULL;
7277c478bd9Sstevel@tonic-gate }
7287c478bd9Sstevel@tonic-gate 
7297c478bd9Sstevel@tonic-gate void
7307c478bd9Sstevel@tonic-gate kaif_mod_loaded(struct modctl *modp)
7317c478bd9Sstevel@tonic-gate {
7327c478bd9Sstevel@tonic-gate 	if (kaif_modchg_cb != NULL)
7337c478bd9Sstevel@tonic-gate 		kaif_modchg_cb(modp, 1);
7347c478bd9Sstevel@tonic-gate }
7357c478bd9Sstevel@tonic-gate 
7367c478bd9Sstevel@tonic-gate void
7377c478bd9Sstevel@tonic-gate kaif_mod_unloading(struct modctl *modp)
7387c478bd9Sstevel@tonic-gate {
7397c478bd9Sstevel@tonic-gate 	if (kaif_modchg_cb != NULL)
7407c478bd9Sstevel@tonic-gate 		kaif_modchg_cb(modp, 0);
7417c478bd9Sstevel@tonic-gate }
7427c478bd9Sstevel@tonic-gate 
7437c478bd9Sstevel@tonic-gate /*
7447c478bd9Sstevel@tonic-gate  * On some processors, we'll need to clear a certain MSR before proceeding into
7457c478bd9Sstevel@tonic-gate  * the debugger.  Complicating matters, this MSR must be cleared before we take
7467c478bd9Sstevel@tonic-gate  * any branches.  We have patch points in every trap handler, which will cover
7477c478bd9Sstevel@tonic-gate  * all entry paths for master CPUs.  We also have a patch point in the slave
7487c478bd9Sstevel@tonic-gate  * entry code.
7497c478bd9Sstevel@tonic-gate  */
7507c478bd9Sstevel@tonic-gate static void
7517c478bd9Sstevel@tonic-gate kaif_msr_add_clrentry(uint_t msr)
7527c478bd9Sstevel@tonic-gate {
7537c478bd9Sstevel@tonic-gate #ifdef __amd64
7547c478bd9Sstevel@tonic-gate 	uchar_t code[] = {
7557c478bd9Sstevel@tonic-gate 		0x51, 0x50, 0x52,		/* pushq %rcx, %rax, %rdx */
7567c478bd9Sstevel@tonic-gate 		0xb9, 0x00, 0x00, 0x00, 0x00,	/* movl $MSRNUM, %ecx */
7577c478bd9Sstevel@tonic-gate 		0x31, 0xc0,			/* clr %eax */
7587c478bd9Sstevel@tonic-gate 		0x31, 0xd2,			/* clr %edx */
7597c478bd9Sstevel@tonic-gate 		0x0f, 0x30,			/* wrmsr */
7607c478bd9Sstevel@tonic-gate 		0x5a, 0x58, 0x59		/* popq %rdx, %rax, %rcx */
7617c478bd9Sstevel@tonic-gate 	};
7627c478bd9Sstevel@tonic-gate 	uchar_t *patch = &code[4];
7637c478bd9Sstevel@tonic-gate #else
7647c478bd9Sstevel@tonic-gate 	uchar_t code[] = {
7657c478bd9Sstevel@tonic-gate 		0x60,				/* pushal */
7667c478bd9Sstevel@tonic-gate 		0xb9, 0x00, 0x00, 0x00, 0x00,	/* movl $MSRNUM, %ecx */
7677c478bd9Sstevel@tonic-gate 		0x31, 0xc0,			/* clr %eax */
7687c478bd9Sstevel@tonic-gate 		0x31, 0xd2,			/* clr %edx */
7697c478bd9Sstevel@tonic-gate 		0x0f, 0x30,			/* wrmsr */
7707c478bd9Sstevel@tonic-gate 		0x61				/* popal */
7717c478bd9Sstevel@tonic-gate 	};
7727c478bd9Sstevel@tonic-gate 	uchar_t *patch = &code[2];
7737c478bd9Sstevel@tonic-gate #endif
7747c478bd9Sstevel@tonic-gate 
7757c478bd9Sstevel@tonic-gate 	bcopy(&msr, patch, sizeof (uint32_t));
7767c478bd9Sstevel@tonic-gate 
7777c478bd9Sstevel@tonic-gate 	kaif_idt_patch((caddr_t)code, sizeof (code));
7787c478bd9Sstevel@tonic-gate 
7797c478bd9Sstevel@tonic-gate 	bcopy(code, &kaif_slave_entry_patch, sizeof (code));
7807c478bd9Sstevel@tonic-gate }
7817c478bd9Sstevel@tonic-gate 
7827c478bd9Sstevel@tonic-gate static void
7837c478bd9Sstevel@tonic-gate kaif_msr_add_wrexit(uint_t msr, uint64_t *valp)
7847c478bd9Sstevel@tonic-gate {
7857c478bd9Sstevel@tonic-gate 	kaif_msr_wrexit_msr = msr;
7867c478bd9Sstevel@tonic-gate 	kaif_msr_wrexit_valp = valp;
7877c478bd9Sstevel@tonic-gate }
7887c478bd9Sstevel@tonic-gate 
7897c478bd9Sstevel@tonic-gate static void
7907c478bd9Sstevel@tonic-gate kaif_msr_add(const kmdb_msr_t *msrs)
7917c478bd9Sstevel@tonic-gate {
7927c478bd9Sstevel@tonic-gate 	kmdb_msr_t *save;
7937c478bd9Sstevel@tonic-gate 	int nmsrs, i;
7947c478bd9Sstevel@tonic-gate 
7957c478bd9Sstevel@tonic-gate 	ASSERT(kaif_cpusave[0].krs_msr == NULL);
7967c478bd9Sstevel@tonic-gate 
7977c478bd9Sstevel@tonic-gate 	for (i = 0; msrs[i].msr_num != 0; i++) {
7987c478bd9Sstevel@tonic-gate 		switch (msrs[i].msr_type) {
7997c478bd9Sstevel@tonic-gate 		case KMDB_MSR_CLEARENTRY:
8007c478bd9Sstevel@tonic-gate 			kaif_msr_add_clrentry(msrs[i].msr_num);
8017c478bd9Sstevel@tonic-gate 			break;
8027c478bd9Sstevel@tonic-gate 
8037c478bd9Sstevel@tonic-gate 		case KMDB_MSR_WRITEDELAY:
8047c478bd9Sstevel@tonic-gate 			kaif_msr_add_wrexit(msrs[i].msr_num, msrs[i].msr_valp);
8057c478bd9Sstevel@tonic-gate 			break;
8067c478bd9Sstevel@tonic-gate 		}
8077c478bd9Sstevel@tonic-gate 	}
8087c478bd9Sstevel@tonic-gate 	nmsrs = i + 1; /* we want to copy the terminating kmdb_msr_t too */
8097c478bd9Sstevel@tonic-gate 
8107c478bd9Sstevel@tonic-gate 	save = mdb_zalloc(sizeof (kmdb_msr_t) * nmsrs * kaif_ncpusave,
8117c478bd9Sstevel@tonic-gate 	    UM_SLEEP);
8127c478bd9Sstevel@tonic-gate 
8137c478bd9Sstevel@tonic-gate 	for (i = 0; i < kaif_ncpusave; i++) {
8147c478bd9Sstevel@tonic-gate 		bcopy(msrs, &save[nmsrs * i], sizeof (kmdb_msr_t) * nmsrs);
8157c478bd9Sstevel@tonic-gate 		kaif_cpusave[i].krs_msr = &save[nmsrs * i];
8167c478bd9Sstevel@tonic-gate 	}
8177c478bd9Sstevel@tonic-gate }
8187c478bd9Sstevel@tonic-gate 
8197c478bd9Sstevel@tonic-gate static uint64_t
8207c478bd9Sstevel@tonic-gate kaif_msr_get(int cpuid, uint_t num)
8217c478bd9Sstevel@tonic-gate {
822acbc304dSjohnlev 	kaif_cpusave_t *save;
8237c478bd9Sstevel@tonic-gate 	kmdb_msr_t *msr;
8247c478bd9Sstevel@tonic-gate 	int i;
8257c478bd9Sstevel@tonic-gate 
826acbc304dSjohnlev 	if ((save = kaif_cpuid2save(cpuid)) == NULL)
827acbc304dSjohnlev 		return (-1); /* errno is set for us */
828acbc304dSjohnlev 
829acbc304dSjohnlev 	msr = save->krs_msr;
8307c478bd9Sstevel@tonic-gate 
8317c478bd9Sstevel@tonic-gate 	for (i = 0; msr[i].msr_num != 0; i++) {
8327c478bd9Sstevel@tonic-gate 		if (msr[i].msr_num == num &&
8337c478bd9Sstevel@tonic-gate 		    (msr[i].msr_type & KMDB_MSR_READ))
8347c478bd9Sstevel@tonic-gate 			return (msr[i].msr_val);
8357c478bd9Sstevel@tonic-gate 	}
8367c478bd9Sstevel@tonic-gate 
8377c478bd9Sstevel@tonic-gate 	return (0);
8387c478bd9Sstevel@tonic-gate }
8397c478bd9Sstevel@tonic-gate 
8407c478bd9Sstevel@tonic-gate int
8417c478bd9Sstevel@tonic-gate kaif_memrange_add(caddr_t base, size_t len)
8427c478bd9Sstevel@tonic-gate {
8437c478bd9Sstevel@tonic-gate 	kaif_memrange_t *mr = &kaif_memranges[kaif_nmemranges];
8447c478bd9Sstevel@tonic-gate 
8457c478bd9Sstevel@tonic-gate 	if (kaif_nmemranges == KAIF_MEMRANGES_MAX)
8467c478bd9Sstevel@tonic-gate 		return (set_errno(ENOSPC));
8477c478bd9Sstevel@tonic-gate 
8487c478bd9Sstevel@tonic-gate 	/*
8497c478bd9Sstevel@tonic-gate 	 * In the unlikely event that someone is stepping through this routine,
8507c478bd9Sstevel@tonic-gate 	 * we need to make sure that kaif_memranges knows about the new range
8517c478bd9Sstevel@tonic-gate 	 * before umem gets it.  That way the entry code can recognize stacks
8527c478bd9Sstevel@tonic-gate 	 * allocated from the new region.
8537c478bd9Sstevel@tonic-gate 	 */
8547c478bd9Sstevel@tonic-gate 	mr->mr_base = base;
8557c478bd9Sstevel@tonic-gate 	mr->mr_lim = base + len - 1;
8567c478bd9Sstevel@tonic-gate 	kaif_nmemranges++;
8577c478bd9Sstevel@tonic-gate 
8587c478bd9Sstevel@tonic-gate 	if (mdb_umem_add(base, len) < 0) {
8597c478bd9Sstevel@tonic-gate 		kaif_nmemranges--;
8607c478bd9Sstevel@tonic-gate 		return (-1); /* errno is set for us */
8617c478bd9Sstevel@tonic-gate 	}
8627c478bd9Sstevel@tonic-gate 
8637c478bd9Sstevel@tonic-gate 	return (0);
8647c478bd9Sstevel@tonic-gate }
8657c478bd9Sstevel@tonic-gate 
8667c478bd9Sstevel@tonic-gate void
8677c478bd9Sstevel@tonic-gate kaif_trap_set_debugger(void)
8687c478bd9Sstevel@tonic-gate {
8697c478bd9Sstevel@tonic-gate 	set_idt(&kaif_idtr);
8707c478bd9Sstevel@tonic-gate }
8717c478bd9Sstevel@tonic-gate 
8727c478bd9Sstevel@tonic-gate void
8737c478bd9Sstevel@tonic-gate kaif_trap_set_saved(kaif_cpusave_t *cpusave)
8747c478bd9Sstevel@tonic-gate {
8757c478bd9Sstevel@tonic-gate 	set_idt(&cpusave->krs_idtr);
8767c478bd9Sstevel@tonic-gate }
8777c478bd9Sstevel@tonic-gate 
8787c478bd9Sstevel@tonic-gate static int
8797c478bd9Sstevel@tonic-gate kaif_init(kmdb_auxv_t *kav)
8807c478bd9Sstevel@tonic-gate {
8817c478bd9Sstevel@tonic-gate 	int i;
8827c478bd9Sstevel@tonic-gate 
8837c478bd9Sstevel@tonic-gate 	/* Allocate the per-CPU save areas */
8847c478bd9Sstevel@tonic-gate 	kaif_cpusave = mdb_zalloc(sizeof (kaif_cpusave_t) * kav->kav_ncpu,
8857c478bd9Sstevel@tonic-gate 	    UM_SLEEP);
8867c478bd9Sstevel@tonic-gate 	kaif_ncpusave = kav->kav_ncpu;
8877c478bd9Sstevel@tonic-gate 
8887c478bd9Sstevel@tonic-gate 	for (i = 0; i < kaif_ncpusave; i++) {
889acbc304dSjohnlev 		kaif_cpusave_t *save = &kaif_cpusave[i];
8907c478bd9Sstevel@tonic-gate 
891acbc304dSjohnlev 		save->krs_cpu_id = i;
892acbc304dSjohnlev 		save->krs_curcrumbidx = KAIF_NCRUMBS - 1;
893acbc304dSjohnlev 		save->krs_curcrumb = &save->krs_crumbs[save->krs_curcrumbidx];
8947c478bd9Sstevel@tonic-gate 	}
8957c478bd9Sstevel@tonic-gate 
8967c478bd9Sstevel@tonic-gate 	kaif_idt_init();
8977c478bd9Sstevel@tonic-gate 
8987c478bd9Sstevel@tonic-gate 	/* The initial selector set.  Updated by the debugger-entry code */
8997c478bd9Sstevel@tonic-gate #ifndef __amd64
9007c478bd9Sstevel@tonic-gate 	kaif_cs = BOOTCODE_SEL;
9017c478bd9Sstevel@tonic-gate 	kaif_ds = kaif_fs = kaif_gs = BOOTFLAT_SEL;
9027c478bd9Sstevel@tonic-gate #endif
9037c478bd9Sstevel@tonic-gate 
9047c478bd9Sstevel@tonic-gate 	kaif_memranges[0].mr_base = kav->kav_dseg;
9057c478bd9Sstevel@tonic-gate 	kaif_memranges[0].mr_lim = kav->kav_dseg + kav->kav_dseg_size - 1;
9067c478bd9Sstevel@tonic-gate 	kaif_nmemranges = 1;
9077c478bd9Sstevel@tonic-gate 
9087c478bd9Sstevel@tonic-gate 	kaif_modchg_cb = NULL;
9097c478bd9Sstevel@tonic-gate 
9107c478bd9Sstevel@tonic-gate 	kaif_waptmap = 0;
9117c478bd9Sstevel@tonic-gate 
9127c478bd9Sstevel@tonic-gate 	kaif_drreg.dr_ctl = KREG_DRCTL_RESERVED;
9137c478bd9Sstevel@tonic-gate 	kaif_drreg.dr_stat = KREG_DRSTAT_RESERVED;
9147c478bd9Sstevel@tonic-gate 
9157c478bd9Sstevel@tonic-gate 	kaif_msr_wrexit_msr = 0;
9167c478bd9Sstevel@tonic-gate 	kaif_msr_wrexit_valp = NULL;
9177c478bd9Sstevel@tonic-gate 
9187c478bd9Sstevel@tonic-gate 	kaif_trap_switch = (kav->kav_flags & KMDB_AUXV_FL_NOTRPSWTCH) == 0;
9197c478bd9Sstevel@tonic-gate 
9207c478bd9Sstevel@tonic-gate 	if ((kaif_sys_sysenter = kmdb_kdi_lookup_by_name("unix",
9217c478bd9Sstevel@tonic-gate 	    "sys_sysenter")) == NULL)
9227c478bd9Sstevel@tonic-gate 		return (set_errno(ENOENT));
9237c478bd9Sstevel@tonic-gate 
9247c478bd9Sstevel@tonic-gate 	return (0);
9257c478bd9Sstevel@tonic-gate }
9267c478bd9Sstevel@tonic-gate 
9277c478bd9Sstevel@tonic-gate dpi_ops_t kmdb_dpi_ops = {
9287c478bd9Sstevel@tonic-gate 	kaif_init,
9297c478bd9Sstevel@tonic-gate 	kaif_activate,
9307c478bd9Sstevel@tonic-gate 	kaif_deactivate,
9317c478bd9Sstevel@tonic-gate 	kaif_enter_mon,
9327c478bd9Sstevel@tonic-gate 	kaif_modchg_register,
9337c478bd9Sstevel@tonic-gate 	kaif_modchg_cancel,
9347c478bd9Sstevel@tonic-gate 	kaif_get_cpu_state,
9357c478bd9Sstevel@tonic-gate 	kaif_get_master_cpuid,
9367c478bd9Sstevel@tonic-gate 	kaif_get_gregs,
937acbc304dSjohnlev 	kaif_get_register,
938acbc304dSjohnlev 	kaif_set_register,
9397c478bd9Sstevel@tonic-gate 	kaif_brkpt_arm,
9407c478bd9Sstevel@tonic-gate 	kaif_brkpt_disarm,
9417c478bd9Sstevel@tonic-gate 	kaif_wapt_validate,
9427c478bd9Sstevel@tonic-gate 	kaif_wapt_reserve,
9437c478bd9Sstevel@tonic-gate 	kaif_wapt_release,
9447c478bd9Sstevel@tonic-gate 	kaif_wapt_arm,
9457c478bd9Sstevel@tonic-gate 	kaif_wapt_disarm,
9467c478bd9Sstevel@tonic-gate 	kaif_wapt_match,
9477c478bd9Sstevel@tonic-gate 	kaif_step,
9487c478bd9Sstevel@tonic-gate 	kaif_step_branch,
9497c478bd9Sstevel@tonic-gate 	kaif_call,
9507c478bd9Sstevel@tonic-gate 	kaif_dump_crumbs,
9517c478bd9Sstevel@tonic-gate 	kaif_memrange_add,
9527c478bd9Sstevel@tonic-gate 	kaif_msr_add,
9537c478bd9Sstevel@tonic-gate 	kaif_msr_get,
9547c478bd9Sstevel@tonic-gate };
955