1 |
1623 |
jcastillo |
/*
|
2 |
|
|
* linux/arch/i386/kernel/setup.c
|
3 |
|
|
*
|
4 |
|
|
* Copyright (C) 1995 Linus Torvalds
|
5 |
|
|
*/
|
6 |
|
|
|
7 |
|
|
/*
|
8 |
|
|
* This file handles the architecture-dependent parts of initialization
|
9 |
|
|
*/
|
10 |
|
|
|
11 |
|
|
#include <linux/errno.h>
|
12 |
|
|
#include <linux/sched.h>
|
13 |
|
|
#include <linux/kernel.h>
|
14 |
|
|
#include <linux/mm.h>
|
15 |
|
|
#include <linux/stddef.h>
|
16 |
|
|
#include <linux/unistd.h>
|
17 |
|
|
#include <linux/ptrace.h>
|
18 |
|
|
#include <linux/malloc.h>
|
19 |
|
|
#include <linux/ldt.h>
|
20 |
|
|
#include <linux/user.h>
|
21 |
|
|
#include <linux/a.out.h>
|
22 |
|
|
#include <linux/tty.h>
|
23 |
|
|
#include <linux/ioport.h>
|
24 |
|
|
#include <linux/delay.h>
|
25 |
|
|
#include <linux/config.h>
|
26 |
|
|
#ifdef CONFIG_APM
|
27 |
|
|
#include <linux/apm_bios.h>
|
28 |
|
|
#endif
|
29 |
|
|
#ifdef CONFIG_BLK_DEV_RAM
|
30 |
|
|
#include <linux/blk.h>
|
31 |
|
|
#endif
|
32 |
|
|
#include <asm/segment.h>
|
33 |
|
|
#include <asm/system.h>
|
34 |
|
|
#include <asm/smp.h>
|
35 |
|
|
#include <asm/io.h>
|
36 |
|
|
|
37 |
|
|
/*
|
38 |
|
|
* Tell us the machine setup..
|
39 |
|
|
*/
|
40 |
|
|
char hard_math = 0; /* set by kernel/head.S */
|
41 |
|
|
char x86 = 0; /* set by kernel/head.S to 3..6 */
|
42 |
|
|
char x86_model = 0; /* set by kernel/head.S */
|
43 |
|
|
char x86_mask = 0; /* set by kernel/head.S */
|
44 |
|
|
int x86_capability = 0; /* set by kernel/head.S */
|
45 |
|
|
int x86_ext_capability = 0; /* newer CPUs have this */
|
46 |
|
|
int fdiv_bug = 0; /* set if Pentium(TM) with FP bug */
|
47 |
|
|
int pentium_f00f_bug = 0; /* set if Pentium(TM) with F00F bug */
|
48 |
|
|
int have_cpuid = 0; /* set if CPUID instruction works */
|
49 |
|
|
int ext_cpuid = 0; /* if != 0, highest available CPUID value */
|
50 |
|
|
|
51 |
|
|
char x86_vendor_id[13] = "GenuineIntel";/* default */
|
52 |
|
|
|
53 |
|
|
static char *Cx86_step = "unknown"; /* stepping info for Cyrix CPUs */
|
54 |
|
|
|
55 |
|
|
static unsigned char Cx86_mult = 0; /* clock multiplier for Cyrix CPUs */
|
56 |
|
|
|
57 |
|
|
static const char *x86_clkmult[] = {
|
58 |
|
|
"unknown", "1", "1.5", "2", "2.5", "3", "3.5", "4", "4.5", "5", "5.5",
|
59 |
|
|
"6", "6.5", "7", "7.5", "8"
|
60 |
|
|
};
|
61 |
|
|
|
62 |
|
|
char ignore_irq13 = 0; /* set if exception 16 works */
|
63 |
|
|
char wp_works_ok = -1; /* set if paging hardware honours WP */
|
64 |
|
|
char hlt_works_ok = 1; /* set if the "hlt" instruction works */
|
65 |
|
|
|
66 |
|
|
/*
|
67 |
|
|
* Bus types ..
|
68 |
|
|
*/
|
69 |
|
|
int EISA_bus = 0;
|
70 |
|
|
|
71 |
|
|
/*
|
72 |
|
|
* Setup options
|
73 |
|
|
*/
|
74 |
|
|
struct drive_info_struct { char dummy[32]; } drive_info;
|
75 |
|
|
struct screen_info screen_info;
|
76 |
|
|
#ifdef CONFIG_APM
|
77 |
|
|
struct apm_bios_info apm_bios_info;
|
78 |
|
|
#endif
|
79 |
|
|
|
80 |
|
|
unsigned char aux_device_present;
|
81 |
|
|
|
82 |
|
|
#ifdef CONFIG_BLK_DEV_RAM
|
83 |
|
|
extern int rd_doload; /* 1 = load ramdisk, 0 = don't load */
|
84 |
|
|
extern int rd_prompt; /* 1 = prompt for ramdisk, 0 = don't prompt */
|
85 |
|
|
extern int rd_image_start; /* starting block # of image */
|
86 |
|
|
#endif
|
87 |
|
|
|
88 |
|
|
extern int root_mountflags;
|
89 |
|
|
extern int _etext, _edata, _end;
|
90 |
|
|
|
91 |
|
|
extern char empty_zero_page[PAGE_SIZE];
|
92 |
|
|
|
93 |
|
|
/*
|
94 |
|
|
* This is set up by the setup-routine at boot-time
|
95 |
|
|
*/
|
96 |
|
|
#define PARAM empty_zero_page
|
97 |
|
|
#define EXT_MEM_K (*(unsigned short *) (PARAM+2))
|
98 |
|
|
#ifndef STANDARD_MEMORY_BIOS_CALL
|
99 |
|
|
#define ALT_MEM_K (*(unsigned long *) (PARAM+0x1e0))
|
100 |
|
|
#endif
|
101 |
|
|
#define APM_BIOS_INFO (*(struct apm_bios_info *) (PARAM+0x40))
|
102 |
|
|
#define DRIVE_INFO (*(struct drive_info_struct *) (PARAM+0x80))
|
103 |
|
|
#define SCREEN_INFO (*(struct screen_info *) (PARAM+0))
|
104 |
|
|
#define MOUNT_ROOT_RDONLY (*(unsigned short *) (PARAM+0x1F2))
|
105 |
|
|
#define RAMDISK_FLAGS (*(unsigned short *) (PARAM+0x1F8))
|
106 |
|
|
#define ORIG_ROOT_DEV (*(unsigned short *) (PARAM+0x1FC))
|
107 |
|
|
#define AUX_DEVICE_INFO (*(unsigned char *) (PARAM+0x1FF))
|
108 |
|
|
#define LOADER_TYPE (*(unsigned char *) (PARAM+0x210))
|
109 |
|
|
#define KERNEL_START (*(unsigned long *) (PARAM+0x214))
|
110 |
|
|
#define INITRD_START (*(unsigned long *) (PARAM+0x218))
|
111 |
|
|
#define INITRD_SIZE (*(unsigned long *) (PARAM+0x21c))
|
112 |
|
|
#define COMMAND_LINE ((char *) (PARAM+2048))
|
113 |
|
|
#define COMMAND_LINE_SIZE 256
|
114 |
|
|
|
115 |
|
|
#define RAMDISK_IMAGE_START_MASK 0x07FF
|
116 |
|
|
#define RAMDISK_PROMPT_FLAG 0x8000
|
117 |
|
|
#define RAMDISK_LOAD_FLAG 0x4000
|
118 |
|
|
|
119 |
|
|
static char command_line[COMMAND_LINE_SIZE] = { 0, };
|
120 |
|
|
char saved_command_line[COMMAND_LINE_SIZE];
|
121 |
|
|
|
122 |
|
|
void setup_arch(char **cmdline_p,
|
123 |
|
|
unsigned long * memory_start_p, unsigned long * memory_end_p)
|
124 |
|
|
{
|
125 |
|
|
unsigned long memory_start, memory_end;
|
126 |
|
|
#ifndef STANDARD_MEMORY_BIOS_CALL
|
127 |
|
|
unsigned long memory_alt_end;
|
128 |
|
|
#endif
|
129 |
|
|
char c = ' ', *to = command_line, *from = COMMAND_LINE;
|
130 |
|
|
int len = 0;
|
131 |
|
|
static unsigned char smptrap=0;
|
132 |
|
|
|
133 |
|
|
if(smptrap==1)
|
134 |
|
|
{
|
135 |
|
|
return;
|
136 |
|
|
}
|
137 |
|
|
smptrap=1;
|
138 |
|
|
|
139 |
|
|
ROOT_DEV = to_kdev_t(ORIG_ROOT_DEV);
|
140 |
|
|
drive_info = DRIVE_INFO;
|
141 |
|
|
screen_info = SCREEN_INFO;
|
142 |
|
|
#ifdef CONFIG_APM
|
143 |
|
|
apm_bios_info = APM_BIOS_INFO;
|
144 |
|
|
#endif
|
145 |
|
|
aux_device_present = AUX_DEVICE_INFO;
|
146 |
|
|
memory_end = (1<<20) + (EXT_MEM_K<<10);
|
147 |
|
|
#ifndef STANDARD_MEMORY_BIOS_CALL
|
148 |
|
|
memory_alt_end = (1<<20) + (ALT_MEM_K<<10);
|
149 |
|
|
if (memory_alt_end > memory_end) {
|
150 |
|
|
printk("Memory: sized by int13 0e801h\n");
|
151 |
|
|
memory_end = memory_alt_end;
|
152 |
|
|
}
|
153 |
|
|
else
|
154 |
|
|
printk("Memory: sized by int13 088h\n");
|
155 |
|
|
#endif
|
156 |
|
|
memory_end &= PAGE_MASK;
|
157 |
|
|
#ifdef CONFIG_BLK_DEV_RAM
|
158 |
|
|
rd_image_start = RAMDISK_FLAGS & RAMDISK_IMAGE_START_MASK;
|
159 |
|
|
rd_prompt = ((RAMDISK_FLAGS & RAMDISK_PROMPT_FLAG) != 0);
|
160 |
|
|
rd_doload = ((RAMDISK_FLAGS & RAMDISK_LOAD_FLAG) != 0);
|
161 |
|
|
#endif
|
162 |
|
|
#ifdef CONFIG_MAX_16M
|
163 |
|
|
if (memory_end > 16*1024*1024)
|
164 |
|
|
memory_end = 16*1024*1024;
|
165 |
|
|
#endif
|
166 |
|
|
|
167 |
|
|
/*
|
168 |
|
|
* The CONFIG_MAX_MEMSIZE sanity checker.
|
169 |
|
|
*/
|
170 |
|
|
|
171 |
|
|
if (memory_end > (CONFIG_MAX_MEMSIZE-128)*1024*1024)
|
172 |
|
|
{
|
173 |
|
|
memory_end = (CONFIG_MAX_MEMSIZE-128)*1024*1024;
|
174 |
|
|
printk(KERN_WARNING "ONLY %dMB RAM will be used, see Documentation/more-than-900MB-RAM.txt!.\n", CONFIG_MAX_MEMSIZE-128);
|
175 |
|
|
udelay(3*1000*1000);
|
176 |
|
|
}
|
177 |
|
|
|
178 |
|
|
if (!MOUNT_ROOT_RDONLY)
|
179 |
|
|
root_mountflags &= ~MS_RDONLY;
|
180 |
|
|
memory_start = (unsigned long) &_end;
|
181 |
|
|
init_task.mm->start_code = TASK_SIZE;
|
182 |
|
|
init_task.mm->end_code = TASK_SIZE + (unsigned long) &_etext;
|
183 |
|
|
init_task.mm->end_data = TASK_SIZE + (unsigned long) &_edata;
|
184 |
|
|
init_task.mm->brk = TASK_SIZE + (unsigned long) &_end;
|
185 |
|
|
|
186 |
|
|
/* Save unparsed command line copy for /proc/cmdline */
|
187 |
|
|
memcpy(saved_command_line, COMMAND_LINE, COMMAND_LINE_SIZE);
|
188 |
|
|
saved_command_line[COMMAND_LINE_SIZE-1] = '\0';
|
189 |
|
|
|
190 |
|
|
for (;;) {
|
191 |
|
|
/*
|
192 |
|
|
* "mem=nopentium" disables the 4MB page tables.
|
193 |
|
|
* "mem=XXX[kKmM]" overrides the BIOS-reported
|
194 |
|
|
* memory size
|
195 |
|
|
*/
|
196 |
|
|
if (c == ' ' && *(const unsigned long *)from == *(const unsigned long *)"mem=") {
|
197 |
|
|
if (to != command_line) to--;
|
198 |
|
|
if (!memcmp(from+4, "nopentium", 9)) {
|
199 |
|
|
from += 9+4;
|
200 |
|
|
x86_capability &= ~8;
|
201 |
|
|
} else {
|
202 |
|
|
memory_end = simple_strtoul(from+4, &from, 0);
|
203 |
|
|
if ( *from == 'K' || *from == 'k' ) {
|
204 |
|
|
memory_end = memory_end << 10;
|
205 |
|
|
from++;
|
206 |
|
|
} else if ( *from == 'M' || *from == 'm' ) {
|
207 |
|
|
memory_end = memory_end << 20;
|
208 |
|
|
from++;
|
209 |
|
|
}
|
210 |
|
|
}
|
211 |
|
|
}
|
212 |
|
|
c = *(from++);
|
213 |
|
|
if (!c)
|
214 |
|
|
break;
|
215 |
|
|
if (COMMAND_LINE_SIZE <= ++len)
|
216 |
|
|
break;
|
217 |
|
|
*(to++) = c;
|
218 |
|
|
}
|
219 |
|
|
*to = '\0';
|
220 |
|
|
*cmdline_p = command_line;
|
221 |
|
|
*memory_start_p = memory_start;
|
222 |
|
|
*memory_end_p = memory_end;
|
223 |
|
|
|
224 |
|
|
#ifdef CONFIG_BLK_DEV_INITRD
|
225 |
|
|
if (LOADER_TYPE) {
|
226 |
|
|
initrd_start = INITRD_START;
|
227 |
|
|
initrd_end = INITRD_START+INITRD_SIZE;
|
228 |
|
|
if (initrd_end > memory_end) {
|
229 |
|
|
printk("initrd extends beyond end of memory "
|
230 |
|
|
"(0x%08lx > 0x%08lx)\ndisabling initrd\n",
|
231 |
|
|
initrd_end,memory_end);
|
232 |
|
|
initrd_start = 0;
|
233 |
|
|
}
|
234 |
|
|
}
|
235 |
|
|
#endif
|
236 |
|
|
|
237 |
|
|
/* request io space for devices used on all i[345]86 PC'S */
|
238 |
|
|
request_region(0x00,0x20,"dma1");
|
239 |
|
|
request_region(0x40,0x20,"timer");
|
240 |
|
|
request_region(0x80,0x20,"dma page reg");
|
241 |
|
|
request_region(0xc0,0x20,"dma2");
|
242 |
|
|
request_region(0xf0,0x10,"npu");
|
243 |
|
|
}
|
244 |
|
|
|
245 |
|
|
static const char * IDTmodel(void)
|
246 |
|
|
/* Right now IDT has a single CPU model in production: the C6.
|
247 |
|
|
* Adjust this when IDT/Centaur comes out with a new CPU model.
|
248 |
|
|
* Stepping information is correctly reported in x86_mask.
|
249 |
|
|
*/
|
250 |
|
|
{
|
251 |
|
|
static const char *model[] = {
|
252 |
|
|
"C6", "C6-3D"
|
253 |
|
|
};
|
254 |
|
|
return model[0];
|
255 |
|
|
}
|
256 |
|
|
|
257 |
|
|
static const char * Cx86model(void)
|
258 |
|
|
/* We know our CPU is a Cyrix now (see bugs.h), so we can use the DIR0/DIR1
|
259 |
|
|
* mechanism to figure out the model, bus clock multiplier and stepping.
|
260 |
|
|
* For the newest CPUs (GXm and MXi) we use the Extended CPUID function.
|
261 |
|
|
*/
|
262 |
|
|
{
|
263 |
|
|
unsigned char nr6x86 = 0;
|
264 |
|
|
unsigned char cx_dir0 = 0; /* Model and bus clock multiplier */
|
265 |
|
|
unsigned char cx_dir1 = 0; /* Stepping info */
|
266 |
|
|
unsigned int flags;
|
267 |
|
|
static const char *model[] = {
|
268 |
|
|
"unknown", "Cx486", "5x86", "MediaGX", "6x86", "6x86L", "6x86MX",
|
269 |
|
|
"M II"
|
270 |
|
|
};
|
271 |
|
|
|
272 |
|
|
if (x86_model == -1) { /* is this an old Cx486 without DIR0/DIR1? */
|
273 |
|
|
nr6x86 = 1; /* Cx486 */
|
274 |
|
|
Cx86_mult = 0; /* unknown multiplier */
|
275 |
|
|
}
|
276 |
|
|
else {
|
277 |
|
|
|
278 |
|
|
/* Get DIR0, DIR1 since all other Cyrix CPUs have them */
|
279 |
|
|
|
280 |
|
|
save_flags(flags);
|
281 |
|
|
cli();
|
282 |
|
|
cx_dir0 = getCx86(CX86_DIR0); /* we use the access macros */
|
283 |
|
|
cx_dir1 = getCx86(CX86_DIR1); /* defined in processor.h */
|
284 |
|
|
restore_flags(flags);
|
285 |
|
|
|
286 |
|
|
/* Now cook; the recipe is by Channing Corn, from Cyrix.
|
287 |
|
|
* We do the same thing for each generation: we work out
|
288 |
|
|
* the model, multiplier and stepping.
|
289 |
|
|
*/
|
290 |
|
|
|
291 |
|
|
if (cx_dir0 < 0x20) {
|
292 |
|
|
nr6x86 = 1; /* Cx486 */
|
293 |
|
|
Cx86_mult = 0; /* unknown multiplier */
|
294 |
|
|
sprintf(Cx86_step, "%d.%d", (cx_dir1 >> 4) + 1, cx_dir1 & 0x0f);
|
295 |
|
|
}
|
296 |
|
|
|
297 |
|
|
if ((cx_dir0 > 0x20) && (cx_dir0 < 0x30)) {
|
298 |
|
|
nr6x86 = 2; /* 5x86 */
|
299 |
|
|
Cx86_mult = ((cx_dir0 & 0x04) ? 5 : 3); /* either 3x or 2x */
|
300 |
|
|
sprintf(Cx86_step, "%d.%d", (cx_dir1 >> 4) + 1, cx_dir1 & 0x0f);
|
301 |
|
|
}
|
302 |
|
|
|
303 |
|
|
if ((cx_dir0 >= 0x30) && (cx_dir0 < 0x38)) {
|
304 |
|
|
nr6x86 = ((x86_capability & (1 << 8)) ? 5 : 4); /* 6x86(L) */
|
305 |
|
|
Cx86_mult = ((cx_dir0 & 0x04) ? 5 : 3); /* either 3x or 2x */
|
306 |
|
|
sprintf(Cx86_step, "%d.%d", (cx_dir1 >> 3), cx_dir1 & 0x0f);
|
307 |
|
|
}
|
308 |
|
|
|
309 |
|
|
if ((cx_dir0 >= 0x40) && (cx_dir0 < 0x50)) {
|
310 |
|
|
if (x86 == 4) { /* MediaGX */
|
311 |
|
|
nr6x86 = 3;
|
312 |
|
|
Cx86_mult = ((cx_dir0 & 0x01) ? 5 : 7); /* either 3x or 4x */
|
313 |
|
|
switch (cx_dir1 >> 4) {
|
314 |
|
|
case (0) :
|
315 |
|
|
case (1) :
|
316 |
|
|
sprintf(Cx86_step, "2.%d", cx_dir1 & 0x0f);
|
317 |
|
|
break;
|
318 |
|
|
case (2) :
|
319 |
|
|
sprintf(Cx86_step, "1.%d", cx_dir1 & 0x0f);
|
320 |
|
|
break;
|
321 |
|
|
default :
|
322 |
|
|
break;
|
323 |
|
|
}
|
324 |
|
|
} /* endif MediaGX */
|
325 |
|
|
if (x86 == 5) { /* GXm */
|
326 |
|
|
char GXm_mult[8] = {7,11,7,11,13,15,13,9}; /* 4 to 8 */
|
327 |
|
|
ext_cpuid = 0x80000005; /* available */
|
328 |
|
|
Cx86_mult = GXm_mult[cx_dir0 & 0x0f];
|
329 |
|
|
sprintf(Cx86_step, "%d.%d", (cx_dir1 >> 4) - 1, cx_dir1 & 0x0f);
|
330 |
|
|
} /* endif GXm */
|
331 |
|
|
}
|
332 |
|
|
|
333 |
|
|
if ((cx_dir0 >= 0x50) && (cx_dir0 < 0x60)) {
|
334 |
|
|
nr6x86 = ((cx_dir1 > 7) ? 7 : 6); /* 6x86Mx or M II */
|
335 |
|
|
Cx86_mult = (cx_dir0 & 0x07) + 2; /* 2 to 5 in 0.5 steps */
|
336 |
|
|
if (((cx_dir1 & 0x0f) > 4) || ((cx_dir1 >> 4) == 2)) cx_dir1 += 0x10;
|
337 |
|
|
sprintf(Cx86_step, "%d.%d", (cx_dir1 >> 4) + 1, cx_dir1 & 0x0f);
|
338 |
|
|
}
|
339 |
|
|
}
|
340 |
|
|
x86_mask = 1; /* we don't use it, but has to be set to something */
|
341 |
|
|
return model[nr6x86];
|
342 |
|
|
}
|
343 |
|
|
|
344 |
|
|
struct cpu_model_info {
|
345 |
|
|
int cpu_x86;
|
346 |
|
|
char *model_names[16];
|
347 |
|
|
};
|
348 |
|
|
|
349 |
|
|
static struct cpu_model_info amd_models[] = {
|
350 |
|
|
{ 4,
|
351 |
|
|
{ NULL, NULL, NULL, "DX/2", NULL, NULL, NULL, "DX/2-WB", "DX/4",
|
352 |
|
|
"DX/4-WB", NULL, NULL, NULL, NULL, "Am5x86-WT", "Am5x86-WB" }},
|
353 |
|
|
{ 5,
|
354 |
|
|
{ "K5/SSA5 (PR-75, PR-90, PR-100)"}},
|
355 |
|
|
};
|
356 |
|
|
|
357 |
|
|
static const char * AMDmodel(void)
|
358 |
|
|
{
|
359 |
|
|
const char *p=NULL;
|
360 |
|
|
int i;
|
361 |
|
|
|
362 |
|
|
if ((x86_model == 0) || (x86 == 4)) {
|
363 |
|
|
for (i=0; i<sizeof(amd_models)/sizeof(struct cpu_model_info); i++)
|
364 |
|
|
if (amd_models[i].cpu_x86 == x86) {
|
365 |
|
|
p = amd_models[i].model_names[(int)x86_model];
|
366 |
|
|
break;
|
367 |
|
|
}
|
368 |
|
|
}
|
369 |
|
|
else ext_cpuid = 0x80000005; /* available */
|
370 |
|
|
return p;
|
371 |
|
|
}
|
372 |
|
|
|
373 |
|
|
static struct cpu_model_info intel_models[] = {
|
374 |
|
|
{ 4,
|
375 |
|
|
{ "486 DX-25/33", "486 DX-50", "486 SX", "486 DX/2", "486 SL",
|
376 |
|
|
"486 SX/2", NULL, "486 DX/2-WB", "486 DX/4", "486 DX/4-WB", NULL,
|
377 |
|
|
NULL, NULL, NULL, NULL, NULL }},
|
378 |
|
|
{ 5,
|
379 |
|
|
{ "Pentium 60/66 A-step", "Pentium 60/66", "Pentium 75+",
|
380 |
|
|
"OverDrive PODP5V83", "Pentium MMX", NULL, NULL,
|
381 |
|
|
"Mobile Pentium 75+", "Mobile Pentium MMX", NULL, NULL, NULL,
|
382 |
|
|
NULL, NULL, NULL, NULL }},
|
383 |
|
|
{ 6,
|
384 |
|
|
{ "Pentium Pro A-step", "Pentium Pro", NULL, "Pentium II (Klamath)",
|
385 |
|
|
NULL, "Pentium II (Deschutes)", "Celeron (Mendocino)", NULL, NULL, NULL, NULL, NULL,
|
386 |
|
|
NULL, NULL, NULL, NULL }},
|
387 |
|
|
};
|
388 |
|
|
|
389 |
|
|
static const char * Intelmodel(void)
|
390 |
|
|
{
|
391 |
|
|
const char *p = "386 SX/DX"; /* default to a 386 */
|
392 |
|
|
int i;
|
393 |
|
|
|
394 |
|
|
/*
|
395 |
|
|
* Old 486SX has no CPU ID. Set the model to 2 for this
|
396 |
|
|
* case.
|
397 |
|
|
*/
|
398 |
|
|
|
399 |
|
|
if( x86==4 && x86_model == 0 && hard_math == 0)
|
400 |
|
|
x86_model = 2;
|
401 |
|
|
|
402 |
|
|
for (i=0; i<sizeof(intel_models)/sizeof(struct cpu_model_info); i++)
|
403 |
|
|
if (intel_models[i].cpu_x86 == x86) {
|
404 |
|
|
p = intel_models[i].model_names[(int)x86_model];
|
405 |
|
|
break;
|
406 |
|
|
}
|
407 |
|
|
|
408 |
|
|
|
409 |
|
|
return p;
|
410 |
|
|
}
|
411 |
|
|
|
412 |
|
|
/* Recent Intel CPUs have an EEPROM and a ROM with CPU information. We'll use
|
413 |
|
|
* this information in future versions of this code.
|
414 |
|
|
* AMD and more recently Cyrix have decided to standardize on an extended
|
415 |
|
|
* cpuid mechanism for their CPUs.
|
416 |
|
|
*/
|
417 |
|
|
|
418 |
|
|
static const char * get_cpu_mkt_name(void)
|
419 |
|
|
{
|
420 |
|
|
static char mktbuf[48];
|
421 |
|
|
int dummy;
|
422 |
|
|
unsigned int *v;
|
423 |
|
|
v = (unsigned int *) mktbuf;
|
424 |
|
|
cpuid(0x80000002, &v[0], &v[1], &v[2], &v[3]); /* name, flags */
|
425 |
|
|
cpuid(0x80000003, &v[4], &v[5], &v[6], &v[7]);
|
426 |
|
|
cpuid(0x80000004, &v[8], &v[9], &v[10], &v[11]);
|
427 |
|
|
cpuid(0x80000001, &dummy, &dummy, &dummy, &x86_ext_capability);
|
428 |
|
|
return mktbuf;
|
429 |
|
|
}
|
430 |
|
|
|
431 |
|
|
static const char * getmodel(void)
|
432 |
|
|
/* Default is Intel. We disregard Nexgen processors. */
|
433 |
|
|
{
|
434 |
|
|
const char *p = NULL;
|
435 |
|
|
if (strcmp(x86_vendor_id, "AuthenticAMD") == 0) /* AuthenticAMD */
|
436 |
|
|
p = AMDmodel();
|
437 |
|
|
else if (strcmp(x86_vendor_id, "CyrixInstead") == 0) /* CyrixInstead */
|
438 |
|
|
p = Cx86model();
|
439 |
|
|
else if (strcmp(x86_vendor_id, "CentaurHauls") == 0) /* CentaurHauls */
|
440 |
|
|
p = IDTmodel();
|
441 |
|
|
/* This isnt quite right */
|
442 |
|
|
else if (strcmp(x86_vendor_id, "UMC UMC UMC ") == 0) /* UMC */
|
443 |
|
|
p = Intelmodel();
|
444 |
|
|
else /* default - this could be anyone */
|
445 |
|
|
p = Intelmodel();
|
446 |
|
|
if (ext_cpuid)
|
447 |
|
|
return get_cpu_mkt_name();
|
448 |
|
|
else
|
449 |
|
|
return p;
|
450 |
|
|
}
|
451 |
|
|
|
452 |
|
|
int get_cpuinfo(char * buffer)
|
453 |
|
|
{
|
454 |
|
|
int i, len = 0;
|
455 |
|
|
static const char *x86_cap_flags[] = {
|
456 |
|
|
"fpu", "vme", "de", "pse", "tsc", "msr", "pae", "mce",
|
457 |
|
|
"cx8", "apic", "10", "sep", "mtrr", "pge", "mca", "cmov",
|
458 |
|
|
"16", "17", "18", "19", "20", "21", "22", "mmx",
|
459 |
|
|
"24", "25", "26", "27", "28", "29", "30", "31"
|
460 |
|
|
};
|
461 |
|
|
static const char *x86_ext_cap_flags[] = {
|
462 |
|
|
"fpu","vme", "de", "pse", "tsc", "msr", "6", "mce",
|
463 |
|
|
"cx8", "9", "10", "syscr", "12", "pge", "14", "cmov",
|
464 |
|
|
"fpcmov", "17", "psn", "19", "20", "21", "22", "mmx",
|
465 |
|
|
"emmx", "25", "26", "27", "28", "29", "30", "3dnow"
|
466 |
|
|
};
|
467 |
|
|
|
468 |
|
|
#ifdef __SMP__
|
469 |
|
|
int n;
|
470 |
|
|
|
471 |
|
|
#define CD(X) (cpu_data[n].X)
|
472 |
|
|
/* SMP has the wrong name for loops_per_sec */
|
473 |
|
|
#define loops_per_sec udelay_val
|
474 |
|
|
#define CPUN n
|
475 |
|
|
|
476 |
|
|
for ( n = 0 ; n < 32 ; n++ ) {
|
477 |
|
|
if ( cpu_present_map & (1<<n) ) {
|
478 |
|
|
if (len) buffer[len++] = '\n';
|
479 |
|
|
|
480 |
|
|
#else
|
481 |
|
|
#define CD(X) (X)
|
482 |
|
|
#define CPUN 0
|
483 |
|
|
#endif
|
484 |
|
|
|
485 |
|
|
len += sprintf(buffer+len,"processor\t: %d\n"
|
486 |
|
|
"cpu\t\t: %c86\n"
|
487 |
|
|
"model\t\t: %s",
|
488 |
|
|
CPUN,
|
489 |
|
|
CD(x86)+'0',
|
490 |
|
|
getmodel());
|
491 |
|
|
len += sprintf(buffer+len,
|
492 |
|
|
"\nvendor_id\t: %s\n",
|
493 |
|
|
x86_vendor_id);
|
494 |
|
|
|
495 |
|
|
if (CD(x86_mask) || have_cpuid)
|
496 |
|
|
if ((strncmp(x86_vendor_id, "Au", 2) == 0)
|
497 |
|
|
&& (x86_model >= 6)) {
|
498 |
|
|
len += sprintf(buffer+len,
|
499 |
|
|
"stepping\t: %c\n",
|
500 |
|
|
x86_mask + 'A');
|
501 |
|
|
}
|
502 |
|
|
else if (strncmp(x86_vendor_id, "Cy", 2) == 0) {
|
503 |
|
|
len += sprintf(buffer+len,
|
504 |
|
|
"stepping\t: %s, core/bus clock ratio: %sx\n",
|
505 |
|
|
Cx86_step, x86_clkmult[Cx86_mult]);
|
506 |
|
|
}
|
507 |
|
|
else {
|
508 |
|
|
len += sprintf(buffer+len,
|
509 |
|
|
"stepping\t: %d\n",
|
510 |
|
|
CD(x86_mask));
|
511 |
|
|
}
|
512 |
|
|
else
|
513 |
|
|
len += sprintf(buffer+len,
|
514 |
|
|
"stepping\t: unknown\n");
|
515 |
|
|
|
516 |
|
|
len += sprintf(buffer+len,
|
517 |
|
|
"fdiv_bug\t: %s\n"
|
518 |
|
|
"hlt_bug\t\t: %s\n"
|
519 |
|
|
"f00f_bug\t: %s\n"
|
520 |
|
|
"fpu\t\t: %s\n"
|
521 |
|
|
"fpu_exception\t: %s\n"
|
522 |
|
|
"cpuid\t\t: %s\n"
|
523 |
|
|
"wp\t\t: %s\n"
|
524 |
|
|
"flags\t\t:",
|
525 |
|
|
CD(fdiv_bug) ? "yes" : "no",
|
526 |
|
|
CD(hlt_works_ok) ? "no" : "yes",
|
527 |
|
|
pentium_f00f_bug ? "yes" : "no",
|
528 |
|
|
CD(hard_math) ? "yes" : "no",
|
529 |
|
|
(CD(hard_math) && ignore_irq13)
|
530 |
|
|
? "yes" : "no",
|
531 |
|
|
CD(have_cpuid) ? "yes" : "no",
|
532 |
|
|
CD(wp_works_ok) ? "yes" : "no");
|
533 |
|
|
|
534 |
|
|
for ( i = 0 ; i < 32 ; i++ ) {
|
535 |
|
|
if ( CD(x86_capability) & (1 << i) ) {
|
536 |
|
|
len += sprintf(buffer+len, " %s",
|
537 |
|
|
x86_cap_flags[i]);
|
538 |
|
|
}
|
539 |
|
|
else if ( CD(x86_ext_capability) & (1 << i) ) {
|
540 |
|
|
len += sprintf(buffer+len, " %s",
|
541 |
|
|
x86_ext_cap_flags[i]);
|
542 |
|
|
}
|
543 |
|
|
}
|
544 |
|
|
len += sprintf(buffer+len,
|
545 |
|
|
"\nbogomips\t: %lu.%02lu\n",
|
546 |
|
|
CD(loops_per_sec+2500)/500000,
|
547 |
|
|
(CD(loops_per_sec+2500)/5000) % 100);
|
548 |
|
|
#ifdef __SMP__
|
549 |
|
|
}
|
550 |
|
|
}
|
551 |
|
|
#endif
|
552 |
|
|
return len;
|
553 |
|
|
}
|