2 * include/asm-i386/bugs.h
4 * Copyright (C) 1994 Linus Torvalds
6 * Cyrix stuff, June 1998 by:
7 * - Rafael R. Reilova (moved everything from head.S),
8 * - Channing Corn (tests & fixes),
9 * - Andrew D. Balsa (code cleanup).
13 * This is included by init/main.c to check for architecture-dependent bugs.
16 * void check_bugs(void);
19 #include <linux/config.h>
20 #include <asm/processor.h>
22 #define CONFIG_BUGi386
24 __initfunc(static void no_halt(char *s
, int *ints
))
26 boot_cpu_data
.hlt_works_ok
= 0;
29 __initfunc(static void no_387(char *s
, int *ints
))
31 boot_cpu_data
.hard_math
= 0;
32 __asm__("movl %%cr0,%%eax\n\t"
34 "movl %%eax,%%cr0\n\t" : : : "ax");
37 static char __initdata fpu_error
= 0;
39 __initfunc(static void copro_timeout(void))
42 timer_table
[COPRO_TIMER
].expires
= jiffies
+100;
43 timer_active
|= 1<<COPRO_TIMER
;
44 printk(KERN_ERR
"387 failed: trying to reset\n");
45 send_sig(SIGFPE
, current
, 1);
50 static double __initdata x
= 4195835.0;
51 static double __initdata y
= 3145727.0;
53 __initfunc(static void check_fpu(void))
55 unsigned short control_word
;
57 if (!boot_cpu_data
.hard_math
) {
58 #ifndef CONFIG_MATH_EMULATION
59 printk(KERN_EMERG
"No coprocessor found and no math emulation present.\n");
60 printk(KERN_EMERG
"Giving up.\n");
66 * check if exception 16 works correctly.. This is truly evil
67 * code: it disables the high 8 interrupts to make sure that
68 * the irq13 doesn't happen. But as this will lead to a lockup
69 * if no exception16 arrives, it depends on the fact that the
70 * high 8 interrupts will be re-enabled by the next timer tick.
71 * So the irq13 will happen eventually, but the exception 16
72 * should get there first..
74 printk(KERN_INFO
"Checking 386/387 coupling... ");
75 timer_table
[COPRO_TIMER
].expires
= jiffies
+50;
76 timer_table
[COPRO_TIMER
].fn
= copro_timeout
;
77 timer_active
|= 1<<COPRO_TIMER
;
78 __asm__("clts ; fninit ; fnstcw %0 ; fwait":"=m" (*&control_word
));
79 control_word
&= 0xffc0;
80 __asm__("fldcw %0 ; fwait": :"m" (*&control_word
));
81 outb_p(inb_p(0x21) | (1 << 2), 0x21);
82 __asm__("fldz ; fld1 ; fdiv %st,%st(1) ; fwait");
83 timer_active
&= ~(1<<COPRO_TIMER
);
87 printk("OK, FPU using old IRQ 13 error reporting\n");
95 "fsubp %%st,%%st(1)\n\t"
99 : "=m" (*&boot_cpu_data
.fdiv_bug
)
100 : "m" (*&x
), "m" (*&y
));
101 if (!boot_cpu_data
.fdiv_bug
)
102 printk("OK, FPU using exception 16 error reporting.\n");
104 printk("Hmm, FPU using exception 16 error reporting with FDIV bug.\n");
107 __initfunc(static void check_hlt(void))
109 printk(KERN_INFO
"Checking 'hlt' instruction... ");
110 if (!boot_cpu_data
.hlt_works_ok
) {
111 printk("disabled\n");
114 __asm__
__volatile__("hlt ; hlt ; hlt ; hlt");
118 __initfunc(static void check_tlb(void))
122 * The 386 chips don't support TLB finegrained invalidation.
123 * They will fault when they hit an invlpg instruction.
125 if (boot_cpu_data
.x86
== 3) {
126 printk(KERN_EMERG
"CPU is a 386 and this kernel was compiled for 486 or better.\n");
127 printk("Giving up.\n");
134 * Most 386 processors have a bug where a POPAD can lock the
135 * machine even from user space.
138 __initfunc(static void check_popad(void))
141 int res
, inp
= (int) &res
;
143 printk(KERN_INFO
"Checking for popad bug... ");
144 __asm__
__volatile__(
145 "movl $12345678,%%eax; movl $0,%%edi; pusha; popa; movl (%%edx,%%edi),%%ecx "
148 : "eax", "ecx", "edx", "edi" );
149 /* If this fails, it means that any user program may lock the CPU hard. Too bad. */
150 if (res
!= 12345678) printk( "Buggy.\n" );
151 else printk( "OK.\n" );
156 * B step AMD K6 before B 9730xxxx have hardware bugs that can cause
157 * misexecution of code under Linux. Owners of such processors should
158 * contact AMD for precise details and a CPU swap.
160 * See http://www.mygale.com/~poulot/k6bug.html
161 * http://www.amd.com/K6/k6docs/revgd.html
163 * The following test is erm.. interesting. AMD neglected to up
164 * the chip setting when fixing the bug but they also tweaked some
165 * performance at the same time..
168 extern void vide(void);
169 __asm__(".align 4\nvide: ret");
171 __initfunc(static void check_amd_k6(void))
173 if (boot_cpu_data
.x86_vendor
== X86_VENDOR_AMD
&&
174 boot_cpu_data
.x86_model
== 6 &&
175 boot_cpu_data
.x86_mask
== 1)
178 void (*f_vide
)(void);
181 printk(KERN_INFO
"AMD K6 stepping B detected - ");
183 #define K6_BUG_LOOP 1000000
186 * It looks like AMD fixed the 2.6.2 bug and improved indirect
187 * calls at the same time.
192 __asm__ ("rdtsc" : "=a" (d
));
195 __asm__ ("rdtsc" : "=a" (d2
));
198 /* Knock these two lines out if it debugs out ok */
199 printk(KERN_INFO
"K6 BUG %ld %d (Report these if test report is incorrect)\n", d
, 20*K6_BUG_LOOP
);
200 printk(KERN_INFO
"AMD K6 stepping B detected - ");
202 if (d
> 20*K6_BUG_LOOP
)
203 printk("system stability may be impaired when more than 32 MB are used.\n");
205 printk("probably OK (after B9730xxxx).\n");
206 printk(KERN_INFO
"Please see http://www.mygale.com/~poulot/k6bug.html\n");
211 * All current models of Pentium and Pentium with MMX technology CPUs
212 * have the F0 0F bug, which lets nonpriviledged users lock up the system:
215 extern void trap_init_f00f_bug(void);
217 __initfunc(static void check_pentium_f00f(void))
220 * Pentium and Pentium MMX
222 boot_cpu_data
.f00f_bug
= 0;
223 if (boot_cpu_data
.x86
== 5 && boot_cpu_data
.x86_vendor
== X86_VENDOR_INTEL
) {
224 printk(KERN_INFO
"Intel Pentium with F0 0F bug - workaround enabled.\n");
225 boot_cpu_data
.f00f_bug
= 1;
226 trap_init_f00f_bug();
231 * Perform the Cyrix 5/2 test. A Cyrix won't change
232 * the flags, while other 486 chips will.
235 static inline int test_cyrix_52div(void)
239 __asm__
__volatile__(
240 "sahf\n\t" /* clear flags (%eax = 0x0005) */
241 "div %b2\n\t" /* divide 5 by 2 */
242 "lahf" /* store flags into %ah */
247 /* AH is 0x02 on Cyrix after the divide.. */
248 return (unsigned char) (test
>> 8) == 0x02;
252 * Cyrix CPUs without cpuid or with cpuid not yet enabled can be detected
253 * by the fact that they preserve the flags across the division of 5/2.
254 * PII and PPro exhibit this behavior too, but they have cpuid available.
257 __initfunc(static void check_cyrix_cpu(void))
259 if ((boot_cpu_data
.cpuid_level
== -1) && (boot_cpu_data
.x86
== 4)
260 && test_cyrix_52div()) {
262 /* default to an unknown Cx486, (we will differentiate later) */
263 /* NOTE: using 0xff since 0x00 is a valid DIR0 value */
264 strcpy(boot_cpu_data
.x86_vendor_id
, "CyrixInstead");
265 boot_cpu_data
.x86_model
= 0xff;
266 boot_cpu_data
.x86_mask
= 0;
271 * Fix two problems with the Cyrix 6x86 and 6x86L:
272 * -- the cpuid is disabled on power up, enable it, use it.
273 * -- the SLOP bit needs resetting on some motherboards due to old BIOS,
274 * so that the udelay loop calibration works well. Recalibrate.
277 extern void calibrate_delay(void) __init
;
279 __initfunc(static void check_cx686_cpuid_slop(void))
281 if (boot_cpu_data
.x86_vendor
== X86_VENDOR_CYRIX
&&
282 (boot_cpu_data
.x86_model
& 0xf0) == 0x30) { /* 6x86(L) */
284 unsigned char ccr3
, ccr4
, ccr5
;
287 ccr3
= getCx86(CX86_CCR3
);
288 setCx86(CX86_CCR3
, (ccr3
& 0x0f) | 0x10); /* enable MAPEN */
289 ccr4
= getCx86(CX86_CCR4
);
290 setCx86(CX86_CCR4
, ccr4
| 0x80); /* enable cpuid */
291 ccr5
= getCx86(CX86_CCR5
);
292 if (ccr5
& 2) /* reset SLOP if needed, old BIOS do this wrong */
293 setCx86(CX86_CCR5
, ccr5
& 0xfd);
294 setCx86(CX86_CCR3
, ccr3
); /* disable MAPEN */
297 boot_cpu_data
.cpuid_level
= 1; /* should cover all 6x86(L) */
298 boot_cpu_data
.x86
= 5;
300 /* we know we have level 1 available on the 6x86(L) */
301 cpuid(1, &dummy
, &dummy
, &dummy
,
302 &boot_cpu_data
.x86_capability
);
304 * DON'T use the x86_mask and x86_model from cpuid, these are
305 * not as accurate (or the same) as those from the DIR regs.
306 * already in place after cyrix_model() in setup.c
309 if (ccr5
& 2) { /* possible wrong calibration done */
310 printk(KERN_INFO
"Recalibrating delay loop with SLOP bit reset\n");
312 boot_cpu_data
.loops_per_sec
= loops_per_sec
;
317 __initfunc(static void check_bugs(void))
320 identify_cpu(&boot_cpu_data
);
323 print_cpu_info(&boot_cpu_data
);
325 check_cx686_cpuid_slop();
331 check_pentium_f00f();
332 system_utsname
.machine
[1] = '0' + boot_cpu_data
.x86
;