xref: /onnv-gate/usr/src/cmd/mdb/intel/kmdb/kvm_isadep.c (revision 0:68f95e015346)
1*0Sstevel@tonic-gate /*
2*0Sstevel@tonic-gate  * CDDL HEADER START
3*0Sstevel@tonic-gate  *
4*0Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5*0Sstevel@tonic-gate  * Common Development and Distribution License, Version 1.0 only
6*0Sstevel@tonic-gate  * (the "License").  You may not use this file except in compliance
7*0Sstevel@tonic-gate  * with the License.
8*0Sstevel@tonic-gate  *
9*0Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10*0Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
11*0Sstevel@tonic-gate  * See the License for the specific language governing permissions
12*0Sstevel@tonic-gate  * and limitations under the License.
13*0Sstevel@tonic-gate  *
14*0Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
15*0Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16*0Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
17*0Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
18*0Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
19*0Sstevel@tonic-gate  *
20*0Sstevel@tonic-gate  * CDDL HEADER END
21*0Sstevel@tonic-gate  */
22*0Sstevel@tonic-gate /*
23*0Sstevel@tonic-gate  * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
24*0Sstevel@tonic-gate  * Use is subject to license terms.
25*0Sstevel@tonic-gate  */
26*0Sstevel@tonic-gate 
27*0Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
28*0Sstevel@tonic-gate 
29*0Sstevel@tonic-gate /*
30*0Sstevel@tonic-gate  * isa-dependent portions of the kmdb target
31*0Sstevel@tonic-gate  */
32*0Sstevel@tonic-gate 
33*0Sstevel@tonic-gate #include <kmdb/kvm.h>
34*0Sstevel@tonic-gate #include <kmdb/kvm_cpu.h>
35*0Sstevel@tonic-gate #include <kmdb/kmdb_kdi.h>
36*0Sstevel@tonic-gate #include <kmdb/kmdb_asmutil.h>
37*0Sstevel@tonic-gate #include <mdb/mdb_debug.h>
38*0Sstevel@tonic-gate #include <mdb/mdb_err.h>
39*0Sstevel@tonic-gate #include <mdb/mdb_list.h>
40*0Sstevel@tonic-gate #include <mdb/mdb_target_impl.h>
41*0Sstevel@tonic-gate #include <mdb/mdb_isautil.h>
42*0Sstevel@tonic-gate #include <mdb/mdb_kreg_impl.h>
43*0Sstevel@tonic-gate #include <mdb/mdb.h>
44*0Sstevel@tonic-gate 
45*0Sstevel@tonic-gate #include <sys/types.h>
46*0Sstevel@tonic-gate #include <sys/frame.h>
47*0Sstevel@tonic-gate #include <sys/trap.h>
48*0Sstevel@tonic-gate #include <sys/bitmap.h>
49*0Sstevel@tonic-gate 
50*0Sstevel@tonic-gate /* Higher than the highest trap number for which we have a defined specifier */
51*0Sstevel@tonic-gate #define	KMT_MAXTRAPNO	0x20
52*0Sstevel@tonic-gate 
53*0Sstevel@tonic-gate #define	IOPORTLIMIT	0xffff	/* XXX find a new home for this */
54*0Sstevel@tonic-gate 
55*0Sstevel@tonic-gate const char *
56*0Sstevel@tonic-gate kmt_def_dismode(void)
57*0Sstevel@tonic-gate {
58*0Sstevel@tonic-gate #ifdef	__amd64
59*0Sstevel@tonic-gate 	return ("amd64");
60*0Sstevel@tonic-gate #else
61*0Sstevel@tonic-gate 	return ("ia32");
62*0Sstevel@tonic-gate #endif
63*0Sstevel@tonic-gate }
64*0Sstevel@tonic-gate 
65*0Sstevel@tonic-gate int
66*0Sstevel@tonic-gate kmt_step_out_validate(mdb_tgt_t *t, uintptr_t pc)
67*0Sstevel@tonic-gate {
68*0Sstevel@tonic-gate 	kmt_data_t *kmt = t->t_data;
69*0Sstevel@tonic-gate 	int i;
70*0Sstevel@tonic-gate 
71*0Sstevel@tonic-gate 	for (i = 0; i < sizeof (kmt->kmt_intrsyms) / sizeof (GElf_Sym); i++) {
72*0Sstevel@tonic-gate 		GElf_Sym *sym = (GElf_Sym *)&kmt->kmt_intrsyms + i;
73*0Sstevel@tonic-gate 
74*0Sstevel@tonic-gate 		if (pc >= sym->st_value && pc < sym->st_value + sym->st_size)
75*0Sstevel@tonic-gate 			return (0);
76*0Sstevel@tonic-gate 	}
77*0Sstevel@tonic-gate 
78*0Sstevel@tonic-gate 	return (1);
79*0Sstevel@tonic-gate }
80*0Sstevel@tonic-gate 
81*0Sstevel@tonic-gate /*
82*0Sstevel@tonic-gate  * Determine the return address for the current frame.
83*0Sstevel@tonic-gate  */
84*0Sstevel@tonic-gate int
85*0Sstevel@tonic-gate kmt_step_out(mdb_tgt_t *t, uintptr_t *p)
86*0Sstevel@tonic-gate {
87*0Sstevel@tonic-gate 	mdb_instr_t instr;
88*0Sstevel@tonic-gate 	kreg_t pc, sp, fp;
89*0Sstevel@tonic-gate 
90*0Sstevel@tonic-gate 	(void) kmdb_dpi_get_register("pc", &pc);
91*0Sstevel@tonic-gate 	(void) kmdb_dpi_get_register("sp", &sp);
92*0Sstevel@tonic-gate 	(void) kmdb_dpi_get_register("fp", &fp);
93*0Sstevel@tonic-gate 
94*0Sstevel@tonic-gate 	if (mdb_tgt_vread(t, &instr, sizeof (mdb_instr_t), pc) !=
95*0Sstevel@tonic-gate 	    sizeof (mdb_instr_t))
96*0Sstevel@tonic-gate 		return (-1); /* errno is set for us */
97*0Sstevel@tonic-gate 
98*0Sstevel@tonic-gate 	if (!kmt_step_out_validate(t, pc))
99*0Sstevel@tonic-gate 		return (set_errno(EMDB_TGTNOTSUP));
100*0Sstevel@tonic-gate 
101*0Sstevel@tonic-gate 	return (mdb_isa_step_out(t, p, pc, fp, sp, instr));
102*0Sstevel@tonic-gate }
103*0Sstevel@tonic-gate 
104*0Sstevel@tonic-gate int
105*0Sstevel@tonic-gate kmt_step_branch(mdb_tgt_t *t)
106*0Sstevel@tonic-gate {
107*0Sstevel@tonic-gate 	kmt_data_t *kmt = t->t_data;
108*0Sstevel@tonic-gate 
109*0Sstevel@tonic-gate 	return (kmt_cpu_step_branch(t, kmt->kmt_cpu));
110*0Sstevel@tonic-gate }
111*0Sstevel@tonic-gate 
112*0Sstevel@tonic-gate /*
113*0Sstevel@tonic-gate  * Return the address of the next instruction following a call, or return -1
114*0Sstevel@tonic-gate  * and set errno to EAGAIN if the target should just single-step.
115*0Sstevel@tonic-gate  */
116*0Sstevel@tonic-gate int
117*0Sstevel@tonic-gate kmt_next(mdb_tgt_t *t, uintptr_t *p)
118*0Sstevel@tonic-gate {
119*0Sstevel@tonic-gate 	kreg_t pc;
120*0Sstevel@tonic-gate 	mdb_instr_t instr;
121*0Sstevel@tonic-gate 
122*0Sstevel@tonic-gate 	(void) kmdb_dpi_get_register("pc", &pc);
123*0Sstevel@tonic-gate 
124*0Sstevel@tonic-gate 	if (mdb_tgt_vread(t, &instr, sizeof (mdb_instr_t), pc) !=
125*0Sstevel@tonic-gate 	    sizeof (mdb_instr_t))
126*0Sstevel@tonic-gate 		return (-1); /* errno is set for us */
127*0Sstevel@tonic-gate 
128*0Sstevel@tonic-gate 	return (mdb_isa_next(t, p, pc, instr));
129*0Sstevel@tonic-gate }
130*0Sstevel@tonic-gate 
131*0Sstevel@tonic-gate /*
132*0Sstevel@tonic-gate  * Return a flag indicating if the specified %eip is likely to have an
133*0Sstevel@tonic-gate  * interrupt frame on the stack.  We do this by comparing the address to the
134*0Sstevel@tonic-gate  * range of addresses spanned by several well-known routines, and looking
135*0Sstevel@tonic-gate  * to see if the next and previous %ebp values are "far" apart.  Sigh.
136*0Sstevel@tonic-gate  */
137*0Sstevel@tonic-gate int
138*0Sstevel@tonic-gate mdb_kvm_intrframe(mdb_tgt_t *t, uintptr_t pc, uintptr_t fp,
139*0Sstevel@tonic-gate     uintptr_t prevfp)
140*0Sstevel@tonic-gate {
141*0Sstevel@tonic-gate 	kmt_data_t *kmt = t->t_data;
142*0Sstevel@tonic-gate 	const size_t dist = 0x800 * sizeof (uintptr_t);
143*0Sstevel@tonic-gate 
144*0Sstevel@tonic-gate 	return ((pc >= kmt->kmt_cmnint.st_value &&
145*0Sstevel@tonic-gate 	    (pc < kmt->kmt_cmnint.st_value + kmt->kmt_cmnint.st_size)) ||
146*0Sstevel@tonic-gate 	    (pc >= kmt->kmt_cmntrap.st_value &&
147*0Sstevel@tonic-gate 	    (pc < kmt->kmt_cmntrap.st_value + kmt->kmt_cmntrap.st_size)) ||
148*0Sstevel@tonic-gate 	    (fp >= prevfp + dist) || (fp <= prevfp - dist));
149*0Sstevel@tonic-gate }
150*0Sstevel@tonic-gate 
151*0Sstevel@tonic-gate /*ARGSUSED*/
152*0Sstevel@tonic-gate static int
153*0Sstevel@tonic-gate kmt_stack_common(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv,
154*0Sstevel@tonic-gate     int cpuid, mdb_tgt_stack_f *func)
155*0Sstevel@tonic-gate {
156*0Sstevel@tonic-gate 	const mdb_tgt_gregset_t *grp = NULL;
157*0Sstevel@tonic-gate 	mdb_tgt_gregset_t gregs;
158*0Sstevel@tonic-gate 	void *arg = (void *)(uintptr_t)mdb.m_nargs;
159*0Sstevel@tonic-gate 
160*0Sstevel@tonic-gate 	if (flags & DCMD_ADDRSPEC) {
161*0Sstevel@tonic-gate 		bzero(&gregs, sizeof (gregs));
162*0Sstevel@tonic-gate 		gregs.kregs[KREG_FP] = addr;
163*0Sstevel@tonic-gate 		grp = &gregs;
164*0Sstevel@tonic-gate 	} else
165*0Sstevel@tonic-gate 		grp = kmdb_dpi_get_gregs(cpuid);
166*0Sstevel@tonic-gate 
167*0Sstevel@tonic-gate 	if (argc != 0) {
168*0Sstevel@tonic-gate 		if (argv->a_type == MDB_TYPE_CHAR || argc > 1)
169*0Sstevel@tonic-gate 			return (DCMD_USAGE);
170*0Sstevel@tonic-gate 
171*0Sstevel@tonic-gate 		if (argv->a_type == MDB_TYPE_STRING)
172*0Sstevel@tonic-gate 			arg = (void *)(uintptr_t)mdb_strtoull(argv->a_un.a_str);
173*0Sstevel@tonic-gate 		else
174*0Sstevel@tonic-gate 			arg = (void *)(uintptr_t)argv->a_un.a_val;
175*0Sstevel@tonic-gate 	}
176*0Sstevel@tonic-gate 
177*0Sstevel@tonic-gate 	(void) mdb_isa_kvm_stack_iter(mdb.m_target, grp, func, arg);
178*0Sstevel@tonic-gate 
179*0Sstevel@tonic-gate 	return (DCMD_OK);
180*0Sstevel@tonic-gate }
181*0Sstevel@tonic-gate 
182*0Sstevel@tonic-gate int
183*0Sstevel@tonic-gate kmt_cpustack(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv,
184*0Sstevel@tonic-gate     int cpuid, int verbose)
185*0Sstevel@tonic-gate {
186*0Sstevel@tonic-gate 	return (kmt_stack_common(addr, flags, argc, argv, cpuid,
187*0Sstevel@tonic-gate 	    (verbose ? mdb_isa_kvm_framev : mdb_isa_kvm_frame)));
188*0Sstevel@tonic-gate }
189*0Sstevel@tonic-gate 
190*0Sstevel@tonic-gate int
191*0Sstevel@tonic-gate kmt_stack(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
192*0Sstevel@tonic-gate {
193*0Sstevel@tonic-gate 	return (kmt_stack_common(addr, flags, argc, argv, DPI_MASTER_CPUID,
194*0Sstevel@tonic-gate 	    mdb_isa_kvm_frame));
195*0Sstevel@tonic-gate }
196*0Sstevel@tonic-gate 
197*0Sstevel@tonic-gate int
198*0Sstevel@tonic-gate kmt_stackv(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
199*0Sstevel@tonic-gate {
200*0Sstevel@tonic-gate 	return (kmt_stack_common(addr, flags, argc, argv, DPI_MASTER_CPUID,
201*0Sstevel@tonic-gate 	    mdb_isa_kvm_framev));
202*0Sstevel@tonic-gate }
203*0Sstevel@tonic-gate 
204*0Sstevel@tonic-gate int
205*0Sstevel@tonic-gate kmt_stackr(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
206*0Sstevel@tonic-gate {
207*0Sstevel@tonic-gate 	return (kmt_stack_common(addr, flags, argc, argv, DPI_MASTER_CPUID,
208*0Sstevel@tonic-gate 	    mdb_isa_kvm_framev));
209*0Sstevel@tonic-gate }
210*0Sstevel@tonic-gate 
211*0Sstevel@tonic-gate /*ARGSUSED*/
212*0Sstevel@tonic-gate void
213*0Sstevel@tonic-gate kmt_printregs(const mdb_tgt_gregset_t *gregs)
214*0Sstevel@tonic-gate {
215*0Sstevel@tonic-gate 	mdb_isa_printregs(gregs);
216*0Sstevel@tonic-gate }
217*0Sstevel@tonic-gate 
218*0Sstevel@tonic-gate #define	IOCHECK_NOWARN	0
219*0Sstevel@tonic-gate #define	IOCHECK_WARN	1
220*0Sstevel@tonic-gate 
221*0Sstevel@tonic-gate static int
222*0Sstevel@tonic-gate kmt_io_check(uint64_t nbytes, uintptr_t addr, int dowarn)
223*0Sstevel@tonic-gate {
224*0Sstevel@tonic-gate 	if (addr > IOPORTLIMIT) {
225*0Sstevel@tonic-gate 		if (dowarn)
226*0Sstevel@tonic-gate 			warn("port address must be 0-%#x\n", IOPORTLIMIT);
227*0Sstevel@tonic-gate 		return (set_errno(EINVAL));
228*0Sstevel@tonic-gate 	}
229*0Sstevel@tonic-gate 
230*0Sstevel@tonic-gate 	if (nbytes != 1 && nbytes != 2 && nbytes != 4) {
231*0Sstevel@tonic-gate 		if (dowarn)
232*0Sstevel@tonic-gate 			warn("port access must be 1, 2, or 4 bytes\n");
233*0Sstevel@tonic-gate 		return (set_errno(EINVAL));
234*0Sstevel@tonic-gate 	}
235*0Sstevel@tonic-gate 
236*0Sstevel@tonic-gate 	if ((addr & (nbytes - 1)) != 0) {
237*0Sstevel@tonic-gate 		if (dowarn) {
238*0Sstevel@tonic-gate 			warn("address for %llu-byte access must be %llu-byte "
239*0Sstevel@tonic-gate 			    "aligned\n", (u_longlong_t)nbytes,
240*0Sstevel@tonic-gate 			    (u_longlong_t)nbytes);
241*0Sstevel@tonic-gate 		}
242*0Sstevel@tonic-gate 		return (set_errno(EINVAL));
243*0Sstevel@tonic-gate 	}
244*0Sstevel@tonic-gate 
245*0Sstevel@tonic-gate 	return (0);
246*0Sstevel@tonic-gate }
247*0Sstevel@tonic-gate 
248*0Sstevel@tonic-gate /*ARGSUSED1*/
249*0Sstevel@tonic-gate int
250*0Sstevel@tonic-gate kmt_in_dcmd(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
251*0Sstevel@tonic-gate {
252*0Sstevel@tonic-gate 	uint64_t len = 0;
253*0Sstevel@tonic-gate 	uint32_t buf;
254*0Sstevel@tonic-gate 
255*0Sstevel@tonic-gate 	if (mdb_getopts(argc, argv,
256*0Sstevel@tonic-gate 	    'L', MDB_OPT_UINT64, &len,
257*0Sstevel@tonic-gate 	    NULL) != argc)
258*0Sstevel@tonic-gate 		return (DCMD_USAGE);
259*0Sstevel@tonic-gate 
260*0Sstevel@tonic-gate 	if (len == 0)
261*0Sstevel@tonic-gate 		len = mdb.m_dcount;
262*0Sstevel@tonic-gate 
263*0Sstevel@tonic-gate 	if (kmt_io_check(len, addr, IOCHECK_WARN) < 0)
264*0Sstevel@tonic-gate 		return (DCMD_ERR);
265*0Sstevel@tonic-gate 
266*0Sstevel@tonic-gate 	if (mdb_tgt_ioread(mdb.m_target, &buf, len, addr) < 0) {
267*0Sstevel@tonic-gate 		warn("failed to read from port 0x%llx", (u_longlong_t)addr);
268*0Sstevel@tonic-gate 		return (DCMD_ERR);
269*0Sstevel@tonic-gate 	}
270*0Sstevel@tonic-gate 
271*0Sstevel@tonic-gate 	mdb_printf("%x\n", buf);
272*0Sstevel@tonic-gate 
273*0Sstevel@tonic-gate 	return (DCMD_OK);
274*0Sstevel@tonic-gate }
275*0Sstevel@tonic-gate 
276*0Sstevel@tonic-gate /*ARGSUSED1*/
277*0Sstevel@tonic-gate int
278*0Sstevel@tonic-gate kmt_out_dcmd(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
279*0Sstevel@tonic-gate {
280*0Sstevel@tonic-gate 	uint64_t len = 0;
281*0Sstevel@tonic-gate 	uint64_t val;
282*0Sstevel@tonic-gate 
283*0Sstevel@tonic-gate 	if (mdb_getopts(argc, argv,
284*0Sstevel@tonic-gate 	    'L', MDB_OPT_UINT64, &len,
285*0Sstevel@tonic-gate 	    NULL) != argc - 1)
286*0Sstevel@tonic-gate 		return (DCMD_USAGE);
287*0Sstevel@tonic-gate 
288*0Sstevel@tonic-gate 	if (len == 0)
289*0Sstevel@tonic-gate 		len = mdb.m_dcount;
290*0Sstevel@tonic-gate 
291*0Sstevel@tonic-gate 	argv += argc - 1;
292*0Sstevel@tonic-gate 	if (argv->a_type == MDB_TYPE_STRING)
293*0Sstevel@tonic-gate 		val = mdb_strtoull(argv->a_un.a_str);
294*0Sstevel@tonic-gate 	else
295*0Sstevel@tonic-gate 		val = argv->a_un.a_val;
296*0Sstevel@tonic-gate 
297*0Sstevel@tonic-gate 	if (kmt_io_check(len, addr, IOCHECK_WARN) < 0)
298*0Sstevel@tonic-gate 		return (DCMD_ERR);
299*0Sstevel@tonic-gate 
300*0Sstevel@tonic-gate 	if (val > (1ULL << (len * NBBY)) - 1) {
301*0Sstevel@tonic-gate 		warn("value is out of range for port size\n");
302*0Sstevel@tonic-gate 		return (DCMD_ERR);
303*0Sstevel@tonic-gate 	}
304*0Sstevel@tonic-gate 
305*0Sstevel@tonic-gate 	if (mdb_tgt_iowrite(mdb.m_target, &val, len, addr) < 0) {
306*0Sstevel@tonic-gate 		warn("failed to write to port %llx", (u_longlong_t)addr);
307*0Sstevel@tonic-gate 		return (DCMD_ERR);
308*0Sstevel@tonic-gate 	}
309*0Sstevel@tonic-gate 
310*0Sstevel@tonic-gate 	return (DCMD_OK);
311*0Sstevel@tonic-gate }
312*0Sstevel@tonic-gate 
313*0Sstevel@tonic-gate static int
314*0Sstevel@tonic-gate kmt_rwmsr(uint32_t addr, uint64_t *valp, void (*rw)(uint32_t, uint64_t *))
315*0Sstevel@tonic-gate {
316*0Sstevel@tonic-gate 	jmp_buf pcb, *oldpcb = NULL;
317*0Sstevel@tonic-gate 
318*0Sstevel@tonic-gate 	if (setjmp(pcb) != 0) {
319*0Sstevel@tonic-gate 		kmdb_dpi_restore_fault_hdlr(oldpcb);
320*0Sstevel@tonic-gate 		return (-1); /* errno is set for us */
321*0Sstevel@tonic-gate 	}
322*0Sstevel@tonic-gate 
323*0Sstevel@tonic-gate 	oldpcb = kmdb_dpi_set_fault_hdlr(&pcb);
324*0Sstevel@tonic-gate 	rw(addr, valp);
325*0Sstevel@tonic-gate 	kmdb_dpi_restore_fault_hdlr(oldpcb);
326*0Sstevel@tonic-gate 
327*0Sstevel@tonic-gate 	return (0);
328*0Sstevel@tonic-gate }
329*0Sstevel@tonic-gate 
330*0Sstevel@tonic-gate /*ARGSUSED*/
331*0Sstevel@tonic-gate int
332*0Sstevel@tonic-gate kmt_rdmsr(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
333*0Sstevel@tonic-gate {
334*0Sstevel@tonic-gate 	uint64_t val;
335*0Sstevel@tonic-gate 
336*0Sstevel@tonic-gate 	if (!(flags & DCMD_ADDRSPEC))
337*0Sstevel@tonic-gate 		return (DCMD_USAGE);
338*0Sstevel@tonic-gate 
339*0Sstevel@tonic-gate 	if (kmt_rwmsr(addr, &val, rdmsr) < 0) {
340*0Sstevel@tonic-gate 		warn("rdmsr failed");
341*0Sstevel@tonic-gate 		return (DCMD_ERR);
342*0Sstevel@tonic-gate 	}
343*0Sstevel@tonic-gate 
344*0Sstevel@tonic-gate 	mdb_printf("%llx\n", (u_longlong_t)val);
345*0Sstevel@tonic-gate 
346*0Sstevel@tonic-gate 	return (DCMD_OK);
347*0Sstevel@tonic-gate }
348*0Sstevel@tonic-gate 
349*0Sstevel@tonic-gate /*ARGSUSED*/
350*0Sstevel@tonic-gate int
351*0Sstevel@tonic-gate kmt_wrmsr(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
352*0Sstevel@tonic-gate {
353*0Sstevel@tonic-gate 	uint64_t val;
354*0Sstevel@tonic-gate 
355*0Sstevel@tonic-gate 	if (!(flags & DCMD_ADDRSPEC) || argc != 1)
356*0Sstevel@tonic-gate 		return (DCMD_USAGE);
357*0Sstevel@tonic-gate 
358*0Sstevel@tonic-gate 	if (argv->a_type == MDB_TYPE_STRING)
359*0Sstevel@tonic-gate 		val = mdb_strtoull(argv->a_un.a_str);
360*0Sstevel@tonic-gate 	else
361*0Sstevel@tonic-gate 		val = argv->a_un.a_val;
362*0Sstevel@tonic-gate 
363*0Sstevel@tonic-gate 	if (kmt_rwmsr(addr, &val, wrmsr)) {
364*0Sstevel@tonic-gate 		warn("wrmsr failed");
365*0Sstevel@tonic-gate 		return (DCMD_ERR);
366*0Sstevel@tonic-gate 	}
367*0Sstevel@tonic-gate 
368*0Sstevel@tonic-gate 	return (DCMD_OK);
369*0Sstevel@tonic-gate }
370*0Sstevel@tonic-gate 
371*0Sstevel@tonic-gate int
372*0Sstevel@tonic-gate kmt_msr_validate(const kmdb_msr_t *msr)
373*0Sstevel@tonic-gate {
374*0Sstevel@tonic-gate 	uint64_t val;
375*0Sstevel@tonic-gate 
376*0Sstevel@tonic-gate 	for (/* */; msr->msr_num != 0; msr++) {
377*0Sstevel@tonic-gate 		if (kmt_rwmsr(msr->msr_num, &val, rdmsr) < 0)
378*0Sstevel@tonic-gate 			return (0);
379*0Sstevel@tonic-gate 	}
380*0Sstevel@tonic-gate 
381*0Sstevel@tonic-gate 	return (1);
382*0Sstevel@tonic-gate }
383*0Sstevel@tonic-gate 
384*0Sstevel@tonic-gate /*ARGSUSED*/
385*0Sstevel@tonic-gate ssize_t
386*0Sstevel@tonic-gate kmt_write(mdb_tgt_t *t, const void *buf, size_t nbytes, uintptr_t addr)
387*0Sstevel@tonic-gate {
388*0Sstevel@tonic-gate 	if (!(t->t_flags & MDB_TGT_F_ALLOWIO) &&
389*0Sstevel@tonic-gate 	    (nbytes = kmdb_kdi_range_is_nontoxic(addr, nbytes, 1)) == 0)
390*0Sstevel@tonic-gate 		return (set_errno(EMDB_NOMAP));
391*0Sstevel@tonic-gate 
392*0Sstevel@tonic-gate 	return (kmt_rw(t, (void *)buf, nbytes, addr, kmt_writer));
393*0Sstevel@tonic-gate }
394*0Sstevel@tonic-gate 
395*0Sstevel@tonic-gate /*ARGSUSED*/
396*0Sstevel@tonic-gate static ssize_t
397*0Sstevel@tonic-gate kmt_iorw(mdb_tgt_t *t, void *buf, size_t nbytes, uint64_t addr,
398*0Sstevel@tonic-gate     void (*iorw)(void *, size_t, uintptr_t))
399*0Sstevel@tonic-gate {
400*0Sstevel@tonic-gate 	jmp_buf pcb, *oldpcb = NULL;
401*0Sstevel@tonic-gate 
402*0Sstevel@tonic-gate 	if (kmt_io_check(nbytes, addr, IOCHECK_NOWARN) < 0)
403*0Sstevel@tonic-gate 		return (-1); /* errno is set for us */
404*0Sstevel@tonic-gate 
405*0Sstevel@tonic-gate 	if (setjmp(pcb) != 0) {
406*0Sstevel@tonic-gate 		kmdb_dpi_restore_fault_hdlr(oldpcb);
407*0Sstevel@tonic-gate 		return (-1); /* errno is set for us */
408*0Sstevel@tonic-gate 	}
409*0Sstevel@tonic-gate 
410*0Sstevel@tonic-gate 	oldpcb = kmdb_dpi_set_fault_hdlr(&pcb);
411*0Sstevel@tonic-gate 	iorw(buf, nbytes, addr);
412*0Sstevel@tonic-gate 	kmdb_dpi_restore_fault_hdlr(oldpcb);
413*0Sstevel@tonic-gate 
414*0Sstevel@tonic-gate 	return (nbytes);
415*0Sstevel@tonic-gate }
416*0Sstevel@tonic-gate 
417*0Sstevel@tonic-gate /*ARGSUSED*/
418*0Sstevel@tonic-gate ssize_t
419*0Sstevel@tonic-gate kmt_ioread(mdb_tgt_t *t, void *buf, size_t nbytes, uintptr_t addr)
420*0Sstevel@tonic-gate {
421*0Sstevel@tonic-gate 	return (kmt_iorw(t, buf, nbytes, addr, kmt_in));
422*0Sstevel@tonic-gate }
423*0Sstevel@tonic-gate 
424*0Sstevel@tonic-gate /*ARGSUSED*/
425*0Sstevel@tonic-gate ssize_t
426*0Sstevel@tonic-gate kmt_iowrite(mdb_tgt_t *t, const void *buf, size_t nbytes, uintptr_t addr)
427*0Sstevel@tonic-gate {
428*0Sstevel@tonic-gate 	return (kmt_iorw(t, (void *)buf, nbytes, addr, kmt_out));
429*0Sstevel@tonic-gate }
430*0Sstevel@tonic-gate 
431*0Sstevel@tonic-gate const char *
432*0Sstevel@tonic-gate kmt_trapname(int trapnum)
433*0Sstevel@tonic-gate {
434*0Sstevel@tonic-gate 	static char trapname[11];
435*0Sstevel@tonic-gate 
436*0Sstevel@tonic-gate 	switch (trapnum) {
437*0Sstevel@tonic-gate 	case T_ZERODIV:
438*0Sstevel@tonic-gate 		return ("division by zero (#de) trap");
439*0Sstevel@tonic-gate 	case T_SGLSTP:
440*0Sstevel@tonic-gate 		return ("single-step (#db) trap");
441*0Sstevel@tonic-gate 	case T_NMIFLT:
442*0Sstevel@tonic-gate 		return ("NMI");
443*0Sstevel@tonic-gate 	case T_BPTFLT:
444*0Sstevel@tonic-gate 		return ("breakpoint (#bp) trap");
445*0Sstevel@tonic-gate 	case T_ILLINST:
446*0Sstevel@tonic-gate 		return ("illegal instruction (#ud) trap");
447*0Sstevel@tonic-gate 	case T_SEGFLT:
448*0Sstevel@tonic-gate 		return ("segment not present (#np) trap");
449*0Sstevel@tonic-gate 	case T_STKFLT:
450*0Sstevel@tonic-gate 		return ("stack (#ss) trap");
451*0Sstevel@tonic-gate 	case T_GPFLT:
452*0Sstevel@tonic-gate 		return ("general protection (#gp) trap");
453*0Sstevel@tonic-gate 	case T_PGFLT:
454*0Sstevel@tonic-gate 		return ("page fault (#pf) trap");
455*0Sstevel@tonic-gate 	case T_ALIGNMENT:
456*0Sstevel@tonic-gate 		return ("alignment check (#ac) trap");
457*0Sstevel@tonic-gate 	case T_MCE:
458*0Sstevel@tonic-gate 		return ("machine check (#mc) trap");
459*0Sstevel@tonic-gate 	case T_SIMDFPE:
460*0Sstevel@tonic-gate 		return ("SSE/SSE2 (#xm) trap");
461*0Sstevel@tonic-gate 	case T_DBGENTR:
462*0Sstevel@tonic-gate 		return ("debugger entry trap");
463*0Sstevel@tonic-gate 	default:
464*0Sstevel@tonic-gate 		(void) mdb_snprintf(trapname, sizeof (trapname), "trap %#x",
465*0Sstevel@tonic-gate 		    trapnum);
466*0Sstevel@tonic-gate 		return (trapname);
467*0Sstevel@tonic-gate 	}
468*0Sstevel@tonic-gate }
469*0Sstevel@tonic-gate 
470*0Sstevel@tonic-gate void
471*0Sstevel@tonic-gate kmt_init_isadep(mdb_tgt_t *t)
472*0Sstevel@tonic-gate {
473*0Sstevel@tonic-gate 	kmt_data_t *kmt = t->t_data;
474*0Sstevel@tonic-gate 
475*0Sstevel@tonic-gate 	kmt->kmt_rds = mdb_isa_kregs;
476*0Sstevel@tonic-gate 
477*0Sstevel@tonic-gate 	kmt->kmt_trapmax = KMT_MAXTRAPNO;
478*0Sstevel@tonic-gate 	kmt->kmt_trapmap = mdb_zalloc(BT_SIZEOFMAP(kmt->kmt_trapmax), UM_SLEEP);
479*0Sstevel@tonic-gate 
480*0Sstevel@tonic-gate 	/* Traps for which we want to provide an explicit message */
481*0Sstevel@tonic-gate 	(void) mdb_tgt_add_fault(t, T_ZERODIV, MDB_TGT_SPEC_INTERNAL,
482*0Sstevel@tonic-gate 	    no_se_f, NULL);
483*0Sstevel@tonic-gate 	(void) mdb_tgt_add_fault(t, T_ILLINST, MDB_TGT_SPEC_INTERNAL,
484*0Sstevel@tonic-gate 	    no_se_f, NULL);
485*0Sstevel@tonic-gate 	(void) mdb_tgt_add_fault(t, T_SEGFLT, MDB_TGT_SPEC_INTERNAL,
486*0Sstevel@tonic-gate 	    no_se_f, NULL);
487*0Sstevel@tonic-gate 	(void) mdb_tgt_add_fault(t, T_STKFLT, MDB_TGT_SPEC_INTERNAL,
488*0Sstevel@tonic-gate 	    no_se_f, NULL);
489*0Sstevel@tonic-gate 	(void) mdb_tgt_add_fault(t, T_GPFLT, MDB_TGT_SPEC_INTERNAL,
490*0Sstevel@tonic-gate 	    no_se_f, NULL);
491*0Sstevel@tonic-gate 	(void) mdb_tgt_add_fault(t, T_PGFLT, MDB_TGT_SPEC_INTERNAL,
492*0Sstevel@tonic-gate 	    no_se_f, NULL);
493*0Sstevel@tonic-gate 	(void) mdb_tgt_add_fault(t, T_ALIGNMENT, MDB_TGT_SPEC_INTERNAL,
494*0Sstevel@tonic-gate 	    no_se_f, NULL);
495*0Sstevel@tonic-gate 	(void) mdb_tgt_add_fault(t, T_MCE, MDB_TGT_SPEC_INTERNAL,
496*0Sstevel@tonic-gate 	    no_se_f, NULL);
497*0Sstevel@tonic-gate 	(void) mdb_tgt_add_fault(t, T_SIMDFPE, MDB_TGT_SPEC_INTERNAL,
498*0Sstevel@tonic-gate 	    no_se_f, NULL);
499*0Sstevel@tonic-gate 
500*0Sstevel@tonic-gate 	/*
501*0Sstevel@tonic-gate 	 * Traps which will be handled elsewhere, and which therefore don't
502*0Sstevel@tonic-gate 	 * need the trap-based message.
503*0Sstevel@tonic-gate 	 */
504*0Sstevel@tonic-gate 	BT_SET(kmt->kmt_trapmap, T_SGLSTP);
505*0Sstevel@tonic-gate 	BT_SET(kmt->kmt_trapmap, T_BPTFLT);
506*0Sstevel@tonic-gate 	BT_SET(kmt->kmt_trapmap, T_DBGENTR);
507*0Sstevel@tonic-gate 
508*0Sstevel@tonic-gate 	/* Catch-all for traps not explicitly listed here */
509*0Sstevel@tonic-gate 	(void) mdb_tgt_add_fault(t, KMT_TRAP_NOTENUM, MDB_TGT_SPEC_INTERNAL,
510*0Sstevel@tonic-gate 	    no_se_f, NULL);
511*0Sstevel@tonic-gate }
512*0Sstevel@tonic-gate 
513*0Sstevel@tonic-gate void
514*0Sstevel@tonic-gate kmt_startup_isadep(mdb_tgt_t *t)
515*0Sstevel@tonic-gate {
516*0Sstevel@tonic-gate 	kmt_data_t *kmt = t->t_data;
517*0Sstevel@tonic-gate 
518*0Sstevel@tonic-gate 	/*
519*0Sstevel@tonic-gate 	 * The stack trace and ::step out code need to detect "interrupt"
520*0Sstevel@tonic-gate 	 * frames.  The heuristic they use to detect said frames requires the
521*0Sstevel@tonic-gate 	 * addresses of routines that can generate them.
522*0Sstevel@tonic-gate 	 */
523*0Sstevel@tonic-gate 	(void) mdb_tgt_lookup_by_name(t, MDB_TGT_OBJ_EXEC,
524*0Sstevel@tonic-gate 	    "cmnint", &kmt->kmt_intrsyms._kmt_cmnint, NULL);
525*0Sstevel@tonic-gate 	(void) mdb_tgt_lookup_by_name(t, MDB_TGT_OBJ_EXEC,
526*0Sstevel@tonic-gate 	    "cmntrap", &kmt->kmt_intrsyms._kmt_cmntrap, NULL);
527*0Sstevel@tonic-gate 	(void) mdb_tgt_lookup_by_name(t, MDB_TGT_OBJ_EXEC,
528*0Sstevel@tonic-gate 	    "sys_sysenter", &kmt->kmt_intrsyms._kmt_sysenter, NULL);
529*0Sstevel@tonic-gate #if defined(__amd64)
530*0Sstevel@tonic-gate 	(void) mdb_tgt_lookup_by_name(t, MDB_TGT_OBJ_EXEC,
531*0Sstevel@tonic-gate 	    "sys_syscall", &kmt->kmt_intrsyms._kmt_syscall, NULL);
532*0Sstevel@tonic-gate #endif
533*0Sstevel@tonic-gate }
534