xref: /onnv-gate/usr/src/cmd/mdb/intel/kmdb/kvm_isadep.c (revision 5084:7d838c5c0eed)
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
51530Sjohnlev  * Common Development and Distribution License (the "License").
61530Sjohnlev  * 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  */
210Sstevel@tonic-gate /*
22*3446Smrj  * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
230Sstevel@tonic-gate  * Use is subject to license terms.
240Sstevel@tonic-gate  */
250Sstevel@tonic-gate 
260Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
270Sstevel@tonic-gate 
280Sstevel@tonic-gate /*
290Sstevel@tonic-gate  * isa-dependent portions of the kmdb target
300Sstevel@tonic-gate  */
310Sstevel@tonic-gate 
320Sstevel@tonic-gate #include <kmdb/kvm.h>
330Sstevel@tonic-gate #include <kmdb/kvm_cpu.h>
340Sstevel@tonic-gate #include <kmdb/kmdb_kdi.h>
350Sstevel@tonic-gate #include <kmdb/kmdb_asmutil.h>
360Sstevel@tonic-gate #include <mdb/mdb_debug.h>
370Sstevel@tonic-gate #include <mdb/mdb_err.h>
380Sstevel@tonic-gate #include <mdb/mdb_list.h>
390Sstevel@tonic-gate #include <mdb/mdb_target_impl.h>
400Sstevel@tonic-gate #include <mdb/mdb_isautil.h>
410Sstevel@tonic-gate #include <mdb/mdb_kreg_impl.h>
420Sstevel@tonic-gate #include <mdb/mdb.h>
430Sstevel@tonic-gate 
440Sstevel@tonic-gate #include <sys/types.h>
450Sstevel@tonic-gate #include <sys/frame.h>
460Sstevel@tonic-gate #include <sys/trap.h>
470Sstevel@tonic-gate #include <sys/bitmap.h>
481414Scindi #include <sys/pci_impl.h>
490Sstevel@tonic-gate 
500Sstevel@tonic-gate /* Higher than the highest trap number for which we have a defined specifier */
510Sstevel@tonic-gate #define	KMT_MAXTRAPNO	0x20
520Sstevel@tonic-gate 
530Sstevel@tonic-gate #define	IOPORTLIMIT	0xffff	/* XXX find a new home for this */
540Sstevel@tonic-gate 
550Sstevel@tonic-gate const char *
kmt_def_dismode(void)560Sstevel@tonic-gate kmt_def_dismode(void)
570Sstevel@tonic-gate {
580Sstevel@tonic-gate #ifdef	__amd64
590Sstevel@tonic-gate 	return ("amd64");
600Sstevel@tonic-gate #else
610Sstevel@tonic-gate 	return ("ia32");
620Sstevel@tonic-gate #endif
630Sstevel@tonic-gate }
640Sstevel@tonic-gate 
650Sstevel@tonic-gate int
kmt_step_out_validate(mdb_tgt_t * t,uintptr_t pc)660Sstevel@tonic-gate kmt_step_out_validate(mdb_tgt_t *t, uintptr_t pc)
670Sstevel@tonic-gate {
680Sstevel@tonic-gate 	kmt_data_t *kmt = t->t_data;
690Sstevel@tonic-gate 	int i;
700Sstevel@tonic-gate 
710Sstevel@tonic-gate 	for (i = 0; i < sizeof (kmt->kmt_intrsyms) / sizeof (GElf_Sym); i++) {
720Sstevel@tonic-gate 		GElf_Sym *sym = (GElf_Sym *)&kmt->kmt_intrsyms + i;
730Sstevel@tonic-gate 
740Sstevel@tonic-gate 		if (pc >= sym->st_value && pc < sym->st_value + sym->st_size)
750Sstevel@tonic-gate 			return (0);
760Sstevel@tonic-gate 	}
770Sstevel@tonic-gate 
780Sstevel@tonic-gate 	return (1);
790Sstevel@tonic-gate }
800Sstevel@tonic-gate 
810Sstevel@tonic-gate /*
820Sstevel@tonic-gate  * Determine the return address for the current frame.
830Sstevel@tonic-gate  */
840Sstevel@tonic-gate int
kmt_step_out(mdb_tgt_t * t,uintptr_t * p)850Sstevel@tonic-gate kmt_step_out(mdb_tgt_t *t, uintptr_t *p)
860Sstevel@tonic-gate {
870Sstevel@tonic-gate 	mdb_instr_t instr;
880Sstevel@tonic-gate 	kreg_t pc, sp, fp;
890Sstevel@tonic-gate 
900Sstevel@tonic-gate 	(void) kmdb_dpi_get_register("pc", &pc);
910Sstevel@tonic-gate 	(void) kmdb_dpi_get_register("sp", &sp);
920Sstevel@tonic-gate 	(void) kmdb_dpi_get_register("fp", &fp);
930Sstevel@tonic-gate 
940Sstevel@tonic-gate 	if (mdb_tgt_vread(t, &instr, sizeof (mdb_instr_t), pc) !=
950Sstevel@tonic-gate 	    sizeof (mdb_instr_t))
960Sstevel@tonic-gate 		return (-1); /* errno is set for us */
970Sstevel@tonic-gate 
980Sstevel@tonic-gate 	if (!kmt_step_out_validate(t, pc))
990Sstevel@tonic-gate 		return (set_errno(EMDB_TGTNOTSUP));
1000Sstevel@tonic-gate 
1010Sstevel@tonic-gate 	return (mdb_isa_step_out(t, p, pc, fp, sp, instr));
1020Sstevel@tonic-gate }
1030Sstevel@tonic-gate 
1040Sstevel@tonic-gate int
kmt_step_branch(mdb_tgt_t * t)1050Sstevel@tonic-gate kmt_step_branch(mdb_tgt_t *t)
1060Sstevel@tonic-gate {
1070Sstevel@tonic-gate 	kmt_data_t *kmt = t->t_data;
1080Sstevel@tonic-gate 
1090Sstevel@tonic-gate 	return (kmt_cpu_step_branch(t, kmt->kmt_cpu));
1100Sstevel@tonic-gate }
1110Sstevel@tonic-gate 
1120Sstevel@tonic-gate /*
1130Sstevel@tonic-gate  * Return the address of the next instruction following a call, or return -1
1140Sstevel@tonic-gate  * and set errno to EAGAIN if the target should just single-step.
1150Sstevel@tonic-gate  */
1160Sstevel@tonic-gate int
kmt_next(mdb_tgt_t * t,uintptr_t * p)1170Sstevel@tonic-gate kmt_next(mdb_tgt_t *t, uintptr_t *p)
1180Sstevel@tonic-gate {
1190Sstevel@tonic-gate 	kreg_t pc;
1200Sstevel@tonic-gate 	mdb_instr_t instr;
1210Sstevel@tonic-gate 
1220Sstevel@tonic-gate 	(void) kmdb_dpi_get_register("pc", &pc);
1230Sstevel@tonic-gate 
1240Sstevel@tonic-gate 	if (mdb_tgt_vread(t, &instr, sizeof (mdb_instr_t), pc) !=
1250Sstevel@tonic-gate 	    sizeof (mdb_instr_t))
1260Sstevel@tonic-gate 		return (-1); /* errno is set for us */
1270Sstevel@tonic-gate 
1280Sstevel@tonic-gate 	return (mdb_isa_next(t, p, pc, instr));
1290Sstevel@tonic-gate }
1300Sstevel@tonic-gate 
1310Sstevel@tonic-gate /*ARGSUSED*/
1320Sstevel@tonic-gate static int
kmt_stack_common(uintptr_t addr,uint_t flags,int argc,const mdb_arg_t * argv,int cpuid,mdb_tgt_stack_f * func)1330Sstevel@tonic-gate kmt_stack_common(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv,
1340Sstevel@tonic-gate     int cpuid, mdb_tgt_stack_f *func)
1350Sstevel@tonic-gate {
1360Sstevel@tonic-gate 	const mdb_tgt_gregset_t *grp = NULL;
1370Sstevel@tonic-gate 	mdb_tgt_gregset_t gregs;
1380Sstevel@tonic-gate 	void *arg = (void *)(uintptr_t)mdb.m_nargs;
1390Sstevel@tonic-gate 
1400Sstevel@tonic-gate 	if (flags & DCMD_ADDRSPEC) {
1410Sstevel@tonic-gate 		bzero(&gregs, sizeof (gregs));
1420Sstevel@tonic-gate 		gregs.kregs[KREG_FP] = addr;
1430Sstevel@tonic-gate 		grp = &gregs;
1440Sstevel@tonic-gate 	} else
1450Sstevel@tonic-gate 		grp = kmdb_dpi_get_gregs(cpuid);
1460Sstevel@tonic-gate 
1471234Sjohnlev 	if (grp == NULL) {
1481234Sjohnlev 		warn("failed to retrieve registers for cpu %d", cpuid);
1491234Sjohnlev 		return (DCMD_ERR);
1501234Sjohnlev 	}
1511234Sjohnlev 
1520Sstevel@tonic-gate 	if (argc != 0) {
1530Sstevel@tonic-gate 		if (argv->a_type == MDB_TYPE_CHAR || argc > 1)
1540Sstevel@tonic-gate 			return (DCMD_USAGE);
1550Sstevel@tonic-gate 
1560Sstevel@tonic-gate 		if (argv->a_type == MDB_TYPE_STRING)
1570Sstevel@tonic-gate 			arg = (void *)(uintptr_t)mdb_strtoull(argv->a_un.a_str);
1580Sstevel@tonic-gate 		else
1590Sstevel@tonic-gate 			arg = (void *)(uintptr_t)argv->a_un.a_val;
1600Sstevel@tonic-gate 	}
1610Sstevel@tonic-gate 
1620Sstevel@tonic-gate 	(void) mdb_isa_kvm_stack_iter(mdb.m_target, grp, func, arg);
1630Sstevel@tonic-gate 
1640Sstevel@tonic-gate 	return (DCMD_OK);
1650Sstevel@tonic-gate }
1660Sstevel@tonic-gate 
1670Sstevel@tonic-gate int
kmt_cpustack(uintptr_t addr,uint_t flags,int argc,const mdb_arg_t * argv,int cpuid,int verbose)1680Sstevel@tonic-gate kmt_cpustack(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv,
1690Sstevel@tonic-gate     int cpuid, int verbose)
1700Sstevel@tonic-gate {
1710Sstevel@tonic-gate 	return (kmt_stack_common(addr, flags, argc, argv, cpuid,
1720Sstevel@tonic-gate 	    (verbose ? mdb_isa_kvm_framev : mdb_isa_kvm_frame)));
1730Sstevel@tonic-gate }
1740Sstevel@tonic-gate 
1750Sstevel@tonic-gate int
kmt_stack(uintptr_t addr,uint_t flags,int argc,const mdb_arg_t * argv)1760Sstevel@tonic-gate kmt_stack(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
1770Sstevel@tonic-gate {
1780Sstevel@tonic-gate 	return (kmt_stack_common(addr, flags, argc, argv, DPI_MASTER_CPUID,
1790Sstevel@tonic-gate 	    mdb_isa_kvm_frame));
1800Sstevel@tonic-gate }
1810Sstevel@tonic-gate 
1820Sstevel@tonic-gate int
kmt_stackv(uintptr_t addr,uint_t flags,int argc,const mdb_arg_t * argv)1830Sstevel@tonic-gate kmt_stackv(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
1840Sstevel@tonic-gate {
1850Sstevel@tonic-gate 	return (kmt_stack_common(addr, flags, argc, argv, DPI_MASTER_CPUID,
1860Sstevel@tonic-gate 	    mdb_isa_kvm_framev));
1870Sstevel@tonic-gate }
1880Sstevel@tonic-gate 
1890Sstevel@tonic-gate int
kmt_stackr(uintptr_t addr,uint_t flags,int argc,const mdb_arg_t * argv)1900Sstevel@tonic-gate kmt_stackr(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
1910Sstevel@tonic-gate {
1920Sstevel@tonic-gate 	return (kmt_stack_common(addr, flags, argc, argv, DPI_MASTER_CPUID,
1930Sstevel@tonic-gate 	    mdb_isa_kvm_framev));
1940Sstevel@tonic-gate }
1950Sstevel@tonic-gate 
1960Sstevel@tonic-gate /*ARGSUSED*/
1970Sstevel@tonic-gate void
kmt_printregs(const mdb_tgt_gregset_t * gregs)1980Sstevel@tonic-gate kmt_printregs(const mdb_tgt_gregset_t *gregs)
1990Sstevel@tonic-gate {
2000Sstevel@tonic-gate 	mdb_isa_printregs(gregs);
2010Sstevel@tonic-gate }
2020Sstevel@tonic-gate 
2030Sstevel@tonic-gate #define	IOCHECK_NOWARN	0
2040Sstevel@tonic-gate #define	IOCHECK_WARN	1
2050Sstevel@tonic-gate 
2060Sstevel@tonic-gate static int
kmt_io_check(uint64_t nbytes,uintptr_t addr,int dowarn)2070Sstevel@tonic-gate kmt_io_check(uint64_t nbytes, uintptr_t addr, int dowarn)
2080Sstevel@tonic-gate {
2090Sstevel@tonic-gate 	if (addr > IOPORTLIMIT) {
2100Sstevel@tonic-gate 		if (dowarn)
2110Sstevel@tonic-gate 			warn("port address must be 0-%#x\n", IOPORTLIMIT);
2120Sstevel@tonic-gate 		return (set_errno(EINVAL));
2130Sstevel@tonic-gate 	}
2140Sstevel@tonic-gate 
2150Sstevel@tonic-gate 	if (nbytes != 1 && nbytes != 2 && nbytes != 4) {
2160Sstevel@tonic-gate 		if (dowarn)
2170Sstevel@tonic-gate 			warn("port access must be 1, 2, or 4 bytes\n");
2180Sstevel@tonic-gate 		return (set_errno(EINVAL));
2190Sstevel@tonic-gate 	}
2200Sstevel@tonic-gate 
2210Sstevel@tonic-gate 	if ((addr & (nbytes - 1)) != 0) {
2220Sstevel@tonic-gate 		if (dowarn) {
2230Sstevel@tonic-gate 			warn("address for %llu-byte access must be %llu-byte "
2240Sstevel@tonic-gate 			    "aligned\n", (u_longlong_t)nbytes,
2250Sstevel@tonic-gate 			    (u_longlong_t)nbytes);
2260Sstevel@tonic-gate 		}
2270Sstevel@tonic-gate 		return (set_errno(EINVAL));
2280Sstevel@tonic-gate 	}
2290Sstevel@tonic-gate 
2300Sstevel@tonic-gate 	return (0);
2310Sstevel@tonic-gate }
2320Sstevel@tonic-gate 
2330Sstevel@tonic-gate /*ARGSUSED1*/
2340Sstevel@tonic-gate int
kmt_in_dcmd(uintptr_t addr,uint_t flags,int argc,const mdb_arg_t * argv)2350Sstevel@tonic-gate kmt_in_dcmd(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
2360Sstevel@tonic-gate {
2370Sstevel@tonic-gate 	uint64_t len = 0;
2380Sstevel@tonic-gate 	uint32_t buf;
2390Sstevel@tonic-gate 
2400Sstevel@tonic-gate 	if (mdb_getopts(argc, argv,
2410Sstevel@tonic-gate 	    'L', MDB_OPT_UINT64, &len,
2420Sstevel@tonic-gate 	    NULL) != argc)
2430Sstevel@tonic-gate 		return (DCMD_USAGE);
2440Sstevel@tonic-gate 
2450Sstevel@tonic-gate 	if (len == 0)
2460Sstevel@tonic-gate 		len = mdb.m_dcount;
2470Sstevel@tonic-gate 
2480Sstevel@tonic-gate 	if (kmt_io_check(len, addr, IOCHECK_WARN) < 0)
2490Sstevel@tonic-gate 		return (DCMD_ERR);
2500Sstevel@tonic-gate 
2510Sstevel@tonic-gate 	if (mdb_tgt_ioread(mdb.m_target, &buf, len, addr) < 0) {
2520Sstevel@tonic-gate 		warn("failed to read from port 0x%llx", (u_longlong_t)addr);
2530Sstevel@tonic-gate 		return (DCMD_ERR);
2540Sstevel@tonic-gate 	}
2550Sstevel@tonic-gate 
2560Sstevel@tonic-gate 	mdb_printf("%x\n", buf);
2570Sstevel@tonic-gate 
2580Sstevel@tonic-gate 	return (DCMD_OK);
2590Sstevel@tonic-gate }
2600Sstevel@tonic-gate 
2611414Scindi static uint64_t
kmt_numarg(const mdb_arg_t * arg)2621414Scindi kmt_numarg(const mdb_arg_t *arg)
2631414Scindi {
2641414Scindi 	if (arg->a_type == MDB_TYPE_STRING)
2651414Scindi 		return (mdb_strtoull(arg->a_un.a_str));
2661414Scindi 	else
2671414Scindi 		return (arg->a_un.a_val);
2681414Scindi }
2691414Scindi 
2700Sstevel@tonic-gate /*ARGSUSED1*/
2710Sstevel@tonic-gate int
kmt_out_dcmd(uintptr_t addr,uint_t flags,int argc,const mdb_arg_t * argv)2720Sstevel@tonic-gate kmt_out_dcmd(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
2730Sstevel@tonic-gate {
2740Sstevel@tonic-gate 	uint64_t len = 0;
2750Sstevel@tonic-gate 	uint64_t val;
2760Sstevel@tonic-gate 
2770Sstevel@tonic-gate 	if (mdb_getopts(argc, argv,
2780Sstevel@tonic-gate 	    'L', MDB_OPT_UINT64, &len,
2790Sstevel@tonic-gate 	    NULL) != argc - 1)
2800Sstevel@tonic-gate 		return (DCMD_USAGE);
2810Sstevel@tonic-gate 
2820Sstevel@tonic-gate 	if (len == 0)
2830Sstevel@tonic-gate 		len = mdb.m_dcount;
2840Sstevel@tonic-gate 
2850Sstevel@tonic-gate 	argv += argc - 1;
2861414Scindi 	val = kmt_numarg(argv);
2870Sstevel@tonic-gate 
2880Sstevel@tonic-gate 	if (kmt_io_check(len, addr, IOCHECK_WARN) < 0)
2890Sstevel@tonic-gate 		return (DCMD_ERR);
2900Sstevel@tonic-gate 
2910Sstevel@tonic-gate 	if (val > (1ULL << (len * NBBY)) - 1) {
2920Sstevel@tonic-gate 		warn("value is out of range for port size\n");
2930Sstevel@tonic-gate 		return (DCMD_ERR);
2940Sstevel@tonic-gate 	}
2950Sstevel@tonic-gate 
2960Sstevel@tonic-gate 	if (mdb_tgt_iowrite(mdb.m_target, &val, len, addr) < 0) {
2970Sstevel@tonic-gate 		warn("failed to write to port %llx", (u_longlong_t)addr);
2980Sstevel@tonic-gate 		return (DCMD_ERR);
2990Sstevel@tonic-gate 	}
3000Sstevel@tonic-gate 
3010Sstevel@tonic-gate 	return (DCMD_OK);
3020Sstevel@tonic-gate }
3030Sstevel@tonic-gate 
3040Sstevel@tonic-gate static int
kmt_rwmsr(uint32_t addr,uint64_t * valp,void (* rw)(uint32_t,uint64_t *))3050Sstevel@tonic-gate kmt_rwmsr(uint32_t addr, uint64_t *valp, void (*rw)(uint32_t, uint64_t *))
3060Sstevel@tonic-gate {
3070Sstevel@tonic-gate 	jmp_buf pcb, *oldpcb = NULL;
3080Sstevel@tonic-gate 
3090Sstevel@tonic-gate 	if (setjmp(pcb) != 0) {
3100Sstevel@tonic-gate 		kmdb_dpi_restore_fault_hdlr(oldpcb);
3110Sstevel@tonic-gate 		return (-1); /* errno is set for us */
3120Sstevel@tonic-gate 	}
3130Sstevel@tonic-gate 
3140Sstevel@tonic-gate 	oldpcb = kmdb_dpi_set_fault_hdlr(&pcb);
3150Sstevel@tonic-gate 	rw(addr, valp);
3160Sstevel@tonic-gate 	kmdb_dpi_restore_fault_hdlr(oldpcb);
3170Sstevel@tonic-gate 
3180Sstevel@tonic-gate 	return (0);
3190Sstevel@tonic-gate }
3200Sstevel@tonic-gate 
3210Sstevel@tonic-gate /*ARGSUSED*/
3220Sstevel@tonic-gate int
kmt_rdmsr(uintptr_t addr,uint_t flags,int argc,const mdb_arg_t * argv)3230Sstevel@tonic-gate kmt_rdmsr(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
3240Sstevel@tonic-gate {
3250Sstevel@tonic-gate 	uint64_t val;
3260Sstevel@tonic-gate 
3270Sstevel@tonic-gate 	if (!(flags & DCMD_ADDRSPEC))
3280Sstevel@tonic-gate 		return (DCMD_USAGE);
3290Sstevel@tonic-gate 
3300Sstevel@tonic-gate 	if (kmt_rwmsr(addr, &val, rdmsr) < 0) {
3310Sstevel@tonic-gate 		warn("rdmsr failed");
3320Sstevel@tonic-gate 		return (DCMD_ERR);
3330Sstevel@tonic-gate 	}
3340Sstevel@tonic-gate 
3350Sstevel@tonic-gate 	mdb_printf("%llx\n", (u_longlong_t)val);
3360Sstevel@tonic-gate 
3370Sstevel@tonic-gate 	return (DCMD_OK);
3380Sstevel@tonic-gate }
3390Sstevel@tonic-gate 
3400Sstevel@tonic-gate /*ARGSUSED*/
3410Sstevel@tonic-gate int
kmt_wrmsr(uintptr_t addr,uint_t flags,int argc,const mdb_arg_t * argv)3420Sstevel@tonic-gate kmt_wrmsr(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
3430Sstevel@tonic-gate {
3440Sstevel@tonic-gate 	uint64_t val;
3450Sstevel@tonic-gate 
3460Sstevel@tonic-gate 	if (!(flags & DCMD_ADDRSPEC) || argc != 1)
3470Sstevel@tonic-gate 		return (DCMD_USAGE);
3480Sstevel@tonic-gate 
3491414Scindi 	val = kmt_numarg(argv);
3500Sstevel@tonic-gate 
3510Sstevel@tonic-gate 	if (kmt_rwmsr(addr, &val, wrmsr)) {
3520Sstevel@tonic-gate 		warn("wrmsr failed");
3530Sstevel@tonic-gate 		return (DCMD_ERR);
3540Sstevel@tonic-gate 	}
3550Sstevel@tonic-gate 
3560Sstevel@tonic-gate 	return (DCMD_OK);
3570Sstevel@tonic-gate }
3580Sstevel@tonic-gate 
3590Sstevel@tonic-gate int
kmt_msr_validate(const kdi_msr_t * msr)360*3446Smrj kmt_msr_validate(const kdi_msr_t *msr)
3610Sstevel@tonic-gate {
3620Sstevel@tonic-gate 	uint64_t val;
3630Sstevel@tonic-gate 
3640Sstevel@tonic-gate 	for (/* */; msr->msr_num != 0; msr++) {
3650Sstevel@tonic-gate 		if (kmt_rwmsr(msr->msr_num, &val, rdmsr) < 0)
3660Sstevel@tonic-gate 			return (0);
3670Sstevel@tonic-gate 	}
3680Sstevel@tonic-gate 
3690Sstevel@tonic-gate 	return (1);
3700Sstevel@tonic-gate }
3710Sstevel@tonic-gate 
3720Sstevel@tonic-gate /*ARGSUSED*/
3730Sstevel@tonic-gate ssize_t
kmt_write(mdb_tgt_t * t,const void * buf,size_t nbytes,uintptr_t addr)3740Sstevel@tonic-gate kmt_write(mdb_tgt_t *t, const void *buf, size_t nbytes, uintptr_t addr)
3750Sstevel@tonic-gate {
3760Sstevel@tonic-gate 	if (!(t->t_flags & MDB_TGT_F_ALLOWIO) &&
3770Sstevel@tonic-gate 	    (nbytes = kmdb_kdi_range_is_nontoxic(addr, nbytes, 1)) == 0)
3780Sstevel@tonic-gate 		return (set_errno(EMDB_NOMAP));
3790Sstevel@tonic-gate 
3801530Sjohnlev 	/*
3811530Sjohnlev 	 * No writes to user space are allowed.  If we were to allow it, we'd
3821530Sjohnlev 	 * be in the unfortunate situation where kmdb could place a breakpoint
3831530Sjohnlev 	 * on a userspace executable page; this dirty page would end up being
3841530Sjohnlev 	 * flushed back to disk, incurring sadness when it's next executed.
3851530Sjohnlev 	 * Besides, we can't allow trapping in from userspace anyway.
3861530Sjohnlev 	 */
3871530Sjohnlev 	if (addr < kmdb_kdi_get_userlimit())
3881530Sjohnlev 		return (set_errno(EMDB_TGTNOTSUP));
3891530Sjohnlev 
3900Sstevel@tonic-gate 	return (kmt_rw(t, (void *)buf, nbytes, addr, kmt_writer));
3910Sstevel@tonic-gate }
3920Sstevel@tonic-gate 
3930Sstevel@tonic-gate /*ARGSUSED*/
3940Sstevel@tonic-gate static ssize_t
kmt_iorw(mdb_tgt_t * t,void * buf,size_t nbytes,uint64_t addr,void (* iorw)(void *,size_t,uintptr_t))3950Sstevel@tonic-gate kmt_iorw(mdb_tgt_t *t, void *buf, size_t nbytes, uint64_t addr,
3960Sstevel@tonic-gate     void (*iorw)(void *, size_t, uintptr_t))
3970Sstevel@tonic-gate {
3980Sstevel@tonic-gate 	jmp_buf pcb, *oldpcb = NULL;
3990Sstevel@tonic-gate 
4000Sstevel@tonic-gate 	if (kmt_io_check(nbytes, addr, IOCHECK_NOWARN) < 0)
4010Sstevel@tonic-gate 		return (-1); /* errno is set for us */
4020Sstevel@tonic-gate 
4030Sstevel@tonic-gate 	if (setjmp(pcb) != 0) {
4040Sstevel@tonic-gate 		kmdb_dpi_restore_fault_hdlr(oldpcb);
4050Sstevel@tonic-gate 		return (-1); /* errno is set for us */
4060Sstevel@tonic-gate 	}
4070Sstevel@tonic-gate 
4080Sstevel@tonic-gate 	oldpcb = kmdb_dpi_set_fault_hdlr(&pcb);
4090Sstevel@tonic-gate 	iorw(buf, nbytes, addr);
4100Sstevel@tonic-gate 	kmdb_dpi_restore_fault_hdlr(oldpcb);
4110Sstevel@tonic-gate 
4120Sstevel@tonic-gate 	return (nbytes);
4130Sstevel@tonic-gate }
4140Sstevel@tonic-gate 
4150Sstevel@tonic-gate /*ARGSUSED*/
4160Sstevel@tonic-gate ssize_t
kmt_ioread(mdb_tgt_t * t,void * buf,size_t nbytes,uintptr_t addr)4170Sstevel@tonic-gate kmt_ioread(mdb_tgt_t *t, void *buf, size_t nbytes, uintptr_t addr)
4180Sstevel@tonic-gate {
4190Sstevel@tonic-gate 	return (kmt_iorw(t, buf, nbytes, addr, kmt_in));
4200Sstevel@tonic-gate }
4210Sstevel@tonic-gate 
4220Sstevel@tonic-gate /*ARGSUSED*/
4230Sstevel@tonic-gate ssize_t
kmt_iowrite(mdb_tgt_t * t,const void * buf,size_t nbytes,uintptr_t addr)4240Sstevel@tonic-gate kmt_iowrite(mdb_tgt_t *t, const void *buf, size_t nbytes, uintptr_t addr)
4250Sstevel@tonic-gate {
4260Sstevel@tonic-gate 	return (kmt_iorw(t, (void *)buf, nbytes, addr, kmt_out));
4270Sstevel@tonic-gate }
4280Sstevel@tonic-gate 
4291414Scindi static int
kmt_pcicfg_common(uintptr_t off,uint32_t * valp,const mdb_arg_t * argv,void (* rw)(void *,size_t,uintptr_t))4301414Scindi kmt_pcicfg_common(uintptr_t off, uint32_t *valp, const mdb_arg_t *argv,
4311414Scindi     void (*rw)(void *, size_t, uintptr_t))
4321414Scindi {
4331414Scindi 	uint32_t bus, dev, func;
4341414Scindi 	uint32_t addr;
4351414Scindi 
4361414Scindi 	bus = kmt_numarg(&argv[0]);
4371414Scindi 	dev = kmt_numarg(&argv[1]);
4381414Scindi 	func = kmt_numarg(&argv[2]);
4391414Scindi 
4401414Scindi 	if ((bus & 0xffff) != bus) {
4411414Scindi 		warn("invalid bus number (must be 0-0xffff)\n");
4421414Scindi 		return (DCMD_ERR);
4431414Scindi 	}
4441414Scindi 
4451414Scindi 	if ((dev & 0x1f) != dev) {
4461414Scindi 		warn("invalid device number (must be 0-0x1f)\n");
4471414Scindi 		return (DCMD_ERR);
4481414Scindi 	}
4491414Scindi 
4501414Scindi 	if ((func & 0x7) != func) {
4511414Scindi 		warn("invalid function number (must be 0-7)\n");
4521414Scindi 		return (DCMD_ERR);
4531414Scindi 	}
4541414Scindi 
4551414Scindi 	if ((off & 0xfc) != off) {
4561414Scindi 		warn("invalid register number (must be 0-0xff, and 4-byte "
4571414Scindi 		    "aligned\n");
4581414Scindi 		return (DCMD_ERR);
4591414Scindi 	}
4601414Scindi 
4611414Scindi 	addr = PCI_CADDR1(bus, dev, func, off);
4621414Scindi 
4631414Scindi 	if (kmt_iowrite(mdb.m_target, &addr, sizeof (addr), PCI_CONFADD) !=
4641414Scindi 	    sizeof (addr)) {
4651414Scindi 		warn("write of PCI_CONFADD failed");
4661414Scindi 		return (DCMD_ERR);
4671414Scindi 	}
4681414Scindi 
4691414Scindi 	if (kmt_iorw(mdb.m_target, valp, sizeof (*valp), PCI_CONFDATA, rw) !=
4701414Scindi 	    sizeof (*valp)) {
4711414Scindi 		warn("access to PCI_CONFDATA failed");
4721414Scindi 		return (DCMD_ERR);
4731414Scindi 	}
4741414Scindi 
4751414Scindi 	return (DCMD_OK);
4761414Scindi }
4771414Scindi 
4781414Scindi /*ARGSUSED*/
4791414Scindi int
kmt_rdpcicfg(uintptr_t addr,uint_t flags,int argc,const mdb_arg_t * argv)4801414Scindi kmt_rdpcicfg(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
4811414Scindi {
4821414Scindi 	uint32_t val;
4831414Scindi 
4841414Scindi 	if (argc != 3 || !(flags & DCMD_ADDRSPEC))
4851414Scindi 		return (DCMD_USAGE);
4861414Scindi 
4871414Scindi 	if (kmt_pcicfg_common(addr, &val, argv, kmt_in) != DCMD_OK)
4881414Scindi 		return (DCMD_ERR);
4891414Scindi 
4901414Scindi 	mdb_printf("%llx\n", (u_longlong_t)val);
4911414Scindi 
4921414Scindi 	return (DCMD_OK);
4931414Scindi }
4941414Scindi 
4951414Scindi /*ARGSUSED*/
4961414Scindi int
kmt_wrpcicfg(uintptr_t addr,uint_t flags,int argc,const mdb_arg_t * argv)4971414Scindi kmt_wrpcicfg(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
4981414Scindi {
4991414Scindi 	uint32_t val;
5001414Scindi 
5011414Scindi 	if (argc != 4 || !(flags & DCMD_ADDRSPEC))
5021414Scindi 		return (DCMD_USAGE);
5031414Scindi 
5041414Scindi 	val = (uint32_t)kmt_numarg(&argv[3]);
5051414Scindi 
5061414Scindi 	if (kmt_pcicfg_common(addr, &val, argv, kmt_out) != DCMD_OK)
5071414Scindi 		return (DCMD_ERR);
5081414Scindi 
5091414Scindi 	return (DCMD_OK);
5101414Scindi }
5111414Scindi 
5120Sstevel@tonic-gate const char *
kmt_trapname(int trapnum)5130Sstevel@tonic-gate kmt_trapname(int trapnum)
5140Sstevel@tonic-gate {
5150Sstevel@tonic-gate 	static char trapname[11];
5160Sstevel@tonic-gate 
5170Sstevel@tonic-gate 	switch (trapnum) {
5180Sstevel@tonic-gate 	case T_ZERODIV:
5190Sstevel@tonic-gate 		return ("division by zero (#de) trap");
5200Sstevel@tonic-gate 	case T_SGLSTP:
5210Sstevel@tonic-gate 		return ("single-step (#db) trap");
5220Sstevel@tonic-gate 	case T_NMIFLT:
5230Sstevel@tonic-gate 		return ("NMI");
5240Sstevel@tonic-gate 	case T_BPTFLT:
5250Sstevel@tonic-gate 		return ("breakpoint (#bp) trap");
5260Sstevel@tonic-gate 	case T_ILLINST:
5270Sstevel@tonic-gate 		return ("illegal instruction (#ud) trap");
5280Sstevel@tonic-gate 	case T_SEGFLT:
5290Sstevel@tonic-gate 		return ("segment not present (#np) trap");
5300Sstevel@tonic-gate 	case T_STKFLT:
5310Sstevel@tonic-gate 		return ("stack (#ss) trap");
5320Sstevel@tonic-gate 	case T_GPFLT:
5330Sstevel@tonic-gate 		return ("general protection (#gp) trap");
5340Sstevel@tonic-gate 	case T_PGFLT:
5350Sstevel@tonic-gate 		return ("page fault (#pf) trap");
5360Sstevel@tonic-gate 	case T_ALIGNMENT:
5370Sstevel@tonic-gate 		return ("alignment check (#ac) trap");
5380Sstevel@tonic-gate 	case T_MCE:
5390Sstevel@tonic-gate 		return ("machine check (#mc) trap");
5400Sstevel@tonic-gate 	case T_SIMDFPE:
5410Sstevel@tonic-gate 		return ("SSE/SSE2 (#xm) trap");
5420Sstevel@tonic-gate 	case T_DBGENTR:
5430Sstevel@tonic-gate 		return ("debugger entry trap");
5440Sstevel@tonic-gate 	default:
5450Sstevel@tonic-gate 		(void) mdb_snprintf(trapname, sizeof (trapname), "trap %#x",
5460Sstevel@tonic-gate 		    trapnum);
5470Sstevel@tonic-gate 		return (trapname);
5480Sstevel@tonic-gate 	}
5490Sstevel@tonic-gate }
5500Sstevel@tonic-gate 
5510Sstevel@tonic-gate void
kmt_init_isadep(mdb_tgt_t * t)5520Sstevel@tonic-gate kmt_init_isadep(mdb_tgt_t *t)
5530Sstevel@tonic-gate {
5540Sstevel@tonic-gate 	kmt_data_t *kmt = t->t_data;
5550Sstevel@tonic-gate 
5560Sstevel@tonic-gate 	kmt->kmt_rds = mdb_isa_kregs;
5570Sstevel@tonic-gate 
5580Sstevel@tonic-gate 	kmt->kmt_trapmax = KMT_MAXTRAPNO;
5590Sstevel@tonic-gate 	kmt->kmt_trapmap = mdb_zalloc(BT_SIZEOFMAP(kmt->kmt_trapmax), UM_SLEEP);
5600Sstevel@tonic-gate 
5610Sstevel@tonic-gate 	/* Traps for which we want to provide an explicit message */
5620Sstevel@tonic-gate 	(void) mdb_tgt_add_fault(t, T_ZERODIV, MDB_TGT_SPEC_INTERNAL,
5630Sstevel@tonic-gate 	    no_se_f, NULL);
5640Sstevel@tonic-gate 	(void) mdb_tgt_add_fault(t, T_ILLINST, MDB_TGT_SPEC_INTERNAL,
5650Sstevel@tonic-gate 	    no_se_f, NULL);
5660Sstevel@tonic-gate 	(void) mdb_tgt_add_fault(t, T_SEGFLT, MDB_TGT_SPEC_INTERNAL,
5670Sstevel@tonic-gate 	    no_se_f, NULL);
5680Sstevel@tonic-gate 	(void) mdb_tgt_add_fault(t, T_STKFLT, MDB_TGT_SPEC_INTERNAL,
5690Sstevel@tonic-gate 	    no_se_f, NULL);
5700Sstevel@tonic-gate 	(void) mdb_tgt_add_fault(t, T_GPFLT, MDB_TGT_SPEC_INTERNAL,
5710Sstevel@tonic-gate 	    no_se_f, NULL);
5720Sstevel@tonic-gate 	(void) mdb_tgt_add_fault(t, T_PGFLT, MDB_TGT_SPEC_INTERNAL,
5730Sstevel@tonic-gate 	    no_se_f, NULL);
5740Sstevel@tonic-gate 	(void) mdb_tgt_add_fault(t, T_ALIGNMENT, MDB_TGT_SPEC_INTERNAL,
5750Sstevel@tonic-gate 	    no_se_f, NULL);
5760Sstevel@tonic-gate 	(void) mdb_tgt_add_fault(t, T_MCE, MDB_TGT_SPEC_INTERNAL,
5770Sstevel@tonic-gate 	    no_se_f, NULL);
5780Sstevel@tonic-gate 	(void) mdb_tgt_add_fault(t, T_SIMDFPE, MDB_TGT_SPEC_INTERNAL,
5790Sstevel@tonic-gate 	    no_se_f, NULL);
5800Sstevel@tonic-gate 
5810Sstevel@tonic-gate 	/*
5820Sstevel@tonic-gate 	 * Traps which will be handled elsewhere, and which therefore don't
5830Sstevel@tonic-gate 	 * need the trap-based message.
5840Sstevel@tonic-gate 	 */
5850Sstevel@tonic-gate 	BT_SET(kmt->kmt_trapmap, T_SGLSTP);
5860Sstevel@tonic-gate 	BT_SET(kmt->kmt_trapmap, T_BPTFLT);
5870Sstevel@tonic-gate 	BT_SET(kmt->kmt_trapmap, T_DBGENTR);
5880Sstevel@tonic-gate 
5890Sstevel@tonic-gate 	/* Catch-all for traps not explicitly listed here */
5900Sstevel@tonic-gate 	(void) mdb_tgt_add_fault(t, KMT_TRAP_NOTENUM, MDB_TGT_SPEC_INTERNAL,
5910Sstevel@tonic-gate 	    no_se_f, NULL);
5920Sstevel@tonic-gate }
5930Sstevel@tonic-gate 
5940Sstevel@tonic-gate void
kmt_startup_isadep(mdb_tgt_t * t)5950Sstevel@tonic-gate kmt_startup_isadep(mdb_tgt_t *t)
5960Sstevel@tonic-gate {
5970Sstevel@tonic-gate 	kmt_data_t *kmt = t->t_data;
5980Sstevel@tonic-gate 
5990Sstevel@tonic-gate 	/*
6000Sstevel@tonic-gate 	 * The stack trace and ::step out code need to detect "interrupt"
6010Sstevel@tonic-gate 	 * frames.  The heuristic they use to detect said frames requires the
6020Sstevel@tonic-gate 	 * addresses of routines that can generate them.
6030Sstevel@tonic-gate 	 */
6040Sstevel@tonic-gate 	(void) mdb_tgt_lookup_by_name(t, MDB_TGT_OBJ_EXEC,
6050Sstevel@tonic-gate 	    "cmnint", &kmt->kmt_intrsyms._kmt_cmnint, NULL);
6060Sstevel@tonic-gate 	(void) mdb_tgt_lookup_by_name(t, MDB_TGT_OBJ_EXEC,
6070Sstevel@tonic-gate 	    "cmntrap", &kmt->kmt_intrsyms._kmt_cmntrap, NULL);
6080Sstevel@tonic-gate 	(void) mdb_tgt_lookup_by_name(t, MDB_TGT_OBJ_EXEC,
6090Sstevel@tonic-gate 	    "sys_sysenter", &kmt->kmt_intrsyms._kmt_sysenter, NULL);
6102712Snn35248 	(void) mdb_tgt_lookup_by_name(t, MDB_TGT_OBJ_EXEC,
6112712Snn35248 	    "brand_sys_sysenter", &kmt->kmt_intrsyms._kmt_brand_sysenter, NULL);
6120Sstevel@tonic-gate #if defined(__amd64)
6130Sstevel@tonic-gate 	(void) mdb_tgt_lookup_by_name(t, MDB_TGT_OBJ_EXEC,
6140Sstevel@tonic-gate 	    "sys_syscall", &kmt->kmt_intrsyms._kmt_syscall, NULL);
6152712Snn35248 	(void) mdb_tgt_lookup_by_name(t, MDB_TGT_OBJ_EXEC,
6162712Snn35248 	    "brand_sys_syscall", &kmt->kmt_intrsyms._kmt_brand_syscall, NULL);
6170Sstevel@tonic-gate #endif
6180Sstevel@tonic-gate }
619