2 * Copyright (c) 2000-2006 Apple Computer, Inc. All rights reserved.
4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. The rights granted to you under the License
10 * may not be used to create, or enable the creation or redistribution of,
11 * unlawful or unlicensed copies of an Apple operating system, or to
12 * circumvent, violate, or enable the circumvention or violation of, any
13 * terms of an Apple operating system software license agreement.
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
18 * The Original Code and all software distributed under the License are
19 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
20 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
22 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
23 * Please see the License for the specific language governing rights and
24 * limitations under the License.
26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
31 #include <platforms.h>
33 #include <vm/vm_page.h>
34 #include <pexpert/pexpert.h>
38 #include <i386/db_machdep.h>
39 #include <ddb/db_aout.h>
40 #include <ddb/db_access.h>
41 #include <ddb/db_sym.h>
42 #include <ddb/db_variables.h>
43 #include <ddb/db_command.h>
44 #include <ddb/db_output.h>
45 #include <ddb/db_expr.h>
48 #define min(a,b) ((a) < (b) ? (a) : (b))
49 #define quad(hi,lo) (((uint64_t)(hi)) << 32 | (lo))
51 #define bit(n) (1UL << (n))
52 #define bitmask(h,l) ((bit(h)|(bit(h)-1)) & ~(bit(l)-1))
53 #define bitfield(x,h,l) (((x) & bitmask(h,l)) >> l)
56 * CPU identification routines.
59 static i386_cpu_info_t
*cpuid_cpu_infop
= NULL
;
60 static i386_cpu_info_t cpuid_cpu_info
;
62 /* this function is Intel-specific */
64 cpuid_set_cache_info( i386_cpu_info_t
* info_p
)
66 uint32_t cpuid_result
[4];
69 uint32_t linesizes
[LCACHE_MAX
];
72 boolean_t cpuid_deterministic_supported
= FALSE
;
74 bzero( linesizes
, sizeof(linesizes
) );
76 /* Get processor cache descriptor info using leaf 2. We don't use
77 * this internally, but must publish it for KEXTs.
79 do_cpuid(2, cpuid_result
);
80 for (j
= 0; j
< 4; j
++) {
81 if ((cpuid_result
[j
] >> 31) == 1) /* bit31 is validity */
83 ((uint32_t *) info_p
->cache_info
)[j
] = cpuid_result
[j
];
85 /* first byte gives number of cpuid calls to get all descriptors */
86 for (i
= 1; i
< info_p
->cache_info
[0]; i
++) {
87 if (i
*16 > sizeof(info_p
->cache_info
))
89 do_cpuid(2, cpuid_result
);
90 for (j
= 0; j
< 4; j
++) {
91 if ((cpuid_result
[j
] >> 31) == 1)
93 ((uint32_t *) info_p
->cache_info
)[4*i
+j
] =
99 * Get cache info using leaf 4, the "deterministic cache parameters."
100 * Most processors Mac OS X supports implement this flavor of CPUID.
101 * Loop over each cache on the processor.
103 do_cpuid(0, cpuid_result
);
104 if (cpuid_result
[eax
] >= 4)
105 cpuid_deterministic_supported
= TRUE
;
107 for (index
= 0; cpuid_deterministic_supported
; index
++) {
108 cache_type_t type
= Lnone
;
110 uint32_t cache_level
;
111 uint32_t cache_sharing
;
112 uint32_t cache_linesize
;
114 uint32_t cache_associativity
;
116 uint32_t cache_partitions
;
119 reg
[eax
] = 4; /* cpuid request 4 */
120 reg
[ecx
] = index
; /* index starting at 0 */
122 //kprintf("cpuid(4) index=%d eax=%p\n", index, reg[eax]);
123 cache_type
= bitfield(reg
[eax
], 4, 0);
125 break; /* no more caches */
126 cache_level
= bitfield(reg
[eax
], 7, 5);
127 cache_sharing
= bitfield(reg
[eax
], 25, 14) + 1;
128 info_p
->cpuid_cores_per_package
129 = bitfield(reg
[eax
], 31, 26) + 1;
130 cache_linesize
= bitfield(reg
[ebx
], 11, 0) + 1;
131 cache_partitions
= bitfield(reg
[ebx
], 21, 12) + 1;
132 cache_associativity
= bitfield(reg
[ebx
], 31, 22) + 1;
133 cache_sets
= bitfield(reg
[ecx
], 31, 0) + 1;
135 /* Map type/levels returned by CPUID into cache_type_t */
136 switch (cache_level
) {
138 type
= cache_type
== 1 ? L1D
:
139 cache_type
== 2 ? L1I
:
143 type
= cache_type
== 3 ? L2U
:
147 type
= cache_type
== 3 ? L3U
:
154 /* The total size of a cache is:
155 * ( linesize * sets * associativity )
158 cache_size
= cache_linesize
* cache_sets
* cache_associativity
;
159 info_p
->cache_size
[type
] = cache_size
;
160 info_p
->cache_sharing
[type
] = cache_sharing
;
161 info_p
->cache_partitions
[type
] = cache_partitions
;
162 linesizes
[type
] = cache_linesize
;
164 /* Compute the number of page colors for this cache,
166 * ( linesize * sets ) / page_size
168 * To help visualize this, consider two views of a
169 * physical address. To the cache, it is composed
170 * of a line offset, a set selector, and a tag.
171 * To VM, it is composed of a page offset, a page
172 * color, and other bits in the pageframe number:
174 * +-----------------+---------+--------+
175 * cache: | tag | set | offset |
176 * +-----------------+---------+--------+
178 * +-----------------+-------+----------+
179 * VM: | don't care | color | pg offset|
180 * +-----------------+-------+----------+
182 * The color is those bits in (set+offset) not covered
183 * by the page offset.
185 colors
= ( cache_linesize
* cache_sets
) >> 12;
187 if ( colors
> vm_cache_geometry_colors
)
188 vm_cache_geometry_colors
= colors
;
193 * If deterministic cache parameters are not available, use
196 if (info_p
->cpuid_cores_per_package
== 0) {
197 info_p
->cpuid_cores_per_package
= 1;
199 /* cpuid define in 1024 quantities */
200 info_p
->cache_size
[L2U
] = info_p
->cpuid_cache_size
* 1024;
201 info_p
->cache_sharing
[L2U
] = 1;
202 info_p
->cache_partitions
[L2U
] = 1;
204 linesizes
[L2U
] = info_p
->cpuid_cache_linesize
;
208 * What linesize to publish? We use the L2 linesize if any,
211 if ( linesizes
[L2U
] )
212 info_p
->cache_linesize
= linesizes
[L2U
];
213 else if (linesizes
[L1D
])
214 info_p
->cache_linesize
= linesizes
[L1D
];
215 else panic("no linesize");
219 cpuid_set_generic_info(i386_cpu_info_t
*info_p
)
221 uint32_t cpuid_reg
[4];
225 /* do cpuid 0 to get vendor */
226 do_cpuid(0, cpuid_reg
);
227 bcopy((char *)&cpuid_reg
[ebx
], &info_p
->cpuid_vendor
[0], 4); /* ug */
228 bcopy((char *)&cpuid_reg
[ecx
], &info_p
->cpuid_vendor
[8], 4);
229 bcopy((char *)&cpuid_reg
[edx
], &info_p
->cpuid_vendor
[4], 4);
230 info_p
->cpuid_vendor
[12] = 0;
232 /* get extended cpuid results */
233 do_cpuid(0x80000000, cpuid_reg
);
234 max_extid
= cpuid_reg
[eax
];
236 /* check to see if we can get brand string */
237 if (max_extid
>= 0x80000004) {
239 * The brand string 48 bytes (max), guaranteed to
242 do_cpuid(0x80000002, cpuid_reg
);
243 bcopy((char *)cpuid_reg
, &str
[0], 16);
244 do_cpuid(0x80000003, cpuid_reg
);
245 bcopy((char *)cpuid_reg
, &str
[16], 16);
246 do_cpuid(0x80000004, cpuid_reg
);
247 bcopy((char *)cpuid_reg
, &str
[32], 16);
248 for (p
= str
; *p
!= '\0'; p
++) {
249 if (*p
!= ' ') break;
251 strlcpy(info_p
->cpuid_brand_string
,
252 p
, sizeof(info_p
->cpuid_brand_string
));
254 if (!strncmp(info_p
->cpuid_brand_string
, CPUID_STRING_UNKNOWN
,
255 min(sizeof(info_p
->cpuid_brand_string
),
256 strlen(CPUID_STRING_UNKNOWN
) + 1))) {
258 * This string means we have a firmware-programmable brand string,
259 * and the firmware couldn't figure out what sort of CPU we have.
261 info_p
->cpuid_brand_string
[0] = '\0';
265 /* Get cache and addressing info. */
266 if (max_extid
>= 0x80000006) {
267 do_cpuid(0x80000006, cpuid_reg
);
268 info_p
->cpuid_cache_linesize
= bitfield(cpuid_reg
[ecx
], 7, 0);
269 info_p
->cpuid_cache_L2_associativity
=
270 bitfield(cpuid_reg
[ecx
],15,12);
271 info_p
->cpuid_cache_size
= bitfield(cpuid_reg
[ecx
],31,16);
272 do_cpuid(0x80000008, cpuid_reg
);
273 info_p
->cpuid_address_bits_physical
=
274 bitfield(cpuid_reg
[eax
], 7, 0);
275 info_p
->cpuid_address_bits_virtual
=
276 bitfield(cpuid_reg
[eax
],15, 8);
279 /* get processor signature and decode */
280 do_cpuid(1, cpuid_reg
);
281 info_p
->cpuid_signature
= cpuid_reg
[eax
];
282 info_p
->cpuid_stepping
= bitfield(cpuid_reg
[eax
], 3, 0);
283 info_p
->cpuid_model
= bitfield(cpuid_reg
[eax
], 7, 4);
284 info_p
->cpuid_family
= bitfield(cpuid_reg
[eax
], 11, 8);
285 info_p
->cpuid_type
= bitfield(cpuid_reg
[eax
], 13, 12);
286 info_p
->cpuid_extmodel
= bitfield(cpuid_reg
[eax
], 19, 16);
287 info_p
->cpuid_extfamily
= bitfield(cpuid_reg
[eax
], 27, 20);
288 info_p
->cpuid_brand
= bitfield(cpuid_reg
[ebx
], 7, 0);
289 info_p
->cpuid_features
= quad(cpuid_reg
[ecx
], cpuid_reg
[edx
]);
291 /* Fold extensions into family/model */
292 if (info_p
->cpuid_family
== 0x0f)
293 info_p
->cpuid_family
+= info_p
->cpuid_extfamily
;
294 if (info_p
->cpuid_family
== 0x0f || info_p
->cpuid_family
== 0x06)
295 info_p
->cpuid_model
+= (info_p
->cpuid_extmodel
<< 4);
297 if (info_p
->cpuid_features
& CPUID_FEATURE_HTT
)
298 info_p
->cpuid_logical_per_package
=
299 bitfield(cpuid_reg
[ebx
], 23, 16);
301 info_p
->cpuid_logical_per_package
= 1;
303 if (max_extid
>= 0x80000001) {
304 do_cpuid(0x80000001, cpuid_reg
);
305 info_p
->cpuid_extfeatures
=
306 quad(cpuid_reg
[ecx
], cpuid_reg
[edx
]);
309 if (info_p
->cpuid_extfeatures
&& CPUID_FEATURE_MONITOR
) {
311 * Extract the Monitor/Mwait Leaf info:
313 do_cpuid(5, cpuid_reg
);
314 info_p
->cpuid_mwait_linesize_min
= cpuid_reg
[eax
];
315 info_p
->cpuid_mwait_linesize_max
= cpuid_reg
[ebx
];
316 info_p
->cpuid_mwait_extensions
= cpuid_reg
[ecx
];
317 info_p
->cpuid_mwait_sub_Cstates
= cpuid_reg
[edx
];
320 * And the thermal and Power Leaf while we're at it:
322 do_cpuid(6, cpuid_reg
);
323 info_p
->cpuid_thermal_sensor
=
324 bitfield(cpuid_reg
[eax
], 0, 0);
325 info_p
->cpuid_thermal_dynamic_acceleration
=
326 bitfield(cpuid_reg
[eax
], 1, 1);
327 info_p
->cpuid_thermal_thresholds
=
328 bitfield(cpuid_reg
[ebx
], 3, 0);
329 info_p
->cpuid_thermal_ACNT_MCNT
=
330 bitfield(cpuid_reg
[ecx
], 0, 0);
333 * And the Architectural Performance Monitoring Leaf:
335 do_cpuid(0xa, cpuid_reg
);
336 info_p
->cpuid_arch_perf_version
=
337 bitfield(cpuid_reg
[eax
], 7, 0);
338 info_p
->cpuid_arch_perf_number
=
339 bitfield(cpuid_reg
[eax
],15, 8);
340 info_p
->cpuid_arch_perf_width
=
341 bitfield(cpuid_reg
[eax
],23,16);
342 info_p
->cpuid_arch_perf_events_number
=
343 bitfield(cpuid_reg
[eax
],31,24);
344 info_p
->cpuid_arch_perf_events
=
346 info_p
->cpuid_arch_perf_fixed_number
=
347 bitfield(cpuid_reg
[edx
], 4, 0);
348 info_p
->cpuid_arch_perf_fixed_width
=
349 bitfield(cpuid_reg
[edx
],12, 5);
359 bzero((void *)&cpuid_cpu_info
, sizeof(cpuid_cpu_info
));
361 cpuid_set_generic_info(&cpuid_cpu_info
);
363 /* verify we are running on a supported CPU */
364 if ((strncmp(CPUID_VID_INTEL
, cpuid_cpu_info
.cpuid_vendor
,
365 min(strlen(CPUID_STRING_UNKNOWN
) + 1,
366 sizeof(cpuid_cpu_info
.cpuid_vendor
)))) ||
367 (cpuid_cpu_info
.cpuid_family
!= 6) ||
368 (cpuid_cpu_info
.cpuid_model
< 13))
369 panic("Unsupported CPU");
371 cpuid_cpu_info
.cpuid_cpu_type
= CPU_TYPE_X86
;
372 cpuid_cpu_info
.cpuid_cpu_subtype
= CPU_SUBTYPE_X86_ARCH1
;
374 cpuid_set_cache_info(&cpuid_cpu_info
);
376 cpuid_cpu_info
.cpuid_model_string
= ""; /* deprecated */
383 {CPUID_FEATURE_FPU
, "FPU",},
384 {CPUID_FEATURE_VME
, "VME",},
385 {CPUID_FEATURE_DE
, "DE",},
386 {CPUID_FEATURE_PSE
, "PSE",},
387 {CPUID_FEATURE_TSC
, "TSC",},
388 {CPUID_FEATURE_MSR
, "MSR",},
389 {CPUID_FEATURE_PAE
, "PAE",},
390 {CPUID_FEATURE_MCE
, "MCE",},
391 {CPUID_FEATURE_CX8
, "CX8",},
392 {CPUID_FEATURE_APIC
, "APIC",},
393 {CPUID_FEATURE_SEP
, "SEP",},
394 {CPUID_FEATURE_MTRR
, "MTRR",},
395 {CPUID_FEATURE_PGE
, "PGE",},
396 {CPUID_FEATURE_MCA
, "MCA",},
397 {CPUID_FEATURE_CMOV
, "CMOV",},
398 {CPUID_FEATURE_PAT
, "PAT",},
399 {CPUID_FEATURE_PSE36
, "PSE36",},
400 {CPUID_FEATURE_PSN
, "PSN",},
401 {CPUID_FEATURE_CLFSH
, "CLFSH",},
402 {CPUID_FEATURE_DS
, "DS",},
403 {CPUID_FEATURE_ACPI
, "ACPI",},
404 {CPUID_FEATURE_MMX
, "MMX",},
405 {CPUID_FEATURE_FXSR
, "FXSR",},
406 {CPUID_FEATURE_SSE
, "SSE",},
407 {CPUID_FEATURE_SSE2
, "SSE2",},
408 {CPUID_FEATURE_SS
, "SS",},
409 {CPUID_FEATURE_HTT
, "HTT",},
410 {CPUID_FEATURE_TM
, "TM",},
411 {CPUID_FEATURE_SSE3
, "SSE3"},
412 {CPUID_FEATURE_MONITOR
, "MON"},
413 {CPUID_FEATURE_DSCPL
, "DSCPL"},
414 {CPUID_FEATURE_VMX
, "VMX"},
415 {CPUID_FEATURE_SMX
, "SMX"},
416 {CPUID_FEATURE_EST
, "EST"},
417 {CPUID_FEATURE_TM2
, "TM2"},
418 {CPUID_FEATURE_SSSE3
, "SSSE3"},
419 {CPUID_FEATURE_CID
, "CID"},
420 {CPUID_FEATURE_CX16
, "CX16"},
421 {CPUID_FEATURE_xTPR
, "TPR"},
422 {CPUID_FEATURE_PDCM
, "PDCM"},
423 {CPUID_FEATURE_SSE4_1
, "SSE4.1"},
424 {CPUID_FEATURE_SSE4_2
, "SSE4.2"},
425 {CPUID_FEATURE_POPCNT
, "POPCNT"},
429 {CPUID_EXTFEATURE_SYSCALL
, "SYSCALL"},
430 {CPUID_EXTFEATURE_XD
, "XD"},
431 {CPUID_EXTFEATURE_EM64T
, "EM64T"},
432 {CPUID_EXTFEATURE_LAHF
, "LAHF"},
439 /* Set-up the cpuid_indo stucture lazily */
440 if (cpuid_cpu_infop
== NULL
) {
442 cpuid_cpu_infop
= &cpuid_cpu_info
;
444 return cpuid_cpu_infop
;
448 cpuid_get_feature_names(uint64_t features
, char *buf
, unsigned buf_len
)
454 for (i
= 0; feature_map
[i
].mask
!= 0; i
++) {
455 if ((features
& feature_map
[i
].mask
) == 0)
459 len
= min(strlen(feature_map
[i
].name
), (buf_len
-1) - (p
-buf
));
462 bcopy(feature_map
[i
].name
, p
, len
);
470 cpuid_get_extfeature_names(uint64_t extfeatures
, char *buf
, unsigned buf_len
)
476 for (i
= 0; extfeature_map
[i
].mask
!= 0; i
++) {
477 if ((extfeatures
& extfeature_map
[i
].mask
) == 0)
481 len
= min(strlen(extfeature_map
[i
].name
), (buf_len
-1)-(p
-buf
));
484 bcopy(extfeature_map
[i
].name
, p
, len
);
492 #if CONFIG_NO_KPRINTF_STRINGS
494 cpuid_feature_display(
495 __unused
const char *header
)
500 cpuid_extfeature_display(
501 __unused
const char *header
)
507 __unused
const char *header
)
510 #else /* CONFIG_NO_KPRINTF_STRINGS */
512 cpuid_feature_display(
517 kprintf("%s: %s\n", header
,
518 cpuid_get_feature_names(cpuid_features(),
520 if (cpuid_features() & CPUID_FEATURE_HTT
) {
521 #define s_if_plural(n) ((n > 1) ? "s" : "")
522 kprintf(" HTT: %d core%s per package;"
523 " %d logical cpu%s per package\n",
524 cpuid_cpu_info
.cpuid_cores_per_package
,
525 s_if_plural(cpuid_cpu_info
.cpuid_cores_per_package
),
526 cpuid_cpu_info
.cpuid_logical_per_package
,
527 s_if_plural(cpuid_cpu_info
.cpuid_logical_per_package
));
532 cpuid_extfeature_display(
537 kprintf("%s: %s\n", header
,
538 cpuid_get_extfeature_names(cpuid_extfeatures(),
546 if (cpuid_cpu_info
.cpuid_brand_string
[0] != '\0') {
547 kprintf("%s: %s\n", header
, cpuid_cpu_info
.cpuid_brand_string
);
550 #endif /* !CONFIG_NO_KPRINTF_STRINGS */
555 return cpuid_info()->cpuid_family
;
561 return cpuid_info()->cpuid_cpu_type
;
565 cpuid_cpusubtype(void)
567 return cpuid_info()->cpuid_cpu_subtype
;
573 static int checked
= 0;
574 char fpu_arg
[16] = { 0 };
578 /* check for boot-time fpu limitations */
579 if (PE_parse_boot_arg("_fpu", &fpu_arg
[0])) {
580 printf("limiting fpu features to: %s\n", fpu_arg
);
581 if (!strncmp("387", fpu_arg
, sizeof("387")) || !strncmp("mmx", fpu_arg
, sizeof("mmx"))) {
582 printf("no sse or sse2\n");
583 cpuid_cpu_info
.cpuid_features
&= ~(CPUID_FEATURE_SSE
| CPUID_FEATURE_SSE2
| CPUID_FEATURE_FXSR
);
584 } else if (!strncmp("sse", fpu_arg
, sizeof("sse"))) {
586 cpuid_cpu_info
.cpuid_features
&= ~(CPUID_FEATURE_SSE2
);
591 return cpuid_cpu_info
.cpuid_features
;
595 cpuid_extfeatures(void)
597 return cpuid_info()->cpuid_extfeatures
;
609 db_cpuid(__unused db_expr_t addr
,
610 __unused
int have_addr
,
611 __unused db_expr_t count
,
612 __unused
char *modif
)
618 do_cpuid(0, cpid
); /* Get the first cpuid which is the number of
620 db_printf("%08X - %08X %08X %08X %08X\n",
621 0, cpid
[eax
], cpid
[ebx
], cpid
[ecx
], cpid
[edx
]);
623 mid
= cpid
[eax
]; /* Set the number */
624 for (i
= 1; i
<= mid
; i
++) { /* Dump 'em out */
625 do_cpuid(i
, cpid
); /* Get the next */
626 db_printf("%08X - %08X %08X %08X %08X\n",
627 i
, cpid
[eax
], cpid
[ebx
], cpid
[ecx
], cpid
[edx
]);
631 do_cpuid(0x80000000, cpid
); /* Get the first extended cpuid which
632 * is the number of extended ids */
633 db_printf("%08X - %08X %08X %08X %08X\n",
634 0x80000000, cpid
[eax
], cpid
[ebx
], cpid
[ecx
], cpid
[edx
]);
636 mid
= cpid
[eax
]; /* Set the number */
637 for (i
= 0x80000001; i
<= mid
; i
++) { /* Dump 'em out */
638 do_cpuid(i
, cpid
); /* Get the next */
639 db_printf("%08X - %08X %08X %08X %08X\n",
640 i
, cpid
[eax
], cpid
[ebx
], cpid
[ecx
], cpid
[edx
]);