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