1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172
|
/*
* include/asm-i386/bugs.h
*
* Copyright (C) 1994 Linus Torvalds
*/
/*
* This is included by init/main.c to check for architecture-dependent bugs.
*
* Needs:
* void check_bugs(void);
*/
#include <linux/config.h>
#define CONFIG_BUGi386
#ifdef CONFIG_MCA
static void mca_pentium( char* s, int* ints ) {
/* some Pentiums with MCA bus have this habit of dying after the
FPU test is done. Has something to do with the IRQs being screwed.
I don't have a Pentium to test, so this is the best I can do to fix
the problem. */
has_mca_pentium = 1;
}
#endif
static void no_halt(char *s, int *ints)
{
hlt_works_ok = 0;
}
static void no_387(char *s, int *ints)
{
hard_math = 0;
__asm__("movl %%cr0,%%eax\n\t"
"orl $0xE,%%eax\n\t"
"movl %%eax,%%cr0\n\t" : : : "ax");
}
static char fpu_error = 0;
static void copro_timeout(void)
{
fpu_error = 1;
timer_table[COPRO_TIMER].expires = jiffies+100;
timer_active |= 1<<COPRO_TIMER;
printk("387 failed: trying to reset\n");
send_sig(SIGFPE, last_task_used_math, 1);
outb_p(0,0xf1);
outb_p(0,0xf0);
}
static void check_fpu(void)
{
static double x = 4195835.0;
static double y = 3145727.0;
unsigned short control_word;
if (!hard_math) {
#ifndef CONFIG_MATH_EMULATION
printk("No coprocessor found and no math emulation present.\n");
printk("Giving up.\n");
for (;;) ;
#endif
return;
}
/*
* check if exception 16 works correctly.. This is truly evil
* code: it disables the high 8 interrupts to make sure that
* the irq13 doesn't happen. But as this will lead to a lockup
* if no exception16 arrives, it depends on the fact that the
* high 8 interrupts will be re-enabled by the next timer tick.
* So the irq13 will happen eventually, but the exception 16
* should get there first..
*/
printk("Checking 386/387 coupling... ");
timer_table[COPRO_TIMER].expires = jiffies+50;
timer_table[COPRO_TIMER].fn = copro_timeout;
timer_active |= 1<<COPRO_TIMER;
__asm__("clts ; fninit ; fnstcw %0 ; fwait":"=m" (*&control_word));
control_word &= 0xffc0;
__asm__("fldcw %0 ; fwait": :"m" (*&control_word));
outb_p(inb_p(0x21) | (1 << 2), 0x21);
__asm__("fldz ; fld1 ; fdiv %st,%st(1) ; fwait");
timer_active &= ~(1<<COPRO_TIMER);
if (fpu_error)
return;
if (!ignore_irq13) {
printk("Ok, fpu using old IRQ13 error reporting\n");
return;
}
__asm__("fninit\n\t"
"fldl %1\n\t"
"fdivl %2\n\t"
"fmull %2\n\t"
"fldl %1\n\t"
"fsubp %%st,%%st(1)\n\t"
"fistpl %0\n\t"
"fwait\n\t"
"fninit"
: "=m" (*&fdiv_bug)
: "m" (*&x), "m" (*&y));
if (!fdiv_bug) {
printk("Ok, fpu using exception 16 error reporting.\n");
return;
}
printk("Hmm, FDIV bug i%c86 system\n", '0'+x86);
}
static void check_hlt(void)
{
printk("Checking 'hlt' instruction... ");
if (!hlt_works_ok) {
printk("disabled\n");
return;
}
__asm__ __volatile__("hlt ; hlt ; hlt ; hlt");
printk("Ok.\n");
}
static void check_tlb(void)
{
#ifndef CONFIG_M386
/*
* The 386 chips don't support TLB finegrained invalidation.
* They will fault when they hit a invlpg instruction.
*/
if (x86 == 3) {
printk("CPU is a 386 and this kernel was compiled for 486 or better.\n");
printk("Giving up.\n");
for (;;) ;
}
#endif
}
/*
* All current models of Pentium and Pentium with MMX technology CPUs
* have the F0 0F bug, which lets nonpriviledged users lock up the system:
*/
extern int pentium_f00f_bug;
extern void trap_init_f00f_bug(void);
static void check_pentium_f00f(void)
{
/*
* Pentium and Pentium MMX
*/
pentium_f00f_bug = 0;
if (x86==5 && !memcmp(x86_vendor_id, "GenuineIntel", 12)) {
printk(KERN_INFO "Intel Pentium with F0 0F bug - workaround enabled.\n");
pentium_f00f_bug = 1;
trap_init_f00f_bug();
}
}
static void check_bugs(void)
{
check_tlb();
#ifdef CONFIG_MCA
if( !has_mca_pentium ) {
check_fpu();
}
#else
check_fpu();
#endif
check_hlt();
check_pentium_f00f();
system_utsname.machine[1] = '0' + x86;
}
|