xref: /onnv-gate/usr/src/cmd/mdb/sparc/kmdb/kaif.c (revision 11583:24344dea001d)
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
52011Shyw  * Common Development and Distribution License (the "License").
62011Shyw  * You may not use this file except in compliance with the License.
70Sstevel@tonic-gate  *
80Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
90Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
100Sstevel@tonic-gate  * See the License for the specific language governing permissions
110Sstevel@tonic-gate  * and limitations under the License.
120Sstevel@tonic-gate  *
130Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
140Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
150Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
160Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
170Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
180Sstevel@tonic-gate  *
190Sstevel@tonic-gate  * CDDL HEADER END
200Sstevel@tonic-gate  */
21*11583SSurya.Prakki@Sun.COM 
220Sstevel@tonic-gate /*
23*11583SSurya.Prakki@Sun.COM  * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
240Sstevel@tonic-gate  * Use is subject to license terms.
250Sstevel@tonic-gate  */
260Sstevel@tonic-gate 
270Sstevel@tonic-gate /*
280Sstevel@tonic-gate  * The debugger/PROM interface
290Sstevel@tonic-gate  */
300Sstevel@tonic-gate 
310Sstevel@tonic-gate #include <sys/types.h>
320Sstevel@tonic-gate #include <sys/mmu.h>
330Sstevel@tonic-gate 
340Sstevel@tonic-gate #ifndef	sun4v
350Sstevel@tonic-gate #include <sys/spitregs.h>
360Sstevel@tonic-gate #endif	/* sun4v */
370Sstevel@tonic-gate 
380Sstevel@tonic-gate #include <sys/machasi.h>
390Sstevel@tonic-gate #include <sys/machtrap.h>
400Sstevel@tonic-gate #include <sys/trap.h>
410Sstevel@tonic-gate #include <sys/privregs.h>
420Sstevel@tonic-gate 
430Sstevel@tonic-gate #include <kmdb/kaif.h>
440Sstevel@tonic-gate #include <kmdb/kaif_regs.h>
450Sstevel@tonic-gate #include <kmdb/kmdb_asmutil.h>
460Sstevel@tonic-gate #include <kmdb/kmdb_kdi.h>
470Sstevel@tonic-gate #include <kmdb/kmdb_promif_isadep.h>
480Sstevel@tonic-gate #include <kmdb/kmdb_dpi_impl.h>
490Sstevel@tonic-gate #include <mdb/mdb_debug.h>
500Sstevel@tonic-gate #include <mdb/mdb_err.h>
510Sstevel@tonic-gate #include <mdb/mdb_modapi.h>
520Sstevel@tonic-gate #include <mdb/mdb_nv.h>
530Sstevel@tonic-gate #include <mdb/mdb_kreg_impl.h>
540Sstevel@tonic-gate #include <mdb/mdb_v9util.h>
550Sstevel@tonic-gate #include <mdb/mdb.h>
560Sstevel@tonic-gate 
570Sstevel@tonic-gate #define	KAIF_PREGNO_PSTATE	0x6		/* %pstate is priv reg 6 */
580Sstevel@tonic-gate #define	KAIF_BRKPT_INSTR	0x91d0207e	/* ta 0x7e */
590Sstevel@tonic-gate 
600Sstevel@tonic-gate 
610Sstevel@tonic-gate #define	OP(x)		((x) >> 30)
620Sstevel@tonic-gate #define	OP2(x)		(((x) >> 22) & 0x07)
630Sstevel@tonic-gate #define	OP3(x)		(((x) >> 19) & 0x3f)
640Sstevel@tonic-gate #define	COND(x)		(((x) >> 25) & 0x0f)
650Sstevel@tonic-gate #define	RD(x)		(((x) >> 25) & 0x1f)
660Sstevel@tonic-gate #define	RS1(x)		(((x) >> 14) & 0x1f)
670Sstevel@tonic-gate #define	RS2(x)		((x) & 0x1f)
680Sstevel@tonic-gate 
690Sstevel@tonic-gate #define	OP_BRANCH	0x0
700Sstevel@tonic-gate #define	OP_ARITH	0x2
710Sstevel@tonic-gate 
720Sstevel@tonic-gate #define	OP2_BPcc	0x1
730Sstevel@tonic-gate #define	OP2_Bicc	0x2
740Sstevel@tonic-gate #define	OP2_BPr		0x3
750Sstevel@tonic-gate #define	OP2_FBPfcc	0x5
760Sstevel@tonic-gate #define	OP2_FBfcc	0x6
770Sstevel@tonic-gate 
780Sstevel@tonic-gate #define	OP3_RDPR	0x2a
790Sstevel@tonic-gate #define	OP3_WRPR	0x32
800Sstevel@tonic-gate 
810Sstevel@tonic-gate #define	A(x)		(((x) >> 29) & 0x01)
820Sstevel@tonic-gate #define	I(x)		(((x) >> 13) & 0x01)
830Sstevel@tonic-gate #define	DISP16(x)	((((x) >> 6) & 0xc000) | ((x) & 0x3fff))
840Sstevel@tonic-gate #define	DISP22(x)	((x) & 0x3fffff)
850Sstevel@tonic-gate #define	DISP19(x)	((x) & 0x7ffff)
860Sstevel@tonic-gate #define	SIMM13(x)	((x) & 0x1fff)
870Sstevel@tonic-gate 
880Sstevel@tonic-gate static uint64_t		kaif_vwapt_addr;
890Sstevel@tonic-gate static uint64_t		kaif_pwapt_addr;
900Sstevel@tonic-gate 
910Sstevel@tonic-gate #ifndef	sun4v
920Sstevel@tonic-gate static uint64_t		kaif_lsuctl;
930Sstevel@tonic-gate #endif	/* sun4v */
940Sstevel@tonic-gate 
950Sstevel@tonic-gate kaif_cpusave_t		*kaif_cpusave;
960Sstevel@tonic-gate int			kaif_ncpusave;
970Sstevel@tonic-gate caddr_t			kaif_dseg;
980Sstevel@tonic-gate caddr_t			kaif_dseg_lim;
990Sstevel@tonic-gate caddr_t			kaif_tba;		/* table currently in use */
1000Sstevel@tonic-gate caddr_t			kaif_tba_obp;		/* obp's trap table */
1010Sstevel@tonic-gate caddr_t			kaif_tba_native;	/* our table; needs khat */
1020Sstevel@tonic-gate #ifdef	sun4v
1030Sstevel@tonic-gate caddr_t			kaif_tba_kernel;	/* kernel's trap table */
1040Sstevel@tonic-gate #endif	/* sun4v */
1050Sstevel@tonic-gate size_t			kaif_tba_native_sz;
1060Sstevel@tonic-gate int			*kaif_promexitarmp;
1070Sstevel@tonic-gate int			kaif_trap_switch;
1080Sstevel@tonic-gate 
1090Sstevel@tonic-gate void (*kaif_modchg_cb)(struct modctl *, int);
1100Sstevel@tonic-gate void (*kaif_ktrap_install)(int, void (*)(void));
1110Sstevel@tonic-gate void (*kaif_ktrap_restore)(void);
1120Sstevel@tonic-gate 
1130Sstevel@tonic-gate static int
kaif_get_master_cpuid(void)1140Sstevel@tonic-gate kaif_get_master_cpuid(void)
1150Sstevel@tonic-gate {
1160Sstevel@tonic-gate 	return (kaif_master_cpuid);
1170Sstevel@tonic-gate }
1180Sstevel@tonic-gate 
1190Sstevel@tonic-gate /*ARGSUSED*/
1200Sstevel@tonic-gate static int
kaif_get_nwin(int cpuid)1210Sstevel@tonic-gate kaif_get_nwin(int cpuid)
1220Sstevel@tonic-gate {
1230Sstevel@tonic-gate 	return (get_nwin());
1240Sstevel@tonic-gate }
1250Sstevel@tonic-gate 
1261234Sjohnlev static kaif_cpusave_t *
kaif_cpuid2save(int cpuid)1271234Sjohnlev kaif_cpuid2save(int cpuid)
1281234Sjohnlev {
1291234Sjohnlev 	kaif_cpusave_t *save;
1301234Sjohnlev 
1311234Sjohnlev 	if (cpuid == DPI_MASTER_CPUID)
1321234Sjohnlev 		return (&kaif_cpusave[kaif_master_cpuid]);
1331234Sjohnlev 
1341234Sjohnlev 	if (cpuid < 0 || cpuid >= kaif_ncpusave) {
1351234Sjohnlev 		(void) set_errno(EINVAL);
1361234Sjohnlev 		return (NULL);
1371234Sjohnlev 	}
1381234Sjohnlev 
1391234Sjohnlev 	save = &kaif_cpusave[cpuid];
1401234Sjohnlev 
1411234Sjohnlev 	if (save->krs_cpu_state != KAIF_CPU_STATE_MASTER &&
1421234Sjohnlev 	    save->krs_cpu_state != KAIF_CPU_STATE_SLAVE) {
1431234Sjohnlev 		(void) set_errno(EINVAL);
1441234Sjohnlev 		return (NULL);
1451234Sjohnlev 	}
1461234Sjohnlev 
1471234Sjohnlev 	return (save);
1481234Sjohnlev }
1491234Sjohnlev 
1500Sstevel@tonic-gate static int
kaif_get_cpu_state(int cpuid)1510Sstevel@tonic-gate kaif_get_cpu_state(int cpuid)
1520Sstevel@tonic-gate {
1531234Sjohnlev 	kaif_cpusave_t *save;
1540Sstevel@tonic-gate 
1551234Sjohnlev 	if ((save = kaif_cpuid2save(cpuid)) == NULL)
1561234Sjohnlev 		return (-1); /* errno is set for us */
1570Sstevel@tonic-gate 
1581234Sjohnlev 	switch (save->krs_cpu_state) {
1590Sstevel@tonic-gate 	case KAIF_CPU_STATE_MASTER:
1600Sstevel@tonic-gate 		return (DPI_CPU_STATE_MASTER);
1610Sstevel@tonic-gate 	case KAIF_CPU_STATE_SLAVE:
1620Sstevel@tonic-gate 		return (DPI_CPU_STATE_SLAVE);
1630Sstevel@tonic-gate 	default:
1640Sstevel@tonic-gate 		return (set_errno(EINVAL));
1650Sstevel@tonic-gate 	}
1660Sstevel@tonic-gate }
1670Sstevel@tonic-gate 
1680Sstevel@tonic-gate static const mdb_tgt_gregset_t *
kaif_get_gregs(int cpuid)1690Sstevel@tonic-gate kaif_get_gregs(int cpuid)
1700Sstevel@tonic-gate {
1711234Sjohnlev 	kaif_cpusave_t *save;
1720Sstevel@tonic-gate 	mdb_tgt_gregset_t *gregs;
1730Sstevel@tonic-gate 	int wp, i;
1740Sstevel@tonic-gate 
1751234Sjohnlev 	if ((save = kaif_cpuid2save(cpuid)) == NULL)
1761234Sjohnlev 		return (NULL); /* errno is set for us */
1770Sstevel@tonic-gate 
1781234Sjohnlev 	gregs = &save->krs_gregs;
1790Sstevel@tonic-gate 
1800Sstevel@tonic-gate 	/*
1810Sstevel@tonic-gate 	 * The DPI startup routine populates the register window portions of
1820Sstevel@tonic-gate 	 * the kaif_cpusave_t.  We copy the current set of ins, outs, and
1830Sstevel@tonic-gate 	 * locals to the gregs.  We also extract %pstate from %tstate.
1840Sstevel@tonic-gate 	 */
1850Sstevel@tonic-gate 	wp = gregs->kregs[KREG_CWP];
1860Sstevel@tonic-gate 	for (i = 0; i < 8; i++) {
1871234Sjohnlev 		gregs->kregs[KREG_L0 + i] = save->krs_rwins[wp].rw_local[i];
1881234Sjohnlev 		gregs->kregs[KREG_I0 + i] = save->krs_rwins[wp].rw_in[i];
1890Sstevel@tonic-gate 	}
1900Sstevel@tonic-gate 
1911234Sjohnlev 	gregs->kregs[KREG_PSTATE] = KREG_TSTATE_PSTATE(save->krs_tstate);
1920Sstevel@tonic-gate 
1930Sstevel@tonic-gate 	if (++wp == kaif_get_nwin(cpuid))
1940Sstevel@tonic-gate 		wp = 0;
1950Sstevel@tonic-gate 
1960Sstevel@tonic-gate 	for (i = 0; i < 8; i++)
1971234Sjohnlev 		gregs->kregs[KREG_O0 + i] = save->krs_rwins[wp].rw_in[i];
1980Sstevel@tonic-gate 
1990Sstevel@tonic-gate 	return (gregs);
2000Sstevel@tonic-gate }
2010Sstevel@tonic-gate 
2020Sstevel@tonic-gate static kreg_t *
kaif_find_regp(kaif_cpusave_t * save,const char * regname)2031234Sjohnlev kaif_find_regp(kaif_cpusave_t *save, const char *regname)
2040Sstevel@tonic-gate {
2050Sstevel@tonic-gate 	mdb_tgt_gregset_t *gregs;
2060Sstevel@tonic-gate 	int nwin, i;
2071234Sjohnlev 	int win;
2080Sstevel@tonic-gate 
2091234Sjohnlev 	nwin = kaif_get_nwin(DPI_MASTER_CPUID);
2100Sstevel@tonic-gate 
2111234Sjohnlev 	gregs = &save->krs_gregs;
2120Sstevel@tonic-gate 
2131234Sjohnlev 	win = gregs->kregs[KREG_CWP];
2140Sstevel@tonic-gate 
2150Sstevel@tonic-gate 	if (strcmp(regname, "sp") == 0)
2160Sstevel@tonic-gate 		regname = "o6";
2170Sstevel@tonic-gate 	else if (strcmp(regname, "fp") == 0)
2180Sstevel@tonic-gate 		regname = "i6";
2190Sstevel@tonic-gate 
2200Sstevel@tonic-gate 	if (strlen(regname) == 2 && regname[1] >= '0' && regname[1] <= '7') {
2210Sstevel@tonic-gate 		int idx = regname[1] - '0';
2220Sstevel@tonic-gate 
2230Sstevel@tonic-gate 		switch (regname[0]) {
2240Sstevel@tonic-gate 		case 'o':
2250Sstevel@tonic-gate 			if (++win == nwin)
2260Sstevel@tonic-gate 				win = 0;
2270Sstevel@tonic-gate 			/*FALLTHROUGH*/
2280Sstevel@tonic-gate 		case 'i':
2291234Sjohnlev 			return ((kreg_t *)&save->krs_rwins[win].rw_in[idx]);
2300Sstevel@tonic-gate 		case 'l':
2311234Sjohnlev 			return ((kreg_t *)&save->krs_rwins[win].rw_local[idx]);
2320Sstevel@tonic-gate 		}
2330Sstevel@tonic-gate 	}
2340Sstevel@tonic-gate 
2350Sstevel@tonic-gate 	for (i = 0; mdb_sparcv9_kregs[i].rd_name != NULL; i++) {
2360Sstevel@tonic-gate 		const mdb_tgt_regdesc_t *rd = &mdb_sparcv9_kregs[i];
2370Sstevel@tonic-gate 
2380Sstevel@tonic-gate 		if (strcmp(rd->rd_name, regname) == 0)
2390Sstevel@tonic-gate 			return (&gregs->kregs[rd->rd_num]);
2400Sstevel@tonic-gate 	}
2410Sstevel@tonic-gate 
2420Sstevel@tonic-gate 	(void) set_errno(ENOENT);
2430Sstevel@tonic-gate 	return (NULL);
2440Sstevel@tonic-gate }
2450Sstevel@tonic-gate 
2460Sstevel@tonic-gate static int
kaif_get_register(const char * regname,kreg_t * valp)2471234Sjohnlev kaif_get_register(const char *regname, kreg_t *valp)
2480Sstevel@tonic-gate {
2491234Sjohnlev 	kaif_cpusave_t *save;
2500Sstevel@tonic-gate 	kreg_t *regp;
2510Sstevel@tonic-gate 
2521234Sjohnlev 	save = kaif_cpuid2save(DPI_MASTER_CPUID);
2530Sstevel@tonic-gate 
2540Sstevel@tonic-gate 	if (strcmp(regname, "pstate") == 0) {
2551234Sjohnlev 		*valp = KREG_TSTATE_PSTATE(save->krs_tstate);
2560Sstevel@tonic-gate 		return (0);
2570Sstevel@tonic-gate 	}
2580Sstevel@tonic-gate 
2591234Sjohnlev 	if ((regp = kaif_find_regp(save, regname)) == NULL)
2600Sstevel@tonic-gate 		return (-1);
2610Sstevel@tonic-gate 
2620Sstevel@tonic-gate 	*valp = *regp;
2630Sstevel@tonic-gate 
2640Sstevel@tonic-gate 	return (0);
2650Sstevel@tonic-gate }
2660Sstevel@tonic-gate 
2670Sstevel@tonic-gate static int
kaif_set_register(const char * regname,kreg_t val)2681234Sjohnlev kaif_set_register(const char *regname, kreg_t val)
2690Sstevel@tonic-gate {
2701234Sjohnlev 	kaif_cpusave_t *save;
2710Sstevel@tonic-gate 	kreg_t *regp;
2720Sstevel@tonic-gate 
2731234Sjohnlev 	save = kaif_cpuid2save(DPI_MASTER_CPUID);
2740Sstevel@tonic-gate 
2750Sstevel@tonic-gate 	if (strcmp(regname, "g0") == 0) {
2760Sstevel@tonic-gate 		return (0);
2770Sstevel@tonic-gate 
2780Sstevel@tonic-gate 	} else if (strcmp(regname, "pstate") == 0) {
2791234Sjohnlev 		save->krs_tstate &= ~KREG_TSTATE_PSTATE_MASK;
2801234Sjohnlev 		save->krs_tstate |= (val & KREG_PSTATE_MASK) <<
2811234Sjohnlev 		    KREG_TSTATE_PSTATE_SHIFT;
2820Sstevel@tonic-gate 		return (0);
2830Sstevel@tonic-gate 	}
2840Sstevel@tonic-gate 
2851234Sjohnlev 	if ((regp = kaif_find_regp(save, regname)) == NULL)
2860Sstevel@tonic-gate 		return (-1);
2870Sstevel@tonic-gate 
2880Sstevel@tonic-gate 	*regp = val;
2890Sstevel@tonic-gate 
2900Sstevel@tonic-gate 	return (0);
2910Sstevel@tonic-gate }
2920Sstevel@tonic-gate 
2930Sstevel@tonic-gate static int
kaif_brkpt_arm(uintptr_t addr,mdb_instr_t * instrp)2940Sstevel@tonic-gate kaif_brkpt_arm(uintptr_t addr, mdb_instr_t *instrp)
2950Sstevel@tonic-gate {
2960Sstevel@tonic-gate 	mdb_instr_t bkpt = KAIF_BRKPT_INSTR;
2970Sstevel@tonic-gate 
2980Sstevel@tonic-gate 	if (mdb_tgt_vread(mdb.m_target, instrp, sizeof (mdb_instr_t), addr) !=
2990Sstevel@tonic-gate 	    sizeof (mdb_instr_t))
3000Sstevel@tonic-gate 		return (-1); /* errno is set for us */
3010Sstevel@tonic-gate 
3020Sstevel@tonic-gate 	if (mdb_tgt_vwrite(mdb.m_target, &bkpt, sizeof (mdb_instr_t), addr) !=
3030Sstevel@tonic-gate 	    sizeof (mdb_instr_t))
3040Sstevel@tonic-gate 		return (-1); /* errno is set for us */
3050Sstevel@tonic-gate 
3060Sstevel@tonic-gate 	return (0);
3070Sstevel@tonic-gate }
3080Sstevel@tonic-gate 
3090Sstevel@tonic-gate static int
kaif_brkpt_disarm(uintptr_t addr,mdb_instr_t instrp)3100Sstevel@tonic-gate kaif_brkpt_disarm(uintptr_t addr, mdb_instr_t instrp)
3110Sstevel@tonic-gate {
3120Sstevel@tonic-gate 	if (mdb_tgt_vwrite(mdb.m_target, &instrp, sizeof (mdb_instr_t), addr) !=
3130Sstevel@tonic-gate 	    sizeof (mdb_instr_t))
3140Sstevel@tonic-gate 		return (-1); /* errno is set for us */
3150Sstevel@tonic-gate 
3160Sstevel@tonic-gate 	return (0);
3170Sstevel@tonic-gate }
3180Sstevel@tonic-gate 
3190Sstevel@tonic-gate /*
3200Sstevel@tonic-gate  * Calculate the watchpoint mask byte (VM or PM, as appropriate).  A 1 bit in
3210Sstevel@tonic-gate  * the mask indicates that the corresponding byte in the watchpoint address
3220Sstevel@tonic-gate  * should be used for activation comparison.
3230Sstevel@tonic-gate  */
3240Sstevel@tonic-gate /*
3251234Sjohnlev  * Sun4v doesn't have watchpoint regs
3260Sstevel@tonic-gate  */
3270Sstevel@tonic-gate #ifndef	sun4v
3280Sstevel@tonic-gate static uchar_t
kaif_wapt_calc_mask(size_t len)3290Sstevel@tonic-gate kaif_wapt_calc_mask(size_t len)
3300Sstevel@tonic-gate {
3310Sstevel@tonic-gate 	int pow;
3320Sstevel@tonic-gate 
3330Sstevel@tonic-gate 	if (len == 8)
3340Sstevel@tonic-gate 		return (0xff);
3350Sstevel@tonic-gate 
336*11583SSurya.Prakki@Sun.COM 	for (pow = 0; len > 1; len /= 256, pow++)
337*11583SSurya.Prakki@Sun.COM 		;
3380Sstevel@tonic-gate 
3390Sstevel@tonic-gate 	return (~((1 << pow) - 1));
3400Sstevel@tonic-gate }
3410Sstevel@tonic-gate #endif
3420Sstevel@tonic-gate 
3430Sstevel@tonic-gate /*
3440Sstevel@tonic-gate  * UltraSPARC processors have one physical and one virtual watchpoint.  These
3450Sstevel@tonic-gate  * watchpoints are specified by setting the address in a register, and by
3460Sstevel@tonic-gate  * setting a selector byte in another register to determine which bytes of the
3470Sstevel@tonic-gate  * address are to be used for comparison.  For simplicity, we only support
3480Sstevel@tonic-gate  * selector byte values whose bit patterns match the regexp "1+0*".  Watchpoint
3490Sstevel@tonic-gate  * addresses must be 8-byte aligned on these chips, so a selector byte of 0xff
3500Sstevel@tonic-gate  * indicates an 8-byte watchpoint.  Successive valid sizes are powers of 256,
3510Sstevel@tonic-gate  * starting with 256.
3520Sstevel@tonic-gate  */
3530Sstevel@tonic-gate static int
kaif_wapt_validate(kmdb_wapt_t * wp)3540Sstevel@tonic-gate kaif_wapt_validate(kmdb_wapt_t *wp)
3550Sstevel@tonic-gate {
3560Sstevel@tonic-gate 	if (wp->wp_wflags & MDB_TGT_WA_X) {
3570Sstevel@tonic-gate 		warn("execute watchpoints are not supported on this "
3580Sstevel@tonic-gate 		    "platform\n");
3590Sstevel@tonic-gate 		return (set_errno(EMDB_TGTNOTSUP));
3600Sstevel@tonic-gate 	}
3610Sstevel@tonic-gate 
3620Sstevel@tonic-gate 	if (wp->wp_size % 0xff != 0 && wp->wp_size != 8) {
3630Sstevel@tonic-gate 		warn("watchpoint size must be 8 or a power of 256 bytes\n");
3640Sstevel@tonic-gate 		return (set_errno(EINVAL));
3650Sstevel@tonic-gate 	}
3660Sstevel@tonic-gate 
3670Sstevel@tonic-gate 	if (wp->wp_addr & (wp->wp_size - 1)) {
3680Sstevel@tonic-gate 		warn("%lu-byte watchpoints must be %lu-byte aligned\n",
3690Sstevel@tonic-gate 		    wp->wp_size, wp->wp_size);
3700Sstevel@tonic-gate 		return (set_errno(EINVAL));
3710Sstevel@tonic-gate 	}
3720Sstevel@tonic-gate 
3730Sstevel@tonic-gate 	if (wp->wp_type != DPI_WAPT_TYPE_PHYS &&
3740Sstevel@tonic-gate 	    wp->wp_type != DPI_WAPT_TYPE_VIRT) {
3750Sstevel@tonic-gate 		warn("requested watchpoint type not supported on this "
3760Sstevel@tonic-gate 		    "platform\n");
3770Sstevel@tonic-gate 		return (set_errno(EMDB_TGTHWNOTSUP));
3780Sstevel@tonic-gate 	}
3790Sstevel@tonic-gate 
3800Sstevel@tonic-gate 	return (0);
3810Sstevel@tonic-gate }
3820Sstevel@tonic-gate 
3830Sstevel@tonic-gate static int
kaif_wapt_reserve(kmdb_wapt_t * wp)3840Sstevel@tonic-gate kaif_wapt_reserve(kmdb_wapt_t *wp)
3850Sstevel@tonic-gate {
3860Sstevel@tonic-gate #ifdef	sun4v
3870Sstevel@tonic-gate #ifdef	lint
3880Sstevel@tonic-gate 	ASSERT(wp == (kmdb_wapt_t *)wp);
3890Sstevel@tonic-gate #endif	/* !lint */
3900Sstevel@tonic-gate 	/* Watchpoints not supported */
3910Sstevel@tonic-gate 	return (set_errno(EMDB_TGTHWNOTSUP));
3920Sstevel@tonic-gate #else
3930Sstevel@tonic-gate 	uint64_t *addrp;
3940Sstevel@tonic-gate 
3950Sstevel@tonic-gate 	if (wp->wp_type == DPI_WAPT_TYPE_PHYS)
3960Sstevel@tonic-gate 		addrp = &kaif_pwapt_addr;
3970Sstevel@tonic-gate 	else
3980Sstevel@tonic-gate 		addrp = &kaif_vwapt_addr;
3990Sstevel@tonic-gate 
4000Sstevel@tonic-gate 	if (*addrp != NULL)
4010Sstevel@tonic-gate 		return (set_errno(EMDB_WPTOOMANY));
4020Sstevel@tonic-gate 
4030Sstevel@tonic-gate 	*addrp = wp->wp_addr;
4040Sstevel@tonic-gate 
4050Sstevel@tonic-gate 	return (0);
4060Sstevel@tonic-gate #endif
4070Sstevel@tonic-gate }
4080Sstevel@tonic-gate 
4090Sstevel@tonic-gate static void
kaif_wapt_release(kmdb_wapt_t * wp)4100Sstevel@tonic-gate kaif_wapt_release(kmdb_wapt_t *wp)
4110Sstevel@tonic-gate {
4120Sstevel@tonic-gate 	uint64_t *addrp = (wp->wp_type == DPI_WAPT_TYPE_PHYS ?
4130Sstevel@tonic-gate 	    &kaif_pwapt_addr : &kaif_vwapt_addr);
4140Sstevel@tonic-gate 
4150Sstevel@tonic-gate 	ASSERT(*addrp != NULL);
4160Sstevel@tonic-gate 	*addrp = NULL;
4170Sstevel@tonic-gate }
4180Sstevel@tonic-gate 
4190Sstevel@tonic-gate /*ARGSUSED*/
4200Sstevel@tonic-gate static void
kaif_wapt_arm(kmdb_wapt_t * wp)4210Sstevel@tonic-gate kaif_wapt_arm(kmdb_wapt_t *wp)
4220Sstevel@tonic-gate {
4230Sstevel@tonic-gate 	/*
4241234Sjohnlev 	 * Sun4v doesn't have watch point regs
4250Sstevel@tonic-gate 	 */
4260Sstevel@tonic-gate #ifndef	sun4v
4270Sstevel@tonic-gate 	uint64_t mask = kaif_wapt_calc_mask(wp->wp_size);
4280Sstevel@tonic-gate 
4290Sstevel@tonic-gate 	if (wp->wp_type == DPI_WAPT_TYPE_PHYS) {
4300Sstevel@tonic-gate 		kaif_lsuctl &= ~KAIF_LSUCTL_PWAPT_MASK;
4310Sstevel@tonic-gate 
4320Sstevel@tonic-gate 		if (wp->wp_wflags & MDB_TGT_WA_R)
4330Sstevel@tonic-gate 			kaif_lsuctl |= LSU_PR;
4340Sstevel@tonic-gate 		if (wp->wp_wflags & MDB_TGT_WA_W)
4350Sstevel@tonic-gate 			kaif_lsuctl |= LSU_PW;
4360Sstevel@tonic-gate 		kaif_lsuctl |= ((mask << LSU_PM_SHIFT) & LSU_PM);
4370Sstevel@tonic-gate 
4380Sstevel@tonic-gate 	} else if (wp->wp_type == DPI_WAPT_TYPE_VIRT) {
4390Sstevel@tonic-gate 		kaif_lsuctl &= ~KAIF_LSUCTL_VWAPT_MASK;
4400Sstevel@tonic-gate 
4410Sstevel@tonic-gate 		if (wp->wp_wflags & MDB_TGT_WA_R)
4420Sstevel@tonic-gate 			kaif_lsuctl |= LSU_VR;
4430Sstevel@tonic-gate 		if (wp->wp_wflags & MDB_TGT_WA_W)
4440Sstevel@tonic-gate 			kaif_lsuctl |= LSU_VW;
4450Sstevel@tonic-gate 		kaif_lsuctl |= ((mask << LSU_VM_SHIFT) & LSU_VM);
4460Sstevel@tonic-gate 	}
4470Sstevel@tonic-gate #endif	/* sun4v */
4480Sstevel@tonic-gate }
4490Sstevel@tonic-gate 
4500Sstevel@tonic-gate /*ARGSUSED*/
4510Sstevel@tonic-gate static void
kaif_wapt_disarm(kmdb_wapt_t * wp)4520Sstevel@tonic-gate kaif_wapt_disarm(kmdb_wapt_t *wp)
4530Sstevel@tonic-gate {
4540Sstevel@tonic-gate 	/*
4551234Sjohnlev 	 * Sun4v doesn't have watch point regs
4560Sstevel@tonic-gate 	 */
4570Sstevel@tonic-gate #ifndef	sun4v
4580Sstevel@tonic-gate 	if (wp->wp_type == DPI_WAPT_TYPE_PHYS) {
4590Sstevel@tonic-gate 		ASSERT(kaif_pwapt_addr != NULL);
4600Sstevel@tonic-gate 		kaif_lsuctl &= ~(LSU_PR|LSU_PW);
4610Sstevel@tonic-gate 	} else {
4620Sstevel@tonic-gate 		ASSERT(kaif_vwapt_addr != NULL);
4630Sstevel@tonic-gate 		kaif_lsuctl &= ~(LSU_VR|LSU_VW);
4640Sstevel@tonic-gate 	}
4650Sstevel@tonic-gate #endif
4660Sstevel@tonic-gate }
4670Sstevel@tonic-gate 
4680Sstevel@tonic-gate /*
4690Sstevel@tonic-gate  * `kaif_wapt_arm' and `kaif_wapt_disarm' modify the global state we keep that
4700Sstevel@tonic-gate  * indicates what the values of the wapt control registers should be.  These
4710Sstevel@tonic-gate  * values must be individually set and cleared on each active CPU, a task which
4720Sstevel@tonic-gate  * is performed by `kaif_wapt_clear_regs' and `kaif_wapt_set_regs', invoked as
4730Sstevel@tonic-gate  * the world is stopped and resumed, respectively.  `kaif_wapt_set_regs' is also
4740Sstevel@tonic-gate  * used for CPU initialization.
4750Sstevel@tonic-gate  */
4760Sstevel@tonic-gate void
kaif_wapt_set_regs(void)4770Sstevel@tonic-gate kaif_wapt_set_regs(void)
4780Sstevel@tonic-gate {
4790Sstevel@tonic-gate 	/*
4801234Sjohnlev 	 * Sun4v doesn't have watch point regs
4810Sstevel@tonic-gate 	 */
4820Sstevel@tonic-gate #ifndef sun4v
4830Sstevel@tonic-gate 	uint64_t lsu;
4840Sstevel@tonic-gate 
4850Sstevel@tonic-gate 	wrasi(ASI_DMMU, MMU_VAW, kaif_vwapt_addr);
4860Sstevel@tonic-gate 	wrasi(ASI_DMMU, MMU_PAW, kaif_pwapt_addr);
4870Sstevel@tonic-gate 
4880Sstevel@tonic-gate 	ASSERT((kaif_lsuctl & ~KAIF_LSUCTL_WAPT_MASK) == NULL);
4890Sstevel@tonic-gate 
4900Sstevel@tonic-gate 	lsu = rdasi(ASI_LSU, NULL);
4910Sstevel@tonic-gate 	lsu &= ~KAIF_LSUCTL_WAPT_MASK;
4920Sstevel@tonic-gate 	lsu |= kaif_lsuctl;
4930Sstevel@tonic-gate 	wrasi(ASI_LSU, NULL, lsu);
4940Sstevel@tonic-gate #endif /* sun4v */
4950Sstevel@tonic-gate }
4960Sstevel@tonic-gate 
4970Sstevel@tonic-gate void
kaif_wapt_clear_regs(void)4980Sstevel@tonic-gate kaif_wapt_clear_regs(void)
4990Sstevel@tonic-gate {
5000Sstevel@tonic-gate 	/*
5011234Sjohnlev 	 * Sun4v doesn't have watch point regs
5020Sstevel@tonic-gate 	 */
5030Sstevel@tonic-gate #ifndef sun4v
5040Sstevel@tonic-gate 	uint64_t lsu = rdasi(ASI_LSU, NULL);
5050Sstevel@tonic-gate 	lsu &= ~KAIF_LSUCTL_WAPT_MASK;
5060Sstevel@tonic-gate 	wrasi(ASI_LSU, NULL, lsu);
5070Sstevel@tonic-gate #endif /* sun4v */
5080Sstevel@tonic-gate }
5090Sstevel@tonic-gate 
5100Sstevel@tonic-gate /*
5110Sstevel@tonic-gate  * UltraSPARC has one PA watchpoint and one VA watchpoint.  The trap we get will
5120Sstevel@tonic-gate  * tell us which one we hit, but it won't tell us where.  We could attempt to
5130Sstevel@tonic-gate  * dissect the instruction at %pc to see where it was reading from or writing
5140Sstevel@tonic-gate  * to, but that gets messy in a hurry.  We can, however, make a couple of
5150Sstevel@tonic-gate  * assumptions:
5160Sstevel@tonic-gate  *
5170Sstevel@tonic-gate  * - kaif_set_watchpoint and kaif_delete_watchpoint will enforce the limits as
5180Sstevel@tonic-gate  *   to the number of watch points.  As such, at most one VA watchpoint and one
5190Sstevel@tonic-gate  *   PA watchpoint will be on the active list.
5200Sstevel@tonic-gate  *
5210Sstevel@tonic-gate  * - We'll only be called on watchpoints that are on the active list.
5220Sstevel@tonic-gate  *
5230Sstevel@tonic-gate  * Taking these two assumptions, we can conclude that, if we're stopped due to
5240Sstevel@tonic-gate  * a watchpoint and we're asked to match against a watchpoint, we must have
5250Sstevel@tonic-gate  * stopped due to the watchpoint.  This is all very terrifying, but the
5260Sstevel@tonic-gate  * alternative (taking instructions apart) is worse.
5270Sstevel@tonic-gate  */
5280Sstevel@tonic-gate /*ARGSUSED*/
5290Sstevel@tonic-gate static int
kaif_wapt_match(kmdb_wapt_t * wp)5300Sstevel@tonic-gate kaif_wapt_match(kmdb_wapt_t *wp)
5310Sstevel@tonic-gate {
5320Sstevel@tonic-gate 	int state, why, deswhy;
5330Sstevel@tonic-gate 
5340Sstevel@tonic-gate 	state = kmdb_dpi_get_state(&why);
5350Sstevel@tonic-gate 
5360Sstevel@tonic-gate 	if (wp->wp_type == DPI_WAPT_TYPE_PHYS)
5370Sstevel@tonic-gate 		deswhy = DPI_STATE_WHY_P_WAPT;
5380Sstevel@tonic-gate 	else
5390Sstevel@tonic-gate 		deswhy = DPI_STATE_WHY_V_WAPT;
5400Sstevel@tonic-gate 
5410Sstevel@tonic-gate 	return (state == DPI_STATE_FAULTED && why == deswhy);
5420Sstevel@tonic-gate }
5430Sstevel@tonic-gate 
5440Sstevel@tonic-gate static const char *
regno2name(int idx)5450Sstevel@tonic-gate regno2name(int idx)
5460Sstevel@tonic-gate {
5470Sstevel@tonic-gate 	const mdb_tgt_regdesc_t *rd;
5480Sstevel@tonic-gate 
5490Sstevel@tonic-gate 	for (rd = mdb_sparcv9_kregs; rd->rd_name != NULL; rd++) {
5500Sstevel@tonic-gate 		if (idx == rd->rd_num)
5510Sstevel@tonic-gate 			return (rd->rd_name);
5520Sstevel@tonic-gate 	}
5530Sstevel@tonic-gate 
5540Sstevel@tonic-gate 	ASSERT(rd->rd_name != NULL);
5550Sstevel@tonic-gate 
5560Sstevel@tonic-gate 	return ("unknown");
5570Sstevel@tonic-gate }
5580Sstevel@tonic-gate 
5590Sstevel@tonic-gate /*
5600Sstevel@tonic-gate  * UltraSPARC doesn't support single-step natively, so we have to do it
5610Sstevel@tonic-gate  * ourselves, by placing breakpoints at the instruction after the current one.
5620Sstevel@tonic-gate  * Note that "after" will be %npc in the simple case, but can be one of
5630Sstevel@tonic-gate  * several places if %pc is a branch.
5640Sstevel@tonic-gate  *
5650Sstevel@tonic-gate  * If %pc is an unconditional annulled branch, we put a breakpoint at the branch
5660Sstevel@tonic-gate  * target.  If it is a conditional annulled branch, we put breakpoints at %pc +
5670Sstevel@tonic-gate  * 8 and the branch target.  For all other branches, %npc will be set correctly
5680Sstevel@tonic-gate  * as determined by the branch condition, and thus we can step through the
5690Sstevel@tonic-gate  * branch by putting a breakpoint at %npc.  If %pc contains a non-branch
5700Sstevel@tonic-gate  * instruction (with the exception of certain rdpr and wrpr instructions,
5710Sstevel@tonic-gate  * described more below), we step over it by placing a breakpoint at %npc.
5720Sstevel@tonic-gate  */
5730Sstevel@tonic-gate static int
kaif_step(void)5740Sstevel@tonic-gate kaif_step(void)
5750Sstevel@tonic-gate {
5760Sstevel@tonic-gate 	kreg_t pc, npc, brtgt, pstate, tt;
5770Sstevel@tonic-gate 	int bptgt = 0, bpnpc = 0, bppc8 = 0;
5780Sstevel@tonic-gate 	mdb_instr_t svtgt = 0, svnpc = 0, svpc8 = 0;
5790Sstevel@tonic-gate 	mdb_instr_t instr;
5800Sstevel@tonic-gate 	int ie, err;
5810Sstevel@tonic-gate 
5820Sstevel@tonic-gate 	(void) kmdb_dpi_get_register("pc", &pc);
5830Sstevel@tonic-gate 	(void) kmdb_dpi_get_register("npc", &npc);
5840Sstevel@tonic-gate 
5850Sstevel@tonic-gate 	if (mdb_tgt_vread(mdb.m_target, &instr, sizeof (instr), pc) !=
5860Sstevel@tonic-gate 	    sizeof (instr)) {
5870Sstevel@tonic-gate 		warn("failed to read %%pc at %p for step", (void *)pc);
5880Sstevel@tonic-gate 		return (-1);
5890Sstevel@tonic-gate 	}
5900Sstevel@tonic-gate 
5910Sstevel@tonic-gate 	/*
5920Sstevel@tonic-gate 	 * If the current instruction is a read or write of PSTATE we need
5930Sstevel@tonic-gate 	 * to emulate it because we've taken over management of PSTATE and
5940Sstevel@tonic-gate 	 * we need keep interrupts disabled. If it's a branch, we may need
5950Sstevel@tonic-gate 	 * to set two breakpoints -- one at the target and one at the
5960Sstevel@tonic-gate 	 * subsequent instruction.
5970Sstevel@tonic-gate 	 */
5980Sstevel@tonic-gate 	if (OP(instr) == OP_ARITH) {
5990Sstevel@tonic-gate 		if (OP3(instr) == OP3_RDPR &&
6000Sstevel@tonic-gate 		    RS1(instr) == KAIF_PREGNO_PSTATE) {
6010Sstevel@tonic-gate 			const char *tgtreg =
6020Sstevel@tonic-gate 			    mdb_sparcv9_kregs[RD(instr)].rd_name;
6030Sstevel@tonic-gate 			kreg_t pstate;
6040Sstevel@tonic-gate 
6050Sstevel@tonic-gate 			(void) kmdb_dpi_get_register("pstate", &pstate);
6060Sstevel@tonic-gate 			(void) kmdb_dpi_set_register(tgtreg, pstate);
6070Sstevel@tonic-gate 
6080Sstevel@tonic-gate 			(void) kmdb_dpi_set_register("pc", npc);
6090Sstevel@tonic-gate 			(void) kmdb_dpi_set_register("npc", npc + 4);
6100Sstevel@tonic-gate 			return (0);
6110Sstevel@tonic-gate 
6120Sstevel@tonic-gate 		} else if (OP3(instr) == OP3_WRPR &&
6130Sstevel@tonic-gate 		    RD(instr) == KAIF_PREGNO_PSTATE) {
6140Sstevel@tonic-gate 			kreg_t rs1, rs2, val;
6150Sstevel@tonic-gate 
6160Sstevel@tonic-gate 			(void) kmdb_dpi_get_register(regno2name(RS1(instr)),
6170Sstevel@tonic-gate 			    &rs1);
6180Sstevel@tonic-gate 
6190Sstevel@tonic-gate 			if (I(instr)) {
6200Sstevel@tonic-gate 				int imm = SIMM13(instr);
6210Sstevel@tonic-gate 				imm <<= 19;
6220Sstevel@tonic-gate 				imm >>= 19;
6230Sstevel@tonic-gate 				rs2 = imm;
6240Sstevel@tonic-gate 			} else {
6250Sstevel@tonic-gate 				(void) kmdb_dpi_get_register(
6260Sstevel@tonic-gate 				    regno2name(RS2(instr)), &rs2);
6270Sstevel@tonic-gate 			}
6280Sstevel@tonic-gate 
6290Sstevel@tonic-gate 			val = rs1 ^ rs2;
6300Sstevel@tonic-gate 
6310Sstevel@tonic-gate 			(void) kmdb_dpi_set_register("pstate", val);
6320Sstevel@tonic-gate 
6330Sstevel@tonic-gate 			(void) kmdb_dpi_set_register("pc", npc);
6340Sstevel@tonic-gate 			(void) kmdb_dpi_set_register("npc", npc + 4);
6350Sstevel@tonic-gate 			return (0);
6360Sstevel@tonic-gate 
6370Sstevel@tonic-gate 		}
6380Sstevel@tonic-gate 
6390Sstevel@tonic-gate 		bpnpc = 1;
6400Sstevel@tonic-gate 
6410Sstevel@tonic-gate 	} else if (OP(instr) == OP_BRANCH) {
6420Sstevel@tonic-gate 		int disp, cond, annul;
6430Sstevel@tonic-gate 
6440Sstevel@tonic-gate 		switch (OP2(instr)) {
6450Sstevel@tonic-gate 		case OP2_BPcc:
6460Sstevel@tonic-gate 		case OP2_FBPfcc:
6470Sstevel@tonic-gate 			cond = (COND(instr) != 8);
6480Sstevel@tonic-gate 
6490Sstevel@tonic-gate 			disp = DISP19(instr);
6500Sstevel@tonic-gate 			disp <<= 13;
6510Sstevel@tonic-gate 			disp >>= 11;
6520Sstevel@tonic-gate 			break;
6530Sstevel@tonic-gate 
6540Sstevel@tonic-gate 		case OP2_Bicc:
6550Sstevel@tonic-gate 		case OP2_FBfcc:
6560Sstevel@tonic-gate 			cond = (COND(instr) != 8);
6570Sstevel@tonic-gate 
6580Sstevel@tonic-gate 			disp = DISP22(instr);
6590Sstevel@tonic-gate 			disp <<= 10;
6600Sstevel@tonic-gate 			disp >>= 8;
6610Sstevel@tonic-gate 			break;
6620Sstevel@tonic-gate 
6630Sstevel@tonic-gate 		case OP2_BPr:
6640Sstevel@tonic-gate 			cond = 1;
6650Sstevel@tonic-gate 
6660Sstevel@tonic-gate 			disp = DISP16(instr);
6670Sstevel@tonic-gate 			disp <<= 16;
6680Sstevel@tonic-gate 			disp >>= 14;
6690Sstevel@tonic-gate 			break;
6700Sstevel@tonic-gate 
6710Sstevel@tonic-gate 		default:
6720Sstevel@tonic-gate 			bpnpc = 1;
6730Sstevel@tonic-gate 		}
6740Sstevel@tonic-gate 
6750Sstevel@tonic-gate 		if (!bpnpc) {
6760Sstevel@tonic-gate 			annul = A(instr);
6770Sstevel@tonic-gate 
6780Sstevel@tonic-gate 			if (!cond && annul) {
6790Sstevel@tonic-gate 				brtgt = pc + disp;
6800Sstevel@tonic-gate 				bptgt = 1;
6810Sstevel@tonic-gate 			} else {
6820Sstevel@tonic-gate 				bpnpc = 1;
6830Sstevel@tonic-gate 
6840Sstevel@tonic-gate 				if (cond && annul)
6850Sstevel@tonic-gate 					bppc8 = 1;
6860Sstevel@tonic-gate 			}
6870Sstevel@tonic-gate 		}
6880Sstevel@tonic-gate 
6890Sstevel@tonic-gate 	} else {
6900Sstevel@tonic-gate 		bpnpc = 1;
6910Sstevel@tonic-gate 	}
6920Sstevel@tonic-gate 
6930Sstevel@tonic-gate 	/*
6940Sstevel@tonic-gate 	 * Place the breakpoints and resume this CPU with IE off.  We'll come
6950Sstevel@tonic-gate 	 * back after having encountered either one of the breakpoints we placed
6960Sstevel@tonic-gate 	 * or a trap.
6970Sstevel@tonic-gate 	 */
6980Sstevel@tonic-gate 	err = 0;
6990Sstevel@tonic-gate 	if ((bpnpc && kaif_brkpt_arm(npc, &svnpc) != 0) ||
7000Sstevel@tonic-gate 	    (bppc8 && kaif_brkpt_arm(pc + 8, &svpc8) != 0) ||
7010Sstevel@tonic-gate 	    (bptgt && kaif_brkpt_arm(brtgt, &svtgt) != 0)) {
7020Sstevel@tonic-gate 		err = errno;
7030Sstevel@tonic-gate 		goto step_done;
7040Sstevel@tonic-gate 	}
7050Sstevel@tonic-gate 
7060Sstevel@tonic-gate 	(void) kmdb_dpi_get_register("pstate", &pstate);
7070Sstevel@tonic-gate 	ie = pstate & KREG_PSTATE_IE_MASK;
7080Sstevel@tonic-gate 	(void) kmdb_dpi_set_register("pstate", (pstate & ~KREG_PSTATE_IE_MASK));
7090Sstevel@tonic-gate 
7100Sstevel@tonic-gate 	kmdb_dpi_resume_master(); /* ... there and back again ... */
7110Sstevel@tonic-gate 
7120Sstevel@tonic-gate 	(void) kmdb_dpi_get_register("pstate", &pstate);
7130Sstevel@tonic-gate 	(void) kmdb_dpi_set_register("pstate",
7140Sstevel@tonic-gate 	    ((pstate & ~KREG_PSTATE_IE_MASK) | ie));
7150Sstevel@tonic-gate 
7160Sstevel@tonic-gate 	(void) kmdb_dpi_get_register("tt", &tt);
7170Sstevel@tonic-gate 
7180Sstevel@tonic-gate step_done:
7190Sstevel@tonic-gate 	if (svnpc)
7200Sstevel@tonic-gate 		(void) kaif_brkpt_disarm(npc, svnpc);
7210Sstevel@tonic-gate 	if (svpc8)
7220Sstevel@tonic-gate 		(void) kaif_brkpt_disarm(pc + 8, svpc8);
7230Sstevel@tonic-gate 	if (svtgt)
7240Sstevel@tonic-gate 		(void) kaif_brkpt_disarm(brtgt, svtgt);
7250Sstevel@tonic-gate 
7260Sstevel@tonic-gate 	return (err == 0 ? 0 : set_errno(err));
7270Sstevel@tonic-gate }
7280Sstevel@tonic-gate 
7290Sstevel@tonic-gate static uintptr_t
kaif_call(uintptr_t funcva,uint_t argc,const uintptr_t * argv)7300Sstevel@tonic-gate kaif_call(uintptr_t funcva, uint_t argc, const uintptr_t *argv)
7310Sstevel@tonic-gate {
7320Sstevel@tonic-gate 	kreg_t g6, g7;
7330Sstevel@tonic-gate 
7340Sstevel@tonic-gate 	(void) kmdb_dpi_get_register("g6", &g6);
7350Sstevel@tonic-gate 	(void) kmdb_dpi_get_register("g7", &g7);
7360Sstevel@tonic-gate 
7370Sstevel@tonic-gate 	return (kaif_invoke(funcva, argc, argv, g6, g7));
7380Sstevel@tonic-gate }
7390Sstevel@tonic-gate 
7400Sstevel@tonic-gate static const mdb_bitmask_t krm_flag_bits[] = {
7410Sstevel@tonic-gate 	{ "M_W",	KAIF_CRUMB_F_MAIN_OBPWAPT, KAIF_CRUMB_F_MAIN_OBPWAPT },
7420Sstevel@tonic-gate 	{ "M_PE",	KAIF_CRUMB_F_MAIN_OBPPENT, KAIF_CRUMB_F_MAIN_OBPPENT },
7430Sstevel@tonic-gate 	{ "M_NRM",	KAIF_CRUMB_F_MAIN_NORMAL, KAIF_CRUMB_F_MAIN_NORMAL },
7440Sstevel@tonic-gate 	{ "I_RE",	KAIF_CRUMB_F_IVEC_REENTER, KAIF_CRUMB_F_IVEC_REENTER },
7450Sstevel@tonic-gate 	{ "I_OBP", 	KAIF_CRUMB_F_IVEC_INOBP, KAIF_CRUMB_F_IVEC_INOBP },
7460Sstevel@tonic-gate 	{ "I_NRM",	KAIF_CRUMB_F_IVEC_NORMAL, KAIF_CRUMB_F_IVEC_NORMAL },
7470Sstevel@tonic-gate 	{ "O_NRM",	KAIF_CRUMB_F_OBP_NORMAL, KAIF_CRUMB_F_OBP_NORMAL },
7480Sstevel@tonic-gate 	{ "O_REVEC",	KAIF_CRUMB_F_OBP_REVECT, KAIF_CRUMB_F_OBP_REVECT },
7490Sstevel@tonic-gate 	{ NULL }
7500Sstevel@tonic-gate };
7510Sstevel@tonic-gate 
7520Sstevel@tonic-gate static void
dump_crumb(kaif_crumb_t * krmp)7531234Sjohnlev dump_crumb(kaif_crumb_t *krmp)
7540Sstevel@tonic-gate {
7551234Sjohnlev 	kaif_crumb_t krm;
7561234Sjohnlev 
7571234Sjohnlev 	if (mdb_vread(&krm, sizeof (kaif_crumb_t), (uintptr_t)krmp) !=
7581234Sjohnlev 	    sizeof (kaif_crumb_t)) {
7591234Sjohnlev 		warn("failed to read crumb at %p", krmp);
7601234Sjohnlev 		return;
7611234Sjohnlev 	}
7621234Sjohnlev 
7630Sstevel@tonic-gate 	mdb_printf(" src: ");
7641234Sjohnlev 	switch (krm.krm_src) {
7650Sstevel@tonic-gate 	case KAIF_CRUMB_SRC_OBP:
7660Sstevel@tonic-gate 		mdb_printf("O");
7670Sstevel@tonic-gate 		break;
7680Sstevel@tonic-gate 	case KAIF_CRUMB_SRC_IVEC:
7690Sstevel@tonic-gate 		mdb_printf("I");
7700Sstevel@tonic-gate 		break;
7710Sstevel@tonic-gate 	case KAIF_CRUMB_SRC_MAIN:
7720Sstevel@tonic-gate 		mdb_printf("M");
7730Sstevel@tonic-gate 		break;
7740Sstevel@tonic-gate 	case 0:
7750Sstevel@tonic-gate 		mdb_printf("-");
7760Sstevel@tonic-gate 		break;
7770Sstevel@tonic-gate 	default:
7781234Sjohnlev 		mdb_printf("%d", krm.krm_src);
7790Sstevel@tonic-gate 	}
7800Sstevel@tonic-gate 
7810Sstevel@tonic-gate 	mdb_printf(" tt %3x pc %8p %-20A <%b>\n",
7821234Sjohnlev 	    krm.krm_tt, krm.krm_pc, krm.krm_pc, krm.krm_flag, krm_flag_bits);
7830Sstevel@tonic-gate }
7840Sstevel@tonic-gate 
7850Sstevel@tonic-gate static void
dump_crumbs(kaif_cpusave_t * save)7860Sstevel@tonic-gate dump_crumbs(kaif_cpusave_t *save)
7870Sstevel@tonic-gate {
7880Sstevel@tonic-gate 	int i;
7890Sstevel@tonic-gate 
7900Sstevel@tonic-gate 	for (i = KAIF_NCRUMBS; i > 0; i--) {
7910Sstevel@tonic-gate 		uint_t idx = (save->krs_curcrumbidx + i) % KAIF_NCRUMBS;
7920Sstevel@tonic-gate 		dump_crumb(&save->krs_crumbs[idx]);
7930Sstevel@tonic-gate 	}
7940Sstevel@tonic-gate }
7950Sstevel@tonic-gate 
7960Sstevel@tonic-gate static void
kaif_dump_crumbs(uintptr_t addr,int cpuid)7970Sstevel@tonic-gate kaif_dump_crumbs(uintptr_t addr, int cpuid)
7980Sstevel@tonic-gate {
7990Sstevel@tonic-gate 	int i;
8000Sstevel@tonic-gate 
8010Sstevel@tonic-gate 	if (addr != NULL) {
8021234Sjohnlev 		/* dump_crumb will protect us from bogus addresses */
8030Sstevel@tonic-gate 		dump_crumb((kaif_crumb_t *)addr);
8040Sstevel@tonic-gate 
8050Sstevel@tonic-gate 	} else if (cpuid != -1) {
8060Sstevel@tonic-gate 		if (cpuid >= kaif_ncpusave)
8070Sstevel@tonic-gate 			return;
8080Sstevel@tonic-gate 
8090Sstevel@tonic-gate 		dump_crumbs(&kaif_cpusave[cpuid]);
8100Sstevel@tonic-gate 
8110Sstevel@tonic-gate 	} else {
8120Sstevel@tonic-gate 		for (i = 0; i < kaif_ncpusave; i++) {
8130Sstevel@tonic-gate 			kaif_cpusave_t *save = &kaif_cpusave[i];
8140Sstevel@tonic-gate 
8150Sstevel@tonic-gate 			if (save->krs_cpu_state == KAIF_CPU_STATE_NONE)
8160Sstevel@tonic-gate 				continue;
8170Sstevel@tonic-gate 
8180Sstevel@tonic-gate 			mdb_printf("%sCPU %d crumbs: (curidx %d)\n",
8190Sstevel@tonic-gate 			    (i == 0 ? "" : "\n"), i, save->krs_curcrumbidx);
8200Sstevel@tonic-gate 
8210Sstevel@tonic-gate 			dump_crumbs(save);
8220Sstevel@tonic-gate 		}
8230Sstevel@tonic-gate 	}
8240Sstevel@tonic-gate }
8250Sstevel@tonic-gate 
8260Sstevel@tonic-gate static int
kaif_get_rwin(int cpuid,int win,struct rwindow * rwin)8270Sstevel@tonic-gate kaif_get_rwin(int cpuid, int win, struct rwindow *rwin)
8280Sstevel@tonic-gate {
8291234Sjohnlev 	kaif_cpusave_t *save;
8301234Sjohnlev 
8311234Sjohnlev 	if ((save = kaif_cpuid2save(cpuid)) == NULL)
8321234Sjohnlev 		return (-1); /* errno is set for us */
8330Sstevel@tonic-gate 
8340Sstevel@tonic-gate 	if (win < 0 || win >= kaif_get_nwin(cpuid))
8350Sstevel@tonic-gate 		return (-1);
8360Sstevel@tonic-gate 
8371234Sjohnlev 	bcopy(&save->krs_rwins[win], rwin, sizeof (struct rwindow));
8380Sstevel@tonic-gate 
8390Sstevel@tonic-gate 	return (0);
8400Sstevel@tonic-gate }
8410Sstevel@tonic-gate 
8420Sstevel@tonic-gate static void
kaif_enter_mon(void)8430Sstevel@tonic-gate kaif_enter_mon(void)
8440Sstevel@tonic-gate {
8450Sstevel@tonic-gate 	kmdb_prom_enter_mon();
8460Sstevel@tonic-gate 	kaif_prom_rearm();
8472011Shyw 	kaif_slave_loop_barrier();
8480Sstevel@tonic-gate }
8490Sstevel@tonic-gate 
8500Sstevel@tonic-gate static void
kaif_modchg_register(void (* func)(struct modctl *,int))8510Sstevel@tonic-gate kaif_modchg_register(void (*func)(struct modctl *, int))
8520Sstevel@tonic-gate {
8530Sstevel@tonic-gate 	kaif_modchg_cb = func;
8540Sstevel@tonic-gate }
8550Sstevel@tonic-gate 
8560Sstevel@tonic-gate static void
kaif_modchg_cancel(void)8570Sstevel@tonic-gate kaif_modchg_cancel(void)
8580Sstevel@tonic-gate {
8590Sstevel@tonic-gate 	ASSERT(kaif_modchg_cb != NULL);
8600Sstevel@tonic-gate 
8610Sstevel@tonic-gate 	kaif_modchg_cb = NULL;
8620Sstevel@tonic-gate }
8630Sstevel@tonic-gate 
8640Sstevel@tonic-gate void
kaif_mod_loaded(struct modctl * modp)8650Sstevel@tonic-gate kaif_mod_loaded(struct modctl *modp)
8660Sstevel@tonic-gate {
8670Sstevel@tonic-gate 	if (kaif_modchg_cb != NULL)
8680Sstevel@tonic-gate 		kaif_modchg_cb(modp, 1);
8690Sstevel@tonic-gate }
8700Sstevel@tonic-gate 
8710Sstevel@tonic-gate void
kaif_mod_unloading(struct modctl * modp)8720Sstevel@tonic-gate kaif_mod_unloading(struct modctl *modp)
8730Sstevel@tonic-gate {
8740Sstevel@tonic-gate 	if (kaif_modchg_cb != NULL)
8750Sstevel@tonic-gate 		kaif_modchg_cb(modp, 0);
8760Sstevel@tonic-gate }
8770Sstevel@tonic-gate 
8780Sstevel@tonic-gate void
kaif_trap_set_debugger(void)8790Sstevel@tonic-gate kaif_trap_set_debugger(void)
8800Sstevel@tonic-gate {
881*11583SSurya.Prakki@Sun.COM 	(void) set_tba((void *)kaif_tba);
8820Sstevel@tonic-gate }
8830Sstevel@tonic-gate 
8840Sstevel@tonic-gate void
kaif_trap_set_saved(kaif_cpusave_t * save)8851234Sjohnlev kaif_trap_set_saved(kaif_cpusave_t *save)
8860Sstevel@tonic-gate {
887*11583SSurya.Prakki@Sun.COM 	(void) set_tba((void *)save->krs_gregs.kregs[KREG_TBA]);
8880Sstevel@tonic-gate }
8890Sstevel@tonic-gate 
8900Sstevel@tonic-gate static void
kaif_kernpanic(int cpuid)8910Sstevel@tonic-gate kaif_kernpanic(int cpuid)
8920Sstevel@tonic-gate {
8930Sstevel@tonic-gate 	struct regs regs;
8940Sstevel@tonic-gate 
8950Sstevel@tonic-gate 	/*
8960Sstevel@tonic-gate 	 * We're going to try to panic the system by using the same entry point
8970Sstevel@tonic-gate 	 * used by the PROM when told to `sync'.  The kernel wants a
8980Sstevel@tonic-gate 	 * fully-populated struct regs, which we're going to build using the
8990Sstevel@tonic-gate 	 * state captured at the time of the debugger fault.  Said state lives
9000Sstevel@tonic-gate 	 * in kaif_cb_save, since we haven't yet copied it over to the cpusave
9010Sstevel@tonic-gate 	 * structure for the current master.
9020Sstevel@tonic-gate 	 */
9030Sstevel@tonic-gate 
9040Sstevel@tonic-gate 	regs.r_tstate = kaif_cb_save.krs_tstate;
9050Sstevel@tonic-gate 
9060Sstevel@tonic-gate 	regs.r_g1 = kaif_cb_save.krs_gregs.kregs[KREG_G1];
9070Sstevel@tonic-gate 	regs.r_g2 = kaif_cb_save.krs_gregs.kregs[KREG_G2];
9080Sstevel@tonic-gate 	regs.r_g3 = kaif_cb_save.krs_gregs.kregs[KREG_G3];
9090Sstevel@tonic-gate 	regs.r_g4 = kaif_cb_save.krs_gregs.kregs[KREG_G4];
9100Sstevel@tonic-gate 	regs.r_g5 = kaif_cb_save.krs_gregs.kregs[KREG_G5];
9110Sstevel@tonic-gate 	regs.r_g6 = kaif_cb_save.krs_gregs.kregs[KREG_G6];
9120Sstevel@tonic-gate 	regs.r_g7 = kaif_cb_save.krs_gregs.kregs[KREG_G7];
9130Sstevel@tonic-gate 
9140Sstevel@tonic-gate 	regs.r_o0 = kaif_cb_save.krs_gregs.kregs[KREG_O0];
9150Sstevel@tonic-gate 	regs.r_o1 = kaif_cb_save.krs_gregs.kregs[KREG_O1];
9160Sstevel@tonic-gate 	regs.r_o2 = kaif_cb_save.krs_gregs.kregs[KREG_O2];
9170Sstevel@tonic-gate 	regs.r_o3 = kaif_cb_save.krs_gregs.kregs[KREG_O3];
9180Sstevel@tonic-gate 	regs.r_o4 = kaif_cb_save.krs_gregs.kregs[KREG_O4];
9190Sstevel@tonic-gate 	regs.r_o5 = kaif_cb_save.krs_gregs.kregs[KREG_O5];
9200Sstevel@tonic-gate 	regs.r_o6 = kaif_cb_save.krs_gregs.kregs[KREG_O6];
9210Sstevel@tonic-gate 	regs.r_o7 = kaif_cb_save.krs_gregs.kregs[KREG_O7];
9220Sstevel@tonic-gate 
9230Sstevel@tonic-gate 	regs.r_pc = kaif_cb_save.krs_gregs.kregs[KREG_PC];
9240Sstevel@tonic-gate 	regs.r_npc = kaif_cb_save.krs_gregs.kregs[KREG_NPC];
9250Sstevel@tonic-gate 	regs.r_y = kaif_cb_save.krs_gregs.kregs[KREG_Y];
9260Sstevel@tonic-gate 
9270Sstevel@tonic-gate 	/*
9280Sstevel@tonic-gate 	 * The %tba is, as ever, different.  We don't want the %tba from the
9290Sstevel@tonic-gate 	 * time of the fault -- that'll be the debugger's.  We want the %tba
9300Sstevel@tonic-gate 	 * saved when the debugger was initially entered.  It'll be saved in
9310Sstevel@tonic-gate 	 * the cpusave area for the current CPU.
9320Sstevel@tonic-gate 	 */
933*11583SSurya.Prakki@Sun.COM 	(void) set_tba((void *)kaif_cpusave[cpuid].krs_gregs.kregs[KREG_TBA]);
9340Sstevel@tonic-gate 
9350Sstevel@tonic-gate 	kmdb_kdi_kernpanic(&regs, kaif_cb_save.krs_gregs.kregs[KREG_TT]);
9360Sstevel@tonic-gate }
9370Sstevel@tonic-gate 
9380Sstevel@tonic-gate static int
kaif_init(kmdb_auxv_t * kav)9390Sstevel@tonic-gate kaif_init(kmdb_auxv_t *kav)
9400Sstevel@tonic-gate {
9410Sstevel@tonic-gate 	struct rwindow *rwins;
9420Sstevel@tonic-gate 	int nwin = get_nwin();
9430Sstevel@tonic-gate 	int i;
9440Sstevel@tonic-gate 
9450Sstevel@tonic-gate 	kaif_vwapt_addr = kaif_pwapt_addr = 0;
9460Sstevel@tonic-gate 
9470Sstevel@tonic-gate 	kaif_tba = kav->kav_tba_active;
9480Sstevel@tonic-gate 	kaif_tba_obp = kav->kav_tba_obp;
9490Sstevel@tonic-gate 	kaif_tba_native = kav->kav_tba_native;
9500Sstevel@tonic-gate 	kaif_tba_native_sz = kav->kav_tba_native_sz;
9510Sstevel@tonic-gate #ifdef	sun4v
9520Sstevel@tonic-gate 	kaif_tba_kernel = kav->kav_tba_kernel;
9530Sstevel@tonic-gate #endif
9540Sstevel@tonic-gate 
9550Sstevel@tonic-gate 	/* Allocate the per-CPU save areas */
9560Sstevel@tonic-gate 	kaif_cpusave = mdb_zalloc(sizeof (kaif_cpusave_t) * kav->kav_ncpu,
9570Sstevel@tonic-gate 	    UM_SLEEP);
9580Sstevel@tonic-gate 	kaif_ncpusave = kav->kav_ncpu;
9590Sstevel@tonic-gate 
9600Sstevel@tonic-gate 	rwins = mdb_zalloc(sizeof (struct rwindow) * nwin * kav->kav_ncpu,
9610Sstevel@tonic-gate 	    UM_SLEEP);
9620Sstevel@tonic-gate 
9630Sstevel@tonic-gate 	for (i = 0; i < kaif_ncpusave; i++) {
9641234Sjohnlev 		kaif_cpusave_t *save = &kaif_cpusave[i];
9650Sstevel@tonic-gate 
9661234Sjohnlev 		save->krs_cpu_id = i;
9671234Sjohnlev 		save->krs_rwins = &rwins[nwin * i];
9681234Sjohnlev 		save->krs_curcrumbidx = KAIF_NCRUMBS - 1;
9691234Sjohnlev 		save->krs_curcrumb = &save->krs_crumbs[save->krs_curcrumbidx];
9700Sstevel@tonic-gate 	}
9710Sstevel@tonic-gate 
9720Sstevel@tonic-gate 	kaif_dseg = kav->kav_dseg;
9730Sstevel@tonic-gate 	kaif_dseg_lim = kav->kav_dseg + kav->kav_dseg_size;
9740Sstevel@tonic-gate 
9750Sstevel@tonic-gate 	kaif_promexitarmp = kav->kav_promexitarmp;
9760Sstevel@tonic-gate 
9770Sstevel@tonic-gate 	kaif_ktrap_install = kav->kav_ktrap_install;
9780Sstevel@tonic-gate 	kaif_ktrap_restore = kav->kav_ktrap_restore;
9790Sstevel@tonic-gate 
9800Sstevel@tonic-gate 	kaif_modchg_cb = NULL;
9810Sstevel@tonic-gate 
9820Sstevel@tonic-gate 	kaif_trap_switch = (kav->kav_flags & KMDB_AUXV_FL_NOTRPSWTCH) == 0;
9830Sstevel@tonic-gate 
9840Sstevel@tonic-gate 	return (0);
9850Sstevel@tonic-gate }
9860Sstevel@tonic-gate 
9870Sstevel@tonic-gate dpi_ops_t kmdb_dpi_ops = {
9880Sstevel@tonic-gate 	kaif_init,
9890Sstevel@tonic-gate 	kaif_activate,
9900Sstevel@tonic-gate 	kaif_deactivate,
9910Sstevel@tonic-gate 	kaif_enter_mon,
9920Sstevel@tonic-gate 	kaif_modchg_register,
9930Sstevel@tonic-gate 	kaif_modchg_cancel,
9940Sstevel@tonic-gate 	kaif_get_cpu_state,
9950Sstevel@tonic-gate 	kaif_get_master_cpuid,
9960Sstevel@tonic-gate 	kaif_get_gregs,
9971234Sjohnlev 	kaif_get_register,
9981234Sjohnlev 	kaif_set_register,
9990Sstevel@tonic-gate 	kaif_get_rwin,
10000Sstevel@tonic-gate 	kaif_get_nwin,
10010Sstevel@tonic-gate 	kaif_brkpt_arm,
10020Sstevel@tonic-gate 	kaif_brkpt_disarm,
10030Sstevel@tonic-gate 	kaif_wapt_validate,
10040Sstevel@tonic-gate 	kaif_wapt_reserve,
10050Sstevel@tonic-gate 	kaif_wapt_release,
10060Sstevel@tonic-gate 	kaif_wapt_arm,
10070Sstevel@tonic-gate 	kaif_wapt_disarm,
10080Sstevel@tonic-gate 	kaif_wapt_match,
10090Sstevel@tonic-gate 	kaif_step,
10100Sstevel@tonic-gate 	kaif_call,
10110Sstevel@tonic-gate 	kaif_dump_crumbs,
10120Sstevel@tonic-gate 	kaif_kernpanic
10130Sstevel@tonic-gate };
1014