OpenCores
URL https://opencores.org/ocsvn/or1k/or1k/trunk

Subversion Repositories or1k

[/] [or1k/] [trunk/] [uclinux/] [uClinux-2.0.x/] [include/] [asm-i386/] [bugs.h] - Blame information for rev 199

Go to most recent revision | Details | Compare with Previous | View Log

Line No. Rev Author Line
1 199 simons
/*
2
 *  include/asm-i386/bugs.h
3
 *
4
 *  Copyright (C) 1994  Linus Torvalds
5
 */
6
 
7
/*
8
 * This is included by init/main.c to check for architecture-dependent bugs.
9
 *
10
 * Needs:
11
 *      void check_bugs(void);
12
 */
13
 
14
#include <linux/config.h>
15
 
16
#define CONFIG_BUGi386
17
 
18
static void no_halt(char *s, int *ints)
19
{
20
        hlt_works_ok = 0;
21
}
22
 
23
static void no_387(char *s, int *ints)
24
{
25
        hard_math = 0;
26
        __asm__("movl %%cr0,%%eax\n\t"
27
                "orl $0xE,%%eax\n\t"
28
                "movl %%eax,%%cr0\n\t" : : : "ax");
29
}
30
 
31
static char fpu_error = 0;
32
 
33
static void copro_timeout(void)
34
{
35
        fpu_error = 1;
36
        timer_table[COPRO_TIMER].expires = jiffies+100;
37
        timer_active |= 1<<COPRO_TIMER;
38
        printk("387 failed: trying to reset\n");
39
        send_sig(SIGFPE, last_task_used_math, 1);
40
        outb_p(0,0xf1);
41
        outb_p(0,0xf0);
42
}
43
 
44
static void check_fpu(void)
45
{
46
        static double x = 4195835.0;
47
        static double y = 3145727.0;
48
        unsigned short control_word;
49
 
50
        if (!hard_math) {
51
#ifndef CONFIG_MATH_EMULATION
52
                printk("No coprocessor found and no math emulation present.\n");
53
                printk("Giving up.\n");
54
                for (;;) ;
55
#endif
56
                return;
57
        }
58
        /*
59
         * check if exception 16 works correctly.. This is truly evil
60
         * code: it disables the high 8 interrupts to make sure that
61
         * the irq13 doesn't happen. But as this will lead to a lockup
62
         * if no exception16 arrives, it depends on the fact that the
63
         * high 8 interrupts will be re-enabled by the next timer tick.
64
         * So the irq13 will happen eventually, but the exception 16
65
         * should get there first..
66
         */
67
        printk("Checking 386/387 coupling... ");
68
        timer_table[COPRO_TIMER].expires = jiffies+50;
69
        timer_table[COPRO_TIMER].fn = copro_timeout;
70
        timer_active |= 1<<COPRO_TIMER;
71
        __asm__("clts ; fninit ; fnstcw %0 ; fwait":"=m" (*&control_word));
72
        control_word &= 0xffc0;
73
        __asm__("fldcw %0 ; fwait": :"m" (*&control_word));
74
        outb_p(inb_p(0x21) | (1 << 2), 0x21);
75
        __asm__("fldz ; fld1 ; fdiv %st,%st(1) ; fwait");
76
        timer_active &= ~(1<<COPRO_TIMER);
77
        if (fpu_error)
78
                return;
79
        if (!ignore_irq13) {
80
                printk("Ok, fpu using old IRQ13 error reporting\n");
81
                return;
82
        }
83
        __asm__("fninit\n\t"
84
                "fldl %1\n\t"
85
                "fdivl %2\n\t"
86
                "fmull %2\n\t"
87
                "fldl %1\n\t"
88
                "fsubp %%st,%%st(1)\n\t"
89
                "fistpl %0\n\t"
90
                "fwait\n\t"
91
                "fninit"
92
                : "=m" (*&fdiv_bug)
93
                : "m" (*&x), "m" (*&y));
94
        if (!fdiv_bug) {
95
                printk("Ok, fpu using exception 16 error reporting.\n");
96
                return;
97
 
98
        }
99
        printk("Hmm, FDIV bug i%c86 system\n", '0'+x86);
100
}
101
 
102
static void check_hlt(void)
103
{
104
        printk("Checking 'hlt' instruction... ");
105
        if (!hlt_works_ok) {
106
                printk("disabled\n");
107
                return;
108
        }
109
        __asm__ __volatile__("hlt ; hlt ; hlt ; hlt");
110
        printk("Ok.\n");
111
}
112
 
113
static void check_tlb(void)
114
{
115
#ifndef CONFIG_M386
116
        /*
117
         * The 386 chips don't support TLB finegrained invalidation.
118
         * They will fault when they hit a invlpg instruction.
119
         */
120
        if (x86 == 3) {
121
                printk("CPU is a 386 and this kernel was compiled for 486 or better.\n");
122
                printk("Giving up.\n");
123
                for (;;) ;
124
        }
125
#endif
126
}
127
 
