identcpu.c revision 25083
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.14 1997/03/22 18:51:57 kato Exp $
40 */
41
42#include "opt_cpu.h"
43
44#include <sys/param.h>
45#include <sys/systm.h>
46#include <sys/sysproto.h>
47#include <sys/kernel.h>
48#include <sys/sysctl.h>
49
50#include <machine/asmacros.h>
51#include <machine/cpu.h>
52#include <machine/reg.h>
53#include <machine/psl.h>
54#include <machine/clock.h>
55#include <machine/specialreg.h>
56#include <machine/sysarch.h>
57#include <machine/md_var.h>
58
59#include <i386/isa/isa_device.h>
60
61/* XXX - should be in header file */
62void	i486_bzero __P((void *buf, size_t len));
63
64void printcpuinfo(void);		/* XXX should be in different header file */
65void finishidentcpu(void);
66void earlysetcpuclass(void);
67void panicifcpuunsupported(void);
68static void identifycyrix(void);
69
70u_long	cyrix_did;		/* Device ID of Cyirx CPU */
71int cpu_class = CPUCLASS_386;	/* least common denominator */
72char machine[] = "i386";
73SYSCTL_STRING(_hw, HW_MACHINE, machine, CTLFLAG_RD, machine, 0, "");
74
75static char cpu_model[128];
76SYSCTL_STRING(_hw, HW_MODEL, model, CTLFLAG_RD, cpu_model, 0, "");
77
78static struct cpu_nameclass i386_cpus[] = {
79	{ "Intel 80286",	CPUCLASS_286 },		/* CPU_286   */
80	{ "i386SX",		CPUCLASS_386 },		/* CPU_386SX */
81	{ "i386DX",		CPUCLASS_386 },		/* CPU_386   */
82	{ "i486SX",		CPUCLASS_486 },		/* CPU_486SX */
83	{ "i486DX",		CPUCLASS_486 },		/* CPU_486   */
84	{ "Pentium",		CPUCLASS_586 },		/* CPU_586   */
85	{ "Cyrix 486",		CPUCLASS_486 },		/* CPU_486DLC */
86	{ "Pentium Pro",	CPUCLASS_686 },		/* CPU_686 */
87	{ "Cyrix 5x86",		CPUCLASS_486 },		/* CPU_M1SC */
88	{ "Cyrix 6x86",		CPUCLASS_486 },		/* CPU_M1 */
89	{ "Blue Lightning",	CPUCLASS_486 },		/* CPU_BLUE */
90	{ "Cyrix 6x86 MMX",	CPUCLASS_586 },		/* CPU_M2 (XXX) */
91	{ "NexGen 586",		CPUCLASS_386 },		/* CPU_NX586 (XXX) */
92};
93
94void
95printcpuinfo(void)
96{
97
98	cpu_class = i386_cpus[cpu].cpu_class;
99	printf("CPU: ");
100	strncpy(cpu_model, i386_cpus[cpu].cpu_name, sizeof cpu_model);
101
102#if defined(I486_CPU) || defined(I586_CPU) || defined(I686_CPU)
103	if (strcmp(cpu_vendor,"GenuineIntel") == 0) {
104		if ((cpu_id & 0xf00) > 3) {
105			cpu_model[0] = '\0';
106
107			switch (cpu_id & 0x3000) {
108			case 0x1000:
109				strcpy(cpu_model, "Overdrive ");
110				break;
111			case 0x2000:
112				strcpy(cpu_model, "Dual ");
113				break;
114			}
115
116			switch (cpu_id & 0xf00) {
117			case 0x400:
118				strcat(cpu_model, "i486 ");
119				break;
120			case 0x500:
121				strcat(cpu_model, "Pentium"); /* nb no space */
122				break;
123			case 0x600:
124				strcat(cpu_model, "Pentium Pro");
125				break;
126			default:
127				strcat(cpu_model, "unknown");
128				break;
129			}
130
131			switch (cpu_id & 0xff0) {
132			case 0x400:
133				strcat(cpu_model, "DX"); break;
134			case 0x410:
135				strcat(cpu_model, "DX"); break;
136			case 0x420:
137				strcat(cpu_model, "SX"); break;
138			case 0x430:
139				strcat(cpu_model, "DX2"); break;
140			case 0x440:
141				strcat(cpu_model, "SL"); break;
142			case 0x450:
143				strcat(cpu_model, "SX2"); break;
144			case 0x470:
145				strcat(cpu_model, "DX2 Write-Back Enhanced");
146				break;
147			case 0x480:
148				strcat(cpu_model, "DX4"); break;
149				break;
150			}
151		}
152	} else if (strcmp(cpu_vendor,"AuthenticAMD") == 0) {
153		/*
154		 * Values taken from AMD Processor Recognition
155		 * http://www.amd.com/html/products/pcd/techdocs/appnotes/20734c.pdf
156		 */
157		strcpy(cpu_model, "AMD ");
158		switch (cpu_id & 0xFF0) {
159		case 0x4E0:
160			strcat(cpu_model, "Am5x86 Write-Through");
161			break;
162		case 0x4F0:
163			strcat(cpu_model, "Am5x86 Write-Back");
164			break;
165		case 0x500:
166			strcat(cpu_model, "K5 model 0");
167			break;
168		case 0x510:
169			strcat(cpu_model, "K5 model 1");
170			break;
171		case 0x560:
172			strcat(cpu_model, "K6");
173			break;
174		default:
175			strcat(cpu_model, "Unknown");
176			break;
177		}
178	} else if (strcmp(cpu_vendor,"CyrixInstead") == 0) {
179		strcpy(cpu_model, "Cyrix ");
180		switch (cyrix_did & 0xf0) {
181		case 0x00:
182			switch (cyrix_did & 0x0f) {
183			case 0x00:
184				strcat(cpu_model, "486SLC");
185				break;
186			case 0x01:
187				strcat(cpu_model, "486DLC");
188				break;
189			case 0x02:
190				strcat(cpu_model, "486SLC2");
191				break;
192			case 0x03:
193				strcat(cpu_model, "486DLC2");
194				break;
195			case 0x04:
196				strcat(cpu_model, "486SRx");
197				break;
198			case 0x05:
199				strcat(cpu_model, "486DRx");
200				break;
201			case 0x06:
202				strcat(cpu_model, "486SRx2");
203				break;
204			case 0x07:
205				strcat(cpu_model, "486DRx2");
206				break;
207			case 0x08:
208				strcat(cpu_model, "486SRu");
209				break;
210			case 0x09:
211				strcat(cpu_model, "486DRu");
212				break;
213			case 0x0a:
214				strcat(cpu_model, "486SRu2");
215				break;
216			case 0x0b:
217				strcat(cpu_model, "486DRu2");
218				break;
219			default:
220				strcat(cpu_model, "Unknown");
221				break;
222			}
223			break;
224		case 0x10:
225			switch (cyrix_did & 0x0f) {
226			case 0x00:
227				strcat(cpu_model, "486S");
228				break;
229			case 0x01:
230				strcat(cpu_model, "486S2");
231				break;
232			case 0x02:
233				strcat(cpu_model, "486Se");
234				break;
235			case 0x03:
236				strcat(cpu_model, "486S2e");
237				break;
238			case 0x0a:
239				strcat(cpu_model, "486DX");
240				break;
241			case 0x0b:
242				strcat(cpu_model, "486DX2");
243				break;
244			case 0x0f:
245				strcat(cpu_model, "486DX4");
246				break;
247			default:
248				strcat(cpu_model, "Unknown");
249				break;
250			}
251			break;
252		case 0x20:
253			if ((cyrix_did & 0x0f) < 8)
254				strcat(cpu_model, "6x86");	/* Where did you get it? */
255			else
256				strcat(cpu_model, "5x86");
257			break;
258		case 0x30:
259			strcat(cpu_model, "6x86");
260			break;
261		case 0x40:
262			/* XXX */
263			strcat(cpu_model, "Gx86");
264			break;
265		case 0x50:
266			strcat(cpu_model, "Enhanced 6x86 with MMX");
267			break;
268		case 0xf0:
269			switch (cyrix_did & 0x0f) {
270			case 0x0d:
271				strcat(cpu_model, "Overdrive CPU");
272			case 0x0e:
273				strcpy(cpu_model, "Texas Instruments 486SXL");
274				break;
275			case 0x0f:
276				strcat(cpu_model, "486SLC/DLC");
277				break;
278			default:
279				strcat(cpu_model, "Unknown");
280				break;
281			}
282			break;
283		default:
284			strcat(cpu_model, "Unknown");
285			break;
286		}
287	} else if (strcmp(cpu_vendor,"IBM") == 0)
288		strcpy(cpu_model, "Blue Lightning CPU");
289#endif
290
291	printf("%s (", cpu_model);
292	switch(cpu_class) {
293	case CPUCLASS_286:
294		printf("286");
295		break;
296#if defined(I386_CPU)
297	case CPUCLASS_386:
298		printf("386");
299		break;
300#endif
301#if defined(I486_CPU)
302	case CPUCLASS_486:
303		printf("486");
304		bzero = i486_bzero;
305		break;
306#endif
307#if defined(I586_CPU)
308	case CPUCLASS_586:
309		printf("%d.%02d-MHz ",
310		       (i586_ctr_freq + 4999) / 1000000,
311		       ((i586_ctr_freq + 4999) / 10000) % 100);
312		printf("586");
313		break;
314#endif
315#if defined(I686_CPU)
316	case CPUCLASS_686:
317		printf("%d.%02d-MHz ",
318		       (i586_ctr_freq + 4999) / 1000000,
319		       ((i586_ctr_freq + 4999) / 10000) % 100);
320		printf("686");
321		break;
322#endif
323	default:
324		printf("unknown");	/* will panic below... */
325	}
326	printf("-class CPU)\n");
327#if defined(I486_CPU) || defined(I586_CPU) || defined(I686_CPU)
328	if(*cpu_vendor)
329		printf("  Origin = \"%s\"",cpu_vendor);
330	if(cpu_id)
331		printf("  Id = 0x%lx",cpu_id);
332
333	if (strcmp(cpu_vendor, "GenuineIntel") == 0 ||
334	    strcmp(cpu_vendor, "AuthenticAMD") == 0) {
335		printf("  Stepping=%ld", cpu_id & 0xf);
336		if (cpu_high > 0) {
337			/*
338			 * Here we should probably set up flags indicating
339			 * whether or not various features are available.
340			 * The interesting ones are probably VME, PSE, PAE,
341			 * and PGE.  The code already assumes without bothering
342			 * to check that all CPUs >= Pentium have a TSC and
343			 * MSRs.
344			 */
345			printf("\n  Features=0x%b", cpu_feature,
346			"\020"
347			"\001FPU"
348			"\002VME"
349			"\003DE"
350			"\004PSE"
351			"\005TSC"
352			"\006MSR"
353			"\007PAE"
354			"\010MCE"
355			"\011CX8"
356			"\012APIC"
357			"\013<b10>"
358			"\014<b11>"
359			"\015MTRR"
360			"\016PGE"
361			"\017MCA"
362			"\020CMOV"
363			);
364		}
365	} else if (strcmp(cpu_vendor, "CyrixInstead") == 0) {
366		printf("  Device ID = 0x%lx", cyrix_did);
367		printf("  Stepping=%ld", (cyrix_did & 0xf000) >> 12);
368		printf("  Revision=%ld", (cyrix_did & 0x0fff) >> 8);
369#ifndef CYRIX_CACHE_REALLY_WORKS
370		if (cpu == CPU_M1 && (cyrix_did & 0xff00) < 0x1700)
371			printf("\n  CPU cache: write-through mode");
372#endif
373	}
374	/* Avoid ugly blank lines: only print newline when we have to. */
375	if (*cpu_vendor || cpu_id)
376		printf("\n");
377#endif
378#ifdef I686_CPU
379	/*
380	 * XXX - Do PPro CPUID level=2 stuff here?
381	 */
382#endif
383}
384
385void
386panicifcpuunsupported(void)
387{
388
389	/*
390	 * Now that we have told the user what they have,
391	 * let them know if that machine type isn't configured.
392	 */
393	switch (cpu_class) {
394	case CPUCLASS_286:	/* a 286 should not make it this far, anyway */
395#if !defined(I386_CPU) && !defined(I486_CPU) && !defined(I586_CPU) && !defined(I686_CPU)
396#error This kernel is not configured for one of the supported CPUs
397#endif
398#if !defined(I386_CPU)
399	case CPUCLASS_386:
400#endif
401#if !defined(I486_CPU)
402	case CPUCLASS_486:
403#endif
404#if !defined(I586_CPU)
405	case CPUCLASS_586:
406#endif
407#if !defined(I686_CPU)
408	case CPUCLASS_686:
409#endif
410		panic("CPU class not configured");
411	default:
412		break;
413	}
414}
415
416
417static	volatile u_int trap_by_wrmsr;
418
419/*
420 * Special exception 16 handler.
421 * The wrmsr instruction generates invalid opcodes fault on 486-class
422 * Cyrix CPU.  Stacked eip register points the wrmsr instruction in the
423 * function identblue() when this handler is called.  Stacked eip should
424 * be advanced.
425 */
426inthand_t	bluetrap;
427asm
428("
429	.text
430	.p2align 2,0x90
431" __XSTRING(CNAME(bluetrap)) ":
432	ss
433	movl	$0xa8c1d," __XSTRING(CNAME(trap_by_wrmsr)) " # Don't ask meaning of the number :-).
434	addl	$2, (%esp)				  # I know wrmsr is a 2-bytes instruction.
435	iret
436");
437
438/*
439 * Distinguish IBM Blue Lightning CPU from Cyrix CPUs that does not
440 * support cpuid instruction.  This function should be called after
441 * loading interrupt descriptor table register.
442 *
443 * I don't like this method that handles fault, but I couldn't get
444 * information for any other methods.  Does blue giant know?
445 */
446static int
447identblue(void)
448{
449
450	trap_by_wrmsr = 0;
451	/*
452	 * Cyrix 486-class CPU does not support wrmsr instruction.
453	 * The wrmsr instruction causes invalid opcode fault, and exception
454	 * will be trapped by bluetrap() on Cyrix 486-class CPU.  The bluetrap()
455	 * set the magic number to tra_by_wrmsr.
456	 */
457	setidt(6, bluetrap, SDT_SYS386TGT, SEL_KPL, GSEL(GCODE_SEL, SEL_KPL));
458	wrmsr(0x1002, 0x03000000LL);	/* Fault on Cyrix 486-class CPU. */
459
460	if (trap_by_wrmsr == 0xa8c1d)
461		return 0;					/* Cyrix CPU sets the magic number. */
462
463	return 1;						/* IBM Blue Lightnig CPU */
464}
465
466
467/*
468 * identifycyrix() set lower 16 bits of cyrix_did as follows:
469 *
470 *  F E D C B A 9 8 7 6 5 4 3 2 1 0
471 * +-------+-------+---------------+
472 * |  SID  |  RID  |   Device ID   |
473 * |    (DIR 1)    |    (DIR 0)    |
474 * +-------+-------+---------------+
475 */
476static void
477identifycyrix(void)
478{
479	u_long	eflags;
480	int	ccr2_test = 0, dir_test = 0;
481	u_char	ccr2, ccr3;
482
483	eflags = read_eflags();
484	disable_intr();
485
486	ccr2 = read_cyrix_reg(CCR2);
487	write_cyrix_reg(CCR2, ccr2 ^ CCR2_LOCK_NW);
488	read_cyrix_reg(CCR2);
489	if (read_cyrix_reg(CCR2) != ccr2)
490		ccr2_test = 1;
491	write_cyrix_reg(CCR2, ccr2);
492
493	ccr3 = read_cyrix_reg(CCR3);
494	write_cyrix_reg(CCR3, ccr3 ^ CCR3_MAPEN3);
495	read_cyrix_reg(CCR3);
496	if (read_cyrix_reg(CCR3) != ccr3)
497		dir_test = 1;					/* CPU supports DIRs. */
498	write_cyrix_reg(CCR3, ccr3);
499
500	if (dir_test) {
501		/* Device ID registers are available. */
502		cyrix_did = read_cyrix_reg(DIR1) << 8;
503		cyrix_did += read_cyrix_reg(DIR0);
504	} else if (ccr2_test)
505		cyrix_did = 0x0010;		/* 486S A-step */
506	else
507		cyrix_did = 0x00ff;		/* Old 486SLC/DLC and TI486SXLC/SXL */
508
509	write_eflags(eflags);
510}
511
512/*
513 * Final stage of CPU identification. -- Should I check TI?
514 */
515void
516finishidentcpu(void)
517{
518
519	if (strcmp(cpu_vendor, "CyrixInstead") == 0) {
520		if (cpu == CPU_486) {
521			/*
522			 * These conditions are equivalent to:
523			 *     - CPU does not support cpuid instruction.
524			 *     - Cyrix/IBM CPU is detected.
525			 */
526			if (identblue()) {
527				strcpy(cpu_vendor, "IBM");
528				cpu = CPU_BLUE;
529				return;
530			}
531		}
532		identifycyrix();
533		/*
534		 * This routine contains a trick.
535		 * Don't check (cpu_id & 0x00f0) == 0x50 to detect M2, now.
536		 */
537		switch (cyrix_did & 0x00f0) {
538		case 0x00:
539		case 0x10:
540		case 0xf0:
541			cpu = CPU_486DLC;
542			break;
543		case 0x20:
544			if ((cyrix_did & 0x00f0) < 8)
545				cpu = CPU_M1;
546			else
547				cpu = CPU_M1SC;
548			break;
549		case 0x30:
550			cpu = CPU_M1;
551			break;
552		case 0x40:
553			cpu = CPU_M1SC;
554			break;
555		default:
556			/* M2 and later CPUs are treated as M2. */
557			cpu = CPU_M2;
558			break;
559		}
560	}
561}
562
563/*
564 * This routine is called specifically to set up cpu_class before
565 * startrtclock() uses it.  Probably this should be rearranged so that
566 * startrtclock() doesn't need to run until after identifycpu() has been
567 * called.  Another alternative formulation would be for this routine
568 * to do all the identification work, and make identifycpu() into a
569 * printing-only routine.
570 */
571void
572earlysetcpuclass(void)
573{
574
575	cpu_class = i386_cpus[cpu].cpu_class;
576}
577