]> git.saurik.com Git - apple/xnu.git/blob - osfmk/i386/cpuid.c
d66f01d30ca1f55aae6e6558255f9893ec0b87e3
[apple/xnu.git] / osfmk / i386 / cpuid.c
1 /*
2 * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * The contents of this file constitute Original Code as defined in and
7 * are subject to the Apple Public Source License Version 1.1 (the
8 * "License"). You may not use this file except in compliance with the
9 * License. Please obtain a copy of the License at
10 * http://www.apple.com/publicsource and read it before using this file.
11 *
12 * This Original Code and all software distributed under the License are
13 * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
14 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
15 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
17 * License for the specific language governing rights and limitations
18 * under the License.
19 *
20 * @APPLE_LICENSE_HEADER_END@
21 */
22 /*
23 * @OSF_COPYRIGHT@
24 */
25
26 /*
27 * Values from http://einstein.et.tudelft.nl/~offerman/chiplist.html
28 * (dated 18 Oct 1995)
29 */
30
31 #include <kern/misc_protos.h>
32 #include <i386/cpuid.h>
33
34 /*
35 * Generic product array (before CPUID)
36 */
37 unsigned int cpuid_i386_freq[] = { 12, 16, 20, 25, 33, 0 };
38 unsigned int cpuid_i486_freq[] = { 20, 25, 33, 50, 0 };
39
40 struct cpuid_product cpuid_generic[] = {
41 {
42 0, CPUID_FAMILY_386, 0,
43 80, cpuid_i386_freq, "i386"
44 },
45 {
46 0, CPUID_FAMILY_486, 0,
47 240, cpuid_i486_freq, "i486"
48 },
49 };
50
51 /*
52 * INTEL product array
53 */
54 unsigned int cpuid_i486_dx_freq[] = { 20, 25, 33, 0 };
55 unsigned int cpuid_i486_dx_s_freq[] = { 50, 0 };
56 unsigned int cpuid_i486_sx_freq[] = { 16, 20, 25, 33, 0 };
57 unsigned int cpuid_i486_dx2_freq[] = { 32, 40, 50, 66, 0 };
58 unsigned int cpuid_i486_sl_freq[] = { 25, 33, 0 };
59 unsigned int cpuid_i486_sx2_freq[] = { 50, 0 };
60 unsigned int cpuid_i486_dx2wb_freq[] = { 50, 66, 0 };
61 unsigned int cpuid_i486_dx4_freq[] = { 90, 100, 0 };
62
63 unsigned int cpuid_i486_dx2wb_od_freq[] = { 32, 40, 50, 66, 0 };
64 unsigned int cpuid_i486_dx4_od_freq[] = { 75, 99, 0 };
65
66 unsigned int cpuid_p5_freq[] = { 60, 66, 0 };
67 unsigned int cpuid_p54_freq[] = { 60, 66, 75, 90, 100, 120, 133, 166, 200, 0 };
68
69 unsigned int cpuid_p24t_freq[] = { 25, 33, 0 };
70 unsigned int cpuid_p24ct_freq[] = { 63, 83, 0 };
71
72 unsigned int cpuid_pii_freq[] = { 300, 0 };
73
74 struct cpuid_product cpuid_intel[] = {
75 {
76 CPUID_TYPE_OEM, CPUID_FAMILY_486, CPUID_MODEL_I486_DX,
77 240, cpuid_i486_dx_freq, "Intel 486DX"
78 },
79 {
80 CPUID_TYPE_OEM, CPUID_FAMILY_486, CPUID_MODEL_I486_DX_S,
81 240, cpuid_i486_dx_s_freq, "Intel 486DX-S"
82 },
83 {
84 CPUID_TYPE_OEM, CPUID_FAMILY_486, CPUID_MODEL_I486_SX,
85 240, cpuid_i486_sx_freq, "Intel 486SX"
86 },
87 {
88 CPUID_TYPE_OEM, CPUID_FAMILY_486, CPUID_MODEL_I486_DX2,
89 240, cpuid_i486_dx2_freq, "Intel 486DX2"
90 },
91 {
92 CPUID_TYPE_OEM, CPUID_FAMILY_486, CPUID_MODEL_I486_SL,
93 240, cpuid_i486_sl_freq, "Intel 486SL"
94 },
95 {
96 CPUID_TYPE_OEM, CPUID_FAMILY_486, CPUID_MODEL_I486_SX2,
97 240, cpuid_i486_sx2_freq, "Intel 486SX2"
98 },
99 {
100 CPUID_TYPE_OEM, CPUID_FAMILY_486, CPUID_MODEL_I486_DX2WB,
101 240, cpuid_i486_dx2wb_freq, "Intel 486DX2WB"
102 },
103 {
104 CPUID_TYPE_OEM, CPUID_FAMILY_486, CPUID_MODEL_I486_DX4,
105 240, cpuid_i486_dx4_freq, "Intel 486DX4"
106 },
107 {
108 CPUID_TYPE_OVERDRIVE, CPUID_FAMILY_486, CPUID_MODEL_I486_DX2,
109 240, cpuid_i486_dx2_freq, "Intel 486DX2 OverDrive"
110 },
111 {
112 CPUID_TYPE_OVERDRIVE, CPUID_FAMILY_486, CPUID_MODEL_I486_DX2WB,
113 240, cpuid_i486_dx2wb_od_freq, "Intel 486DX2WB OverDrive"
114 },
115 {
116 CPUID_TYPE_OVERDRIVE, CPUID_FAMILY_486, CPUID_MODEL_I486_DX4,
117 240, cpuid_i486_dx4_od_freq, "Intel 486DX4 OverDrive"
118 },
119 {
120 CPUID_TYPE_OVERDRIVE, CPUID_FAMILY_P5, CPUID_MODEL_P24T,
121 208, cpuid_p24t_freq, "Intel Pentium P24T OverDrive"
122 },
123 {
124 CPUID_TYPE_OVERDRIVE, CPUID_FAMILY_P5, CPUID_MODEL_P54,
125 207, cpuid_p24ct_freq, "Intel Pentium P24CT OverDrive"
126 },
127 {
128 CPUID_TYPE_OEM, CPUID_FAMILY_P5, CPUID_MODEL_P5A,
129 207, cpuid_p5_freq, "Intel Pentium P5 rev A"
130 },
131 {
132 CPUID_TYPE_OEM, CPUID_FAMILY_P5, CPUID_MODEL_P5,
133 207, cpuid_p5_freq, "Intel Pentium P5"
134 },
135 {
136 CPUID_TYPE_OEM, CPUID_FAMILY_P5, CPUID_MODEL_P54,
137 207, cpuid_p54_freq, "Intel Pentium P54"
138 },
139 {
140 CPUID_TYPE_OEM, CPUID_FAMILY_PPRO, CPUID_MODEL_PII,
141 480, cpuid_pii_freq, "Intel Pentium II"
142 }
143 };
144 unsigned int cpuid_intel_size = sizeof (cpuid_intel) / sizeof (cpuid_intel[0]);
145
146 /*
147 * AMD product arrays
148 */
149 unsigned int cpuid_am486_dx_freq[] = { 33, 40, 0 };
150 unsigned int cpuid_am486_dx2_freq[] = { 50, 66, 80, 99, 0 };
151 unsigned int cpuid_am486_dx4_freq[] = { 99, 120, 133, 0 };
152 unsigned int cpuid_am486_dx4wb_freq[] = { 99, 120, 133, 0 };
153
154 /*
155 * UMC product array
156 */
157 unsigned int cpuid_u5sd_freq[] = { 25, 33, 40, 0 };
158 unsigned int cpuid_u5s_freq[] = { 25, 33, 40, 0 };
159
160 /*
161 * Vendor ID array
162 */
163 struct cpuid_name cpuid_name[] = {
164 { CPUID_VID_INTEL,
165 cpuid_intel, sizeof (cpuid_intel) / sizeof (cpuid_intel[0])
166 },
167 { CPUID_VID_UMC,
168 (struct cpuid_product *)0,
169 },
170 { CPUID_VID_AMD,
171 (struct cpuid_product *)0,
172 },
173 { CPUID_VID_CYRIX,
174 (struct cpuid_product *)0,
175 },
176 { CPUID_VID_NEXTGEN,
177 (struct cpuid_product *)0
178 },
179 { "",
180 cpuid_generic, sizeof (cpuid_generic) / sizeof (cpuid_generic[0])
181 },
182 { (char *)0,
183 }
184 };
185
186 /*
187 * Feature Flag values
188 */
189 char *cpuid_flag[] = {
190 "FPU", /* Floating point unit on-chip */
191 "VME", /* Virtual Mode Extension */
192 "DE", /* Debugging Extension */
193 "PSE", /* Page Size Extension */
194 "TSC", /* Time Stamp Counter */
195 "MSR", /* Model Specific Registers */
196 "PAE", /* Physical Address Extension */
197 "MCE", /* Machine Check Exception */
198 "CX8", /* CMPXCHG8 Instruction sSupported */
199 "APIC", /* Local APIC Supported */
200 "(bit 10)",
201 "(bit 11)",
202 "MTRR", /* Machine Type Range Register */
203 "PGE", /* Page Global Enable */
204 "MCA", /* Machine Check Architecture */
205 "CMOV", /* Conditional Move Instruction Supported */
206 "(bit 16)",
207 "(bit 17)",
208 "(bit 18)",
209 "(bit 19)",
210 "(bit 20)",
211 "(bit 21)",
212 "(bit 22)",
213 "MMX", /* Supports MMX instructions */
214 "(bit 24)",
215 "(bit 25)",
216 "(bit 26)",
217 "(bit 27)",
218 "(bit 28)",
219 "(bit 29)",
220 "(bit 30)",
221 "(bit 31)",
222 };
223
224 /*
225 * Cache description array
226 */
227 struct cpuid_cache_desc cpuid_cache_desc[] = {
228 { CPUID_CACHE_ITLB_4K,
229 "Instruction TBL, 4K, pages 4-way set associative, 64 entries"
230 },
231 { CPUID_CACHE_ITLB_4M,
232 "Instruction TBL, 4M, pages 4-way set associative, 4 entries"
233 },
234 { CPUID_CACHE_DTLB_4K,
235 "Data TBL, 4K pages, 4-way set associative, 64 entries"
236 },
237 { CPUID_CACHE_DTLB_4M,
238 "Data TBL, 4M pages, 4-way set associative, 4 entries"
239 },
240 { CPUID_CACHE_ICACHE_8K,
241 "Instruction L1 cache, 8K, 4-way set associative, 32byte line size"
242 },
243 { CPUID_CACHE_DCACHE_8K,
244 "Data L1 cache, 8K, 2-way set associative, 32byte line size"
245 },
246 { CPUID_CACHE_UCACHE_128K,
247 "Unified L2 cache, 128K, 4-way set associative, 32byte line size"
248 },
249 { CPUID_CACHE_UCACHE_256K,
250 "Unified L2 cache, 256K, 4-way set associative, 32byte line size"
251 },
252 { CPUID_CACHE_UCACHE_512K,
253 "Unified L2 cache, 512K, 4-way set associative, 32byte line size"
254 },
255 { CPUID_CACHE_NULL,
256 (char *)0
257 }
258 };
259
260 /*
261 * CPU identification
262 */
263 unsigned int cpuid_value;
264 unsigned char cpuid_type;
265 unsigned char cpuid_family;
266 unsigned char cpuid_model;
267 unsigned char cpuid_stepping;
268 unsigned int cpuid_feature;
269 char cpuid_vid[CPUID_VID_SIZE + 1];
270 unsigned char cpuid_cache[CPUID_CACHE_SIZE];
271
272 /*
273 * Return correct CPU_TYPE
274 */
275 /*ARGSUSED*/
276 cpu_type_t
277 cpuid_cputype(
278 int my_cpu)
279 {
280 #ifndef MACH_BSD /* FIXME - add more family/chip types */
281 switch (cpuid_family) {
282 case CPUID_FAMILY_PPRO:
283 return (CPU_TYPE_PENTIUMPRO);
284 case CPUID_FAMILY_P5:
285 return (CPU_TYPE_PENTIUM);
286 case CPUID_FAMILY_486:
287 return (CPU_TYPE_I486);
288 default:
289 break;
290 }
291 #endif
292 return (CPU_TYPE_I386);
293 }
294
295 /*
296 * Display processor signature
297 */
298 /*ARGSUSED*/
299 void
300 cpuid_cpu_display(
301 char *header,
302 int my_cpu)
303 {
304 struct cpuid_name *name;
305 unsigned int i;
306 unsigned int *freq;
307 unsigned int mhz;
308 unsigned int feature;
309 char **flag;
310 extern unsigned int delaycount;
311
312 /*
313 * Identify vendor ID
314 */
315 for (name = cpuid_name; name->name != (char *)0; name++) {
316 char *p = name->name;
317 char *q = cpuid_vid;
318 while (*p == *q && *p != 0) {
319 p++;
320 q++;
321 }
322 if (*p == '\0' && *q == '\0')
323 break;
324 }
325 if (name->name == (char *)0) {
326 printf("Unrecognized processor vendor id = '%s'\n", cpuid_vid);
327 return;
328 }
329
330 /*
331 * Identify Product ID
332 */
333 for (i = 0; i < name->size; i++)
334 if (name->product[i].type == cpuid_type &&
335 name->product[i].family == cpuid_family &&
336 name->product[i].model == cpuid_model)
337 break;
338 if (i == name->size) {
339 printf("%s processor (type = 0x%x, family = 0x%x, model = 0x%x)\n",
340 "Unrecognized", cpuid_type, cpuid_family, cpuid_model);
341 return;
342 }
343
344 /*
345 * Look for frequency and adjust it to known values
346 */
347 mhz = (1000 * delaycount) / name->product[i].delay;
348 for (freq = name->product[i].frequency; *freq != 0; freq++)
349 if (*freq >= mhz)
350 break;
351 if (*freq == 0)
352 mhz = *(freq - 1);
353 else if (freq == name->product[i].frequency)
354 mhz = *freq;
355 else if (*freq - mhz > mhz - *(freq - 1))
356 mhz = *(freq - 1);
357 else if (*freq != mhz)
358 mhz = *freq;
359
360 /*
361 * Display product and frequency
362 */
363 printf("%s: %s at %d MHz (signature = %d/%d/%d/%d)\n",
364 header, name->product[i].name, mhz, cpuid_type,
365 cpuid_family, cpuid_model, cpuid_stepping);
366
367 /*
368 * Display feature (if any)
369 */
370 if (cpuid_feature) {
371 i = 0;
372 flag = cpuid_flag;
373 for (feature = cpuid_feature; feature != 0; feature >>= 1) {
374 if (feature & 1)
375 if (i == 0) {
376 printf("%s: %s", header, *flag);
377 i = 1;
378 } else
379 printf(", %s", *flag);
380 flag++;
381 }
382 printf("\n");
383 }
384 }
385
386 /*
387 * Display processor configuration information
388 */
389 /*ARGSUSED*/
390 void
391 cpuid_cache_display(
392 char *header,
393 int my_cpu)
394 {
395 struct cpuid_cache_desc *desc;
396 unsigned int i;
397
398 if (cpuid_cache[CPUID_CACHE_VALID] == 1)
399 for (i = 0; i < CPUID_CACHE_SIZE; i++) {
400 if (i != CPUID_CACHE_VALID || cpuid_cache[i] == CPUID_CACHE_NULL)
401 continue;
402 for (desc = cpuid_cache_desc;
403 desc->description != (char *)0; desc++)
404 if (desc->value == cpuid_cache[i])
405 break;
406 if (desc->description != (char *)0)
407 printf("%s: %s\n", header, desc->description);
408 }
409 }