xref: /onnv-gate/usr/src/cmd/mdb/intel/kmdb/kvm_cpu_p4.c (revision 3446:5903aece022d)
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 2007 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  * This plugin supports debugging functionality unique to Intel processors based
30  * on the NetBurst (P4) microarchitecture.  It also supports the Pentium M, a
31  * processor which uses the P6 family code but provides a P4-style branch
32  * tracing stack.
33  */
34 
35 #include <kmdb/kvm_cpu_impl.h>
36 #include <kmdb/kmdb_dpi.h>
37 #include <kmdb/kmdb_kdi.h>
38 #include <kmdb/kvm.h>
39 #include <mdb/mdb_err.h>
40 #include <mdb/mdb_debug.h>
41 #include <mdb/mdb.h>
42 
43 #include <sys/x86_archext.h>
44 
45 /*
46  * As of this writing, Intel has three different flavors of branch stack.
47  * They're essentially the same, but the MSR addresses, stack size, and access
48  * methods differ.  We've got one kmt_p4_flavor_t for each type of branch
49  * stack.
50  */
51 typedef struct kmt_p4_flavor {
52 	const char *p4f_name;			/* name for CPU support */
53 	const kdi_msr_t *p4f_msrs;		/* MSR r/w list */
54 	int (*p4f_branches)(const struct kmt_p4_flavor *, uint_t,
55 	    intptr_t, int);			/* dumper for CPU branch stk */
56 	uint_t p4f_msr_tos;			/* branch stk index MSR */
57 	uint_t p4f_lbrstk_from_base;		/* low "from" branch stk MSR */
58 	uint_t p4f_lbrstk_to_base;		/* low "to" branch stk MSR */
59 	size_t p4f_lbrstk_num;			/* number of entries in stk */
60 } kmt_p4_flavor_t;
61 
62 typedef struct kmt_cpu_p4 {
63 	uint64_t p4_debugctl;			/* value for debugctl MSR */
64 	const kmt_p4_flavor_t *p4_flavor;	/* parameters for this proc */
65 	uint_t p4_model;			/* CPUID model */
66 } kmt_cpu_p4_t;
67 
68 /* See 07/04 AP-485 Intel Processor Identification and the CPUID Instruction */
69 #define	KMT_CPU_FAMILY_P6	0x6	/* For this plugin, the Pentium M */
70 #define	KMT_CPU_FAMILY_P4	0xf	/* "Netburst" CPUs (P4s) */
71 #define	KMT_CPU_MODEL_PM_9	0x9	/* Pentium M, model 9 */
72 #define	KMT_CPU_MODEL_PM_D	0xd	/* Pentium M, model d */
73 
74 
75 static kmt_cpu_p4_t kmt_cpu_p4;
76 
77 static void
78 kmt_p4_branch(uintptr_t from, uintptr_t to, int verbose)
79 {
80 	if (verbose) {
81 		uintptr_t addr = mdb_dis_previns(mdb.m_disasm, mdb.m_target,
82 		    MDB_TGT_AS_VIRT, from, 3);
83 
84 		mdb_printf("%<b>%-39a %-39a%</b>\n", from, to);
85 
86 		while (addr <= from) {
87 			char buf[80];
88 			uintptr_t next;
89 			char *c;
90 
91 			if ((next = mdb_dis_ins2str(mdb.m_disasm, mdb.m_target,
92 			    MDB_TGT_AS_VIRT, buf, sizeof (buf), addr)) == addr)
93 				strcpy(buf, "???");
94 
95 			for (c = buf + strlen(buf) - 1;
96 			    c > buf && (*c == ' ' || *c == '\t');
97 			    c--);
98 
99 			if (*c == '>') {
100 				while (c > buf && *c != '<')
101 					c--;
102 
103 				if (*c == '<')
104 					*c = '\0';
105 			}
106 
107 			if (addr == from) {
108 				mdb_printf("\t%<b>%-#32a%8T%s%</b>\n",
109 				    addr, buf);
110 			} else {
111 				mdb_printf("\t%-#32a%8T%s\n", addr, buf);
112 			}
113 
114 			if (next == addr)
115 				break;
116 
117 			addr = next;
118 		}
119 		mdb_printf("\n");
120 	} else {
121 		mdb_printf("%-39a %-39a\n", from, to);
122 	}
123 }
124 
125 #ifndef __amd64
126 static int
127 kmt_p4_branches_unified(const kmt_p4_flavor_t *p4f, uint_t tos, intptr_t cpuid,
128     int verbose)
129 {
130 	uint_t cur;
131 	int i;
132 
133 	for (cur = tos, i = 0; i < p4f->p4f_lbrstk_num;
134 	    i++, cur = (cur + p4f->p4f_lbrstk_num - 1) % p4f->p4f_lbrstk_num) {
135 		uint64_t rec = kmdb_dpi_msr_get_by_cpu(cpuid,
136 		    p4f->p4f_lbrstk_from_base + cur);
137 
138 		kmt_p4_branch((rec & 0xffffffff), rec >> 32, verbose);
139 	}
140 
141 	return (0);
142 }
143 #endif	/* !__amd64 */
144 
145 static int
146 kmt_p4_branches_split(const kmt_p4_flavor_t *p4f, uint_t tos, intptr_t cpuid,
147     int verbose)
148 {
149 	uint_t cur;
150 	int i;
151 
152 	for (cur = tos, i = 0; i < p4f->p4f_lbrstk_num;
153 	    i++, cur = (cur + p4f->p4f_lbrstk_num - 1) % p4f->p4f_lbrstk_num) {
154 		uintptr_t from = (uintptr_t)kmdb_dpi_msr_get_by_cpu(cpuid,
155 		    p4f->p4f_lbrstk_from_base + cur);
156 		uintptr_t to = (uintptr_t)kmdb_dpi_msr_get_by_cpu(cpuid,
157 		    p4f->p4f_lbrstk_to_base + cur);
158 
159 		kmt_p4_branch(from, to, verbose);
160 	}
161 
162 	return (0);
163 }
164 
165 #ifndef __amd64
166 static const kdi_msr_t kmt_p4orig_msrs[] = {
167 	{ MSR_DEBUGCTL,		KDI_MSR_CLEARENTRY },
168 	{ MSR_DEBUGCTL,		KDI_MSR_WRITEDELAY, &kmt_cpu_p4.p4_debugctl },
169 	{ MSR_P4_LBSTK_TOS,	KDI_MSR_READ },
170 	{ MSR_P4_LBSTK_0,	KDI_MSR_READ },
171 	{ MSR_P4_LBSTK_1,	KDI_MSR_READ },
172 	{ MSR_P4_LBSTK_2,	KDI_MSR_READ },
173 	{ MSR_P4_LBSTK_3,	KDI_MSR_READ },
174 	{ NULL }
175 };
176 
177 static const kmt_p4_flavor_t kmt_p4_original = {
178 	"Intel Pentium 4 (pre-Prescott)",
179 	kmt_p4orig_msrs, kmt_p4_branches_unified, MSR_P4_LBSTK_TOS,
180 	MSR_P4_LBSTK_0, MSR_P4_LBSTK_0, 4
181 };
182 
183 static const kdi_msr_t kmt_p6m_msrs[] = {
184 	{ MSR_DEBUGCTL,		KDI_MSR_CLEARENTRY },
185 	{ MSR_DEBUGCTL,		KDI_MSR_WRITEDELAY, &kmt_cpu_p4.p4_debugctl },
186 	{ MSR_P6M_LBSTK_TOS,	KDI_MSR_READ },
187 	{ MSR_P6M_LBSTK_0,	KDI_MSR_READ },
188 	{ MSR_P6M_LBSTK_1,	KDI_MSR_READ },
189 	{ MSR_P6M_LBSTK_2,	KDI_MSR_READ },
190 	{ MSR_P6M_LBSTK_3,	KDI_MSR_READ },
191 	{ MSR_P6M_LBSTK_4,	KDI_MSR_READ },
192 	{ MSR_P6M_LBSTK_5,	KDI_MSR_READ },
193 	{ MSR_P6M_LBSTK_6,	KDI_MSR_READ },
194 	{ MSR_P6M_LBSTK_7,	KDI_MSR_READ },
195 	{ NULL }
196 };
197 
198 static const kmt_p4_flavor_t kmt_p6_m = {
199 	"Intel Pentium M",
200 	kmt_p6m_msrs, kmt_p4_branches_unified, MSR_P6M_LBSTK_TOS,
201 	MSR_P6M_LBSTK_0, MSR_P6M_LBSTK_0, 8
202 };
203 #endif	/* __amd64 */
204 
205 static const kdi_msr_t kmt_prp4_msrs[] = {
206 	{ MSR_DEBUGCTL,		KDI_MSR_CLEARENTRY },
207 	{ MSR_DEBUGCTL,		KDI_MSR_WRITEDELAY, &kmt_cpu_p4.p4_debugctl },
208 	{ MSR_PRP4_LBSTK_TOS,	KDI_MSR_READ },
209 	{ MSR_PRP4_LBSTK_FROM_0, KDI_MSR_READ },
210 	{ MSR_PRP4_LBSTK_FROM_1, KDI_MSR_READ },
211 	{ MSR_PRP4_LBSTK_FROM_2, KDI_MSR_READ },
212 	{ MSR_PRP4_LBSTK_FROM_3, KDI_MSR_READ },
213 	{ MSR_PRP4_LBSTK_FROM_4, KDI_MSR_READ },
214 	{ MSR_PRP4_LBSTK_FROM_5, KDI_MSR_READ },
215 	{ MSR_PRP4_LBSTK_FROM_6, KDI_MSR_READ },
216 	{ MSR_PRP4_LBSTK_FROM_7, KDI_MSR_READ },
217 	{ MSR_PRP4_LBSTK_FROM_8, KDI_MSR_READ },
218 	{ MSR_PRP4_LBSTK_FROM_9, KDI_MSR_READ },
219 	{ MSR_PRP4_LBSTK_FROM_10, KDI_MSR_READ },
220 	{ MSR_PRP4_LBSTK_FROM_11, KDI_MSR_READ },
221 	{ MSR_PRP4_LBSTK_FROM_12, KDI_MSR_READ },
222 	{ MSR_PRP4_LBSTK_FROM_13, KDI_MSR_READ },
223 	{ MSR_PRP4_LBSTK_FROM_14, KDI_MSR_READ },
224 	{ MSR_PRP4_LBSTK_FROM_15, KDI_MSR_READ },
225 	{ MSR_PRP4_LBSTK_TO_0,	KDI_MSR_READ },
226 	{ MSR_PRP4_LBSTK_TO_1,	KDI_MSR_READ },
227 	{ MSR_PRP4_LBSTK_TO_2,	KDI_MSR_READ },
228 	{ MSR_PRP4_LBSTK_TO_3,	KDI_MSR_READ },
229 	{ MSR_PRP4_LBSTK_TO_4,	KDI_MSR_READ },
230 	{ MSR_PRP4_LBSTK_TO_5,	KDI_MSR_READ },
231 	{ MSR_PRP4_LBSTK_TO_6,	KDI_MSR_READ },
232 	{ MSR_PRP4_LBSTK_TO_7,	KDI_MSR_READ },
233 	{ MSR_PRP4_LBSTK_TO_8,	KDI_MSR_READ },
234 	{ MSR_PRP4_LBSTK_TO_9,	KDI_MSR_READ },
235 	{ MSR_PRP4_LBSTK_TO_10,	KDI_MSR_READ },
236 	{ MSR_PRP4_LBSTK_TO_11,	KDI_MSR_READ },
237 	{ MSR_PRP4_LBSTK_TO_12,	KDI_MSR_READ },
238 	{ MSR_PRP4_LBSTK_TO_13,	KDI_MSR_READ },
239 	{ MSR_PRP4_LBSTK_TO_14,	KDI_MSR_READ },
240 	{ MSR_PRP4_LBSTK_TO_15,	KDI_MSR_READ },
241 	{ NULL }
242 };
243 
244 static const kmt_p4_flavor_t kmt_p4_prescott = {
245 	"Intel Pentium 4 (Prescott)",
246 	kmt_prp4_msrs, kmt_p4_branches_split, MSR_PRP4_LBSTK_TOS,
247 	MSR_PRP4_LBSTK_FROM_0, MSR_PRP4_LBSTK_TO_0, 16
248 };
249 
250 static const kdi_msr_t kmt_p4unk_msrs[] = {
251 	{ MSR_DEBUGCTL,		KDI_MSR_CLEARENTRY },
252 	{ MSR_DEBUGCTL,		KDI_MSR_WRITEDELAY, &kmt_cpu_p4.p4_debugctl },
253 	{ NULL }
254 };
255 
256 static const kmt_p4_flavor_t kmt_p4_unknown = {
257 	"Unrecognized Intel Pentium 4",
258 	kmt_p4unk_msrs, NULL, 0,
259 	0, 0, 0
260 };
261 
262 /*ARGSUSED*/
263 static void
264 kmt_p4_destroy(kmt_cpu_t *cpu)
265 {
266 	/* Leave LBR on */
267 
268 	mdb_free(cpu, sizeof (kmt_cpu_t));
269 }
270 
271 /*ARGSUSED*/
272 static const char *
273 kmt_p4_name(kmt_cpu_t *cpu)
274 {
275 	return (kmt_cpu_p4.p4_flavor->p4f_name);
276 }
277 
278 /*ARGSUSED*/
279 static void
280 kmt_p4_btf_clear(mdb_tgt_t *t, int id, void *arg)
281 {
282 	kmt_cpu_p4_t *p4 = arg;
283 	kreg_t efl;
284 
285 	p4->p4_debugctl &= ~DEBUGCTL_BTF;
286 
287 	(void) kmdb_dpi_get_register("eflags", &efl);
288 	efl &= ~(1 << KREG_EFLAGS_TF_SHIFT);
289 	(void) kmdb_dpi_set_register("eflags", efl);
290 }
291 
292 static int
293 kmt_p4_step_branch(kmt_cpu_t *cpu, mdb_tgt_t *t)
294 {
295 	kmt_cpu_p4_t *p4 = cpu->kmt_cpu_data;
296 	kreg_t efl;
297 
298 	(void) kmdb_dpi_get_register("eflags", &efl);
299 	(void) kmdb_dpi_set_register("eflags",
300 	    (efl | (1 << KREG_EFLAGS_TF_SHIFT)));
301 
302 	p4->p4_debugctl |= DEBUGCTL_BTF;
303 
304 	return (mdb_tgt_add_fault(t, KMT_TRAP_ALL,
305 	    MDB_TGT_SPEC_HIDDEN | MDB_TGT_SPEC_TEMPORARY,
306 	    kmt_p4_btf_clear, p4));
307 }
308 
309 static kmt_cpu_ops_t kmt_p4_ops = {
310 	kmt_p4_destroy,
311 	kmt_p4_name,
312 	kmt_p4_step_branch
313 };
314 
315 /*ARGSUSED*/
316 static int
317 kmt_p4_branches(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
318 {
319 	const kmt_p4_flavor_t *p4f = kmt_cpu_p4.p4_flavor;
320 	intptr_t cpuid = DPI_MASTER_CPUID;
321 	uint_t tos;
322 	int verbose = FALSE;
323 
324 	if (p4f->p4f_branches == NULL) {
325 		warn("branch tracing unavailable on unknown P4 CPU "
326 		    "(model %x)\n", kmt_cpu_p4.p4_model);
327 		return (DCMD_ERR);
328 	}
329 
330 	if (mdb_getopts(argc, argv,
331 	    'c', MDB_OPT_UINTPTR, &cpuid,
332 	    'v', MDB_OPT_SETBITS, TRUE, &verbose,
333 	    NULL) != argc)
334 		return (DCMD_USAGE);
335 
336 	ASSERT(!(p4f->p4f_lbrstk_num & (p4f->p4f_lbrstk_num - 1)));
337 
338 	tos = (uintptr_t)kmdb_dpi_msr_get_by_cpu(cpuid, p4f->p4f_msr_tos);
339 	tos &= p4f->p4f_lbrstk_num - 1;
340 
341 	mdb_printf("%<u>%-39s %-39s%</u>\n", "FROM", "TO");
342 
343 	return (p4f->p4f_branches(p4f, tos, cpuid, verbose));
344 }
345 
346 static const mdb_dcmd_t kmt_p4_dcmds[] = {
347 	{ "branches", NULL, "describe the recently-taken branches",
348 	    kmt_p4_branches },
349 	{ NULL }
350 };
351 
352 /*ARGSUSED*/
353 const kmt_p4_flavor_t *
354 cpu2flavor(uint_t vendor, uint_t family, uint_t model)
355 {
356 	if (vendor != X86_VENDOR_Intel)
357 		return (NULL);
358 
359 #ifndef __amd64
360 	if (family == KMT_CPU_FAMILY_P6) {
361 		if (model == KMT_CPU_MODEL_PM_9 || model == KMT_CPU_MODEL_PM_D)
362 			return (&kmt_p6_m);
363 		else
364 			return (NULL);
365 	}
366 
367 	if (family == KMT_CPU_FAMILY_P4 && model < 3)
368 		return (&kmt_p4_original);
369 #endif	/* !__amd64 */
370 
371 	if (family == KMT_CPU_FAMILY_P4) {
372 		/*
373 		 * If this is a model 3, then we've got a Prescott.  On the
374 		 * other hand, this could be the future, and Intel could have
375 		 * released a whizzy new processor.  Users shouldn't have to
376 		 * wait for us to patch the debugger for each new P4 model,
377 		 * so we'll try to use this CPU as a Prescott.  In the past,
378 		 * when Intel has changed the branch stack, they've done it by
379 		 * moving the MSRs, returning #gp's for the old ones.  Our
380 		 * Prescott check will therefore be an attempt to read the
381 		 * Prescott MSRs.  This attempt should fail if Intel has changed
382 		 * the branch stack again.
383 		 */
384 		if (kmt_msr_validate(kmt_prp4_msrs))
385 			return (&kmt_p4_prescott);
386 		else
387 			return (&kmt_p4_unknown);
388 	}
389 
390 	return (NULL);
391 }
392 
393 kmt_cpu_t *
394 kmt_cpu_p4_create(mdb_tgt_t *t)
395 {
396 	uint_t vendor, family, model;
397 	kmt_cpu_t *cpu;
398 
399 	if (kmdb_kdi_get_cpuinfo(&vendor, &family, &model) < 0)
400 		return (NULL); /* errno is set for us */
401 
402 	if ((kmt_cpu_p4.p4_flavor = cpu2flavor(vendor, family, model)) ==
403 	    NULL) {
404 		(void) set_errno(ENOTSUP);
405 		return (NULL);
406 	}
407 
408 	kmt_cpu_p4.p4_model = model;
409 	kmt_cpu_p4.p4_debugctl = DEBUGCTL_LBR; /* enable LBR on resume */
410 
411 	cpu = mdb_zalloc(sizeof (kmt_cpu_t), UM_SLEEP);
412 	cpu->kmt_cpu_ops = &kmt_p4_ops;
413 	cpu->kmt_cpu_data = &kmt_cpu_p4;
414 
415 	kmdb_dpi_msr_add(kmt_cpu_p4.p4_flavor->p4f_msrs);
416 	(void) mdb_tgt_register_dcmds(t, kmt_p4_dcmds, MDB_MOD_FORCE);
417 
418 	return (cpu);
419 }
420