1 /*
2 * Copyright (c) 1992 Terrence R. Lambert.
3 * Copyright (c) 1982, 1987, 1990 The Regents of the University of California.
4 * Copyright (c) 1997 KATO Takenori.
5 * All rights reserved.
6 *
7 * This code is derived from software contributed to Berkeley by
8 * William Jolitz.
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 * 3. All advertising materials mentioning features or use of this software
19 * must display the following acknowledgement:
20 * This product includes software developed by the University of
21 * California, Berkeley and its contributors.
22 * 4. Neither the name of the University nor the names of its contributors
23 * may be used to endorse or promote products derived from this software
24 * without specific prior written permission.
25 *
26 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
27 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
28 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
29 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
30 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
31 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
32 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
33 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
34 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
35 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
36 * SUCH DAMAGE.
37 *
38 * from: Id: machdep.c,v 1.193 1996/06/18 01:22:04 bde Exp
39 * $FreeBSD: src/sys/i386/i386/identcpu.c,v 1.7.2.19 1999/09/05 08:11:07 peter Exp $
40 */
41
42 #include "opt_cpu.h"
43
44 #include <sys/param.h>
45 #include <sys/systm.h>
46 #include <sys/kernel.h>
47 #include <sys/sysctl.h>
48
49 #include <machine/asmacros.h>
50 #include <machine/cpu.h>
51 #include <machine/clock.h>
52 #include <machine/cputypes.h>
53 #include <machine/segments.h>
54 #include <machine/specialreg.h>
55 #include <machine/md_var.h>
56
57 #include <i386/isa/isa_device.h>
58
59 #define IDENTBLUE_CYRIX486 0
60 #define IDENTBLUE_IBMCPU 1
61 #define IDENTBLUE_CYRIXM2 2
62
63 /* XXX - should be in header file */
64 void i486_bzero __P((void *buf, size_t len));
65
66 void printcpuinfo(void); /* XXX should be in different header file */
67 void finishidentcpu(void);
68 void earlysetcpuclass(void);
69 void panicifcpuunsupported(void);
70 static void identifycyrix(void);
71 static void print_AMD_info(void);
72 static void print_AMD_assoc(int i);
73 static void do_cpuid(u_long ax, u_long *p);
74
75 u_long cyrix_did; /* Device ID of Cyrix CPU */
76 int cpu_class = CPUCLASS_386; /* least common denominator */
77 char machine[] = "i386";
78 SYSCTL_STRING(_hw, HW_MACHINE, machine, CTLFLAG_RD, machine, 0, "");
79
80 static char cpu_model[128];
81 SYSCTL_STRING(_hw, HW_MODEL, model, CTLFLAG_RD, cpu_model, 0, "");
82
83 static struct cpu_nameclass i386_cpus[] = {
84 { "Intel 80286", CPUCLASS_286 }, /* CPU_286 */
85 { "i386SX", CPUCLASS_386 }, /* CPU_386SX */
86 { "i386DX", CPUCLASS_386 }, /* CPU_386 */
87 { "i486SX", CPUCLASS_486 }, /* CPU_486SX */
88 { "i486DX", CPUCLASS_486 }, /* CPU_486 */
89 { "Pentium", CPUCLASS_586 }, /* CPU_586 */
90 { "Cyrix 486", CPUCLASS_486 }, /* CPU_486DLC */
91 { "Pentium Pro", CPUCLASS_686 }, /* CPU_686 */
92 { "Cyrix 5x86", CPUCLASS_486 }, /* CPU_M1SC */
93 { "Cyrix 6x86", CPUCLASS_486 }, /* CPU_M1 */
94 { "Blue Lightning", CPUCLASS_486 }, /* CPU_BLUE */
95 { "Cyrix 6x86MX", CPUCLASS_686 }, /* CPU_M2 */
96 { "NexGen 586", CPUCLASS_386 }, /* CPU_NX586 (XXX) */
97 { "Cyrix 486S/DX", CPUCLASS_486 }, /* CPU_CY486DX */
98 { "Pentium II", CPUCLASS_686 }, /* CPU_PII */
99 };
100
101 static void
102 do_cpuid(u_long ax, u_long *p)
103 {
104 __asm __volatile(
105 ".byte 0x0f, 0xa2;"
106 "movl %%eax, (%%esi);"
107 "movl %%ebx, (4)(%%esi);"
108 "movl %%ecx, (8)(%%esi);"
109 "movl %%edx, (12)(%%esi);"
110 :
111 : "a" (ax), "S" (p)
112 : "ax", "bx", "cx", "dx"
113 );
114 }
115
116 #if defined(I586_CPU) && !defined(NO_F00F_HACK)
117 int has_f00f_bug = 0;
118 #endif
119
120 void
121 printcpuinfo(void)
122 {
123
124 u_long regs[4], nreg;
125 cpu_class = i386_cpus[cpu].cpu_class;
126 printf("CPU: ");
127 strncpy(cpu_model, i386_cpus[cpu].cpu_name, sizeof cpu_model);
128
129 #if defined(I486_CPU) || defined(I586_CPU) || defined(I686_CPU)
130 if (strcmp(cpu_vendor,"GenuineIntel") == 0) {
131 if ((cpu_id & 0xf00) > 3) {
132 cpu_model[0] = '\0';
133
134 switch (cpu_id & 0x3000) {
135 case 0x1000:
136 strcpy(cpu_model, "Overdrive ");
137 break;
138 case 0x2000:
139 strcpy(cpu_model, "Dual ");
140 break;
141 }
142
143 switch (cpu_id & 0xf00) {
144 case 0x400:
145 strcat(cpu_model, "i486 ");
146 break;
147 case 0x500:
148 /* Check the particular flavor of 586 */
149 strcat(cpu_model, "Pentium");
150 switch (cpu_id & 0xf0) {
151 case 0x00:
152 strcat(cpu_model, " A-step");
153 break;
154 case 0x10:
155 strcat(cpu_model, "/P5");
156 break;
157 case 0x20:
158 strcat(cpu_model, "/P54C");
159 break;
160 case 0x30:
161 strcat(cpu_model, "/P54T Overdrive");
162 break;
163 case 0x40:
164 strcat(cpu_model, "/P55C");
165 break;
166 case 0x70:
167 strcat(cpu_model, "/P54C");
168 break;
169 case 0x80:
170 strcat(cpu_model, "/P55C (quarter-micron)");
171 break;
172 default:
173 /* nothing */
174 break;
175 }
176 #if defined(I586_CPU) && !defined(NO_F00F_HACK)
177 /*
178 * XXX - If/when Intel fixes the bug, this
179 * should also check the version of the
180 * CPU, not just that it's a Pentium.
181 */
182 has_f00f_bug = 1;
183 #endif
184 break;
185 case 0x600:
186 /* Check the particular flavor of 686 */
187 switch (cpu_id & 0xf0) {
188 case 0x00:
189 strcat(cpu_model, "Pentium Pro A-step");
190 break;
191 case 0x10:
192 strcat(cpu_model, "Pentium Pro");
193 break;
194 case 0x30:
195 strcat(cpu_model, "Pentium II");
196 cpu = CPU_PII;
197 break;
198 case 0x50:
199 strcat(cpu_model, "Pentium II (quarter-micron)");
200 cpu = CPU_PII;
201 break;
202 default:
203 strcat(cpu_model, "Unknown 80686");
204 break;
205 }
206 break;
207 default:
208 strcat(cpu_model, "unknown");
209 break;
210 }
211
212 switch (cpu_id & 0xff0) {
213 case 0x400:
214 strcat(cpu_model, "DX"); break;
215 case 0x410:
216 strcat(cpu_model, "DX"); break;
217 case 0x420:
218 strcat(cpu_model, "SX"); break;
219 case 0x430:
220 strcat(cpu_model, "DX2"); break;
221 case 0x440:
222 strcat(cpu_model, "SL"); break;
223 case 0x450:
224 strcat(cpu_model, "SX2"); break;
225 case 0x470:
226 strcat(cpu_model, "DX2 Write-Back Enhanced");
227 break;
228 case 0x480:
229 strcat(cpu_model, "DX4"); break;
230 break;
231 }
232 }
233 } else if (strcmp(cpu_vendor,"AuthenticAMD") == 0) {
234 /*
235 * Values taken from AMD Processor Recognition
236 * http://www.amd.com/K6/k6docs/pdf/20734g.pdf
237 * (also describes ``Features'' encodings.
238 */
239 strcpy(cpu_model, "AMD ");
240 switch (cpu_id & 0xFF0) {
241 case 0x410:
242 strcat(cpu_model, "Standard Am486DX");
243 break;
244 case 0x430:
245 strcat(cpu_model, "Am486DX2/4 Write-Through");
246 break;
247 case 0x470:
248 strcat(cpu_model, "Enhanced Am486DX4 Write-Back");
249 break;
250 case 0x480:
251 strcat(cpu_model, "Enhanced Am486DX4 Write-Through");
252 break;
253 case 0x490:
254 strcat(cpu_model, "Enhanced Am486DX4 Write-Back");
255 break;
256 case 0x4E0:
257 strcat(cpu_model, "Am5x86 Write-Through");
258 break;
259 case 0x4F0:
260 strcat(cpu_model, "Am5x86 Write-Back");
261 break;
262 case 0x500:
263 strcat(cpu_model, "K5 model 0");
264 break;
265 case 0x510:
266 strcat(cpu_model, "K5 model 1");
267 break;
268 case 0x520:
269 strcat(cpu_model, "K5 PR166 (model 2)");
270 break;
271 case 0x530:
272 strcat(cpu_model, "K5 PR200 (model 3)");
273 break;
274 case 0x560:
275 strcat(cpu_model, "K6");
276 break;
277 default:
278 strcat(cpu_model, "Unknown");
279 break;
280 }
281 do_cpuid(0x80000000, regs);
282 nreg = regs[0];
283 /* Probe to see if we can improve on the model string. */
284 if (nreg >= 0x80000004) {
285 do_cpuid(0x80000002, regs);
286 memcpy(cpu_model, regs, sizeof regs);
287 do_cpuid(0x80000003, regs);
288 memcpy(cpu_model+16, regs, sizeof regs);
289 do_cpuid(0x80000004, regs);
290 memcpy(cpu_model+32, regs, sizeof regs);
291 }
292 } else if (strcmp(cpu_vendor,"CyrixInstead") == 0) {
293 strcpy(cpu_model, "Cyrix ");
294 switch (cpu_id & 0xff0) {
295 case 0x440:
296 strcat(cpu_model, "MediaGX");
297 break;
298 case 0x520:
299 strcat(cpu_model, "6x86");
300 break;
301 case 0x540:
302 cpu_class = CPUCLASS_586;
303 strcat(cpu_model, "GXm");
304 break;
305 case 0x600:
306 strcat(cpu_model, "6x86MX");
307 break;
308 default:
309 /*
310 * Even though CPU supports the cpuid
311 * instruction, it can be disabled.
312 * Therefore, this routine supports all Cyrix
313 * CPUs.
314 */
315 switch (cyrix_did & 0xf0) {
316 case 0x00:
317 switch (cyrix_did & 0x0f) {
318 case 0x00:
319 strcat(cpu_model, "486SLC");
320 break;
321 case 0x01:
322 strcat(cpu_model, "486DLC");
323 break;
324 case 0x02:
325 strcat(cpu_model, "486SLC2");
326 break;
327 case 0x03:
328 strcat(cpu_model, "486DLC2");
329 break;
330 case 0x04:
331 strcat(cpu_model, "486SRx");
332 break;
333 case 0x05:
334 strcat(cpu_model, "486DRx");
335 break;
336 case 0x06:
337 strcat(cpu_model, "486SRx2");
338 break;
339 case 0x07:
340 strcat(cpu_model, "486DRx2");
341 break;
342 case 0x08:
343 strcat(cpu_model, "486SRu");
344 break;
345 case 0x09:
346 strcat(cpu_model, "486DRu");
347 break;
348 case 0x0a:
349 strcat(cpu_model, "486SRu2");
350 break;
351 case 0x0b:
352 strcat(cpu_model, "486DRu2");
353 break;
354 default:
355 strcat(cpu_model, "Unknown");
356 break;
357 }
358 break;
359 case 0x10:
360 switch (cyrix_did & 0x0f) {
361 case 0x00:
362 strcat(cpu_model, "486S");
363 break;
364 case 0x01:
365 strcat(cpu_model, "486S2");
366 break;
367 case 0x02:
368 strcat(cpu_model, "486Se");
369 break;
370 case 0x03:
371 strcat(cpu_model, "486S2e");
372 break;
373 case 0x0a:
374 strcat(cpu_model, "486DX");
375 break;
376 case 0x0b:
377 strcat(cpu_model, "486DX2");
378 break;
379 case 0x0f:
380 strcat(cpu_model, "486DX4");
381 break;
382 default:
383 strcat(cpu_model, "Unknown");
384 break;
385 }
386 break;
387 case 0x20:
388 if ((cyrix_did & 0x0f) < 8)
389 strcat(cpu_model, "6x86"); /* Where did you get it? */
390 else
391 strcat(cpu_model, "5x86");
392 break;
393 case 0x30:
394 strcat(cpu_model, "6x86");
395 break;
396 case 0x40:
397 if ((cyrix_did & 0xf000) == 0x3000) {
398 cpu_class = CPUCLASS_586;
399 strcat(cpu_model, "GXm");
400 } else
401 strcat(cpu_model, "MediaGX");
402 break;
403 case 0x50:
404 strcat(cpu_model, "6x86MX");
405 break;
406 case 0xf0:
407 switch (cyrix_did & 0x0f) {
408 case 0x0d:
409 strcat(cpu_model, "Overdrive CPU");
410 case 0x0e:
411 strcpy(cpu_model, "Texas Instruments 486SXL");
412 break;
413 case 0x0f:
414 strcat(cpu_model, "486SLC/DLC");
415 break;
416 default:
417 strcat(cpu_model, "Unknown");
418 break;
419 }
420 break;
421 default:
422 strcat(cpu_model, "Unknown");
423 break;
424 }
425 break;
426 }
427 } else if (strcmp(cpu_vendor,"IBM") == 0)
428 strcpy(cpu_model, "Blue Lightning CPU");
429 #endif
430
431 printf("%s (", cpu_model);
432 switch(cpu_class) {
433 case CPUCLASS_286:
434 printf("286");
435 break;
436 #if defined(I386_CPU)
437 case CPUCLASS_386:
438 printf("386");
439 break;
440 #endif
441 #if defined(I486_CPU)
442 case CPUCLASS_486:
443 printf("486");
444 bzero = i486_bzero;
445 break;
446 #endif
447 #if defined(I586_CPU)
448 case CPUCLASS_586:
449 printf("%d.%02d-MHz ",
450 (i586_ctr_freq + 4999) / 1000000,
451 ((i586_ctr_freq + 4999) / 10000) % 100);
452 printf("586");
453 break;
454 #endif
455 #if defined(I686_CPU)
456 case CPUCLASS_686:
457 printf("%d.%02d-MHz ",
458 (i586_ctr_freq + 4999) / 1000000,
459 ((i586_ctr_freq + 4999) / 10000) % 100);
460 printf("686");
461 break;
462 #endif
463 default:
464 printf("unknown"); /* will panic below... */
465 }
466 printf("-class CPU)\n");
467 #if defined(I486_CPU) || defined(I586_CPU) || defined(I686_CPU)
468 if(*cpu_vendor)
469 printf(" Origin = \"%s\"",cpu_vendor);
470 if(cpu_id)
471 printf(" Id = 0x%lx",cpu_id);
472
473 if (strcmp(cpu_vendor, "GenuineIntel") == 0 ||
474 strcmp(cpu_vendor, "AuthenticAMD") == 0 ||
475 ((strcmp(cpu_vendor, "CyrixInstead") == 0) &&
476 (cpu_id & 0xf00 > 5))) {
477 printf(" Stepping=%ld", cpu_id & 0xf);
478 if (cpu_high > 0) {
479 /*
480 * Here we should probably set up flags indicating
481 * whether or not various features are available.
482 * The interesting ones are probably VME, PSE, PAE,
483 * and PGE. The code already assumes without bothering
484 * to check that all CPUs >= Pentium have a TSC and
485 * MSRs.
486 */
487 printf("\n Features=0x%b", cpu_feature,
488 "\020"
489 "\001FPU"
490 "\002VME"
491 "\003DE"
492 "\004PSE"
493 "\005TSC"
494 "\006MSR"
495 "\007PAE"
496 "\010MCE"
497 "\011CX8"
498 "\012APIC"
499 "\013oldMTRR"
500 "\014SEP"
501 "\015MTRR"
502 "\016PGE"
503 "\017MCA"
504 "\020CMOV"
505 "\021<b16>"
506 "\022<b17>"
507 "\023<b18>"
508 "\024<b19>"
509 "\025<b20>"
510 "\026<b21>"
511 "\027<b22>"
512 "\030MMX"
513 "\031<b24>"
514 "\032<b25>"
515 "\033<b26>"
516 "\034<b27>"
517 "\035<b28>"
518 "\036<b29>"
519 "\037<b30>"
520 "\040<b31>"
521 );
522 }
523 } else if (strcmp(cpu_vendor, "CyrixInstead") == 0) {
524 printf(" DIR=0x%lx", cyrix_did);
525 printf(" Stepping=%ld", (cyrix_did & 0xf000) >> 12);
526 printf(" Revision=%ld", (cyrix_did & 0x0fff) >> 8);
527 #ifndef CYRIX_CACHE_REALLY_WORKS
528 if (cpu == CPU_M1 && (cyrix_did & 0xff00) < 0x1700)
529 printf("\n CPU cache: write-through mode");
530 #endif
531 }
532 /* Avoid ugly blank lines: only print newline when we have to. */
533 if (*cpu_vendor || cpu_id)
534 printf("\n");
535
536 #endif
537 if (!bootverbose)
538 return;
539
540 if (strcmp(cpu_vendor, "AuthenticAMD") == 0)
541 print_AMD_info();
542 #ifdef I686_CPU
543 /*
544 * XXX - Do PPro CPUID level=2 stuff here?
545 *
546 * No, but maybe in a print_Intel_info() function called from here.
547 */
548 #endif
549 }
550
551 void
552 panicifcpuunsupported(void)
553 {
554
555 /*
556 * Now that we have told the user what they have,
557 * let them know if that machine type isn't configured.
558 */
559 switch (cpu_class) {
560 case CPUCLASS_286: /* a 286 should not make it this far, anyway */
561 #if !defined(I386_CPU) && !defined(I486_CPU) && !defined(I586_CPU) && !defined(I686_CPU)
562 #error This kernel is not configured for one of the supported CPUs
563 #endif
564 #if !defined(I386_CPU)
565 case CPUCLASS_386:
566 #endif
567 #if !defined(I486_CPU)
568 case CPUCLASS_486:
569 #endif
570 #if !defined(I586_CPU)
571 case CPUCLASS_586:
572 #endif
573 #if !defined(I686_CPU)
574 case CPUCLASS_686:
575 #endif
576 panic("CPU class not configured");
577 default:
578 break;
579 }
580 }
581
582
583 static volatile u_int trap_by_rdmsr;
584
585 /*
586 * Special exception 6 handler.
587 * The rdmsr instruction generates invalid opcodes fault on 486-class
588 * Cyrix CPU. Stacked eip register points the rdmsr instruction in the
589 * function identblue() when this handler is called. Stacked eip should
590 * be advanced.
591 */
592 inthand_t bluetrap6;
593 __asm
594 ("
595 .text
596 .p2align 2,0x90
597 " __XSTRING(CNAME(bluetrap6)) ":
598 ss
599 movl $0xa8c1d," __XSTRING(CNAME(trap_by_rdmsr)) "
600 addl $2, (%esp) # I know rdmsr is a 2-bytes instruction.
601 iret
602 ");
603
604 /*
605 * Special exception 13 handler.
606 * Accessing non-existent MSR generates general protection fault.
607 */
608 inthand_t bluetrap13;
609 __asm
610 ("
611 .text
612 .p2align 2,0x90
613 " __XSTRING(CNAME(bluetrap13)) ":
614 ss
615 movl $0xa89c4," __XSTRING(CNAME(trap_by_rdmsr)) "
616 popl %eax # discard errorcode.
617 addl $2, (%esp) # I know rdmsr is a 2-bytes instruction.
618 iret
619 ");
620
621 /*
622 * Distinguish IBM Blue Lightning CPU from Cyrix CPUs that does not
623 * support cpuid instruction. This function should be called after
624 * loading interrupt descriptor table register.
625 *
626 * I don't like this method that handles fault, but I couldn't get
627 * information for any other methods. Does blue giant know?
628 */
629 static int
630 identblue(void)
631 {
632
633 trap_by_rdmsr = 0;
634
635 /*
636 * Cyrix 486-class CPU does not support rdmsr instruction.
637 * The rdmsr instruction generates invalid opcode fault, and exception
638 * will be trapped by bluetrap6() on Cyrix 486-class CPU. The
639 * bluetrap6() set the magic number to trap_by_rdmsr.
640 */
641 setidt(6, bluetrap6, SDT_SYS386TGT, SEL_KPL, GSEL(GCODE_SEL, SEL_KPL));
642
643 /*
644 * Certain BIOS disables cpuid instructnion of Cyrix 6x86MX CPU.
645 * In this case, rdmsr generates general protection fault, and
646 * exception will be trapped by bluetrap13().
647 */
648 setidt(13, bluetrap13, SDT_SYS386TGT, SEL_KPL, GSEL(GCODE_SEL, SEL_KPL));
649
650 rdmsr(0x1002); /* Cyrix CPU generates fault. */
651
652 if (trap_by_rdmsr == 0xa8c1d)
653 return IDENTBLUE_CYRIX486;
654 else if (trap_by_rdmsr == 0xa89c4)
655 return IDENTBLUE_CYRIXM2;
656 return IDENTBLUE_IBMCPU;
657 }
658
659
660 /*
661 * identifycyrix() set lower 16 bits of cyrix_did as follows:
662 *
663 * F E D C B A 9 8 7 6 5 4 3 2 1 0
664 * +-------+-------+---------------+
665 * | SID | RID | Device ID |
666 * | (DIR 1) | (DIR 0) |
667 * +-------+-------+---------------+
668 */
669 static void
670 identifycyrix(void)
671 {
672 u_long eflags;
673 int ccr2_test = 0, dir_test = 0;
674 u_char ccr2, ccr3;
675
676 eflags = read_eflags();
677 disable_intr();
678
679 ccr2 = read_cyrix_reg(CCR2);
680 write_cyrix_reg(CCR2, ccr2 ^ CCR2_LOCK_NW);
681 read_cyrix_reg(CCR2);
682 if (read_cyrix_reg(CCR2) != ccr2)
683 ccr2_test = 1;
684 write_cyrix_reg(CCR2, ccr2);
685
686 ccr3 = read_cyrix_reg(CCR3);
687 write_cyrix_reg(CCR3, ccr3 ^ CCR3_MAPEN3);
688 read_cyrix_reg(CCR3);
689 if (read_cyrix_reg(CCR3) != ccr3)
690 dir_test = 1; /* CPU supports DIRs. */
691 write_cyrix_reg(CCR3, ccr3);
692
693 if (dir_test) {
694 /* Device ID registers are available. */
695 cyrix_did = read_cyrix_reg(DIR1) << 8;
696 cyrix_did += read_cyrix_reg(DIR0);
697 } else if (ccr2_test)
698 cyrix_did = 0x0010; /* 486S A-step */
699 else
700 cyrix_did = 0x00ff; /* Old 486SLC/DLC and TI486SXLC/SXL */
701
702 write_eflags(eflags);
703 }
704
705 /*
706 * Final stage of CPU identification. -- Should I check TI?
707 */
708 void
709 finishidentcpu(void)
710 {
711 int isblue = 0;
712 u_char ccr3;
713 u_long regs[4];
714
715 if (strcmp(cpu_vendor, "CyrixInstead") == 0) {
716 if (cpu == CPU_486) {
717 /*
718 * These conditions are equivalent to:
719 * - CPU does not support cpuid instruction.
720 * - Cyrix/IBM CPU is detected.
721 */
722 isblue = identblue();
723 if (isblue == IDENTBLUE_IBMCPU) {
724 strcpy(cpu_vendor, "IBM");
725 cpu = CPU_BLUE;
726 return;
727 }
728 }
729 switch (cpu_id & 0xf00) {
730 case 0x600:
731 /*
732 * Cyrix's datasheet does not describe DIRs.
733 * Therefor, I assume it does not have them
734 * and use the result of the cpuid instruction.
735 */
736 identifycyrix();
737 cpu = CPU_M2;
738 break;
739 default:
740 identifycyrix();
741 /*
742 * This routine contains a trick.
743 * Don't check (cpu_id & 0x00f0) == 0x50 to detect M2, now.
744 */
745 switch (cyrix_did & 0x00f0) {
746 case 0x00:
747 case 0xf0:
748 cpu = CPU_486DLC;
749 break;
750 case 0x10:
751 cpu = CPU_CY486DX;
752 break;
753 case 0x20:
754 if ((cyrix_did & 0x000f) < 8)
755 cpu = CPU_M1;
756 else
757 cpu = CPU_M1SC;
758 break;
759 case 0x30:
760 cpu = CPU_M1;
761 break;
762 case 0x40:
763 /* MediaGX CPU */
764 cpu = CPU_M1SC;
765 break;
766 default:
767 /* M2 and later CPUs are treated as M2. */
768 cpu = CPU_M2;
769
770 /*
771 * enable cpuid instruction.
772 */
773 ccr3 = read_cyrix_reg(CCR3);
774 write_cyrix_reg(CCR3, CCR3_MAPEN0);
775 write_cyrix_reg(CCR4, read_cyrix_reg(CCR4) | CCR4_CPUID);
776 write_cyrix_reg(CCR3, ccr3);
777
778 do_cpuid(1, regs);
779 cpu_id = regs[0]; /* eax */
780 cpu_feature = regs[3]; /* edx */
781 break;
782 }
783 }
784 }
785 }
786
787 /*
788 * This routine is called specifically to set up cpu_class before
789 * startrtclock() uses it. Probably this should be rearranged so that
790 * startrtclock() doesn't need to run until after identifycpu() has been
791 * called. Another alternative formulation would be for this routine
792 * to do all the identification work, and make identifycpu() into a
793 * printing-only routine.
794 */
795 void
796 earlysetcpuclass(void)
797 {
798
799 cpu_class = i386_cpus[cpu].cpu_class;
800 }
801
802 static void
803 print_AMD_assoc(int i)
804 {
805 if (i == 255)
806 printf(", fully associative\n");
807 else
808 printf(", %d-way associative\n", i);
809 }
810
811 static void
812 print_AMD_info(void)
813 {
814 u_long regs[4];
815
816 do_cpuid(0x80000000, regs);
817 if (regs[0] >= 0x80000005) {
818 do_cpuid(0x80000005, regs);
819 printf("Data TLB: %d entries", (regs[1] >> 16) & 0xff);
820 print_AMD_assoc(regs[1] >> 24);
821 printf("Instruction TLB: %d entries", regs[1] & 0xff);
822 print_AMD_assoc((regs[1] >> 8) & 0xff);
823 printf("L1 data cache: %d kbytes", regs[2] >> 24);
824 printf(", %d bytes/line", regs[2] & 0xff);
825 printf(", %d lines/tag", (regs[2] >> 8) & 0xff);
826 print_AMD_assoc((regs[2] >> 16) & 0xff);
827 printf("L1 instruction cache: %d kbytes", regs[3] >> 24);
828 printf(", %d bytes/line", regs[3] & 0xff);
829 printf(", %d lines/tag", (regs[3] >> 8) & 0xff);
830 print_AMD_assoc((regs[3] >> 16) & 0xff);
831 }
832 }
Cache object: 2c60f65d83ec7ce92ce13035c0b2dac9
|