1 | /* $NetBSD: identcpu.c,v 1.50 2016/01/01 19:46:48 tls Exp $ */ |
2 | |
3 | /*- |
4 | * Copyright (c) 1999, 2000, 2001, 2006, 2007, 2008 The NetBSD Foundation, Inc. |
5 | * All rights reserved. |
6 | * |
7 | * This code is derived from software contributed to The NetBSD Foundation |
8 | * by Frank van der Linden, and by Jason R. Thorpe. |
9 | * |
10 | * Redistribution and use in source and binary forms, with or without |
11 | * modification, are permitted provided that the following conditions |
12 | * are met: |
13 | * 1. Redistributions of source code must retain the above copyright |
14 | * notice, this list of conditions and the following disclaimer. |
15 | * 2. Redistributions in binary form must reproduce the above copyright |
16 | * notice, this list of conditions and the following disclaimer in the |
17 | * documentation and/or other materials provided with the distribution. |
18 | * |
19 | * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS |
20 | * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED |
21 | * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR |
22 | * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS |
23 | * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR |
24 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF |
25 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS |
26 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN |
27 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) |
28 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE |
29 | * POSSIBILITY OF SUCH DAMAGE. |
30 | */ |
31 | |
32 | #include <sys/cdefs.h> |
33 | __KERNEL_RCSID(0, "$NetBSD: identcpu.c,v 1.50 2016/01/01 19:46:48 tls Exp $" ); |
34 | |
35 | #include "opt_xen.h" |
36 | |
37 | #include <sys/param.h> |
38 | #include <sys/systm.h> |
39 | #include <sys/device.h> |
40 | #include <sys/cpu.h> |
41 | |
42 | #include <uvm/uvm_extern.h> |
43 | |
44 | #include <machine/specialreg.h> |
45 | #include <machine/pio.h> |
46 | #include <machine/cpu.h> |
47 | |
48 | #include <x86/cputypes.h> |
49 | #include <x86/cacheinfo.h> |
50 | #include <x86/cpuvar.h> |
51 | #include <x86/cpu_msr.h> |
52 | |
53 | static const struct x86_cache_info intel_cpuid_cache_info[] = INTEL_CACHE_INFO; |
54 | |
55 | static const struct x86_cache_info amd_cpuid_l2cache_assoc_info[] = |
56 | AMD_L2CACHE_INFO; |
57 | |
58 | static const struct x86_cache_info amd_cpuid_l3cache_assoc_info[] = |
59 | AMD_L3CACHE_INFO; |
60 | |
61 | int cpu_vendor; |
62 | char cpu_brand_string[49]; |
63 | |
64 | int x86_fpu_save = FPU_SAVE_FSAVE; |
65 | unsigned int x86_fpu_save_size = 512; |
66 | uint64_t x86_xsave_features = 0; |
67 | |
68 | /* |
69 | * Note: these are just the ones that may not have a cpuid instruction. |
70 | * We deal with the rest in a different way. |
71 | */ |
72 | const int i386_nocpuid_cpus[] = { |
73 | CPUVENDOR_INTEL, CPUCLASS_386, /* CPU_386SX */ |
74 | CPUVENDOR_INTEL, CPUCLASS_386, /* CPU_386 */ |
75 | CPUVENDOR_INTEL, CPUCLASS_486, /* CPU_486SX */ |
76 | CPUVENDOR_INTEL, CPUCLASS_486, /* CPU_486 */ |
77 | CPUVENDOR_CYRIX, CPUCLASS_486, /* CPU_486DLC */ |
78 | CPUVENDOR_CYRIX, CPUCLASS_486, /* CPU_6x86 */ |
79 | CPUVENDOR_NEXGEN, CPUCLASS_386, /* CPU_NX586 */ |
80 | }; |
81 | |
82 | static const char cpu_vendor_names[][10] = { |
83 | "Unknown" , "Intel" , "NS/Cyrix" , "NexGen" , "AMD" , "IDT/VIA" , "Transmeta" , |
84 | "Vortex86" |
85 | }; |
86 | |
87 | static const struct x86_cache_info * |
88 | cache_info_lookup(const struct x86_cache_info *cai, uint8_t desc) |
89 | { |
90 | int i; |
91 | |
92 | for (i = 0; cai[i].cai_desc != 0; i++) { |
93 | if (cai[i].cai_desc == desc) |
94 | return (&cai[i]); |
95 | } |
96 | |
97 | return (NULL); |
98 | } |
99 | |
100 | static void |
101 | cpu_probe_intel_cache(struct cpu_info *ci) |
102 | { |
103 | const struct x86_cache_info *cai; |
104 | u_int descs[4]; |
105 | int iterations, i, j; |
106 | uint8_t desc; |
107 | |
108 | if (cpuid_level >= 2) { |
109 | /* Parse the cache info from `cpuid leaf 2', if we have it. */ |
110 | x86_cpuid(2, descs); |
111 | iterations = descs[0] & 0xff; |
112 | while (iterations-- > 0) { |
113 | for (i = 0; i < 4; i++) { |
114 | if (descs[i] & 0x80000000) |
115 | continue; |
116 | for (j = 0; j < 4; j++) { |
117 | if (i == 0 && j == 0) |
118 | continue; |
119 | desc = (descs[i] >> (j * 8)) & 0xff; |
120 | if (desc == 0) |
121 | continue; |
122 | cai = cache_info_lookup( |
123 | intel_cpuid_cache_info, desc); |
124 | if (cai != NULL) { |
125 | ci->ci_cinfo[cai->cai_index] = |
126 | *cai; |
127 | } |
128 | } |
129 | } |
130 | } |
131 | } |
132 | |
133 | if (cpuid_level >= 4) { |
134 | int type, level; |
135 | int ways, partitions, linesize, sets; |
136 | int caitype = -1; |
137 | int totalsize; |
138 | |
139 | /* Parse the cache info from `cpuid leaf 4', if we have it. */ |
140 | for (i = 0; ; i++) { |
141 | x86_cpuid2(4, i, descs); |
142 | type = __SHIFTOUT(descs[0], CPUID_DCP_CACHETYPE); |
143 | if (type == CPUID_DCP_CACHETYPE_N) |
144 | break; |
145 | level = __SHIFTOUT(descs[0], CPUID_DCP_CACHELEVEL); |
146 | switch (level) { |
147 | case 1: |
148 | if (type == CPUID_DCP_CACHETYPE_I) |
149 | caitype = CAI_ICACHE; |
150 | else if (type == CPUID_DCP_CACHETYPE_D) |
151 | caitype = CAI_DCACHE; |
152 | else |
153 | caitype = -1; |
154 | break; |
155 | case 2: |
156 | if (type == CPUID_DCP_CACHETYPE_U) |
157 | caitype = CAI_L2CACHE; |
158 | else |
159 | caitype = -1; |
160 | break; |
161 | case 3: |
162 | if (type == CPUID_DCP_CACHETYPE_U) |
163 | caitype = CAI_L3CACHE; |
164 | else |
165 | caitype = -1; |
166 | break; |
167 | default: |
168 | caitype = -1; |
169 | break; |
170 | } |
171 | if (caitype == -1) |
172 | continue; |
173 | |
174 | ways = __SHIFTOUT(descs[1], CPUID_DCP_WAYS) + 1; |
175 | partitions =__SHIFTOUT(descs[1], CPUID_DCP_PARTITIONS) |
176 | + 1; |
177 | linesize = __SHIFTOUT(descs[1], CPUID_DCP_LINESIZE) |
178 | + 1; |
179 | sets = descs[2] + 1; |
180 | totalsize = ways * partitions * linesize * sets; |
181 | ci->ci_cinfo[caitype].cai_totalsize = totalsize; |
182 | ci->ci_cinfo[caitype].cai_associativity = ways; |
183 | ci->ci_cinfo[caitype].cai_linesize = linesize; |
184 | } |
185 | } |
186 | } |
187 | |
188 | static void |
189 | cpu_probe_intel(struct cpu_info *ci) |
190 | { |
191 | |
192 | if (cpu_vendor != CPUVENDOR_INTEL) |
193 | return; |
194 | |
195 | cpu_probe_intel_cache(ci); |
196 | } |
197 | |
198 | static void |
199 | cpu_probe_amd_cache(struct cpu_info *ci) |
200 | { |
201 | const struct x86_cache_info *cp; |
202 | struct x86_cache_info *cai; |
203 | int family, model; |
204 | u_int descs[4]; |
205 | u_int lfunc; |
206 | |
207 | family = CPUID_TO_FAMILY(ci->ci_signature); |
208 | model = CPUID_TO_MODEL(ci->ci_signature); |
209 | |
210 | /* |
211 | * K5 model 0 has none of this info. |
212 | */ |
213 | if (family == 5 && model == 0) |
214 | return; |
215 | |
216 | /* |
217 | * Determine the largest extended function value. |
218 | */ |
219 | x86_cpuid(0x80000000, descs); |
220 | lfunc = descs[0]; |
221 | |
222 | /* |
223 | * Determine L1 cache/TLB info. |
224 | */ |
225 | if (lfunc < 0x80000005) { |
226 | /* No L1 cache info available. */ |
227 | return; |
228 | } |
229 | |
230 | x86_cpuid(0x80000005, descs); |
231 | |
232 | /* |
233 | * K6-III and higher have large page TLBs. |
234 | */ |
235 | if ((family == 5 && model >= 9) || family >= 6) { |
236 | cai = &ci->ci_cinfo[CAI_ITLB2]; |
237 | cai->cai_totalsize = AMD_L1_EAX_ITLB_ENTRIES(descs[0]); |
238 | cai->cai_associativity = AMD_L1_EAX_ITLB_ASSOC(descs[0]); |
239 | cai->cai_linesize = (4 * 1024 * 1024); |
240 | |
241 | cai = &ci->ci_cinfo[CAI_DTLB2]; |
242 | cai->cai_totalsize = AMD_L1_EAX_DTLB_ENTRIES(descs[0]); |
243 | cai->cai_associativity = AMD_L1_EAX_DTLB_ASSOC(descs[0]); |
244 | cai->cai_linesize = (4 * 1024 * 1024); |
245 | } |
246 | |
247 | cai = &ci->ci_cinfo[CAI_ITLB]; |
248 | cai->cai_totalsize = AMD_L1_EBX_ITLB_ENTRIES(descs[1]); |
249 | cai->cai_associativity = AMD_L1_EBX_ITLB_ASSOC(descs[1]); |
250 | cai->cai_linesize = (4 * 1024); |
251 | |
252 | cai = &ci->ci_cinfo[CAI_DTLB]; |
253 | cai->cai_totalsize = AMD_L1_EBX_DTLB_ENTRIES(descs[1]); |
254 | cai->cai_associativity = AMD_L1_EBX_DTLB_ASSOC(descs[1]); |
255 | cai->cai_linesize = (4 * 1024); |
256 | |
257 | cai = &ci->ci_cinfo[CAI_DCACHE]; |
258 | cai->cai_totalsize = AMD_L1_ECX_DC_SIZE(descs[2]); |
259 | cai->cai_associativity = AMD_L1_ECX_DC_ASSOC(descs[2]); |
260 | cai->cai_linesize = AMD_L1_ECX_DC_LS(descs[2]); |
261 | |
262 | cai = &ci->ci_cinfo[CAI_ICACHE]; |
263 | cai->cai_totalsize = AMD_L1_EDX_IC_SIZE(descs[3]); |
264 | cai->cai_associativity = AMD_L1_EDX_IC_ASSOC(descs[3]); |
265 | cai->cai_linesize = AMD_L1_EDX_IC_LS(descs[3]); |
266 | |
267 | /* |
268 | * Determine L2 cache/TLB info. |
269 | */ |
270 | if (lfunc < 0x80000006) { |
271 | /* No L2 cache info available. */ |
272 | return; |
273 | } |
274 | |
275 | x86_cpuid(0x80000006, descs); |
276 | |
277 | cai = &ci->ci_cinfo[CAI_L2CACHE]; |
278 | cai->cai_totalsize = AMD_L2_ECX_C_SIZE(descs[2]); |
279 | cai->cai_associativity = AMD_L2_ECX_C_ASSOC(descs[2]); |
280 | cai->cai_linesize = AMD_L2_ECX_C_LS(descs[2]); |
281 | |
282 | cp = cache_info_lookup(amd_cpuid_l2cache_assoc_info, |
283 | cai->cai_associativity); |
284 | if (cp != NULL) |
285 | cai->cai_associativity = cp->cai_associativity; |
286 | else |
287 | cai->cai_associativity = 0; /* XXX Unknown/reserved */ |
288 | |
289 | if (family < 0xf) { |
290 | /* No L3 cache info available. */ |
291 | return; |
292 | } |
293 | |
294 | cai = &ci->ci_cinfo[CAI_L3CACHE]; |
295 | cai->cai_totalsize = AMD_L3_EDX_C_SIZE(descs[3]); |
296 | cai->cai_associativity = AMD_L3_EDX_C_ASSOC(descs[3]); |
297 | cai->cai_linesize = AMD_L3_EDX_C_LS(descs[3]); |
298 | |
299 | cp = cache_info_lookup(amd_cpuid_l3cache_assoc_info, |
300 | cai->cai_associativity); |
301 | if (cp != NULL) |
302 | cai->cai_associativity = cp->cai_associativity; |
303 | else |
304 | cai->cai_associativity = 0; /* XXX Unknown reserved */ |
305 | |
306 | if (lfunc < 0x80000019) { |
307 | /* No 1GB Page TLB */ |
308 | return; |
309 | } |
310 | |
311 | x86_cpuid(0x80000019, descs); |
312 | |
313 | cai = &ci->ci_cinfo[CAI_L1_1GBDTLB]; |
314 | cai->cai_totalsize = AMD_L1_1GB_EAX_DTLB_ENTRIES(descs[1]); |
315 | cai->cai_associativity = AMD_L1_1GB_EAX_DTLB_ASSOC(descs[1]); |
316 | cai->cai_linesize = (1 * 1024); |
317 | |
318 | cai = &ci->ci_cinfo[CAI_L1_1GBITLB]; |
319 | cai->cai_totalsize = AMD_L1_1GB_EAX_IUTLB_ENTRIES(descs[0]); |
320 | cai->cai_associativity = AMD_L1_1GB_EAX_IUTLB_ASSOC(descs[0]); |
321 | cai->cai_linesize = (1 * 1024); |
322 | |
323 | cai = &ci->ci_cinfo[CAI_L2_1GBDTLB]; |
324 | cai->cai_totalsize = AMD_L2_1GB_EBX_DUTLB_ENTRIES(descs[1]); |
325 | cai->cai_associativity = AMD_L2_1GB_EBX_DUTLB_ASSOC(descs[1]); |
326 | cai->cai_linesize = (1 * 1024); |
327 | |
328 | cai = &ci->ci_cinfo[CAI_L2_1GBITLB]; |
329 | cai->cai_totalsize = AMD_L2_1GB_EBX_IUTLB_ENTRIES(descs[0]); |
330 | cai->cai_associativity = AMD_L2_1GB_EBX_IUTLB_ASSOC(descs[0]); |
331 | cai->cai_linesize = (1 * 1024); |
332 | } |
333 | |
334 | static void |
335 | cpu_probe_k5(struct cpu_info *ci) |
336 | { |
337 | int flag; |
338 | |
339 | if (cpu_vendor != CPUVENDOR_AMD || |
340 | CPUID_TO_FAMILY(ci->ci_signature) != 5) |
341 | return; |
342 | |
343 | if (CPUID_TO_MODEL(ci->ci_signature) == 0) { |
344 | /* |
345 | * According to the AMD Processor Recognition App Note, |
346 | * the AMD-K5 Model 0 uses the wrong bit to indicate |
347 | * support for global PTEs, instead using bit 9 (APIC) |
348 | * rather than bit 13 (i.e. "0x200" vs. 0x2000". Oops!). |
349 | */ |
350 | flag = ci->ci_feat_val[0]; |
351 | if ((flag & CPUID_APIC) != 0) |
352 | flag = (flag & ~CPUID_APIC) | CPUID_PGE; |
353 | ci->ci_feat_val[0] = flag; |
354 | } |
355 | |
356 | cpu_probe_amd_cache(ci); |
357 | } |
358 | |
359 | static void |
360 | cpu_probe_k678(struct cpu_info *ci) |
361 | { |
362 | |
363 | if (cpu_vendor != CPUVENDOR_AMD || |
364 | CPUID_TO_FAMILY(ci->ci_signature) < 6) |
365 | return; |
366 | |
367 | cpu_probe_amd_cache(ci); |
368 | } |
369 | |
370 | static inline uint8_t |
371 | cyrix_read_reg(uint8_t reg) |
372 | { |
373 | |
374 | outb(0x22, reg); |
375 | return inb(0x23); |
376 | } |
377 | |
378 | static inline void |
379 | cyrix_write_reg(uint8_t reg, uint8_t data) |
380 | { |
381 | |
382 | outb(0x22, reg); |
383 | outb(0x23, data); |
384 | } |
385 | |
386 | static void |
387 | cpu_probe_cyrix_cmn(struct cpu_info *ci) |
388 | { |
389 | /* |
390 | * i8254 latch check routine: |
391 | * National Geode (formerly Cyrix MediaGX) has a serious bug in |
392 | * its built-in i8254-compatible clock module (cs5510 cs5520). |
393 | * Set the variable 'clock_broken_latch' to indicate it. |
394 | * |
395 | * This bug is not present in the cs5530, and the flag |
396 | * is disabled again in sys/arch/i386/pci/pcib.c if this later |
397 | * model device is detected. Ideally, this work-around should not |
398 | * even be in here, it should be in there. XXX |
399 | */ |
400 | uint8_t c3; |
401 | #ifndef XEN |
402 | extern int clock_broken_latch; |
403 | |
404 | switch (ci->ci_signature) { |
405 | case 0x440: /* Cyrix MediaGX */ |
406 | case 0x540: /* GXm */ |
407 | clock_broken_latch = 1; |
408 | break; |
409 | } |
410 | #endif |
411 | |
412 | /* set up various cyrix registers */ |
413 | /* |
414 | * Enable suspend on halt (powersave mode). |
415 | * When powersave mode is enabled, the TSC stops counting |
416 | * while the CPU is halted in idle() waiting for an interrupt. |
417 | * This means we can't use the TSC for interval time in |
418 | * microtime(9), and thus it is disabled here. |
419 | * |
420 | * It still makes a perfectly good cycle counter |
421 | * for program profiling, so long as you remember you're |
422 | * counting cycles, and not time. Further, if you don't |
423 | * mind not using powersave mode, the TSC works just fine, |
424 | * so this should really be optional. XXX |
425 | */ |
426 | cyrix_write_reg(0xc2, cyrix_read_reg(0xc2) | 0x08); |
427 | |
428 | /* |
429 | * Do not disable the TSC on the Geode GX, it's reported to |
430 | * work fine. |
431 | */ |
432 | if (ci->ci_signature != 0x552) |
433 | ci->ci_feat_val[0] &= ~CPUID_TSC; |
434 | |
435 | /* enable access to ccr4/ccr5 */ |
436 | c3 = cyrix_read_reg(0xC3); |
437 | cyrix_write_reg(0xC3, c3 | 0x10); |
438 | /* cyrix's workaround for the "coma bug" */ |
439 | cyrix_write_reg(0x31, cyrix_read_reg(0x31) | 0xf8); |
440 | cyrix_write_reg(0x32, cyrix_read_reg(0x32) | 0x7f); |
441 | cyrix_write_reg(0x33, cyrix_read_reg(0x33) & ~0xff); |
442 | cyrix_write_reg(0x3c, cyrix_read_reg(0x3c) | 0x87); |
443 | /* disable access to ccr4/ccr5 */ |
444 | cyrix_write_reg(0xC3, c3); |
445 | } |
446 | |
447 | static void |
448 | cpu_probe_cyrix(struct cpu_info *ci) |
449 | { |
450 | |
451 | if (cpu_vendor != CPUVENDOR_CYRIX || |
452 | CPUID_TO_FAMILY(ci->ci_signature) < 4 || |
453 | CPUID_TO_FAMILY(ci->ci_signature) > 6) |
454 | return; |
455 | |
456 | cpu_probe_cyrix_cmn(ci); |
457 | } |
458 | |
459 | static void |
460 | cpu_probe_winchip(struct cpu_info *ci) |
461 | { |
462 | |
463 | if (cpu_vendor != CPUVENDOR_IDT) |
464 | return; |
465 | |
466 | switch (CPUID_TO_FAMILY(ci->ci_signature)) { |
467 | case 5: |
468 | /* WinChip C6 */ |
469 | if (CPUID_TO_MODEL(ci->ci_signature) == 4) |
470 | ci->ci_feat_val[0] &= ~CPUID_TSC; |
471 | break; |
472 | case 6: |
473 | /* |
474 | * VIA Eden ESP |
475 | * |
476 | * Quoting from page 3-4 of: "VIA Eden ESP Processor Datasheet" |
477 | * http://www.via.com.tw/download/mainboards/6/14/Eden20v115.pdf |
478 | * |
479 | * 1. The CMPXCHG8B instruction is provided and always enabled, |
480 | * however, it appears disabled in the corresponding CPUID |
481 | * function bit 0 to avoid a bug in an early version of |
482 | * Windows NT. However, this default can be changed via a |
483 | * bit in the FCR MSR. |
484 | */ |
485 | ci->ci_feat_val[0] |= CPUID_CX8; |
486 | wrmsr(MSR_VIA_FCR, rdmsr(MSR_VIA_FCR) | 0x00000001); |
487 | break; |
488 | } |
489 | } |
490 | |
491 | static void |
492 | cpu_probe_c3(struct cpu_info *ci) |
493 | { |
494 | u_int family, model, stepping, descs[4], lfunc, msr; |
495 | struct x86_cache_info *cai; |
496 | |
497 | if (cpu_vendor != CPUVENDOR_IDT || |
498 | CPUID_TO_FAMILY(ci->ci_signature) < 6) |
499 | return; |
500 | |
501 | family = CPUID_TO_FAMILY(ci->ci_signature); |
502 | model = CPUID_TO_MODEL(ci->ci_signature); |
503 | stepping = CPUID_TO_STEPPING(ci->ci_signature); |
504 | |
505 | /* Determine the largest extended function value. */ |
506 | x86_cpuid(0x80000000, descs); |
507 | lfunc = descs[0]; |
508 | |
509 | if (family > 6 || model > 0x9 || (model == 0x9 && stepping >= 3)) { |
510 | /* Nehemiah or Esther */ |
511 | x86_cpuid(0xc0000000, descs); |
512 | lfunc = descs[0]; |
513 | if (lfunc >= 0xc0000001) { /* has ACE, RNG */ |
514 | int rng_enable = 0, ace_enable = 0; |
515 | x86_cpuid(0xc0000001, descs); |
516 | lfunc = descs[3]; |
517 | ci->ci_feat_val[4] = lfunc; |
518 | /* Check for and enable RNG */ |
519 | if (lfunc & CPUID_VIA_HAS_RNG) { |
520 | if (!(lfunc & CPUID_VIA_DO_RNG)) { |
521 | rng_enable++; |
522 | ci->ci_feat_val[4] |= CPUID_VIA_DO_RNG; |
523 | } |
524 | } |
525 | /* Check for and enable ACE (AES-CBC) */ |
526 | if (lfunc & CPUID_VIA_HAS_ACE) { |
527 | if (!(lfunc & CPUID_VIA_DO_ACE)) { |
528 | ace_enable++; |
529 | ci->ci_feat_val[4] |= CPUID_VIA_DO_ACE; |
530 | } |
531 | } |
532 | /* Check for and enable SHA */ |
533 | if (lfunc & CPUID_VIA_HAS_PHE) { |
534 | if (!(lfunc & CPUID_VIA_DO_PHE)) { |
535 | ace_enable++; |
536 | ci->ci_feat_val[4] |= CPUID_VIA_DO_PHE; |
537 | } |
538 | } |
539 | /* Check for and enable ACE2 (AES-CTR) */ |
540 | if (lfunc & CPUID_VIA_HAS_ACE2) { |
541 | if (!(lfunc & CPUID_VIA_DO_ACE2)) { |
542 | ace_enable++; |
543 | ci->ci_feat_val[4] |= CPUID_VIA_DO_ACE2; |
544 | } |
545 | } |
546 | /* Check for and enable PMM (modmult engine) */ |
547 | if (lfunc & CPUID_VIA_HAS_PMM) { |
548 | if (!(lfunc & CPUID_VIA_DO_PMM)) { |
549 | ace_enable++; |
550 | ci->ci_feat_val[4] |= CPUID_VIA_DO_PMM; |
551 | } |
552 | } |
553 | |
554 | /* Actually do the enables. */ |
555 | if (rng_enable) { |
556 | msr = rdmsr(MSR_VIA_RNG); |
557 | msr |= MSR_VIA_RNG_ENABLE; |
558 | /* C7 stepping 8 and subsequent CPUs have dual RNG */ |
559 | if (model > 0xA || (model == 0xA && stepping > 0x7)) { |
560 | msr |= MSR_VIA_RNG_2NOISE; |
561 | } |
562 | wrmsr(MSR_VIA_RNG, msr); |
563 | } |
564 | |
565 | if (ace_enable) { |
566 | msr = rdmsr(MSR_VIA_ACE); |
567 | wrmsr(MSR_VIA_ACE, msr | MSR_VIA_ACE_ENABLE); |
568 | } |
569 | |
570 | } |
571 | } |
572 | |
573 | /* |
574 | * Determine L1 cache/TLB info. |
575 | */ |
576 | if (lfunc < 0x80000005) { |
577 | /* No L1 cache info available. */ |
578 | return; |
579 | } |
580 | |
581 | x86_cpuid(0x80000005, descs); |
582 | |
583 | cai = &ci->ci_cinfo[CAI_ITLB]; |
584 | cai->cai_totalsize = VIA_L1_EBX_ITLB_ENTRIES(descs[1]); |
585 | cai->cai_associativity = VIA_L1_EBX_ITLB_ASSOC(descs[1]); |
586 | cai->cai_linesize = (4 * 1024); |
587 | |
588 | cai = &ci->ci_cinfo[CAI_DTLB]; |
589 | cai->cai_totalsize = VIA_L1_EBX_DTLB_ENTRIES(descs[1]); |
590 | cai->cai_associativity = VIA_L1_EBX_DTLB_ASSOC(descs[1]); |
591 | cai->cai_linesize = (4 * 1024); |
592 | |
593 | cai = &ci->ci_cinfo[CAI_DCACHE]; |
594 | cai->cai_totalsize = VIA_L1_ECX_DC_SIZE(descs[2]); |
595 | cai->cai_associativity = VIA_L1_ECX_DC_ASSOC(descs[2]); |
596 | cai->cai_linesize = VIA_L1_EDX_IC_LS(descs[2]); |
597 | if (family == 6 && model == 9 && stepping == 8) { |
598 | /* Erratum: stepping 8 reports 4 when it should be 2 */ |
599 | cai->cai_associativity = 2; |
600 | } |
601 | |
602 | cai = &ci->ci_cinfo[CAI_ICACHE]; |
603 | cai->cai_totalsize = VIA_L1_EDX_IC_SIZE(descs[3]); |
604 | cai->cai_associativity = VIA_L1_EDX_IC_ASSOC(descs[3]); |
605 | cai->cai_linesize = VIA_L1_EDX_IC_LS(descs[3]); |
606 | if (family == 6 && model == 9 && stepping == 8) { |
607 | /* Erratum: stepping 8 reports 4 when it should be 2 */ |
608 | cai->cai_associativity = 2; |
609 | } |
610 | |
611 | /* |
612 | * Determine L2 cache/TLB info. |
613 | */ |
614 | if (lfunc < 0x80000006) { |
615 | /* No L2 cache info available. */ |
616 | return; |
617 | } |
618 | |
619 | x86_cpuid(0x80000006, descs); |
620 | |
621 | cai = &ci->ci_cinfo[CAI_L2CACHE]; |
622 | if (family > 6 || model >= 9) { |
623 | cai->cai_totalsize = VIA_L2N_ECX_C_SIZE(descs[2]); |
624 | cai->cai_associativity = VIA_L2N_ECX_C_ASSOC(descs[2]); |
625 | cai->cai_linesize = VIA_L2N_ECX_C_LS(descs[2]); |
626 | } else { |
627 | cai->cai_totalsize = VIA_L2_ECX_C_SIZE(descs[2]); |
628 | cai->cai_associativity = VIA_L2_ECX_C_ASSOC(descs[2]); |
629 | cai->cai_linesize = VIA_L2_ECX_C_LS(descs[2]); |
630 | } |
631 | } |
632 | |
633 | static void |
634 | cpu_probe_geode(struct cpu_info *ci) |
635 | { |
636 | |
637 | if (memcmp("Geode by NSC" , ci->ci_vendor, 12) != 0 || |
638 | CPUID_TO_FAMILY(ci->ci_signature) != 5) |
639 | return; |
640 | |
641 | cpu_probe_cyrix_cmn(ci); |
642 | cpu_probe_amd_cache(ci); |
643 | } |
644 | |
645 | static void |
646 | cpu_probe_vortex86(struct cpu_info *ci) |
647 | { |
648 | #define PCI_MODE1_ADDRESS_REG 0x0cf8 |
649 | #define PCI_MODE1_DATA_REG 0x0cfc |
650 | #define PCI_MODE1_ENABLE 0x80000000UL |
651 | |
652 | uint32_t reg; |
653 | |
654 | if (cpu_vendor != CPUVENDOR_VORTEX86) |
655 | return; |
656 | /* |
657 | * CPU model available from "Customer ID register" in |
658 | * North Bridge Function 0 PCI space |
659 | * we can't use pci_conf_read() because the PCI subsystem is not |
660 | * not initialised early enough |
661 | */ |
662 | |
663 | outl(PCI_MODE1_ADDRESS_REG, PCI_MODE1_ENABLE | 0x90); |
664 | reg = inl(PCI_MODE1_DATA_REG); |
665 | |
666 | switch(reg) { |
667 | case 0x31504d44: |
668 | strcpy(cpu_brand_string, "Vortex86SX" ); |
669 | break; |
670 | case 0x32504d44: |
671 | strcpy(cpu_brand_string, "Vortex86DX" ); |
672 | break; |
673 | case 0x33504d44: |
674 | strcpy(cpu_brand_string, "Vortex86MX" ); |
675 | break; |
676 | case 0x37504d44: |
677 | strcpy(cpu_brand_string, "Vortex86EX" ); |
678 | break; |
679 | default: |
680 | strcpy(cpu_brand_string, "Unknown Vortex86" ); |
681 | break; |
682 | } |
683 | |
684 | #undef PCI_MODE1_ENABLE |
685 | #undef PCI_MODE1_ADDRESS_REG |
686 | #undef PCI_MODE1_DATA_REG |
687 | } |
688 | |
689 | #if !defined(__i386__) || defined(XEN) |
690 | #define cpu_probe_old_fpu(ci) |
691 | #else |
692 | static void |
693 | cpu_probe_old_fpu(struct cpu_info *ci) |
694 | { |
695 | uint16_t control; |
696 | |
697 | /* Check that there really is an fpu (496SX) */ |
698 | clts(); |
699 | fninit(); |
700 | /* Read default control word */ |
701 | fnstcw(&control); |
702 | if (control != __INITIAL_NPXCW__) { |
703 | /* Must be a 486SX, trap FP instructions */ |
704 | lcr0((rcr0() & ~CR0_MP) | CR0_EM); |
705 | i386_fpu_present = 0; |
706 | return; |
707 | } |
708 | |
709 | /* Check for 'FDIV' bug on the original Pentium */ |
710 | if (npx586bug1(4195835, 3145727) != 0) |
711 | /* NB 120+MHz cpus are not affected */ |
712 | i386_fpu_fdivbug = 1; |
713 | |
714 | stts(); |
715 | } |
716 | #endif |
717 | |
718 | static void |
719 | cpu_probe_fpu(struct cpu_info *ci) |
720 | { |
721 | u_int descs[4]; |
722 | |
723 | #ifdef i386 /* amd64 always has fxsave, sse and sse2 */ |
724 | /* If we have FXSAVE/FXRESTOR, use them. */ |
725 | if ((ci->ci_feat_val[0] & CPUID_FXSR) == 0) { |
726 | i386_use_fxsave = 0; |
727 | /* Allow for no fpu even if cpuid is supported */ |
728 | cpu_probe_old_fpu(ci); |
729 | return; |
730 | } |
731 | |
732 | i386_use_fxsave = 1; |
733 | /* |
734 | * If we have SSE/SSE2, enable XMM exceptions, and |
735 | * notify userland. |
736 | */ |
737 | if (ci->ci_feat_val[0] & CPUID_SSE) |
738 | i386_has_sse = 1; |
739 | if (ci->ci_feat_val[0] & CPUID_SSE2) |
740 | i386_has_sse2 = 1; |
741 | #else |
742 | /* |
743 | * For amd64 i386_use_fxsave, i386_has_sse and i386_has_sse2 are |
744 | * #defined to 1. |
745 | */ |
746 | #endif /* i386 */ |
747 | |
748 | x86_fpu_save = FPU_SAVE_FXSAVE; |
749 | |
750 | /* See if xsave (for AVX is supported) */ |
751 | if ((ci->ci_feat_val[1] & CPUID2_XSAVE) == 0) |
752 | return; |
753 | |
754 | x86_fpu_save = FPU_SAVE_XSAVE; |
755 | |
756 | /* xsaveopt ought to be faster than xsave */ |
757 | x86_cpuid2(0xd, 1, descs); |
758 | if (descs[0] & CPUID_PES1_XSAVEOPT) |
759 | x86_fpu_save = FPU_SAVE_XSAVEOPT; |
760 | |
761 | /* Get features and maximum size of the save area */ |
762 | x86_cpuid(0xd, descs); |
763 | /* XXX these probably ought to be per-cpu */ |
764 | if (descs[2] > 512) |
765 | x86_fpu_save_size = descs[2]; |
766 | #ifndef XEN |
767 | x86_xsave_features = (uint64_t)descs[3] << 32 | descs[0]; |
768 | #endif |
769 | } |
770 | |
771 | void |
772 | cpu_probe(struct cpu_info *ci) |
773 | { |
774 | u_int descs[4]; |
775 | int i; |
776 | uint32_t miscbytes; |
777 | uint32_t brand[12]; |
778 | |
779 | cpu_vendor = i386_nocpuid_cpus[cputype << 1]; |
780 | cpu_class = i386_nocpuid_cpus[(cputype << 1) + 1]; |
781 | |
782 | if (cpuid_level < 0) { |
783 | /* cpuid instruction not supported */ |
784 | cpu_probe_old_fpu(ci); |
785 | return; |
786 | } |
787 | |
788 | for (i = 0; i < __arraycount(ci->ci_feat_val); i++) { |
789 | ci->ci_feat_val[i] = 0; |
790 | } |
791 | |
792 | x86_cpuid(0, descs); |
793 | cpuid_level = descs[0]; |
794 | ci->ci_max_cpuid = descs[0]; |
795 | |
796 | ci->ci_vendor[0] = descs[1]; |
797 | ci->ci_vendor[2] = descs[2]; |
798 | ci->ci_vendor[1] = descs[3]; |
799 | ci->ci_vendor[3] = 0; |
800 | |
801 | if (memcmp(ci->ci_vendor, "GenuineIntel" , 12) == 0) |
802 | cpu_vendor = CPUVENDOR_INTEL; |
803 | else if (memcmp(ci->ci_vendor, "AuthenticAMD" , 12) == 0) |
804 | cpu_vendor = CPUVENDOR_AMD; |
805 | else if (memcmp(ci->ci_vendor, "CyrixInstead" , 12) == 0) |
806 | cpu_vendor = CPUVENDOR_CYRIX; |
807 | else if (memcmp(ci->ci_vendor, "Geode by NSC" , 12) == 0) |
808 | cpu_vendor = CPUVENDOR_CYRIX; |
809 | else if (memcmp(ci->ci_vendor, "CentaurHauls" , 12) == 0) |
810 | cpu_vendor = CPUVENDOR_IDT; |
811 | else if (memcmp(ci->ci_vendor, "GenuineTMx86" , 12) == 0) |
812 | cpu_vendor = CPUVENDOR_TRANSMETA; |
813 | else if (memcmp(ci->ci_vendor, "Vortex86 SoC" , 12) == 0) |
814 | cpu_vendor = CPUVENDOR_VORTEX86; |
815 | else |
816 | cpu_vendor = CPUVENDOR_UNKNOWN; |
817 | |
818 | if (cpuid_level >= 1) { |
819 | x86_cpuid(1, descs); |
820 | ci->ci_signature = descs[0]; |
821 | miscbytes = descs[1]; |
822 | ci->ci_feat_val[1] = descs[2]; |
823 | ci->ci_feat_val[0] = descs[3]; |
824 | |
825 | /* Determine family + class. */ |
826 | cpu_class = CPUID_TO_FAMILY(ci->ci_signature) |
827 | + (CPUCLASS_386 - 3); |
828 | if (cpu_class > CPUCLASS_686) |
829 | cpu_class = CPUCLASS_686; |
830 | |
831 | /* CLFLUSH line size is next 8 bits */ |
832 | if (ci->ci_feat_val[0] & CPUID_CFLUSH) |
833 | ci->ci_cflush_lsize = ((miscbytes >> 8) & 0xff) << 3; |
834 | ci->ci_initapicid = (miscbytes >> 24) & 0xff; |
835 | } |
836 | |
837 | /* |
838 | * Get the basic information from the extended cpuid leafs. |
839 | * These were first implemented by amd, but most of the values |
840 | * match with those generated by modern intel cpus. |
841 | */ |
842 | x86_cpuid(0x80000000, descs); |
843 | if (descs[0] >= 0x80000000) |
844 | ci->ci_max_ext_cpuid = descs[0]; |
845 | else |
846 | ci->ci_max_ext_cpuid = 0; |
847 | |
848 | if (ci->ci_max_ext_cpuid >= 0x80000001) { |
849 | /* Determine the extended feature flags. */ |
850 | x86_cpuid(0x80000001, descs); |
851 | ci->ci_feat_val[3] = descs[2]; /* %ecx */ |
852 | ci->ci_feat_val[2] = descs[3]; /* %edx */ |
853 | } |
854 | |
855 | if (ci->ci_max_ext_cpuid >= 0x80000004) { |
856 | x86_cpuid(0x80000002, brand); |
857 | x86_cpuid(0x80000003, brand + 4); |
858 | x86_cpuid(0x80000004, brand + 8); |
859 | /* Skip leading spaces on brand */ |
860 | for (i = 0; i < 48; i++) { |
861 | if (((char *) brand)[i] != ' ') |
862 | break; |
863 | } |
864 | memcpy(cpu_brand_string, ((char *) brand) + i, 48 - i); |
865 | } |
866 | |
867 | /* |
868 | * Get the structured extended features. |
869 | */ |
870 | if (cpuid_level >= 7) { |
871 | x86_cpuid(7, descs); |
872 | ci->ci_feat_val[5] = descs[1]; /* %ebx */ |
873 | ci->ci_feat_val[6] = descs[2]; /* %ecx */ |
874 | } |
875 | |
876 | cpu_probe_intel(ci); |
877 | cpu_probe_k5(ci); |
878 | cpu_probe_k678(ci); |
879 | cpu_probe_cyrix(ci); |
880 | cpu_probe_winchip(ci); |
881 | cpu_probe_c3(ci); |
882 | cpu_probe_geode(ci); |
883 | cpu_probe_vortex86(ci); |
884 | |
885 | cpu_probe_fpu(ci); |
886 | |
887 | x86_cpu_topology(ci); |
888 | |
889 | if (cpu_vendor != CPUVENDOR_AMD && (ci->ci_feat_val[0] & CPUID_TM) && |
890 | (rdmsr(MSR_MISC_ENABLE) & (1 << 3)) == 0) { |
891 | /* Enable thermal monitor 1. */ |
892 | wrmsr(MSR_MISC_ENABLE, rdmsr(MSR_MISC_ENABLE) | (1<<3)); |
893 | } |
894 | |
895 | ci->ci_feat_val[0] &= ~CPUID_FEAT_BLACKLIST; |
896 | if (ci == &cpu_info_primary) { |
897 | /* If first. Boot Processor is the cpu_feature reference. */ |
898 | for (i = 0; i < __arraycount(cpu_feature); i++) { |
899 | cpu_feature[i] = ci->ci_feat_val[i]; |
900 | } |
901 | #ifndef XEN |
902 | /* Early patch of text segment. */ |
903 | x86_patch(true); |
904 | #endif |
905 | } else { |
906 | /* |
907 | * If not first. Warn about cpu_feature mismatch for |
908 | * secondary CPUs. |
909 | */ |
910 | for (i = 0; i < __arraycount(cpu_feature); i++) { |
911 | if (cpu_feature[i] != ci->ci_feat_val[i]) |
912 | aprint_error_dev(ci->ci_dev, |
913 | "feature mismatch: cpu_feature[%d] is " |
914 | "%#x, but CPU reported %#x\n" , |
915 | i, cpu_feature[i], ci->ci_feat_val[i]); |
916 | } |
917 | } |
918 | } |
919 | |
920 | /* Write what we know about the cpu to the console... */ |
921 | void |
922 | cpu_identify(struct cpu_info *ci) |
923 | { |
924 | |
925 | cpu_setmodel("%s %d86-class" , |
926 | cpu_vendor_names[cpu_vendor], cpu_class + 3); |
927 | if (cpu_brand_string[0] != '\0') { |
928 | aprint_normal_dev(ci->ci_dev, "%s" , cpu_brand_string); |
929 | } else { |
930 | aprint_normal_dev(ci->ci_dev, "%s" , cpu_getmodel()); |
931 | if (ci->ci_data.cpu_cc_freq != 0) |
932 | aprint_normal(", %dMHz" , |
933 | (int)(ci->ci_data.cpu_cc_freq / 1000000)); |
934 | } |
935 | if (ci->ci_signature != 0) |
936 | aprint_normal(", id 0x%x" , ci->ci_signature); |
937 | aprint_normal("\n" ); |
938 | |
939 | if (cpu_brand_string[0] == '\0') { |
940 | strlcpy(cpu_brand_string, cpu_getmodel(), |
941 | sizeof(cpu_brand_string)); |
942 | } |
943 | if (cpu_class == CPUCLASS_386) { |
944 | panic("NetBSD requires an 80486DX or later processor" ); |
945 | } |
946 | if (cputype == CPU_486DLC) { |
947 | aprint_error("WARNING: BUGGY CYRIX CACHE\n" ); |
948 | } |
949 | |
950 | #if !defined(XEN) || defined(DOM0OPS) /* on Xen rdmsr is for Dom0 only */ |
951 | if (cpu_vendor == CPUVENDOR_AMD /* check enablement of an */ |
952 | && device_unit(ci->ci_dev) == 0 /* AMD feature only once */ |
953 | && ((cpu_feature[3] & CPUID_SVM) == CPUID_SVM)) { |
954 | uint64_t val; |
955 | |
956 | val = rdmsr(MSR_VMCR); |
957 | if (((val & VMCR_SVMED) == VMCR_SVMED) |
958 | && ((val & VMCR_LOCK) == VMCR_LOCK)) { |
959 | aprint_normal_dev(ci->ci_dev, |
960 | "SVM disabled by the BIOS\n" ); |
961 | } |
962 | } |
963 | #endif |
964 | |
965 | #ifdef i386 |
966 | if (i386_fpu_present == 0) |
967 | aprint_normal_dev(ci->ci_dev, "no fpu\n" ); |
968 | |
969 | if (i386_fpu_fdivbug == 1) |
970 | aprint_normal_dev(ci->ci_dev, |
971 | "WARNING: Pentium FDIV bug detected!\n" ); |
972 | |
973 | if (cpu_vendor == CPUVENDOR_TRANSMETA) { |
974 | u_int descs[4]; |
975 | x86_cpuid(0x80860000, descs); |
976 | if (descs[0] >= 0x80860007) |
977 | /* Create longrun sysctls */ |
978 | tmx86_init_longrun(); |
979 | } |
980 | #endif /* i386 */ |
981 | |
982 | } |
983 | |