Mercurial > illumos > onarm
annotate usr/src/cmd/mdb/intel/kmdb/kvm_cpu_p4.c @ 4:1a15d5aaf794
synchronized with onnv_86 (6202) in onnv-gate
author | Koji Uno <koji.uno@sun.com> |
---|---|
date | Mon, 31 Aug 2009 14:38:03 +0900 |
parents | c9caec207d52 |
children |
rev | line source |
---|---|
0 | 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 | |
4
1a15d5aaf794
synchronized with onnv_86 (6202) in onnv-gate
Koji Uno <koji.uno@sun.com>
parents:
0
diff
changeset
|
26 #pragma ident "%Z%%M% %I% %E% SMI" |
0 | 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 } |