identcpu.c revision 48571
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.65 1999/06/24 20:08:56 jlemon 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		case 0x590:
299			strcat(cpu_model, "K6-III");
300			break;
301		default:
302			strcat(cpu_model, "Unknown");
303			break;
304		}
305#if defined(I586_CPU) && defined(CPU_WT_ALLOC)
306		if ((cpu_id & 0xf00) == 0x500) {
307			if (((cpu_id & 0x0f0) > 0)
308			    && ((cpu_id & 0x0f0) < 0x60)
309			    && ((cpu_id & 0x00f) > 3))
310				enable_K5_wt_alloc();
311			else if (((cpu_id & 0x0f0) > 0x80)
312				 || (((cpu_id & 0x0f0) == 0x80)
313				     && (cpu_id & 0x00f) > 0x07))
314				enable_K6_2_wt_alloc();
315			else if ((cpu_id & 0x0f0) > 0x50)
316				enable_K6_wt_alloc();
317		}
318#endif
319		do_cpuid(0x80000000, regs);
320		nreg = regs[0];
321		if (nreg >= 0x80000004) {
322			do_cpuid(0x80000002, regs);
323			memcpy(cpu_model, regs, sizeof regs);
324			do_cpuid(0x80000003, regs);
325			memcpy(cpu_model+16, regs, sizeof regs);
326			do_cpuid(0x80000004, regs);
327			memcpy(cpu_model+32, regs, sizeof regs);
328		}
329	} else if (strcmp(cpu_vendor,"CyrixInstead") == 0) {
330		strcpy(cpu_model, "Cyrix ");
331		switch (cpu_id & 0xff0) {
332		case 0x440:
333			strcat(cpu_model, "MediaGX");
334			break;
335		case 0x520:
336			strcat(cpu_model, "6x86");
337			break;
338		case 0x540:
339			cpu_class = CPUCLASS_586;
340			strcat(cpu_model, "GXm");
341			break;
342		case 0x600:
343			strcat(cpu_model, "6x86MX");
344			break;
345		default:
346			/*
347			 * Even though CPU supports the cpuid
348			 * instruction, it can be disabled.
349			 * Therefore, this routine supports all Cyrix
350			 * CPUs.
351			 */
352			switch (cyrix_did & 0xf0) {
353			case 0x00:
354				switch (cyrix_did & 0x0f) {
355				case 0x00:
356					strcat(cpu_model, "486SLC");
357					break;
358				case 0x01:
359					strcat(cpu_model, "486DLC");
360					break;
361				case 0x02:
362					strcat(cpu_model, "486SLC2");
363					break;
364				case 0x03:
365					strcat(cpu_model, "486DLC2");
366					break;
367				case 0x04:
368					strcat(cpu_model, "486SRx");
369					break;
370				case 0x05:
371					strcat(cpu_model, "486DRx");
372					break;
373				case 0x06:
374					strcat(cpu_model, "486SRx2");
375					break;
376				case 0x07:
377					strcat(cpu_model, "486DRx2");
378					break;
379				case 0x08:
380					strcat(cpu_model, "486SRu");
381					break;
382				case 0x09:
383					strcat(cpu_model, "486DRu");
384					break;
385				case 0x0a:
386					strcat(cpu_model, "486SRu2");
387					break;
388				case 0x0b:
389					strcat(cpu_model, "486DRu2");
390					break;
391				default:
392					strcat(cpu_model, "Unknown");
393					break;
394				}
395				break;
396			case 0x10:
397				switch (cyrix_did & 0x0f) {
398				case 0x00:
399					strcat(cpu_model, "486S");
400					break;
401				case 0x01:
402					strcat(cpu_model, "486S2");
403					break;
404				case 0x02:
405					strcat(cpu_model, "486Se");
406					break;
407				case 0x03:
408					strcat(cpu_model, "486S2e");
409					break;
410				case 0x0a:
411					strcat(cpu_model, "486DX");
412					break;
413				case 0x0b:
414					strcat(cpu_model, "486DX2");
415					break;
416				case 0x0f:
417					strcat(cpu_model, "486DX4");
418					break;
419				default:
420					strcat(cpu_model, "Unknown");
421					break;
422				}
423				break;
424			case 0x20:
425				if ((cyrix_did & 0x0f) < 8)
426					strcat(cpu_model, "6x86");	/* Where did you get it? */
427				else
428					strcat(cpu_model, "5x86");
429				break;
430			case 0x30:
431				strcat(cpu_model, "6x86");
432				break;
433			case 0x40:
434				if ((cyrix_did & 0xf000) == 0x3000) {
435					cpu_class = CPUCLASS_586;
436					strcat(cpu_model, "GXm");
437				} else
438					strcat(cpu_model, "MediaGX");
439				break;
440			case 0x50:
441				strcat(cpu_model, "6x86MX");
442				break;
443			case 0xf0:
444				switch (cyrix_did & 0x0f) {
445				case 0x0d:
446					strcat(cpu_model, "Overdrive CPU");
447				case 0x0e:
448					strcpy(cpu_model, "Texas Instruments 486SXL");
449					break;
450				case 0x0f:
451					strcat(cpu_model, "486SLC/DLC");
452					break;
453				default:
454					strcat(cpu_model, "Unknown");
455					break;
456				}
457				break;
458			default:
459				strcat(cpu_model, "Unknown");
460				break;
461			}
462			break;
463		}
464	} else if (strcmp(cpu_vendor, "RiseRiseRise") == 0) {
465		strcpy(cpu_model, "Rise ");
466		switch (cpu_id & 0xff0) {
467		case 0x500:
468			strcat(cpu_model, "mP6");
469			break;
470		default:
471			strcat(cpu_model, "Unknown");
472		}
473	} else if (strcmp(cpu_vendor, "IBM") == 0)
474		strcpy(cpu_model, "Blue Lightning CPU");
475#endif
476
477	printf("%s (", cpu_model);
478	switch(cpu_class) {
479	case CPUCLASS_286:
480		printf("286");
481		break;
482#if defined(I386_CPU)
483	case CPUCLASS_386:
484		printf("386");
485		break;
486#endif
487#if defined(I486_CPU)
488	case CPUCLASS_486:
489		printf("486");
490		bzero = i486_bzero;
491		break;
492#endif
493#if defined(I586_CPU)
494	case CPUCLASS_586:
495#ifndef SMP
496		printf("%d.%02d-MHz ",
497		       (tsc_freq + 4999) / 1000000,
498		       ((tsc_freq + 4999) / 10000) % 100);
499#endif
500		printf("586");
501		break;
502#endif
503#if defined(I686_CPU)
504	case CPUCLASS_686:
505#ifndef SMP
506		printf("%d.%02d-MHz ",
507		       (tsc_freq + 4999) / 1000000,
508		       ((tsc_freq + 4999) / 10000) % 100);
509#endif
510		printf("686");
511		break;
512#endif
513	default:
514		printf("unknown");	/* will panic below... */
515	}
516	printf("-class CPU)\n");
517#if defined(I486_CPU) || defined(I586_CPU) || defined(I686_CPU)
518	if(*cpu_vendor)
519		printf("  Origin = \"%s\"",cpu_vendor);
520	if(cpu_id)
521		printf("  Id = 0x%x", cpu_id);
522
523	if (strcmp(cpu_vendor, "GenuineIntel") == 0 ||
524	    strcmp(cpu_vendor, "AuthenticAMD") == 0 ||
525	    strcmp(cpu_vendor, "RiseRiseRise") == 0 ||
526		((strcmp(cpu_vendor, "CyrixInstead") == 0) &&
527		 ((cpu_id & 0xf00) > 0x500))) {
528		printf("  Stepping=%u", cpu_id & 0xf);
529		if (strcmp(cpu_vendor, "CyrixInstead") == 0)
530			printf("  DIR=0x%04x", cyrix_did);
531		if (cpu_high > 0) {
532			/*
533			 * Here we should probably set up flags indicating
534			 * whether or not various features are available.
535			 * The interesting ones are probably VME, PSE, PAE,
536			 * and PGE.  The code already assumes without bothering
537			 * to check that all CPUs >= Pentium have a TSC and
538			 * MSRs.
539			 */
540			printf("\n  Features=0x%b", cpu_feature,
541			"\020"
542			"\001FPU"
543			"\002VME"
544			"\003DE"
545			"\004PSE"
546			"\005TSC"
547			"\006MSR"
548			"\007PAE"
549			"\010MCE"
550			"\011CX8"
551			"\012APIC"
552			"\013oldMTRR"
553			"\014SEP"
554			"\015MTRR"
555			"\016PGE"
556			"\017MCA"
557			"\020CMOV"
558			"\021PAT"
559			"\022PSE36"
560			"\023<b18>"
561			"\024<b19>"
562			"\025<b20>"
563			"\026<b21>"
564			"\027<b22>"
565			"\030MMX"
566			"\031FXSR"
567			"\032<b25>"
568			"\033<b26>"
569			"\034<b27>"
570			"\035<b28>"
571			"\036<b29>"
572			"\037<b30>"
573			"\040<b31>"
574			);
575		}
576	} else if (strcmp(cpu_vendor, "CyrixInstead") == 0) {
577		printf("  DIR=0x%04x", cyrix_did);
578		printf("  Stepping=%u", (cyrix_did & 0xf000) >> 12);
579		printf("  Revision=%u", (cyrix_did & 0x0f00) >> 8);
580#ifndef CYRIX_CACHE_REALLY_WORKS
581		if (cpu == CPU_M1 && (cyrix_did & 0xff00) < 0x1700)
582			printf("\n  CPU cache: write-through mode");
583#endif
584	}
585	/* Avoid ugly blank lines: only print newline when we have to. */
586	if (*cpu_vendor || cpu_id)
587		printf("\n");
588
589#endif
590	if (!bootverbose)
591		return;
592
593	if (strcmp(cpu_vendor, "AuthenticAMD") == 0)
594		print_AMD_info();
595#ifdef I686_CPU
596	/*
597	 * XXX - Do PPro CPUID level=2 stuff here?
598	 *
599	 * No, but maybe in a print_Intel_info() function called from here.
600	 */
601#endif
602}
603
604void
605panicifcpuunsupported(void)
606{
607
608	/*
609	 * Now that we have told the user what they have,
610	 * let them know if that machine type isn't configured.
611	 */
612	switch (cpu_class) {
613	case CPUCLASS_286:	/* a 286 should not make it this far, anyway */
614#if !defined(I386_CPU) && !defined(I486_CPU) && !defined(I586_CPU) && !defined(I686_CPU)
615#error This kernel is not configured for one of the supported CPUs
616#endif
617#if !defined(I386_CPU)
618	case CPUCLASS_386:
619#endif
620#if !defined(I486_CPU)
621	case CPUCLASS_486:
622#endif
623#if !defined(I586_CPU)
624	case CPUCLASS_586:
625#endif
626#if !defined(I686_CPU)
627	case CPUCLASS_686:
628#endif
629		panic("CPU class not configured");
630	default:
631		break;
632	}
633}
634
635
636static	volatile u_int trap_by_rdmsr;
637
638/*
639 * Special exception 6 handler.
640 * The rdmsr instruction generates invalid opcodes fault on 486-class
641 * Cyrix CPU.  Stacked eip register points the rdmsr instruction in the
642 * function identblue() when this handler is called.  Stacked eip should
643 * be advanced.
644 */
645inthand_t	bluetrap6;
646__asm
647("
648	.text
649	.p2align 2,0x90
650	.type	" __XSTRING(CNAME(bluetrap6)) ",@function
651" __XSTRING(CNAME(bluetrap6)) ":
652	ss
653	movl	$0xa8c1d," __XSTRING(CNAME(trap_by_rdmsr)) "
654	addl	$2, (%esp)		  # I know rdmsr is a 2-bytes instruction.
655	iret
656");
657
658/*
659 * Special exception 13 handler.
660 * Accessing non-existent MSR generates general protection fault.
661 */
662inthand_t	bluetrap13;
663__asm
664("
665	.text
666	.p2align 2,0x90
667	.type " __XSTRING(CNAME(bluetrap13)) ",@function
668" __XSTRING(CNAME(bluetrap13)) ":
669	ss
670	movl	$0xa89c4," __XSTRING(CNAME(trap_by_rdmsr)) "
671	popl	%eax				# discard errorcode.
672	addl	$2, (%esp)			# I know rdmsr is a 2-bytes instruction.
673	iret
674");
675
676/*
677 * Distinguish IBM Blue Lightning CPU from Cyrix CPUs that does not
678 * support cpuid instruction.  This function should be called after
679 * loading interrupt descriptor table register.
680 *
681 * I don't like this method that handles fault, but I couldn't get
682 * information for any other methods.  Does blue giant know?
683 */
684static int
685identblue(void)
686{
687
688	trap_by_rdmsr = 0;
689
690	/*
691	 * Cyrix 486-class CPU does not support rdmsr instruction.
692	 * The rdmsr instruction generates invalid opcode fault, and exception
693	 * will be trapped by bluetrap6() on Cyrix 486-class CPU.  The
694	 * bluetrap6() set the magic number to trap_by_rdmsr.
695	 */
696	setidt(6, bluetrap6, SDT_SYS386TGT, SEL_KPL, GSEL(GCODE_SEL, SEL_KPL));
697
698	/*
699	 * Certain BIOS disables cpuid instructnion of Cyrix 6x86MX CPU.
700	 * In this case, rdmsr generates general protection fault, and
701	 * exception will be trapped by bluetrap13().
702	 */
703	setidt(13, bluetrap13, SDT_SYS386TGT, SEL_KPL, GSEL(GCODE_SEL, SEL_KPL));
704
705	rdmsr(0x1002);		/* Cyrix CPU generates fault. */
706
707	if (trap_by_rdmsr == 0xa8c1d)
708		return IDENTBLUE_CYRIX486;
709	else if (trap_by_rdmsr == 0xa89c4)
710		return IDENTBLUE_CYRIXM2;
711	return IDENTBLUE_IBMCPU;
712}
713
714
715/*
716 * identifycyrix() set lower 16 bits of cyrix_did as follows:
717 *
718 *  F E D C B A 9 8 7 6 5 4 3 2 1 0
719 * +-------+-------+---------------+
720 * |  SID  |  RID  |   Device ID   |
721 * |    (DIR 1)    |    (DIR 0)    |
722 * +-------+-------+---------------+
723 */
724static void
725identifycyrix(void)
726{
727	u_int	eflags;
728	int	ccr2_test = 0, dir_test = 0;
729	u_char	ccr2, ccr3;
730
731	eflags = read_eflags();
732	disable_intr();
733
734	ccr2 = read_cyrix_reg(CCR2);
735	write_cyrix_reg(CCR2, ccr2 ^ CCR2_LOCK_NW);
736	read_cyrix_reg(CCR2);
737	if (read_cyrix_reg(CCR2) != ccr2)
738		ccr2_test = 1;
739	write_cyrix_reg(CCR2, ccr2);
740
741	ccr3 = read_cyrix_reg(CCR3);
742	write_cyrix_reg(CCR3, ccr3 ^ CCR3_MAPEN3);
743	read_cyrix_reg(CCR3);
744	if (read_cyrix_reg(CCR3) != ccr3)
745		dir_test = 1;					/* CPU supports DIRs. */
746	write_cyrix_reg(CCR3, ccr3);
747
748	if (dir_test) {
749		/* Device ID registers are available. */
750		cyrix_did = read_cyrix_reg(DIR1) << 8;
751		cyrix_did += read_cyrix_reg(DIR0);
752	} else if (ccr2_test)
753		cyrix_did = 0x0010;		/* 486S A-step */
754	else
755		cyrix_did = 0x00ff;		/* Old 486SLC/DLC and TI486SXLC/SXL */
756
757	write_eflags(eflags);
758}
759
760/*
761 * Final stage of CPU identification. -- Should I check TI?
762 */
763void
764finishidentcpu(void)
765{
766	int	isblue = 0;
767	u_char	ccr3;
768	u_int	regs[4];
769
770	if (strcmp(cpu_vendor, "CyrixInstead") == 0) {
771		if (cpu == CPU_486) {
772			/*
773			 * These conditions are equivalent to:
774			 *     - CPU does not support cpuid instruction.
775			 *     - Cyrix/IBM CPU is detected.
776			 */
777			isblue = identblue();
778			if (isblue == IDENTBLUE_IBMCPU) {
779				strcpy(cpu_vendor, "IBM");
780				cpu = CPU_BLUE;
781				return;
782			}
783		}
784		switch (cpu_id & 0xf00) {
785		case 0x600:
786			/*
787			 * Cyrix's datasheet does not describe DIRs.
788			 * Therefor, I assume it does not have them
789			 * and use the result of the cpuid instruction.
790			 * XXX they seem to have it for now at least. -Peter
791			 */
792			identifycyrix();
793			cpu = CPU_M2;
794			break;
795		default:
796			identifycyrix();
797			/*
798			 * This routine contains a trick.
799			 * Don't check (cpu_id & 0x00f0) == 0x50 to detect M2, now.
800			 */
801			switch (cyrix_did & 0x00f0) {
802			case 0x00:
803			case 0xf0:
804				cpu = CPU_486DLC;
805				break;
806			case 0x10:
807				cpu = CPU_CY486DX;
808				break;
809			case 0x20:
810				if ((cyrix_did & 0x000f) < 8)
811					cpu = CPU_M1;
812				else
813					cpu = CPU_M1SC;
814				break;
815			case 0x30:
816				cpu = CPU_M1;
817				break;
818			case 0x40:
819				/* MediaGX CPU */
820				cpu = CPU_M1SC;
821				break;
822			default:
823				/* M2 and later CPUs are treated as M2. */
824				cpu = CPU_M2;
825
826				/*
827				 * enable cpuid instruction.
828				 */
829				ccr3 = read_cyrix_reg(CCR3);
830				write_cyrix_reg(CCR3, CCR3_MAPEN0);
831				write_cyrix_reg(CCR4, read_cyrix_reg(CCR4) | CCR4_CPUID);
832				write_cyrix_reg(CCR3, ccr3);
833
834				do_cpuid(0, regs);
835				cpu_high = regs[0];	/* eax */
836				do_cpuid(1, regs);
837				cpu_id = regs[0];	/* eax */
838				cpu_feature = regs[3];	/* edx */
839				break;
840			}
841		}
842	}
843}
844
845/*
846 * This routine is called specifically to set up cpu_class before
847 * startrtclock() uses it.  Probably this should be rearranged so that
848 * startrtclock() doesn't need to run until after identifycpu() has been
849 * called.  Another alternative formulation would be for this routine
850 * to do all the identification work, and make identifycpu() into a
851 * printing-only routine.
852 */
853void
854earlysetcpuclass(void)
855{
856
857	cpu_class = i386_cpus[cpu].cpu_class;
858}
859
860static void
861print_AMD_assoc(int i)
862{
863	if (i == 255)
864		printf(", fully associative\n");
865	else
866		printf(", %d-way associative\n", i);
867}
868
869static void
870print_AMD_info(void)
871{
872	u_int regs[4], amd_maxregs;
873	quad_t amd_whcr;
874
875	do_cpuid(0x80000000, regs);
876	amd_maxregs = regs[0];
877
878	if (amd_maxregs >= 0x80000001) {
879		do_cpuid(0x80000001, regs);
880		printf(" AMD Features=0x%b\n", regs[3],
881			"\020"		/* in hex */
882			"\001FPU"
883			"\002VME"
884			"\003DE"
885			"\004PSE"
886			"\005TSC"
887			"\006MSR"
888			"\007<b6>"
889			"\010MCE"
890			"\011CX8"
891			"\012<b9>"
892			"\013<b10>"
893			"\014SYSCALL"
894			"\015<b12>"
895			"\016PGE"
896			"\017<b14>"
897			"\020ICMOV"
898			"\021FCMOV"
899			"\022<b17>"
900			"\023<b18>"
901			"\024<b19>"
902			"\025<b20>"
903			"\026<b21>"
904			"\027<b22>"
905			"\030MMX"
906			"\031<b24>"
907			"\032<b25>"
908			"\033<b26>"
909			"\034<b27>"
910			"\035<b28>"
911			"\036<b29>"
912			"\037<b30>"
913			"\0403DNow!"
914			);
915	}
916	if (amd_maxregs >= 0x80000005) {
917		do_cpuid(0x80000005, regs);
918		printf("Data TLB: %d entries", (regs[1] >> 16) & 0xff);
919		print_AMD_assoc(regs[1] >> 24);
920		printf("Instruction TLB: %d entries", regs[1] & 0xff);
921		print_AMD_assoc((regs[1] >> 8) & 0xff);
922		printf("L1 data cache: %d kbytes", regs[2] >> 24);
923		printf(", %d bytes/line", regs[2] & 0xff);
924		printf(", %d lines/tag", (regs[2] >> 8) & 0xff);
925		print_AMD_assoc((regs[2] >> 16) & 0xff);
926		printf("L1 instruction cache: %d kbytes", regs[3] >> 24);
927		printf(", %d bytes/line", regs[3] & 0xff);
928		printf(", %d lines/tag", (regs[3] >> 8) & 0xff);
929		print_AMD_assoc((regs[3] >> 16) & 0xff);
930		if (amd_maxregs >= 0x80000006) {	/* K6-III only */
931			do_cpuid(0x80000006, regs);
932			printf("L2 internal cache: %d kbytes", regs[2] >> 16);
933			printf(", %d bytes/line", regs[2] & 0xff);
934			printf(", %d lines/tag", (regs[2] >> 8) & 0x0f);
935			print_AMD_assoc((regs[2] >> 12) & 0x0f);
936		}
937	}
938	if (((cpu_id & 0xf00) == 0x500)
939	    && (((cpu_id & 0x0f0) > 0x80)
940		|| (((cpu_id & 0x0f0) == 0x80)
941		    && (cpu_id & 0x00f) > 0x07))) {
942		/* K6-2(new core [Stepping 8-F]), K6-III or later */
943		amd_whcr = rdmsr(0xc0000082);
944		if (!(amd_whcr & (0x3ff << 22))) {
945			printf("Write Allocate Disable\n");
946		} else {
947			printf("Write Allocate Enable Limit: %dM bytes\n",
948			    (u_int32_t)((amd_whcr & (0x3ff << 22)) >> 22) * 4);
949			printf("Write Allocate 15-16M bytes: %s\n",
950			    (amd_whcr & (1 << 16)) ? "Enable" : "Disable");
951		}
952	} else if (((cpu_id & 0xf00) == 0x500)
953		   && ((cpu_id & 0x0f0) > 0x50)) {
954		/* K6, K6-2(old core) */
955		amd_whcr = rdmsr(0xc0000082);
956		if (!(amd_whcr & (0x7f << 1))) {
957			printf("Write Allocate Disable\n");
958		} else {
959			printf("Write Allocate Enable Limit: %dM bytes\n",
960			    (u_int32_t)((amd_whcr & (0x7f << 1)) >> 1) * 4);
961			printf("Write Allocate 15-16M bytes: %s\n",
962			    (amd_whcr & 0x0001) ? "Enable" : "Disable");
963			printf("Hardware Write Allocate Control: %s\n",
964			    (amd_whcr & 0x0100) ? "Enable" : "Disable");
965		}
966	}
967}
968