linux/arch/x86/kernel/cpu/bugs.c
<<
>>
Prefs
   1/*
   2 *  Copyright (C) 1994  Linus Torvalds
   3 *
   4 *  Cyrix stuff, June 1998 by:
   5 *      - Rafael R. Reilova (moved everything from head.S),
   6 *        <rreilova@ececs.uc.edu>
   7 *      - Channing Corn (tests & fixes),
   8 *      - Andrew D. Balsa (code cleanup).
   9 */
  10#include <linux/init.h>
  11#include <linux/utsname.h>
  12#include <asm/bugs.h>
  13#include <asm/processor.h>
  14#include <asm/processor-flags.h>
  15#include <asm/i387.h>
  16#include <asm/msr.h>
  17#include <asm/paravirt.h>
  18#include <asm/alternative.h>
  19
  20static int __init no_halt(char *s)
  21{
  22        boot_cpu_data.hlt_works_ok = 0;
  23        return 1;
  24}
  25
  26__setup("no-hlt", no_halt);
  27
  28static int __init no_387(char *s)
  29{
  30        boot_cpu_data.hard_math = 0;
  31        write_cr0(X86_CR0_TS | X86_CR0_EM | X86_CR0_MP | read_cr0());
  32        return 1;
  33}
  34
  35__setup("no387", no_387);
  36
  37static double __initdata x = 4195835.0;
  38static double __initdata y = 3145727.0;
  39
  40/*
  41 * This used to check for exceptions..
  42 * However, it turns out that to support that,
  43 * the XMM trap handlers basically had to
  44 * be buggy. So let's have a correct XMM trap
  45 * handler, and forget about printing out
  46 * some status at boot.
  47 *
  48 * We should really only care about bugs here
  49 * anyway. Not features.
  50 */
  51static void __init check_fpu(void)
  52{
  53        s32 fdiv_bug;
  54
  55        if (!boot_cpu_data.hard_math) {
  56#ifndef CONFIG_MATH_EMULATION
  57                printk(KERN_EMERG "No coprocessor found and no math emulation present.\n");
  58                printk(KERN_EMERG "Giving up.\n");
  59                for (;;) ;
  60#endif
  61                return;
  62        }
  63
  64        /*
  65         * trap_init() enabled FXSR and company _before_ testing for FP
  66         * problems here.
  67         *
  68         * Test for the divl bug..
  69         */
  70        __asm__("fninit\n\t"
  71                "fldl %1\n\t"
  72                "fdivl %2\n\t"
  73                "fmull %2\n\t"
  74                "fldl %1\n\t"
  75                "fsubp %%st,%%st(1)\n\t"
  76                "fistpl %0\n\t"
  77                "fwait\n\t"
  78                "fninit"
  79                : "=m" (*&fdiv_bug)
  80                : "m" (*&x), "m" (*&y));
  81
  82        boot_cpu_data.fdiv_bug = fdiv_bug;
  83        if (boot_cpu_data.fdiv_bug)
  84                printk(KERN_WARNING "Hmm, FPU with FDIV bug.\n");
  85}
  86
  87static void __init check_hlt(void)
  88{
  89        if (boot_cpu_data.x86 >= 5 || paravirt_enabled())
  90                return;
  91
  92        printk(KERN_INFO "Checking 'hlt' instruction... ");
  93        if (!boot_cpu_data.hlt_works_ok) {
  94                printk("disabled\n");
  95                return;
  96        }
  97        halt();
  98        halt();
  99        halt();
 100        halt();
 101        printk(KERN_CONT "OK.\n");
 102}
 103
 104/*
 105 *      Most 386 processors have a bug where a POPAD can lock the
 106 *      machine even from user space.
 107 */
 108
 109static void __init check_popad(void)
 110{
 111#ifndef CONFIG_X86_POPAD_OK
 112        int res, inp = (int) &res;
 113
 114        printk(KERN_INFO "Checking for popad bug... ");
 115        __asm__ __volatile__(
 116          "movl $12345678,%%eax; movl $0,%%edi; pusha; popa; movl (%%edx,%%edi),%%ecx "
 117          : "=&a" (res)
 118          : "d" (inp)
 119          : "ecx", "edi");
 120        /*
 121         * If this fails, it means that any user program may lock the
 122         * CPU hard. Too bad.
 123         */
 124        if (res != 12345678)
 125                printk(KERN_CONT "Buggy.\n");
 126        else
 127                printk(KERN_CONT "OK.\n");
 128#endif
 129}
 130
 131/*
 132 * Check whether we are able to run this kernel safely on SMP.
 133 *
 134 * - In order to run on a i386, we need to be compiled for i386
 135 *   (for due to lack of "invlpg" and working WP on a i386)
 136 * - In order to run on anything without a TSC, we need to be
 137 *   compiled for a i486.
 138 */
 139
 140static void __init check_config(void)
 141{
 142/*
 143 * We'd better not be a i386 if we're configured to use some
 144 * i486+ only features! (WP works in supervisor mode and the
 145 * new "invlpg" and "bswap" instructions)
 146 */
 147#if defined(CONFIG_X86_WP_WORKS_OK) || defined(CONFIG_X86_INVLPG) || \
 148        defined(CONFIG_X86_BSWAP)
 149        if (boot_cpu_data.x86 == 3)
 150                panic("Kernel requires i486+ for 'invlpg' and other features");
 151#endif
 152}
 153
 154
 155void __init check_bugs(void)
 156{
 157        identify_boot_cpu();
 158#ifndef CONFIG_SMP
 159        printk(KERN_INFO "CPU: ");
 160        print_cpu_info(&boot_cpu_data);
 161#endif
 162        check_config();
 163        check_fpu();
 164        check_hlt();
 165        check_popad();
 166        init_utsname()->machine[1] =
 167                '0' + (boot_cpu_data.x86 > 6 ? 6 : boot_cpu_data.x86);
 168        alternative_instructions();
 169}
 170