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