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