xref: /illumos-gate/usr/src/cmd/mdb/intel/kmdb/kvm_isadep.c (revision 1a220b56b93ff1dc80855691548503117af4cc10)
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 
55 const char *
56 kmt_def_dismode(void)
57 {
58 #ifdef	__amd64
59 	return ("amd64");
60 #else
61 	return ("ia32");
62 #endif
63 }
64 
65 int
66 kmt_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  */
84 int
85 kmt_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 
104 int
105 kmt_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  */
116 int
117 kmt_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  */
137 int
138 mdb_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*/
152 static int
153 kmt_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 
187 int
188 kmt_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 
195 int
196 kmt_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 
202 int
203 kmt_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 
209 int
210 kmt_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*/
217 void
218 kmt_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 
226 static int
227 kmt_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*/
254 int
255 kmt_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 
281 static uint64_t
282 kmt_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*/
291 int
292 kmt_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 
324 static int
325 kmt_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*/
342 int
343 kmt_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*/
361 int
362 kmt_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 
379 int
380 kmt_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*/
393 ssize_t
394 kmt_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*/
414 static ssize_t
415 kmt_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*/
436 ssize_t
437 kmt_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*/
443 ssize_t
444 kmt_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 
449 static int
450 kmt_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*/
499 int
500 kmt_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*/
516 int
517 kmt_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 
532 const char *
533 kmt_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 
571 void
572 kmt_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 
614 void
615 kmt_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 #if defined(__amd64)
631 	(void) mdb_tgt_lookup_by_name(t, MDB_TGT_OBJ_EXEC,
632 	    "sys_syscall", &kmt->kmt_intrsyms._kmt_syscall, NULL);
633 #endif
634 }
635