128
/*
129
 * All current models of Pentium and Pentium with MMX technology CPUs
130
 * have the F0 0F bug, which lets nonpriviledged users lock up the system:
131
 */
132
extern int pentium_f00f_bug;
133
extern void trap_init_f00f_bug(void);
134
 
135
/*
136
 * Access to machine-specific registers (available on 586 and better only)
137
 * Note: the rd* operations modify the parameters directly (without using
138
 * pointer indirection), this allows gcc to optimize better
139
 * Code from Richard Gooch's 2.2 MTRR drivers.
140
 */
141
 
142
#define rdmsr(msr,val1,val2) \
143
       __asm__ __volatile__("rdmsr" \
144
                            : "=a" (val1), "=d" (val2) \
145
                            : "c" (msr))
146
 
147
#define wrmsr(msr,val1,val2) \
148
     __asm__ __volatile__("wrmsr" \
149
                          : /* no outputs */ \
150
                          : "c" (msr), "a" (val1), "d" (val2))
151
 
152
 
153
static void check_pentium_f00f(void)
154
{
155
        /*
156
         * Pentium and Pentium MMX
157
         */
158
        pentium_f00f_bug = 0;
159
        if (x86==5 && !memcmp(x86_vendor_id, "GenuineIntel", 12)) {
160
                printk(KERN_INFO "Intel Pentium with F0 0F bug - workaround enabled.\n");
161
                pentium_f00f_bug = 1;
162
                trap_init_f00f_bug();
163
        }
164
}
165
 
166
static void check_privacy(void)
167
{
168
        /*
169
         * Pentium III or higher - processors with mtrrs/cpuid
170
         */
171
        if(memcmp(x86_vendor_id, "GenuineIntel", 12))
172
                return;
173
        if(x86_capability & (1<<18))
174
        {
175
                /*
176
                 *      Thanks to Phil Karn for this bit.
177
                 */
178
                unsigned long lo,hi;
179
                rdmsr(0x119,lo,hi);
180
                lo |= 0x200000;
181
                wrmsr(0x119,lo,hi);
182
                printk(KERN_INFO "Pentium-III serial number disabled.\n");
183
        }
184
}
185
 
186
/*
187
 *      B step AMD K6 before B 9730xxxx have hardware bugs that can cause
188
 *      misexecution of code under Linux. Owners of such processors should
189
 *      contact AMD for precise details and a (free) CPU exchange.
190
 *
191
 *      See     http://www.chorus.com/~poulot/k6bug.html
192
 *              http://www.amd.com/K6/k6docs/revgd.html
193
 *
194
 *      The following test is erm... interesting. AMD neglected to up
195
 *      the chip stepping when fixing the bug but they also tweaked some
196
 *      performance at the same time...
197
 */
198
 
199
extern void vide(void);
200
__asm__(".align 4\nvide: ret");
201
 
202
static void check_k6_bug(void)
203
{
204
 
205
        if ((strcmp(x86_vendor_id, "AuthenticAMD") == 0) &&
206
            (x86_model == 6) && (x86_mask == 1))
207
        {
208
                int n;
209
                void (*f_vide)(void);
210
                unsigned long d, d2;
211
 
212
                printk(KERN_INFO "AMD K6 stepping B detected - ");
213
 
214
#define K6_BUG_LOOP 1000000
215
 
216
                /*
217
                 * It looks like AMD fixed the 2.6.2 bug and improved indirect
218
                 * calls at the same time.
219
                 */
220
 
221
                n = K6_BUG_LOOP;
222
                f_vide = vide;
223
                __asm__ ("rdtsc" : "=a" (d));
224
                while (n--)
225
                        f_vide();
226
                __asm__ ("rdtsc" : "=a" (d2));
227
                d = d2-d;
228
 
229
                if (d > 20*K6_BUG_LOOP) {
230
                        printk("system stability may be impaired when more than 32 MB are used.\n");
231
                }
232
                else
233
                        printk("probably OK (after B9730xxxx).\n");
234
        }
235
}
236
 
237
/* Cyrix stuff from this point on */
238
 
239
/* Cyrix 5/2 test (return 0x200 if it's a Cyrix) */
240
static inline int test_cyrix_52div(void)
241
{
242
        int test;
243
 
244
        __asm__ __volatile__("xor %%eax,%%eax\n\t"
245
             "sahf\n\t"
246
             "movb $5,%%al\n\t"
247
             "movb $2,%%bl\n\t"
248
             "div %%bl\n\t"
249
             "lahf\n\t"
250
             "andl $0xff00,%%eax": "=eax" (test) : : "bx");
251
 
252
        return test;
253
}
254
 
