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