1/*
2 *  arch/i386/cpu/bugs.c
3 *
4 *  Copyright (C) 1994  Linus Torvalds
5 *
6 *  Cyrix stuff, June 1998 by:
7 *	- Rafael R. Reilova (moved everything from head.S),
8 *        <rreilova@ececs.uc.edu>
9 *	- Channing Corn (tests & fixes),
10 *	- Andrew D. Balsa (code cleanup).
11 */
12#include <linux/init.h>
13#include <linux/utsname.h>
14#include <asm/processor.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 mca_pentium(char *s)
29{
30	mca_pentium_flag = 1;
31	return 1;
32}
33
34__setup("mca-pentium", mca_pentium);
35
36static int __init no_387(char *s)
37{
38	boot_cpu_data.hard_math = 0;
39	write_cr0(0xE | read_cr0());
40	return 1;
41}
42
43__setup("no387", no_387);
44
45static double __initdata x = 4195835.0;
46static double __initdata y = 3145727.0;
47
48/*
49 * This used to check for exceptions..
50 * However, it turns out that to support that,
51 * the XMM trap handlers basically had to
52 * be buggy. So let's have a correct XMM trap
53 * handler, and forget about printing out
54 * some status at boot.
55 *
56 * We should really only care about bugs here
57 * anyway. Not features.
58 */
59static void __init check_fpu(void)
60{
61	if (!boot_cpu_data.hard_math) {
62#ifndef CONFIG_MATH_EMULATION
63		printk(KERN_EMERG "No coprocessor found and no math emulation present.\n");
64		printk(KERN_EMERG "Giving up.\n");
65		for (;;) ;
66#endif
67		return;
68	}
69
70/* trap_init() enabled FXSR and company _before_ testing for FP problems here. */
71	/* Test for the divl bug.. */
72	__asm__("fninit\n\t"
73		"fldl %1\n\t"
74		"fdivl %2\n\t"
75		"fmull %2\n\t"
76		"fldl %1\n\t"
77		"fsubp %%st,%%st(1)\n\t"
78		"fistpl %0\n\t"
79		"fwait\n\t"
80		"fninit"
81		: "=m" (*&boot_cpu_data.fdiv_bug)
82		: "m" (*&x), "m" (*&y));
83	if (boot_cpu_data.fdiv_bug)
84		printk("Hmm, FPU with FDIV bug.\n");
85}
86
87static void __init check_hlt(void)
88{
89	if (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("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	/* If this fails, it means that any user program may lock the CPU hard. Too bad. */
121	if (res != 12345678) printk( "Buggy.\n" );
122		        else printk( "OK.\n" );
123#endif
124}
125
126/*
127 * Check whether we are able to run this kernel safely on SMP.
128 *
129 * - In order to run on a i386, we need to be compiled for i386
130 *   (for due to lack of "invlpg" and working WP on a i386)
131 * - In order to run on anything without a TSC, we need to be
132 *   compiled for a i486.
133 * - In order to support the local APIC on a buggy Pentium machine,
134 *   we need to be compiled with CONFIG_X86_GOOD_APIC disabled,
135 *   which happens implicitly if compiled for a Pentium or lower
136 *   (unless an advanced selection of CPU features is used) as an
137 *   otherwise config implies a properly working local APIC without
138 *   the need to do extra reads from the APIC.
139*/
140
141static void __init check_config(void)
142{
143/*
144 * We'd better not be a i386 if we're configured to use some
145 * i486+ only features! (WP works in supervisor mode and the
146 * new "invlpg" and "bswap" instructions)
147 */
148#if defined(CONFIG_X86_WP_WORKS_OK) || defined(CONFIG_X86_INVLPG) || \
149	defined(CONFIG_X86_BSWAP)
150	if (boot_cpu_data.x86 == 3)
151		panic("Kernel requires i486+ for 'invlpg' and other features");
152#endif
153
154/*
155 * If we configured ourselves for a TSC, we'd better have one!
156 */
157#ifdef CONFIG_X86_TSC
158	if (!cpu_has_tsc && !tsc_disable)
159		panic("Kernel compiled for Pentium+, requires TSC feature!");
160#endif
161
162/*
163 * If we were told we had a good local APIC, check for buggy Pentia,
164 * i.e. all B steppings and the C2 stepping of P54C when using their
165 * integrated APIC (see 11AP erratum in "Pentium Processor
166 * Specification Update").
167 */
168#if defined(CONFIG_X86_LOCAL_APIC) && defined(CONFIG_X86_GOOD_APIC)
169	if (boot_cpu_data.x86_vendor == X86_VENDOR_INTEL
170	    && cpu_has_apic
171	    && boot_cpu_data.x86 == 5
172	    && boot_cpu_data.x86_model == 2
173	    && (boot_cpu_data.x86_mask < 6 || boot_cpu_data.x86_mask == 11))
174		panic("Kernel compiled for PMMX+, assumes a local APIC without the read-before-write bug!");
175#endif
176}
177
178
179void __init check_bugs(void)
180{
181	identify_boot_cpu();
182#ifndef CONFIG_SMP
183	printk("CPU: ");
184	print_cpu_info(&boot_cpu_data);
185#endif
186	check_config();
187	check_fpu();
188	check_hlt();
189	check_popad();
190	init_utsname()->machine[1] = '0' + (boot_cpu_data.x86 > 6 ? 6 : boot_cpu_data.x86);
191	alternative_instructions();
192}
193