identcpu.c revision 18837
1/*-
2 * Copyright (c) 1992 Terrence R. Lambert.
3 * Copyright (c) 1982, 1987, 1990 The Regents of the University of California.
4 * All rights reserved.
5 *
6 * This code is derived from software contributed to Berkeley by
7 * William Jolitz.
8 *
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
11 * are met:
12 * 1. Redistributions of source code must retain the above copyright
13 *    notice, this list of conditions and the following disclaimer.
14 * 2. Redistributions in binary form must reproduce the above copyright
15 *    notice, this list of conditions and the following disclaimer in the
16 *    documentation and/or other materials provided with the distribution.
17 * 3. All advertising materials mentioning features or use of this software
18 *    must display the following acknowledgement:
19 *	This product includes software developed by the University of
20 *	California, Berkeley and its contributors.
21 * 4. Neither the name of the University nor the names of its contributors
22 *    may be used to endorse or promote products derived from this software
23 *    without specific prior written permission.
24 *
25 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
26 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
27 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
28 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
29 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
30 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
31 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
32 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
33 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
34 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
35 * SUCH DAMAGE.
36 *
37 *	from: Id: machdep.c,v 1.193 1996/06/18 01:22:04 bde Exp
38 *	$Id: identcpu.c,v 1.5 1996/09/06 23:07:02 phk Exp $
39 */
40
41#include "opt_temporary.h"			/* for I586_OPTIMIZED_B* */
42
43#include <sys/param.h>
44#include <sys/systm.h>
45#include <sys/sysproto.h>
46#include <sys/kernel.h>
47#include <sys/sysctl.h>
48
49#include <machine/cpu.h>
50#include <machine/reg.h>
51#include <machine/psl.h>
52#include <machine/clock.h>
53#include <machine/specialreg.h>
54#include <machine/sysarch.h>
55#include <machine/md_var.h>
56
57/* XXX - should be in header file */
58extern void (*bcopy_vector) __P((const void *from, void *to, size_t len));
59extern void (*ovbcopy_vector) __P((const void *from, void *to, size_t len));
60
61void	i486_bzero __P((void *buf, size_t len));
62void	i586_bcopy __P((const void *from, void *to, size_t len));
63void	i586_bzero __P((void *buf, size_t len));
64
65void identifycpu(void);		/* XXX should be in different header file */
66void earlysetcpuclass(void);
67
68int cpu_class = CPUCLASS_386;	/* least common denominator */
69char machine[] = "i386";
70SYSCTL_STRING(_hw, HW_MACHINE, machine, CTLFLAG_RD, machine, 0, "");
71
72static char cpu_model[128];
73SYSCTL_STRING(_hw, HW_MODEL, model, CTLFLAG_RD, cpu_model, 0, "");
74
75static struct cpu_nameclass i386_cpus[] = {
76	{ "Intel 80286",	CPUCLASS_286 },		/* CPU_286   */
77	{ "i386SX",		CPUCLASS_386 },		/* CPU_386SX */
78	{ "i386DX",		CPUCLASS_386 },		/* CPU_386   */
79	{ "i486SX",		CPUCLASS_486 },		/* CPU_486SX */
80	{ "i486DX",		CPUCLASS_486 },		/* CPU_486   */
81	{ "Pentium",		CPUCLASS_586 },		/* CPU_586   */
82	{ "Cy486DLC",		CPUCLASS_486 },		/* CPU_486DLC */
83	{ "Pentium Pro",	CPUCLASS_686 },		/* CPU_686 */
84};
85
86void
87identifycpu(void)
88{
89	cpu_class = i386_cpus[cpu].cpu_class;
90	printf("CPU: ");
91	strncpy(cpu_model, i386_cpus[cpu].cpu_name, sizeof cpu_model);
92
93#if defined(I486_CPU) || defined(I586_CPU) || defined(I686_CPU)
94	if (!strcmp(cpu_vendor,"GenuineIntel")) {
95		if ((cpu_id & 0xf00) > 3) {
96			cpu_model[0] = '\0';
97
98			switch (cpu_id & 0x3000) {
99			case 0x1000:
100				strcpy(cpu_model, "Overdrive ");
101				break;
102			case 0x2000:
103				strcpy(cpu_model, "Dual ");
104				break;
105			}
106
107			switch (cpu_id & 0xf00) {
108			case 0x400:
109				strcat(cpu_model, "i486 ");
110				break;
111			case 0x500:
112				strcat(cpu_model, "Pentium"); /* nb no space */
113				break;
114			case 0x600:
115				strcat(cpu_model, "Pentium Pro");
116				break;
117			default:
118				strcat(cpu_model, "unknown");
119				break;
120			}
121
122			switch (cpu_id & 0xff0) {
123			case 0x400:
124				strcat(cpu_model, "DX"); break;
125			case 0x410:
126				strcat(cpu_model, "DX"); break;
127			case 0x420:
128				strcat(cpu_model, "SX"); break;
129			case 0x430:
130				strcat(cpu_model, "DX2"); break;
131			case 0x440:
132				strcat(cpu_model, "SL"); break;
133			case 0x450:
134				strcat(cpu_model, "SX2"); break;
135			case 0x470:
136				strcat(cpu_model, "DX2 Write-Back Enhanced");
137				break;
138			case 0x480:
139				strcat(cpu_model, "DX4"); break;
140				break;
141			}
142		}
143	} else if (!strcmp(cpu_vendor,"AuthenticAMD")) {
144		cpu_model[0] = '\0';
145		strcpy(cpu_model, "AMD ");
146		switch (cpu_id & 0xF0) {
147		case 0xE0:
148			strcat(cpu_model, "Am5x86 Write-Through");
149			break;
150		case 0xF0:
151			strcat(cpu_model, "Am5x86 Write-Back");
152			break;
153		default:
154			strcat(cpu_model, "Unknown");
155			break;
156		}
157	}
158#endif
159	printf("%s (", cpu_model);
160	switch(cpu_class) {
161	case CPUCLASS_286:
162		printf("286");
163		break;
164#if defined(I386_CPU)
165	case CPUCLASS_386:
166		printf("386");
167		break;
168#endif
169#if defined(I486_CPU)
170	case CPUCLASS_486:
171		printf("486");
172		bzero = i486_bzero;
173		break;
174#endif
175#if defined(I586_CPU)
176	case CPUCLASS_586:
177		printf("%d.%02d-MHz ",
178		       (i586_ctr_freq + 4999) / 1000000,
179		       ((i586_ctr_freq + 4999) / 10000) % 100);
180		printf("586");
181#ifdef I586_OPTIMIZED_BCOPY
182		bcopy_vector = i586_bcopy;
183		ovbcopy_vector = i586_bcopy;
184#endif
185#ifdef I586_OPTIMIZED_BZERO
186		bzero = i586_bzero;
187#endif
188		break;
189#endif
190#if defined(I686_CPU)
191	case CPUCLASS_686:
192		printf("%d.%02d-MHz ",
193		       (i586_ctr_freq + 4999) / 1000000,
194		       ((i586_ctr_freq + 4999) / 10000) % 100);
195		printf("686");
196		break;
197#endif
198	default:
199		printf("unknown");	/* will panic below... */
200	}
201	printf("-class CPU)\n");
202#if defined(I486_CPU) || defined(I586_CPU) || defined(I686_CPU)
203	if(*cpu_vendor)
204		printf("  Origin = \"%s\"",cpu_vendor);
205	if(cpu_id)
206		printf("  Id = 0x%lx",cpu_id);
207
208	if (!strcmp(cpu_vendor, "GenuineIntel")) {
209		printf("  Stepping=%ld", cpu_id & 0xf);
210		if (cpu_high > 0) {
211			/*
212			 * Here we should probably set up flags indicating
213			 * whether or not various features are available.
214			 * The interesting ones are probably VME, PSE, PAE,
215			 * and PGE.  The code already assumes without bothering
216			 * to check that all CPUs >= Pentium have a TSC and
217			 * MSRs.
218			 */
219			printf("\n  Features=0x%b", cpu_feature,
220			"\020"
221			"\001FPU"
222			"\002VME"
223			"\003DE"
224			"\004PSE"
225			"\005TSC"
226			"\006MSR"
227			"\007PAE"
228			"\010MCE"
229			"\011CX8"
230			"\012APIC"
231			"\013<b10>"
232			"\014<b11>"
233			"\015MTRR"
234			"\016PGE"
235			"\017MCA"
236			"\020CMOV"
237			);
238		}
239	}
240	/* Avoid ugly blank lines: only print newline when we have to. */
241	if (*cpu_vendor || cpu_id)
242		printf("\n");
243#endif
244#ifdef I686_CPU
245	/*
246	 * XXX - Do PPro CPUID level=2 stuff here?
247	 */
248#endif
249
250	/*
251	 * Now that we have told the user what they have,
252	 * let them know if that machine type isn't configured.
253	 */
254	switch (cpu_class) {
255	case CPUCLASS_286:	/* a 286 should not make it this far, anyway */
256#if !defined(I386_CPU) && !defined(I486_CPU) && !defined(I586_CPU) && !defined(I686_CPU)
257#error This kernel is not configured for one of the supported CPUs
258#endif
259#if !defined(I386_CPU)
260	case CPUCLASS_386:
261#endif
262#if !defined(I486_CPU)
263	case CPUCLASS_486:
264#endif
265#if !defined(I586_CPU)
266	case CPUCLASS_586:
267#endif
268#if !defined(I686_CPU)
269	case CPUCLASS_686:
270#endif
271		panic("CPU class not configured");
272	default:
273		break;
274	}
275}
276
277/*
278 * This routine is called specifically to set up cpu_class before
279 * startrtclock() uses it.  Probably this should be rearranged so that
280 * startrtclock() doesn't need to run until after identifycpu() has been
281 * called.  Another alternative formulation would be for this routine
282 * to do all the identification work, and make identifycpu() into a
283 * printing-only routine.
284 */
285void
286earlysetcpuclass(void)
287{
288	cpu_class = i386_cpus[cpu].cpu_class;
289}
290