255
/* test for CCR3 bit 7 r/w */
256
static char test_cyrix_cr3rw(void)
257
{
258
        char temp, test;
259
 
260
        temp = getCx86(CX86_CCR3);      /* get current CCR3 value */
261
        setCx86(CX86_CCR3, temp ^ 0x80); /* toggle test bit and write */
262
        getCx86(0xc0);                  /* dummy to change bus */
263
        test = temp - getCx86(CX86_CCR3);       /* != 0 if ccr3 r/w */
264
        setCx86(CX86_CCR3, temp);       /* return CCR3 to original value */
265
 
266
        return test;
267
}
268
 
269
/* redo the cpuid test in head.S, so that those 6x86(L) now get
270
   detected properly (0 == no cpuid) */
271
static inline int test_cpuid(void)
272
{
273
        int test;
274
 
275
        __asm__("pushfl\n\t"
276
             "popl %%eax\n\t"
277
             "movl %%eax,%%ecx\n\t"
278
             "xorl $0x200000,%%eax\n\t"
279
             "pushl %%eax\n\t"
280
             "popfl\n\t"
281
             "pushfl\n\t"
282
             "popl %%eax\n\t"
283
             "xorl %%ecx,%%eax\n\t"
284
             "pushl %%ecx\n\t"
285
             "popfl" : "=eax" (test) : : "cx");
286
 
287
        return test;
288
}
289
 
290
/* All Cyrix 6x86 and 6x86L need the SLOP bit reset so that the udelay loop
291
 * calibration works well.
292
 * This routine must be called with MAPEN enabled, otherwise we don't
293
 * have access to CCR5.
294
 */
295
 
296
static void check_6x86_slop(void)
297
{
298
        if (x86_model == 2)     /* if 6x86 or 6x86L */
299
                setCx86(CX86_CCR5, getCx86(CX86_CCR5) & 0xfd); /* reset SLOP */
300
}
301
 
302
/* Cyrix CPUs without cpuid or with cpuid not yet enabled can be detected
303
 * by the fact that they preserve the flags across the division of 5/2.
304
 * PII and PPro exhibit this behavior too, but they have cpuid available.
305
 */
306
 
307
static void check_cyrix_various(void)
308
{
309
        if ((x86 == 4) && (test_cyrix_52div()==0x200))
310
        {
311
                /* if it's a Cyrix */
312
 
313
                unsigned long flags;
314
 
315
                /* default to an "old" Cx486 */
316
                strcpy(x86_vendor_id, "CyrixInstead");
317
                x86_model = -1;
318
                x86_mask = 0;
319
 
320
                /* Disable interrupts */
321
                save_flags(flags);
322
                cli();
323
 
324
                /* First check for very old CX486 models */
325
                /* that did not have DIR0/DIR1. */
326
                if (test_cyrix_cr3rw())
327
                {       /* if has DIR0/DIR1 */
328
 
329
                        char ccr3;
330
                        char dir0;
331
                        x86_model = 0;
332
 
333
                        /* Enable MAPEN */
334
                        ccr3 = getCx86(CX86_CCR3);
335
                        setCx86(CX86_CCR3, (ccr3 & 0x0f) | 0x10);
336
 
337
                        dir0 = getCx86(CX86_DIR0);
338
                        if ((dir0 & 0xf0) == 0x30)      /* Use DIR0 to determine if this is a 6x86 class processor */
339
                        {
340
                                /* try enabling cpuid */
341
                                setCx86(CX86_CCR4, getCx86(CX86_CCR4) | 0x80);
342
                        }
343
 
344
                        if (test_cpuid())
345
                        {
346
                                int eax, dummy;
347
 
348
                                /* get processor info */
349
 
350
                                cpuid(1, &eax, &dummy, &dummy,
351
                                      &x86_capability);
352
 
353
                                have_cpuid = 1;
354
                                x86_model = (eax >> 4) & 0xf;
355
                                x86 = (eax >> 8) & 0xf;
356
                                check_6x86_slop();
357
                        }
358
                        /* disable MAPEN */
359
                        setCx86(CX86_CCR3, ccr3);
360
                } /* endif has DIR0/DIR1 */
361
                sti();
362
                restore_flags(flags);   /* restore interrupt state */
363
        } /* endif it's a Cyrix */
364
}
365
 
366
/* Check various processor bugs */
367
 
368
static void check_bugs(void)
369
{
370
        check_cyrix_various();
371
        check_k6_bug();
372
        check_tlb();
373
        check_fpu();
374
        check_hlt();
375
        check_pentium_f00f();
376
        check_privacy();
377
        system_utsname.machine[1] = '0' + x86;
378
}

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.