xref: /onnv-gate/usr/src/cmd/mdb/intel/kmdb/kaif.c (revision 1234:f13b951c0f14)
10Sstevel@tonic-gate /*
20Sstevel@tonic-gate  * CDDL HEADER START
30Sstevel@tonic-gate  *
40Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
50Sstevel@tonic-gate  * Common Development and Distribution License, Version 1.0 only
60Sstevel@tonic-gate  * (the "License").  You may not use this file except in compliance
70Sstevel@tonic-gate  * with the License.
80Sstevel@tonic-gate  *
90Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
100Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
110Sstevel@tonic-gate  * See the License for the specific language governing permissions
120Sstevel@tonic-gate  * and limitations under the License.
130Sstevel@tonic-gate  *
140Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
150Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
160Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
170Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
180Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
190Sstevel@tonic-gate  *
200Sstevel@tonic-gate  * CDDL HEADER END
210Sstevel@tonic-gate  */
220Sstevel@tonic-gate /*
23*1234Sjohnlev  * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
240Sstevel@tonic-gate  * Use is subject to license terms.
250Sstevel@tonic-gate  */
260Sstevel@tonic-gate 
270Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
280Sstevel@tonic-gate 
290Sstevel@tonic-gate /*
300Sstevel@tonic-gate  * The debugger/"PROM" interface layer
310Sstevel@tonic-gate  *
320Sstevel@tonic-gate  * (it makes more sense on SPARC)
330Sstevel@tonic-gate  */
340Sstevel@tonic-gate 
350Sstevel@tonic-gate #include <kmdb/kmdb_dpi_impl.h>
360Sstevel@tonic-gate #include <kmdb/kmdb_kdi.h>
370Sstevel@tonic-gate #include <kmdb/kmdb_umemglue.h>
380Sstevel@tonic-gate #include <kmdb/kaif.h>
390Sstevel@tonic-gate #include <kmdb/kaif_asmutil.h>
400Sstevel@tonic-gate #include <mdb/mdb_err.h>
410Sstevel@tonic-gate #include <mdb/mdb_debug.h>
420Sstevel@tonic-gate #include <mdb/mdb_isautil.h>
430Sstevel@tonic-gate #include <mdb/mdb_io_impl.h>
440Sstevel@tonic-gate #include <mdb/mdb_kreg.h>
450Sstevel@tonic-gate #include <mdb/mdb.h>
460Sstevel@tonic-gate 
470Sstevel@tonic-gate #include <sys/types.h>
480Sstevel@tonic-gate #include <sys/segments.h>
490Sstevel@tonic-gate #include <sys/bitmap.h>
500Sstevel@tonic-gate 
510Sstevel@tonic-gate kaif_cpusave_t	*kaif_cpusave;
520Sstevel@tonic-gate int		kaif_ncpusave;
530Sstevel@tonic-gate 
540Sstevel@tonic-gate kaif_drreg_t	kaif_drreg;
550Sstevel@tonic-gate 
560Sstevel@tonic-gate uint32_t	kaif_waptmap;
570Sstevel@tonic-gate 
580Sstevel@tonic-gate #ifndef __amd64
590Sstevel@tonic-gate /* Used to track the current set of valid kernel selectors. */
600Sstevel@tonic-gate uint32_t	kaif_cs;
610Sstevel@tonic-gate uint32_t	kaif_ds;
620Sstevel@tonic-gate uint32_t	kaif_fs;
630Sstevel@tonic-gate uint32_t	kaif_gs;
640Sstevel@tonic-gate #endif
650Sstevel@tonic-gate 
660Sstevel@tonic-gate uint_t		kaif_msr_wrexit_msr;
670Sstevel@tonic-gate uint64_t	*kaif_msr_wrexit_valp;
680Sstevel@tonic-gate 
690Sstevel@tonic-gate uintptr_t	kaif_kernel_handler;
700Sstevel@tonic-gate uintptr_t	kaif_sys_sysenter;
710Sstevel@tonic-gate 
720Sstevel@tonic-gate int		kaif_trap_switch;
730Sstevel@tonic-gate 
740Sstevel@tonic-gate void (*kaif_modchg_cb)(struct modctl *, int);
750Sstevel@tonic-gate 
760Sstevel@tonic-gate #define	KAIF_MEMRANGES_MAX	2
770Sstevel@tonic-gate 
780Sstevel@tonic-gate kaif_memrange_t	kaif_memranges[KAIF_MEMRANGES_MAX];
790Sstevel@tonic-gate int		kaif_nmemranges;
800Sstevel@tonic-gate 
810Sstevel@tonic-gate enum {
820Sstevel@tonic-gate 	M_SYSRET	= 0x07, /* after M_ESC */
830Sstevel@tonic-gate 	M_ESC		= 0x0f,
840Sstevel@tonic-gate 	M_SYSEXIT	= 0x35, /* after M_ESC */
850Sstevel@tonic-gate 	M_REX_LO	= 0x40, /* first REX prefix */
860Sstevel@tonic-gate 	M_REX_HI	= 0x4f, /* last REX prefix */
870Sstevel@tonic-gate 	M_PUSHF		= 0x9c,	/* pushfl and pushfq */
880Sstevel@tonic-gate 	M_POPF		= 0x9d,	/* popfl and popfq */
890Sstevel@tonic-gate 	M_INT3		= 0xcc,
900Sstevel@tonic-gate 	M_INTX		= 0xcd,
910Sstevel@tonic-gate 	M_INTO		= 0xce,
920Sstevel@tonic-gate 	M_IRET		= 0xcf,
930Sstevel@tonic-gate 	M_CLI		= 0xfa,
940Sstevel@tonic-gate 	M_STI		= 0xfb
950Sstevel@tonic-gate };
960Sstevel@tonic-gate 
970Sstevel@tonic-gate #define	KAIF_BREAKPOINT_INSTR	M_INT3
980Sstevel@tonic-gate 
990Sstevel@tonic-gate #define	KAIF_WPPRIV2ID(wp)	(int)(uintptr_t)((wp)->wp_priv)
1000Sstevel@tonic-gate 
1010Sstevel@tonic-gate #ifdef __amd64
1020Sstevel@tonic-gate #define	FLAGS_REG_NAME		"rflags"
1030Sstevel@tonic-gate #else
1040Sstevel@tonic-gate #define	FLAGS_REG_NAME		"eflags"
1050Sstevel@tonic-gate #endif
1060Sstevel@tonic-gate 
1070Sstevel@tonic-gate /*
1080Sstevel@tonic-gate  * Called during normal debugger operation and during debugger faults.
1090Sstevel@tonic-gate  */
1100Sstevel@tonic-gate static void
1110Sstevel@tonic-gate kaif_enter_mon(void)
1120Sstevel@tonic-gate {
1130Sstevel@tonic-gate 	char c;
1140Sstevel@tonic-gate 
1150Sstevel@tonic-gate 	for (;;) {
1160Sstevel@tonic-gate 		mdb_iob_printf(mdb.m_out,
1170Sstevel@tonic-gate 		    "%s: Do you really want to reboot? (y/n) ",
1180Sstevel@tonic-gate 		    mdb.m_pname);
1190Sstevel@tonic-gate 		mdb_iob_flush(mdb.m_out);
1200Sstevel@tonic-gate 
1210Sstevel@tonic-gate 		while (IOP_READ(mdb.m_term, &c, 1) != 1)
1220Sstevel@tonic-gate 			continue;
1230Sstevel@tonic-gate 		mdb_iob_printf(mdb.m_out, "%c%s", c, (c == '\n' ? "" : "\n"));
1240Sstevel@tonic-gate 
1250Sstevel@tonic-gate 		if (c == 'n' || c == 'N')
1260Sstevel@tonic-gate 			return;
1270Sstevel@tonic-gate 		else if (c == 'y' || c == 'Y') {
1280Sstevel@tonic-gate 			mdb_iob_printf(mdb.m_out, "Rebooting...\n");
1290Sstevel@tonic-gate 
1300Sstevel@tonic-gate 			kmdb_dpi_reboot();
1310Sstevel@tonic-gate 		}
1320Sstevel@tonic-gate 	}
1330Sstevel@tonic-gate }
1340Sstevel@tonic-gate 
135*1234Sjohnlev static kaif_cpusave_t *
136*1234Sjohnlev kaif_cpuid2save(int cpuid)
137*1234Sjohnlev {
138*1234Sjohnlev 	kaif_cpusave_t *save;
139*1234Sjohnlev 
140*1234Sjohnlev 	if (cpuid == DPI_MASTER_CPUID)
141*1234Sjohnlev 		return (&kaif_cpusave[kaif_master_cpuid]);
142*1234Sjohnlev 
143*1234Sjohnlev 	if (cpuid < 0 || cpuid >= kaif_ncpusave) {
144*1234Sjohnlev 		(void) set_errno(EINVAL);
145*1234Sjohnlev 		return (NULL);
146*1234Sjohnlev 	}
147*1234Sjohnlev 
148*1234Sjohnlev 	save = &kaif_cpusave[cpuid];
149*1234Sjohnlev 
150*1234Sjohnlev 	if (save->krs_cpu_state != KAIF_CPU_STATE_MASTER &&
151*1234Sjohnlev 	    save->krs_cpu_state != KAIF_CPU_STATE_SLAVE) {
152*1234Sjohnlev 		(void) set_errno(EINVAL);
153*1234Sjohnlev 		return (NULL);
154*1234Sjohnlev 	}
155*1234Sjohnlev 
156*1234Sjohnlev 	return (save);
157*1234Sjohnlev }
158*1234Sjohnlev 
1590Sstevel@tonic-gate static int
1600Sstevel@tonic-gate kaif_get_cpu_state(int cpuid)
1610Sstevel@tonic-gate {
162*1234Sjohnlev 	kaif_cpusave_t *save;
1630Sstevel@tonic-gate 
164*1234Sjohnlev 	if ((save = kaif_cpuid2save(cpuid)) == NULL)
165*1234Sjohnlev 		return (-1); /* errno is set for us */
1660Sstevel@tonic-gate 
167*1234Sjohnlev 	switch (save->krs_cpu_state) {
1680Sstevel@tonic-gate 	case KAIF_CPU_STATE_MASTER:
1690Sstevel@tonic-gate 		return (DPI_CPU_STATE_MASTER);
1700Sstevel@tonic-gate 	case KAIF_CPU_STATE_SLAVE:
1710Sstevel@tonic-gate 		return (DPI_CPU_STATE_SLAVE);
1720Sstevel@tonic-gate 	default:
1730Sstevel@tonic-gate 		return (set_errno(EINVAL));
1740Sstevel@tonic-gate 	}
1750Sstevel@tonic-gate }
1760Sstevel@tonic-gate 
1770Sstevel@tonic-gate static int
1780Sstevel@tonic-gate kaif_get_master_cpuid(void)
1790Sstevel@tonic-gate {
1800Sstevel@tonic-gate 	return (kaif_master_cpuid);
1810Sstevel@tonic-gate }
1820Sstevel@tonic-gate 
1830Sstevel@tonic-gate static const mdb_tgt_gregset_t *
1840Sstevel@tonic-gate kaif_get_gregs(int cpuid)
1850Sstevel@tonic-gate {
186*1234Sjohnlev 	kaif_cpusave_t *save;
1870Sstevel@tonic-gate 
188*1234Sjohnlev 	if ((save = kaif_cpuid2save(cpuid)) == NULL)
189*1234Sjohnlev 		return (NULL); /* errno is set for us */
1900Sstevel@tonic-gate 
191*1234Sjohnlev 	return (save->krs_gregs);
1920Sstevel@tonic-gate }
1930Sstevel@tonic-gate 
1940Sstevel@tonic-gate typedef struct kaif_reg_synonyms {
1950Sstevel@tonic-gate 	const char *rs_syn;
1960Sstevel@tonic-gate 	const char *rs_name;
1970Sstevel@tonic-gate } kaif_reg_synonyms_t;
1980Sstevel@tonic-gate 
1990Sstevel@tonic-gate static kreg_t *
200*1234Sjohnlev kaif_find_regp(const char *regname)
2010Sstevel@tonic-gate {
2020Sstevel@tonic-gate 	static const kaif_reg_synonyms_t synonyms[] = {
2030Sstevel@tonic-gate #ifdef __amd64
2040Sstevel@tonic-gate 	    { "pc", "rip" },
2050Sstevel@tonic-gate 	    { "sp", "rsp" },
2060Sstevel@tonic-gate 	    { "fp", "rbp" },
2070Sstevel@tonic-gate #else
2080Sstevel@tonic-gate 	    { "pc", "eip" },
2090Sstevel@tonic-gate 	    { "sp", "esp" },
2100Sstevel@tonic-gate 	    { "fp", "ebp" },
2110Sstevel@tonic-gate #endif
2120Sstevel@tonic-gate 	    { "tt", "trapno" }
2130Sstevel@tonic-gate 	};
214*1234Sjohnlev 
215*1234Sjohnlev 	kaif_cpusave_t *save;
2160Sstevel@tonic-gate 	int i;
2170Sstevel@tonic-gate 
218*1234Sjohnlev 	save = kaif_cpuid2save(DPI_MASTER_CPUID);
2190Sstevel@tonic-gate 
2200Sstevel@tonic-gate 	for (i = 0; i < sizeof (synonyms) / sizeof (synonyms[0]); i++) {
2210Sstevel@tonic-gate 		if (strcmp(synonyms[i].rs_syn, regname) == 0)
2220Sstevel@tonic-gate 			regname = synonyms[i].rs_name;
2230Sstevel@tonic-gate 	}
2240Sstevel@tonic-gate 
2250Sstevel@tonic-gate 	for (i = 0; mdb_isa_kregs[i].rd_name != NULL; i++) {
2260Sstevel@tonic-gate 		const mdb_tgt_regdesc_t *rd = &mdb_isa_kregs[i];
2270Sstevel@tonic-gate 
2280Sstevel@tonic-gate 		if (strcmp(rd->rd_name, regname) == 0)
229*1234Sjohnlev 			return (&save->krs_gregs->kregs[rd->rd_num]);
2300Sstevel@tonic-gate 	}
2310Sstevel@tonic-gate 
2320Sstevel@tonic-gate 	(void) set_errno(ENOENT);
2330Sstevel@tonic-gate 	return (NULL);
2340Sstevel@tonic-gate }
2350Sstevel@tonic-gate 
2360Sstevel@tonic-gate /*ARGSUSED*/
2370Sstevel@tonic-gate static int
238*1234Sjohnlev kaif_get_register(const char *regname, kreg_t *valp)
2390Sstevel@tonic-gate {
2400Sstevel@tonic-gate 	kreg_t *regp;
2410Sstevel@tonic-gate 
242*1234Sjohnlev 	if ((regp = kaif_find_regp(regname)) == NULL)
2430Sstevel@tonic-gate 		return (-1);
2440Sstevel@tonic-gate 
2450Sstevel@tonic-gate 	*valp = *regp;
2460Sstevel@tonic-gate 
2470Sstevel@tonic-gate 	return (0);
2480Sstevel@tonic-gate }
2490Sstevel@tonic-gate 
2500Sstevel@tonic-gate static int
251*1234Sjohnlev kaif_set_register(const char *regname, kreg_t val)
2520Sstevel@tonic-gate {
2530Sstevel@tonic-gate 	kreg_t *regp;
2540Sstevel@tonic-gate 
255*1234Sjohnlev 	if ((regp = kaif_find_regp(regname)) == NULL)
2560Sstevel@tonic-gate 		return (-1);
2570Sstevel@tonic-gate 
2580Sstevel@tonic-gate 	*regp = val;
2590Sstevel@tonic-gate 
2600Sstevel@tonic-gate 	return (0);
2610Sstevel@tonic-gate }
2620Sstevel@tonic-gate 
2630Sstevel@tonic-gate static int
2640Sstevel@tonic-gate kaif_brkpt_arm(uintptr_t addr, mdb_instr_t *instrp)
2650Sstevel@tonic-gate {
2660Sstevel@tonic-gate 	mdb_instr_t bkpt = KAIF_BREAKPOINT_INSTR;
2670Sstevel@tonic-gate 
2680Sstevel@tonic-gate 	if (mdb_tgt_vread(mdb.m_target, instrp, sizeof (mdb_instr_t), addr) !=
2690Sstevel@tonic-gate 	    sizeof (mdb_instr_t))
2700Sstevel@tonic-gate 		return (-1); /* errno is set for us */
2710Sstevel@tonic-gate 
2720Sstevel@tonic-gate 	if (mdb_tgt_vwrite(mdb.m_target, &bkpt, sizeof (mdb_instr_t), addr) !=
2730Sstevel@tonic-gate 	    sizeof (mdb_instr_t))
2740Sstevel@tonic-gate 		return (-1); /* errno is set for us */
2750Sstevel@tonic-gate 
2760Sstevel@tonic-gate 	return (0);
2770Sstevel@tonic-gate }
2780Sstevel@tonic-gate 
2790Sstevel@tonic-gate static int
2800Sstevel@tonic-gate kaif_brkpt_disarm(uintptr_t addr, mdb_instr_t instrp)
2810Sstevel@tonic-gate {
2820Sstevel@tonic-gate 	if (mdb_tgt_vwrite(mdb.m_target, &instrp, sizeof (mdb_instr_t), addr) !=
2830Sstevel@tonic-gate 	    sizeof (mdb_instr_t))
2840Sstevel@tonic-gate 		return (-1); /* errno is set for us */
2850Sstevel@tonic-gate 
2860Sstevel@tonic-gate 	return (0);
2870Sstevel@tonic-gate }
2880Sstevel@tonic-gate 
2890Sstevel@tonic-gate /*
2900Sstevel@tonic-gate  * Intel watchpoints are even more fun than SPARC ones.  The Intel architecture
2910Sstevel@tonic-gate  * manuals refer to watchpoints as breakpoints.  For consistency  with the
2920Sstevel@tonic-gate  * terminology used in other portions of kmdb, we will, however, refer to them
2930Sstevel@tonic-gate  * as watchpoints.
2940Sstevel@tonic-gate  *
2950Sstevel@tonic-gate  * Execute, data write, I/O read/write, and data read/write watchpoints are
2960Sstevel@tonic-gate  * supported by the hardware.  Execute watchpoints must be one byte in length,
2970Sstevel@tonic-gate  * and must be placed on the first byte of the instruction to be watched.
2980Sstevel@tonic-gate  * Lengths of other watchpoints are more varied.
2990Sstevel@tonic-gate  *
3000Sstevel@tonic-gate  * Given that we already have a breakpoint facility, and given the restrictions
3010Sstevel@tonic-gate  * placed on execute watchpoints, we're going to disallow the creation of
3020Sstevel@tonic-gate  * execute watchpoints.  The others will be fully supported.  See the Debugging
3030Sstevel@tonic-gate  * chapter in both the IA32 and AMD64 System Programming books for more details.
3040Sstevel@tonic-gate  */
3050Sstevel@tonic-gate 
3060Sstevel@tonic-gate #ifdef __amd64
3070Sstevel@tonic-gate #define	WAPT_DATA_MAX_SIZE	8
3080Sstevel@tonic-gate #define	WAPT_DATA_SIZES_MSG	"1, 2, 4, or 8"
3090Sstevel@tonic-gate #else
3100Sstevel@tonic-gate #define	WAPT_DATA_MAX_SIZE	4
3110Sstevel@tonic-gate #define	WAPT_DATA_SIZES_MSG	"1, 2, or 4"
3120Sstevel@tonic-gate #endif
3130Sstevel@tonic-gate 
3140Sstevel@tonic-gate static int
3150Sstevel@tonic-gate kaif_wapt_validate(kmdb_wapt_t *wp)
3160Sstevel@tonic-gate {
3170Sstevel@tonic-gate 	if (wp->wp_type == DPI_WAPT_TYPE_IO) {
3180Sstevel@tonic-gate 		if (wp->wp_wflags != (MDB_TGT_WA_R | MDB_TGT_WA_W)) {
3190Sstevel@tonic-gate 			warn("I/O port watchpoints must be read/write\n");
3200Sstevel@tonic-gate 			return (set_errno(EINVAL));
3210Sstevel@tonic-gate 		}
3220Sstevel@tonic-gate 
3230Sstevel@tonic-gate 		if (wp->wp_size != 1 && wp->wp_size != 2 && wp->wp_size != 4) {
3240Sstevel@tonic-gate 			warn("I/O watchpoint size must be 1, 2, or 4 bytes\n");
3250Sstevel@tonic-gate 			return (set_errno(EINVAL));
3260Sstevel@tonic-gate 		}
3270Sstevel@tonic-gate 
3280Sstevel@tonic-gate 	} else if (wp->wp_type == DPI_WAPT_TYPE_PHYS) {
3290Sstevel@tonic-gate 		warn("physical address watchpoints are not supported on this "
3300Sstevel@tonic-gate 		    "platform\n");
3310Sstevel@tonic-gate 		return (set_errno(EMDB_TGTHWNOTSUP));
3320Sstevel@tonic-gate 
3330Sstevel@tonic-gate 	} else {
3340Sstevel@tonic-gate 		if (wp->wp_wflags != (MDB_TGT_WA_R | MDB_TGT_WA_W) &&
3350Sstevel@tonic-gate 		    wp->wp_wflags != MDB_TGT_WA_W) {
3360Sstevel@tonic-gate 			warn("watchpoints must be read/write or write-only\n");
3370Sstevel@tonic-gate 			return (set_errno(EINVAL));
3380Sstevel@tonic-gate 		}
3390Sstevel@tonic-gate 
3400Sstevel@tonic-gate 		if ((wp->wp_size & -(wp->wp_size)) != wp->wp_size ||
3410Sstevel@tonic-gate 		    wp->wp_size > WAPT_DATA_MAX_SIZE) {
3420Sstevel@tonic-gate 			warn("data watchpoint size must be " WAPT_DATA_SIZES_MSG
3430Sstevel@tonic-gate 			    " bytes\n");
3440Sstevel@tonic-gate 			return (set_errno(EINVAL));
3450Sstevel@tonic-gate 		}
3460Sstevel@tonic-gate 
3470Sstevel@tonic-gate 	}
3480Sstevel@tonic-gate 
3490Sstevel@tonic-gate 	if (wp->wp_addr & (wp->wp_size - 1)) {
3500Sstevel@tonic-gate 		warn("%lu-byte watchpoints must be %lu-byte aligned\n",
3510Sstevel@tonic-gate 		    (ulong_t)wp->wp_size, (ulong_t)wp->wp_size);
3520Sstevel@tonic-gate 		return (set_errno(EINVAL));
3530Sstevel@tonic-gate 	}
3540Sstevel@tonic-gate 
3550Sstevel@tonic-gate 	return (0);
3560Sstevel@tonic-gate }
3570Sstevel@tonic-gate 
3580Sstevel@tonic-gate static int
3590Sstevel@tonic-gate kaif_wapt_reserve(kmdb_wapt_t *wp)
3600Sstevel@tonic-gate {
3610Sstevel@tonic-gate 	int id;
3620Sstevel@tonic-gate 
3630Sstevel@tonic-gate 	for (id = 0; id <= KREG_MAXWPIDX; id++) {
3640Sstevel@tonic-gate 		if (!BT_TEST(&kaif_waptmap, id)) {
3650Sstevel@tonic-gate 			/* found one */
3660Sstevel@tonic-gate 			BT_SET(&kaif_waptmap, id);
3670Sstevel@tonic-gate 			wp->wp_priv = (void *)(uintptr_t)id;
3680Sstevel@tonic-gate 			return (0);
3690Sstevel@tonic-gate 		}
3700Sstevel@tonic-gate 	}
3710Sstevel@tonic-gate 
3720Sstevel@tonic-gate 	return (set_errno(EMDB_WPTOOMANY));
3730Sstevel@tonic-gate }
3740Sstevel@tonic-gate 
3750Sstevel@tonic-gate static void
3760Sstevel@tonic-gate kaif_wapt_release(kmdb_wapt_t *wp)
3770Sstevel@tonic-gate {
3780Sstevel@tonic-gate 	int id = KAIF_WPPRIV2ID(wp);
3790Sstevel@tonic-gate 
3800Sstevel@tonic-gate 	ASSERT(BT_TEST(&kaif_waptmap, id));
3810Sstevel@tonic-gate 	BT_CLEAR(&kaif_waptmap, id);
3820Sstevel@tonic-gate }
3830Sstevel@tonic-gate 
3840Sstevel@tonic-gate /*ARGSUSED*/
3850Sstevel@tonic-gate static void
3860Sstevel@tonic-gate kaif_wapt_arm(kmdb_wapt_t *wp)
3870Sstevel@tonic-gate {
3880Sstevel@tonic-gate 	uint_t rw;
3890Sstevel@tonic-gate 	int hwid = KAIF_WPPRIV2ID(wp);
3900Sstevel@tonic-gate 
3910Sstevel@tonic-gate 	ASSERT(BT_TEST(&kaif_waptmap, hwid));
3920Sstevel@tonic-gate 
3930Sstevel@tonic-gate 	if (wp->wp_type == DPI_WAPT_TYPE_IO)
3940Sstevel@tonic-gate 		rw = KREG_DRCTL_WP_IORW;
3950Sstevel@tonic-gate 	else if (wp->wp_wflags & MDB_TGT_WA_R)
3960Sstevel@tonic-gate 		rw = KREG_DRCTL_WP_RW;
3970Sstevel@tonic-gate 	else if (wp->wp_wflags & MDB_TGT_WA_X)
3980Sstevel@tonic-gate 		rw = KREG_DRCTL_WP_EXEC;
3990Sstevel@tonic-gate 	else
4000Sstevel@tonic-gate 		rw = KREG_DRCTL_WP_WONLY;
4010Sstevel@tonic-gate 
4020Sstevel@tonic-gate 	kaif_drreg.dr_addr[hwid] = wp->wp_addr;
4030Sstevel@tonic-gate 
4040Sstevel@tonic-gate 	kaif_drreg.dr_ctl &= ~KREG_DRCTL_WP_MASK(hwid);
4050Sstevel@tonic-gate 	kaif_drreg.dr_ctl |= KREG_DRCTL_WP_LENRW(hwid, wp->wp_size - 1, rw);
4060Sstevel@tonic-gate 	kaif_drreg.dr_ctl |= KREG_DRCTL_WPEN(hwid);
4070Sstevel@tonic-gate }
4080Sstevel@tonic-gate 
4090Sstevel@tonic-gate /*ARGSUSED*/
4100Sstevel@tonic-gate static void
4110Sstevel@tonic-gate kaif_wapt_disarm(kmdb_wapt_t *wp)
4120Sstevel@tonic-gate {
4130Sstevel@tonic-gate 	int hwid = KAIF_WPPRIV2ID(wp);
4140Sstevel@tonic-gate 
4150Sstevel@tonic-gate 	ASSERT(BT_TEST(&kaif_waptmap, hwid));
4160Sstevel@tonic-gate 
4170Sstevel@tonic-gate 	kaif_drreg.dr_addr[hwid] = 0;
4180Sstevel@tonic-gate 	kaif_drreg.dr_ctl &= ~(KREG_DRCTL_WP_MASK(hwid) |
4190Sstevel@tonic-gate 	    KREG_DRCTL_WPEN_MASK(hwid));
4200Sstevel@tonic-gate }
4210Sstevel@tonic-gate 
4220Sstevel@tonic-gate /*ARGSUSED*/
4230Sstevel@tonic-gate static int
4240Sstevel@tonic-gate kaif_wapt_match(kmdb_wapt_t *wp)
4250Sstevel@tonic-gate {
4260Sstevel@tonic-gate 	int hwid = KAIF_WPPRIV2ID(wp);
4270Sstevel@tonic-gate 	uint32_t mask = KREG_DRSTAT_WP_MASK(hwid);
4280Sstevel@tonic-gate 	int n = 0;
4290Sstevel@tonic-gate 	int i;
4300Sstevel@tonic-gate 
4310Sstevel@tonic-gate 	ASSERT(BT_TEST(&kaif_waptmap, hwid));
4320Sstevel@tonic-gate 
4330Sstevel@tonic-gate 	for (i = 0; i < kaif_ncpusave; i++)
4340Sstevel@tonic-gate 		n += (kaif_cpusave[i].krs_dr.dr_stat & mask) != 0;
4350Sstevel@tonic-gate 
4360Sstevel@tonic-gate 	return (n);
4370Sstevel@tonic-gate }
4380Sstevel@tonic-gate 
4390Sstevel@tonic-gate static int
4400Sstevel@tonic-gate kaif_step(void)
4410Sstevel@tonic-gate {
4420Sstevel@tonic-gate 	kreg_t pc, fl, oldfl, newfl, sp;
4430Sstevel@tonic-gate 	mdb_tgt_addr_t npc;
4440Sstevel@tonic-gate 	mdb_instr_t instr;
4450Sstevel@tonic-gate 	int emulated = 0, rchk = 0;
4460Sstevel@tonic-gate 	size_t pcoff = 0;
4470Sstevel@tonic-gate 
4480Sstevel@tonic-gate 	(void) kmdb_dpi_get_register("pc", &pc);
4490Sstevel@tonic-gate 
4500Sstevel@tonic-gate 	if ((npc = mdb_dis_nextins(mdb.m_disasm, mdb.m_target,
4510Sstevel@tonic-gate 	    MDB_TGT_AS_VIRT, pc)) == pc) {
4520Sstevel@tonic-gate 		warn("failed to decode instruction at %a for step\n", pc);
4530Sstevel@tonic-gate 		return (set_errno(EINVAL));
4540Sstevel@tonic-gate 	}
4550Sstevel@tonic-gate 
4560Sstevel@tonic-gate 	/*
4570Sstevel@tonic-gate 	 * Stepping behavior depends on the type of instruction.  It does not
4580Sstevel@tonic-gate 	 * depend on the presence of a REX prefix, as the action we take for a
4590Sstevel@tonic-gate 	 * given instruction doesn't currently vary for 32-bit instructions
4600Sstevel@tonic-gate 	 * versus their 64-bit counterparts.
4610Sstevel@tonic-gate 	 */
4620Sstevel@tonic-gate 	do {
4630Sstevel@tonic-gate 		if (mdb_tgt_vread(mdb.m_target, &instr, sizeof (mdb_instr_t),
4640Sstevel@tonic-gate 		    pc + pcoff) != sizeof (mdb_instr_t)) {
4650Sstevel@tonic-gate 			warn("failed to read at %p for step",
4660Sstevel@tonic-gate 			    (void *)(pc + pcoff));
4670Sstevel@tonic-gate 			return (-1);
4680Sstevel@tonic-gate 		}
4690Sstevel@tonic-gate 	} while (pcoff++, (instr >= M_REX_LO && instr <= M_REX_HI && !rchk++));
4700Sstevel@tonic-gate 
4710Sstevel@tonic-gate 	switch (instr) {
4720Sstevel@tonic-gate 	case M_IRET:
4730Sstevel@tonic-gate 		warn("iret cannot be stepped\n");
4740Sstevel@tonic-gate 		return (set_errno(EMDB_TGTNOTSUP));
4750Sstevel@tonic-gate 
4760Sstevel@tonic-gate 	case M_INT3:
4770Sstevel@tonic-gate 	case M_INTX:
4780Sstevel@tonic-gate 	case M_INTO:
4790Sstevel@tonic-gate 		warn("int cannot be stepped\n");
4800Sstevel@tonic-gate 		return (set_errno(EMDB_TGTNOTSUP));
4810Sstevel@tonic-gate 
4820Sstevel@tonic-gate 	case M_ESC:
4830Sstevel@tonic-gate 		if (mdb_tgt_vread(mdb.m_target, &instr, sizeof (mdb_instr_t),
4840Sstevel@tonic-gate 		    pc + pcoff) != sizeof (mdb_instr_t)) {
4850Sstevel@tonic-gate 			warn("failed to read at %p for step",
4860Sstevel@tonic-gate 			    (void *)(pc + pcoff));
4870Sstevel@tonic-gate 			return (-1);
4880Sstevel@tonic-gate 		}
4890Sstevel@tonic-gate 
4900Sstevel@tonic-gate 		switch (instr) {
4910Sstevel@tonic-gate 		case M_SYSRET:
4920Sstevel@tonic-gate 			warn("sysret cannot be stepped\n");
4930Sstevel@tonic-gate 			return (set_errno(EMDB_TGTNOTSUP));
4940Sstevel@tonic-gate 		case M_SYSEXIT:
4950Sstevel@tonic-gate 			warn("sysexit cannot be stepped\n");
4960Sstevel@tonic-gate 			return (set_errno(EMDB_TGTNOTSUP));
4970Sstevel@tonic-gate 		}
4980Sstevel@tonic-gate 		break;
4990Sstevel@tonic-gate 
5000Sstevel@tonic-gate 	/*
5010Sstevel@tonic-gate 	 * Some instructions need to be emulated.  We need to prevent direct
5020Sstevel@tonic-gate 	 * manipulations of EFLAGS, so we'll emulate cli, sti.  pushfl and
5030Sstevel@tonic-gate 	 * popfl also receive special handling, as they manipulate both EFLAGS
5040Sstevel@tonic-gate 	 * and %esp.
5050Sstevel@tonic-gate 	 */
5060Sstevel@tonic-gate 	case M_CLI:
5070Sstevel@tonic-gate 		(void) kmdb_dpi_get_register(FLAGS_REG_NAME, &fl);
5080Sstevel@tonic-gate 		fl &= ~KREG_EFLAGS_IF_MASK;
5090Sstevel@tonic-gate 		(void) kmdb_dpi_set_register(FLAGS_REG_NAME, fl);
5100Sstevel@tonic-gate 
5110Sstevel@tonic-gate 		emulated = 1;
5120Sstevel@tonic-gate 		break;
5130Sstevel@tonic-gate 
5140Sstevel@tonic-gate 	case M_STI:
5150Sstevel@tonic-gate 		(void) kmdb_dpi_get_register(FLAGS_REG_NAME, &fl);
5160Sstevel@tonic-gate 		fl |= (1 << KREG_EFLAGS_IF_SHIFT);
5170Sstevel@tonic-gate 		(void) kmdb_dpi_set_register(FLAGS_REG_NAME, fl);
5180Sstevel@tonic-gate 
5190Sstevel@tonic-gate 		emulated = 1;
5200Sstevel@tonic-gate 		break;
5210Sstevel@tonic-gate 
5220Sstevel@tonic-gate 	case M_POPF:
5230Sstevel@tonic-gate 		/*
5240Sstevel@tonic-gate 		 * popfl will restore a pushed EFLAGS from the stack, and could
5250Sstevel@tonic-gate 		 * in so doing cause IF to be turned on, if only for a a brief
5260Sstevel@tonic-gate 		 * period.  To avoid this, we'll secretly replace the stack's
5270Sstevel@tonic-gate 		 * EFLAGS with our decaffeinated brand.  We'll then manually
5280Sstevel@tonic-gate 		 * load our EFLAGS copy with the real verion after the step.
5290Sstevel@tonic-gate 		 */
5300Sstevel@tonic-gate 		(void) kmdb_dpi_get_register("sp", &sp);
5310Sstevel@tonic-gate 		(void) kmdb_dpi_get_register(FLAGS_REG_NAME, &fl);
5320Sstevel@tonic-gate 
5330Sstevel@tonic-gate 		if (mdb_tgt_vread(mdb.m_target, &newfl, sizeof (kreg_t),
5340Sstevel@tonic-gate 		    sp) != sizeof (kreg_t)) {
5350Sstevel@tonic-gate 			warn("failed to read " FLAGS_REG_NAME
5360Sstevel@tonic-gate 			    " at %p for popfl step\n", (void *)sp);
5370Sstevel@tonic-gate 			return (set_errno(EMDB_TGTNOTSUP)); /* XXX ? */
5380Sstevel@tonic-gate 		}
5390Sstevel@tonic-gate 
5400Sstevel@tonic-gate 		fl = (fl & ~KREG_EFLAGS_IF_MASK) | KREG_EFLAGS_TF_MASK;
5410Sstevel@tonic-gate 
5420Sstevel@tonic-gate 		if (mdb_tgt_vwrite(mdb.m_target, &fl, sizeof (kreg_t),
5430Sstevel@tonic-gate 		    sp) != sizeof (kreg_t)) {
5440Sstevel@tonic-gate 			warn("failed to update " FLAGS_REG_NAME
5450Sstevel@tonic-gate 			    " at %p for popfl step\n", (void *)sp);
5460Sstevel@tonic-gate 			return (set_errno(EMDB_TGTNOTSUP)); /* XXX ? */
5470Sstevel@tonic-gate 		}
5480Sstevel@tonic-gate 		break;
5490Sstevel@tonic-gate 	}
5500Sstevel@tonic-gate 
5510Sstevel@tonic-gate 	if (emulated) {
5520Sstevel@tonic-gate 		(void) kmdb_dpi_set_register("pc", npc);
5530Sstevel@tonic-gate 		return (0);
5540Sstevel@tonic-gate 	}
5550Sstevel@tonic-gate 
5560Sstevel@tonic-gate 	/* Do the step with IF off, and TF (step) on */
5570Sstevel@tonic-gate 	(void) kmdb_dpi_get_register(FLAGS_REG_NAME, &oldfl);
5580Sstevel@tonic-gate 	(void) kmdb_dpi_set_register(FLAGS_REG_NAME,
5590Sstevel@tonic-gate 	    ((oldfl | (1 << KREG_EFLAGS_TF_SHIFT)) & ~KREG_EFLAGS_IF_MASK));
5600Sstevel@tonic-gate 
5610Sstevel@tonic-gate 	kmdb_dpi_resume_master(); /* ... there and back again ... */
5620Sstevel@tonic-gate 
5630Sstevel@tonic-gate 	/* EFLAGS has now changed, and may require tuning */
5640Sstevel@tonic-gate 
5650Sstevel@tonic-gate 	switch (instr) {
5660Sstevel@tonic-gate 	case M_POPF:
5670Sstevel@tonic-gate 		/*
5680Sstevel@tonic-gate 		 * Use the EFLAGS we grabbed before the pop - see the pre-step
5690Sstevel@tonic-gate 		 * M_POPFL comment.
5700Sstevel@tonic-gate 		 */
5710Sstevel@tonic-gate 		(void) kmdb_dpi_set_register(FLAGS_REG_NAME, newfl);
5720Sstevel@tonic-gate 		return (0);
5730Sstevel@tonic-gate 
5740Sstevel@tonic-gate 	case M_PUSHF:
5750Sstevel@tonic-gate 		/*
5760Sstevel@tonic-gate 		 * We pushed our modified EFLAGS (with IF and TF turned off)
5770Sstevel@tonic-gate 		 * onto the stack.  Replace the pushed version with our
5780Sstevel@tonic-gate 		 * unmodified one.
5790Sstevel@tonic-gate 		 */
5800Sstevel@tonic-gate 		(void) kmdb_dpi_get_register("sp", &sp);
5810Sstevel@tonic-gate 
5820Sstevel@tonic-gate 		if (mdb_tgt_vwrite(mdb.m_target, &oldfl, sizeof (kreg_t),
5830Sstevel@tonic-gate 		    sp) != sizeof (kreg_t)) {
5840Sstevel@tonic-gate 			warn("failed to update pushed " FLAGS_REG_NAME
5850Sstevel@tonic-gate 			    " at %p after pushfl step\n", (void *)sp);
5860Sstevel@tonic-gate 			return (set_errno(EMDB_TGTNOTSUP)); /* XXX ? */
5870Sstevel@tonic-gate 		}
5880Sstevel@tonic-gate 
5890Sstevel@tonic-gate 		/* Go back to using the EFLAGS we were using before the step */
5900Sstevel@tonic-gate 		(void) kmdb_dpi_set_register(FLAGS_REG_NAME, oldfl);
5910Sstevel@tonic-gate 		return (0);
5920Sstevel@tonic-gate 
5930Sstevel@tonic-gate 	default:
5940Sstevel@tonic-gate 		/*
5950Sstevel@tonic-gate 		 * The stepped instruction may have altered EFLAGS.  We only
5960Sstevel@tonic-gate 		 * really care about the value of IF, and we know the stepped
5970Sstevel@tonic-gate 		 * instruction didn't alter it, so we can simply copy the
5980Sstevel@tonic-gate 		 * pre-step value.  We'll also need to turn TF back off.
5990Sstevel@tonic-gate 		 */
6000Sstevel@tonic-gate 		(void) kmdb_dpi_get_register(FLAGS_REG_NAME, &fl);
6010Sstevel@tonic-gate 		(void) kmdb_dpi_set_register(FLAGS_REG_NAME,
6020Sstevel@tonic-gate 		    ((fl & ~(KREG_EFLAGS_TF_MASK|KREG_EFLAGS_IF_MASK)) |
6030Sstevel@tonic-gate 		    (oldfl & KREG_EFLAGS_IF_MASK)));
6040Sstevel@tonic-gate 		return (0);
6050Sstevel@tonic-gate 	}
6060Sstevel@tonic-gate }
6070Sstevel@tonic-gate 
6080Sstevel@tonic-gate /*
6090Sstevel@tonic-gate  * The target has already configured the chip for branch step, leaving us to
6100Sstevel@tonic-gate  * actually make the machine go.  Due to a number of issues involving
6110Sstevel@tonic-gate  * the potential alteration of system state via instructions like sti, cli,
6120Sstevel@tonic-gate  * pushfl, and popfl, we're going to treat this like a normal system resume.
6130Sstevel@tonic-gate  * All CPUs will be released, on the kernel's IDT.  Our primary concern is
6140Sstevel@tonic-gate  * the alteration/storage of our TF'd EFLAGS via pushfl and popfl.  There's no
6150Sstevel@tonic-gate  * real workaround - we don't have opcode breakpoints - so the best we can do is
6160Sstevel@tonic-gate  * to ensure that the world won't end if someone does bad things to EFLAGS.
6170Sstevel@tonic-gate  *
6180Sstevel@tonic-gate  * Two things can happen:
6190Sstevel@tonic-gate  *  1. EFLAGS.TF may be cleared, either maliciously or via a popfl from saved
6200Sstevel@tonic-gate  *     state.  The CPU will continue execution beyond the branch, and will not
6210Sstevel@tonic-gate  *     reenter the debugger unless brought/sent in by other means.
6220Sstevel@tonic-gate  *  2. Someone may pushlf the TF'd EFLAGS, and may stash a copy of it somewhere.
6230Sstevel@tonic-gate  *     When the saved version is popfl'd back into place, the debugger will be
6240Sstevel@tonic-gate  *     re-entered on a single-step trap.
6250Sstevel@tonic-gate  */
6260Sstevel@tonic-gate static void
6270Sstevel@tonic-gate kaif_step_branch(void)
6280Sstevel@tonic-gate {
6290Sstevel@tonic-gate 	kreg_t fl;
6300Sstevel@tonic-gate 
6310Sstevel@tonic-gate 	(void) kmdb_dpi_get_register(FLAGS_REG_NAME, &fl);
6320Sstevel@tonic-gate 	(void) kmdb_dpi_set_register(FLAGS_REG_NAME,
6330Sstevel@tonic-gate 	    (fl | (1 << KREG_EFLAGS_TF_SHIFT)));
6340Sstevel@tonic-gate 
6350Sstevel@tonic-gate 	kmdb_dpi_resume_master();
6360Sstevel@tonic-gate 
6370Sstevel@tonic-gate 	(void) kmdb_dpi_set_register(FLAGS_REG_NAME, fl);
6380Sstevel@tonic-gate }
6390Sstevel@tonic-gate 
6400Sstevel@tonic-gate /*ARGSUSED*/
6410Sstevel@tonic-gate static uintptr_t
6420Sstevel@tonic-gate kaif_call(uintptr_t funcva, uint_t argc, const uintptr_t argv[])
6430Sstevel@tonic-gate {
6440Sstevel@tonic-gate 	return (kaif_invoke(funcva, argc, argv));
6450Sstevel@tonic-gate }
6460Sstevel@tonic-gate 
6470Sstevel@tonic-gate static void
648*1234Sjohnlev dump_crumb(kaif_crumb_t *krmp)
6490Sstevel@tonic-gate {
650*1234Sjohnlev 	kaif_crumb_t krm;
651*1234Sjohnlev 
652*1234Sjohnlev 	if (mdb_vread(&krm, sizeof (kaif_crumb_t), (uintptr_t)krmp) !=
653*1234Sjohnlev 	    sizeof (kaif_crumb_t)) {
654*1234Sjohnlev 		warn("failed to read crumb at %p", krmp);
655*1234Sjohnlev 		return;
656*1234Sjohnlev 	}
657*1234Sjohnlev 
6580Sstevel@tonic-gate 	mdb_printf("state: ");
659*1234Sjohnlev 	switch (krm.krm_cpu_state) {
6600Sstevel@tonic-gate 	case KAIF_CPU_STATE_MASTER:
6610Sstevel@tonic-gate 		mdb_printf("M");
6620Sstevel@tonic-gate 		break;
6630Sstevel@tonic-gate 	case KAIF_CPU_STATE_SLAVE:
6640Sstevel@tonic-gate 		mdb_printf("S");
6650Sstevel@tonic-gate 		break;
6660Sstevel@tonic-gate 	default:
667*1234Sjohnlev 		mdb_printf("%d", krm.krm_cpu_state);
6680Sstevel@tonic-gate 	}
6690Sstevel@tonic-gate 
6700Sstevel@tonic-gate 	mdb_printf(" trapno %3d sp %08x flag %d pc %p %A\n",
671*1234Sjohnlev 	    krm.krm_trapno, krm.krm_sp, krm.krm_flag, krm.krm_pc, krm.krm_pc);
6720Sstevel@tonic-gate }
6730Sstevel@tonic-gate 
6740Sstevel@tonic-gate static void
6750Sstevel@tonic-gate dump_crumbs(kaif_cpusave_t *save)
6760Sstevel@tonic-gate {
6770Sstevel@tonic-gate 	int i;
6780Sstevel@tonic-gate 
6790Sstevel@tonic-gate 	for (i = KAIF_NCRUMBS; i > 0; i--) {
6800Sstevel@tonic-gate 		uint_t idx = (save->krs_curcrumbidx + i) % KAIF_NCRUMBS;
6810Sstevel@tonic-gate 		dump_crumb(&save->krs_crumbs[idx]);
6820Sstevel@tonic-gate 	}
6830Sstevel@tonic-gate }
6840Sstevel@tonic-gate 
6850Sstevel@tonic-gate static void
6860Sstevel@tonic-gate kaif_dump_crumbs(uintptr_t addr, int cpuid)
6870Sstevel@tonic-gate {
6880Sstevel@tonic-gate 	int i;
6890Sstevel@tonic-gate 
6900Sstevel@tonic-gate 	if (addr != NULL) {
691*1234Sjohnlev 		/* dump_crumb will protect us against bogus addresses */
6920Sstevel@tonic-gate 		dump_crumb((kaif_crumb_t *)addr);
6930Sstevel@tonic-gate 
6940Sstevel@tonic-gate 	} else if (cpuid != -1) {
695*1234Sjohnlev 		if (cpuid < 0 || cpuid >= kaif_ncpusave)
6960Sstevel@tonic-gate 			return;
6970Sstevel@tonic-gate 
6980Sstevel@tonic-gate 		dump_crumbs(&kaif_cpusave[cpuid]);
6990Sstevel@tonic-gate 
7000Sstevel@tonic-gate 	} else {
7010Sstevel@tonic-gate 		for (i = 0; i < kaif_ncpusave; i++) {
7020Sstevel@tonic-gate 			kaif_cpusave_t *save = &kaif_cpusave[i];
7030Sstevel@tonic-gate 
7040Sstevel@tonic-gate 			if (save->krs_cpu_state == KAIF_CPU_STATE_NONE)
7050Sstevel@tonic-gate 				continue;
7060Sstevel@tonic-gate 
7070Sstevel@tonic-gate 			mdb_printf("%sCPU %d crumbs: (curidx %d)\n",
7080Sstevel@tonic-gate 			    (i == 0 ? "" : "\n"), i, save->krs_curcrumbidx);
7090Sstevel@tonic-gate 
7100Sstevel@tonic-gate 			dump_crumbs(save);
7110Sstevel@tonic-gate 		}
7120Sstevel@tonic-gate 	}
7130Sstevel@tonic-gate }
7140Sstevel@tonic-gate 
7150Sstevel@tonic-gate static void
7160Sstevel@tonic-gate kaif_modchg_register(void (*func)(struct modctl *, int))
7170Sstevel@tonic-gate {
7180Sstevel@tonic-gate 	kaif_modchg_cb = func;
7190Sstevel@tonic-gate }
7200Sstevel@tonic-gate 
7210Sstevel@tonic-gate static void
7220Sstevel@tonic-gate kaif_modchg_cancel(void)
7230Sstevel@tonic-gate {
7240Sstevel@tonic-gate 	ASSERT(kaif_modchg_cb != NULL);
7250Sstevel@tonic-gate 
7260Sstevel@tonic-gate 	kaif_modchg_cb = NULL;
7270Sstevel@tonic-gate }
7280Sstevel@tonic-gate 
7290Sstevel@tonic-gate void
7300Sstevel@tonic-gate kaif_mod_loaded(struct modctl *modp)
7310Sstevel@tonic-gate {
7320Sstevel@tonic-gate 	if (kaif_modchg_cb != NULL)
7330Sstevel@tonic-gate 		kaif_modchg_cb(modp, 1);
7340Sstevel@tonic-gate }
7350Sstevel@tonic-gate 
7360Sstevel@tonic-gate void
7370Sstevel@tonic-gate kaif_mod_unloading(struct modctl *modp)
7380Sstevel@tonic-gate {
7390Sstevel@tonic-gate 	if (kaif_modchg_cb != NULL)
7400Sstevel@tonic-gate 		kaif_modchg_cb(modp, 0);
7410Sstevel@tonic-gate }
7420Sstevel@tonic-gate 
7430Sstevel@tonic-gate /*
7440Sstevel@tonic-gate  * On some processors, we'll need to clear a certain MSR before proceeding into
7450Sstevel@tonic-gate  * the debugger.  Complicating matters, this MSR must be cleared before we take
7460Sstevel@tonic-gate  * any branches.  We have patch points in every trap handler, which will cover
7470Sstevel@tonic-gate  * all entry paths for master CPUs.  We also have a patch point in the slave
7480Sstevel@tonic-gate  * entry code.
7490Sstevel@tonic-gate  */
7500Sstevel@tonic-gate static void
7510Sstevel@tonic-gate kaif_msr_add_clrentry(uint_t msr)
7520Sstevel@tonic-gate {
7530Sstevel@tonic-gate #ifdef __amd64
7540Sstevel@tonic-gate 	uchar_t code[] = {
7550Sstevel@tonic-gate 		0x51, 0x50, 0x52,		/* pushq %rcx, %rax, %rdx */
7560Sstevel@tonic-gate 		0xb9, 0x00, 0x00, 0x00, 0x00,	/* movl $MSRNUM, %ecx */
7570Sstevel@tonic-gate 		0x31, 0xc0,			/* clr %eax */
7580Sstevel@tonic-gate 		0x31, 0xd2,			/* clr %edx */
7590Sstevel@tonic-gate 		0x0f, 0x30,			/* wrmsr */
7600Sstevel@tonic-gate 		0x5a, 0x58, 0x59		/* popq %rdx, %rax, %rcx */
7610Sstevel@tonic-gate 	};
7620Sstevel@tonic-gate 	uchar_t *patch = &code[4];
7630Sstevel@tonic-gate #else
7640Sstevel@tonic-gate 	uchar_t code[] = {
7650Sstevel@tonic-gate 		0x60,				/* pushal */
7660Sstevel@tonic-gate 		0xb9, 0x00, 0x00, 0x00, 0x00,	/* movl $MSRNUM, %ecx */
7670Sstevel@tonic-gate 		0x31, 0xc0,			/* clr %eax */
7680Sstevel@tonic-gate 		0x31, 0xd2,			/* clr %edx */
7690Sstevel@tonic-gate 		0x0f, 0x30,			/* wrmsr */
7700Sstevel@tonic-gate 		0x61				/* popal */
7710Sstevel@tonic-gate 	};
7720Sstevel@tonic-gate 	uchar_t *patch = &code[2];
7730Sstevel@tonic-gate #endif
7740Sstevel@tonic-gate 
7750Sstevel@tonic-gate 	bcopy(&msr, patch, sizeof (uint32_t));
7760Sstevel@tonic-gate 
7770Sstevel@tonic-gate 	kaif_idt_patch((caddr_t)code, sizeof (code));
7780Sstevel@tonic-gate 
7790Sstevel@tonic-gate 	bcopy(code, &kaif_slave_entry_patch, sizeof (code));
7800Sstevel@tonic-gate }
7810Sstevel@tonic-gate 
7820Sstevel@tonic-gate static void
7830Sstevel@tonic-gate kaif_msr_add_wrexit(uint_t msr, uint64_t *valp)
7840Sstevel@tonic-gate {
7850Sstevel@tonic-gate 	kaif_msr_wrexit_msr = msr;
7860Sstevel@tonic-gate 	kaif_msr_wrexit_valp = valp;
7870Sstevel@tonic-gate }
7880Sstevel@tonic-gate 
7890Sstevel@tonic-gate static void
7900Sstevel@tonic-gate kaif_msr_add(const kmdb_msr_t *msrs)
7910Sstevel@tonic-gate {
7920Sstevel@tonic-gate 	kmdb_msr_t *save;
7930Sstevel@tonic-gate 	int nmsrs, i;
7940Sstevel@tonic-gate 
7950Sstevel@tonic-gate 	ASSERT(kaif_cpusave[0].krs_msr == NULL);
7960Sstevel@tonic-gate 
7970Sstevel@tonic-gate 	for (i = 0; msrs[i].msr_num != 0; i++) {
7980Sstevel@tonic-gate 		switch (msrs[i].msr_type) {
7990Sstevel@tonic-gate 		case KMDB_MSR_CLEARENTRY:
8000Sstevel@tonic-gate 			kaif_msr_add_clrentry(msrs[i].msr_num);
8010Sstevel@tonic-gate 			break;
8020Sstevel@tonic-gate 
8030Sstevel@tonic-gate 		case KMDB_MSR_WRITEDELAY:
8040Sstevel@tonic-gate 			kaif_msr_add_wrexit(msrs[i].msr_num, msrs[i].msr_valp);
8050Sstevel@tonic-gate 			break;
8060Sstevel@tonic-gate 		}
8070Sstevel@tonic-gate 	}
8080Sstevel@tonic-gate 	nmsrs = i + 1; /* we want to copy the terminating kmdb_msr_t too */
8090Sstevel@tonic-gate 
8100Sstevel@tonic-gate 	save = mdb_zalloc(sizeof (kmdb_msr_t) * nmsrs * kaif_ncpusave,
8110Sstevel@tonic-gate 	    UM_SLEEP);
8120Sstevel@tonic-gate 
8130Sstevel@tonic-gate 	for (i = 0; i < kaif_ncpusave; i++) {
8140Sstevel@tonic-gate 		bcopy(msrs, &save[nmsrs * i], sizeof (kmdb_msr_t) * nmsrs);
8150Sstevel@tonic-gate 		kaif_cpusave[i].krs_msr = &save[nmsrs * i];
8160Sstevel@tonic-gate 	}
8170Sstevel@tonic-gate }
8180Sstevel@tonic-gate 
8190Sstevel@tonic-gate static uint64_t
8200Sstevel@tonic-gate kaif_msr_get(int cpuid, uint_t num)
8210Sstevel@tonic-gate {
822*1234Sjohnlev 	kaif_cpusave_t *save;
8230Sstevel@tonic-gate 	kmdb_msr_t *msr;
8240Sstevel@tonic-gate 	int i;
8250Sstevel@tonic-gate 
826*1234Sjohnlev 	if ((save = kaif_cpuid2save(cpuid)) == NULL)
827*1234Sjohnlev 		return (-1); /* errno is set for us */
828*1234Sjohnlev 
829*1234Sjohnlev 	msr = save->krs_msr;
8300Sstevel@tonic-gate 
8310Sstevel@tonic-gate 	for (i = 0; msr[i].msr_num != 0; i++) {
8320Sstevel@tonic-gate 		if (msr[i].msr_num == num &&
8330Sstevel@tonic-gate 		    (msr[i].msr_type & KMDB_MSR_READ))
8340Sstevel@tonic-gate 			return (msr[i].msr_val);
8350Sstevel@tonic-gate 	}
8360Sstevel@tonic-gate 
8370Sstevel@tonic-gate 	return (0);
8380Sstevel@tonic-gate }
8390Sstevel@tonic-gate 
8400Sstevel@tonic-gate int
8410Sstevel@tonic-gate kaif_memrange_add(caddr_t base, size_t len)
8420Sstevel@tonic-gate {
8430Sstevel@tonic-gate 	kaif_memrange_t *mr = &kaif_memranges[kaif_nmemranges];
8440Sstevel@tonic-gate 
8450Sstevel@tonic-gate 	if (kaif_nmemranges == KAIF_MEMRANGES_MAX)
8460Sstevel@tonic-gate 		return (set_errno(ENOSPC));
8470Sstevel@tonic-gate 
8480Sstevel@tonic-gate 	/*
8490Sstevel@tonic-gate 	 * In the unlikely event that someone is stepping through this routine,
8500Sstevel@tonic-gate 	 * we need to make sure that kaif_memranges knows about the new range
8510Sstevel@tonic-gate 	 * before umem gets it.  That way the entry code can recognize stacks
8520Sstevel@tonic-gate 	 * allocated from the new region.
8530Sstevel@tonic-gate 	 */
8540Sstevel@tonic-gate 	mr->mr_base = base;
8550Sstevel@tonic-gate 	mr->mr_lim = base + len - 1;
8560Sstevel@tonic-gate 	kaif_nmemranges++;
8570Sstevel@tonic-gate 
8580Sstevel@tonic-gate 	if (mdb_umem_add(base, len) < 0) {
8590Sstevel@tonic-gate 		kaif_nmemranges--;
8600Sstevel@tonic-gate 		return (-1); /* errno is set for us */
8610Sstevel@tonic-gate 	}
8620Sstevel@tonic-gate 
8630Sstevel@tonic-gate 	return (0);
8640Sstevel@tonic-gate }
8650Sstevel@tonic-gate 
8660Sstevel@tonic-gate void
8670Sstevel@tonic-gate kaif_trap_set_debugger(void)
8680Sstevel@tonic-gate {
8690Sstevel@tonic-gate 	set_idt(&kaif_idtr);
8700Sstevel@tonic-gate }
8710Sstevel@tonic-gate 
8720Sstevel@tonic-gate void
8730Sstevel@tonic-gate kaif_trap_set_saved(kaif_cpusave_t *cpusave)
8740Sstevel@tonic-gate {
8750Sstevel@tonic-gate 	set_idt(&cpusave->krs_idtr);
8760Sstevel@tonic-gate }
8770Sstevel@tonic-gate 
8780Sstevel@tonic-gate static int
8790Sstevel@tonic-gate kaif_init(kmdb_auxv_t *kav)
8800Sstevel@tonic-gate {
8810Sstevel@tonic-gate 	int i;
8820Sstevel@tonic-gate 
8830Sstevel@tonic-gate 	/* Allocate the per-CPU save areas */
8840Sstevel@tonic-gate 	kaif_cpusave = mdb_zalloc(sizeof (kaif_cpusave_t) * kav->kav_ncpu,
8850Sstevel@tonic-gate 	    UM_SLEEP);
8860Sstevel@tonic-gate 	kaif_ncpusave = kav->kav_ncpu;
8870Sstevel@tonic-gate 
8880Sstevel@tonic-gate 	for (i = 0; i < kaif_ncpusave; i++) {
889*1234Sjohnlev 		kaif_cpusave_t *save = &kaif_cpusave[i];
8900Sstevel@tonic-gate 
891*1234Sjohnlev 		save->krs_cpu_id = i;
892*1234Sjohnlev 		save->krs_curcrumbidx = KAIF_NCRUMBS - 1;
893*1234Sjohnlev 		save->krs_curcrumb = &save->krs_crumbs[save->krs_curcrumbidx];
8940Sstevel@tonic-gate 	}
8950Sstevel@tonic-gate 
8960Sstevel@tonic-gate 	kaif_idt_init();
8970Sstevel@tonic-gate 
8980Sstevel@tonic-gate 	/* The initial selector set.  Updated by the debugger-entry code */
8990Sstevel@tonic-gate #ifndef __amd64
9000Sstevel@tonic-gate 	kaif_cs = BOOTCODE_SEL;
9010Sstevel@tonic-gate 	kaif_ds = kaif_fs = kaif_gs = BOOTFLAT_SEL;
9020Sstevel@tonic-gate #endif
9030Sstevel@tonic-gate 
9040Sstevel@tonic-gate 	kaif_memranges[0].mr_base = kav->kav_dseg;
9050Sstevel@tonic-gate 	kaif_memranges[0].mr_lim = kav->kav_dseg + kav->kav_dseg_size - 1;
9060Sstevel@tonic-gate 	kaif_nmemranges = 1;
9070Sstevel@tonic-gate 
9080Sstevel@tonic-gate 	kaif_modchg_cb = NULL;
9090Sstevel@tonic-gate 
9100Sstevel@tonic-gate 	kaif_waptmap = 0;
9110Sstevel@tonic-gate 
9120Sstevel@tonic-gate 	kaif_drreg.dr_ctl = KREG_DRCTL_RESERVED;
9130Sstevel@tonic-gate 	kaif_drreg.dr_stat = KREG_DRSTAT_RESERVED;
9140Sstevel@tonic-gate 
9150Sstevel@tonic-gate 	kaif_msr_wrexit_msr = 0;
9160Sstevel@tonic-gate 	kaif_msr_wrexit_valp = NULL;
9170Sstevel@tonic-gate 
9180Sstevel@tonic-gate 	kaif_trap_switch = (kav->kav_flags & KMDB_AUXV_FL_NOTRPSWTCH) == 0;
9190Sstevel@tonic-gate 
9200Sstevel@tonic-gate 	if ((kaif_sys_sysenter = kmdb_kdi_lookup_by_name("unix",
9210Sstevel@tonic-gate 	    "sys_sysenter")) == NULL)
9220Sstevel@tonic-gate 		return (set_errno(ENOENT));
9230Sstevel@tonic-gate 
9240Sstevel@tonic-gate 	return (0);
9250Sstevel@tonic-gate }
9260Sstevel@tonic-gate 
9270Sstevel@tonic-gate dpi_ops_t kmdb_dpi_ops = {
9280Sstevel@tonic-gate 	kaif_init,
9290Sstevel@tonic-gate 	kaif_activate,
9300Sstevel@tonic-gate 	kaif_deactivate,
9310Sstevel@tonic-gate 	kaif_enter_mon,
9320Sstevel@tonic-gate 	kaif_modchg_register,
9330Sstevel@tonic-gate 	kaif_modchg_cancel,
9340Sstevel@tonic-gate 	kaif_get_cpu_state,
9350Sstevel@tonic-gate 	kaif_get_master_cpuid,
9360Sstevel@tonic-gate 	kaif_get_gregs,
937*1234Sjohnlev 	kaif_get_register,
938*1234Sjohnlev 	kaif_set_register,
9390Sstevel@tonic-gate 	kaif_brkpt_arm,
9400Sstevel@tonic-gate 	kaif_brkpt_disarm,
9410Sstevel@tonic-gate 	kaif_wapt_validate,
9420Sstevel@tonic-gate 	kaif_wapt_reserve,
9430Sstevel@tonic-gate 	kaif_wapt_release,
9440Sstevel@tonic-gate 	kaif_wapt_arm,
9450Sstevel@tonic-gate 	kaif_wapt_disarm,
9460Sstevel@tonic-gate 	kaif_wapt_match,
9470Sstevel@tonic-gate 	kaif_step,
9480Sstevel@tonic-gate 	kaif_step_branch,
9490Sstevel@tonic-gate 	kaif_call,
9500Sstevel@tonic-gate 	kaif_dump_crumbs,
9510Sstevel@tonic-gate 	kaif_memrange_add,
9520Sstevel@tonic-gate 	kaif_msr_add,
9530Sstevel@tonic-gate 	kaif_msr_get,
9540Sstevel@tonic-gate };
955