blob: 30d2d5d03cb01791529931975551a962e90ea1f1 [file] [log] [blame]
Ingo Molnar0c867532015-04-22 10:53:34 +02001/*
2 * x86 FPU boot time init code
3 */
Ingo Molnar78f7f1e2015-04-24 02:54:44 +02004#include <asm/fpu/internal.h>
Ingo Molnar0c867532015-04-22 10:53:34 +02005#include <asm/tlbflush.h>
6
Ingo Molnar4d164092015-04-22 13:44:25 +02007/*
8 * Boot time CPU/FPU FDIV bug detection code:
9 */
10
11static double __initdata x = 4195835.0;
12static double __initdata y = 3145727.0;
13
14/*
15 * This used to check for exceptions..
16 * However, it turns out that to support that,
17 * the XMM trap handlers basically had to
18 * be buggy. So let's have a correct XMM trap
19 * handler, and forget about printing out
20 * some status at boot.
21 *
22 * We should really only care about bugs here
23 * anyway. Not features.
24 */
25static void __init check_fpu(void)
26{
27 s32 fdiv_bug;
28
29 kernel_fpu_begin();
30
31 /*
32 * trap_init() enabled FXSR and company _before_ testing for FP
33 * problems here.
34 *
35 * Test for the divl bug: http://en.wikipedia.org/wiki/Fdiv_bug
36 */
37 __asm__("fninit\n\t"
38 "fldl %1\n\t"
39 "fdivl %2\n\t"
40 "fmull %2\n\t"
41 "fldl %1\n\t"
42 "fsubp %%st,%%st(1)\n\t"
43 "fistpl %0\n\t"
44 "fwait\n\t"
45 "fninit"
46 : "=m" (*&fdiv_bug)
47 : "m" (*&x), "m" (*&y));
48
49 kernel_fpu_end();
50
51 if (fdiv_bug) {
52 set_cpu_bug(&boot_cpu_data, X86_BUG_FDIV);
53 pr_warn("Hmm, FPU with FDIV bug\n");
54 }
55}
56
57void fpu__init_check_bugs(void)
58{
59 /*
60 * kernel_fpu_begin/end() in check_fpu() relies on the patched
61 * alternative instructions.
62 */
63 if (cpu_has_fpu)
64 check_fpu();
65}
66
67/*
68 * Boot time FPU feature detection code:
69 */
Ingo Molnar0c867532015-04-22 10:53:34 +020070unsigned int mxcsr_feature_mask __read_mostly = 0xffffffffu;
Ingo Molnar91a8c2a2015-04-24 10:49:11 +020071
Ingo Molnar0c867532015-04-22 10:53:34 +020072unsigned int xstate_size;
73EXPORT_SYMBOL_GPL(xstate_size);
Ingo Molnar0c867532015-04-22 10:53:34 +020074
75static void mxcsr_feature_mask_init(void)
76{
Ingo Molnar91a8c2a2015-04-24 10:49:11 +020077 unsigned int mask = 0;
Ingo Molnar0c867532015-04-22 10:53:34 +020078
79 if (cpu_has_fxsr) {
Ingo Molnar91a8c2a2015-04-24 10:49:11 +020080 struct i387_fxsave_struct fx_tmp __aligned(32) = { };
81
82 asm volatile("fxsave %0" : "+m" (fx_tmp));
83
84 mask = fx_tmp.mxcsr_mask;
85
86 /*
87 * If zero then use the default features mask,
88 * which has all features set, except the
89 * denormals-are-zero feature bit:
90 */
Ingo Molnar0c867532015-04-22 10:53:34 +020091 if (mask == 0)
92 mask = 0x0000ffbf;
93 }
94 mxcsr_feature_mask &= mask;
95}
96
97static void fpstate_xstate_init_size(void)
98{
99 /*
100 * Note that xstate_size might be overwriten later during
Ingo Molnarc42103b2015-04-25 06:52:53 +0200101 * fpu__init_system_xstate().
Ingo Molnar0c867532015-04-22 10:53:34 +0200102 */
103
104 if (!cpu_has_fpu) {
105 /*
106 * Disable xsave as we do not support it if i387
107 * emulation is enabled.
108 */
109 setup_clear_cpu_cap(X86_FEATURE_XSAVE);
110 setup_clear_cpu_cap(X86_FEATURE_XSAVEOPT);
111 xstate_size = sizeof(struct i387_soft_struct);
Ingo Molnar6a133202015-04-25 04:29:26 +0200112 } else {
113 if (cpu_has_fxsr)
114 xstate_size = sizeof(struct i387_fxsave_struct);
115 else
116 xstate_size = sizeof(struct i387_fsave_struct);
Ingo Molnar0c867532015-04-22 10:53:34 +0200117 }
Ingo Molnar0c867532015-04-22 10:53:34 +0200118}
119
120/*
Ingo Molnare35f6f12015-04-25 04:34:48 +0200121 * Enable all supported FPU features. Called when a CPU is brought online.
Ingo Molnar0c867532015-04-22 10:53:34 +0200122 */
Ingo Molnare35f6f12015-04-25 04:34:48 +0200123void fpu__init_cpu(void)
Ingo Molnar0c867532015-04-22 10:53:34 +0200124{
125 unsigned long cr0;
126 unsigned long cr4_mask = 0;
127
128#ifndef CONFIG_MATH_EMULATION
129 if (!cpu_has_fpu) {
130 pr_emerg("No FPU found and no math emulation present\n");
131 pr_emerg("Giving up\n");
132 for (;;)
133 asm volatile("hlt");
134 }
135#endif
136 if (cpu_has_fxsr)
137 cr4_mask |= X86_CR4_OSFXSR;
138 if (cpu_has_xmm)
139 cr4_mask |= X86_CR4_OSXMMEXCPT;
140 if (cr4_mask)
141 cr4_set_bits(cr4_mask);
142
143 cr0 = read_cr0();
144 cr0 &= ~(X86_CR0_TS|X86_CR0_EM); /* clear TS and EM */
145 if (!cpu_has_fpu)
146 cr0 |= X86_CR0_EM;
147 write_cr0(cr0);
148
Ingo Molnarc42103b2015-04-25 06:52:53 +0200149 fpu__init_cpu_xstate();
Ingo Molnare35f6f12015-04-25 04:34:48 +0200150}
151
152/*
153 * Called on the boot CPU once per system bootup, to set up the initial FPU state that
154 * is later cloned into all processes.
155 */
156void fpu__init_system(void)
157{
158 /* The FPU has to be operational for some of the later FPU init activities: */
159 fpu__init_cpu();
Ingo Molnar0c867532015-04-22 10:53:34 +0200160
Ingo Molnar2507e1c2015-04-25 08:35:53 +0200161 /*
162 * Set up the legacy init FPU context. (xstate init might overwrite this
163 * with a more modern format, if the CPU supports it.)
164 */
165 fx_finit(&init_xstate_ctx.i387);
166
Ingo Molnar0c867532015-04-22 10:53:34 +0200167 mxcsr_feature_mask_init();
Ingo Molnarc42103b2015-04-25 06:52:53 +0200168 fpu__init_system_xstate();
Ingo Molnar0c867532015-04-22 10:53:34 +0200169 eager_fpu_init();
170}
Ingo Molnar146ed592015-04-22 11:36:14 +0200171
Ingo Molnare35f6f12015-04-25 04:34:48 +0200172void fpu__cpu_init(void)
173{
174 fpu__init_cpu();
175 fpu__init_system();
176}
177
Ingo Molnar146ed592015-04-22 11:36:14 +0200178static int __init no_387(char *s)
179{
180 setup_clear_cpu_cap(X86_FEATURE_FPU);
181 return 1;
182}
183
184__setup("no387", no_387);
185
186/*
187 * Set the X86_FEATURE_FPU CPU-capability bit based on
188 * trying to execute an actual sequence of FPU instructions:
189 */
190void fpu__detect(struct cpuinfo_x86 *c)
191{
192 unsigned long cr0;
193 u16 fsw, fcw;
194
195 fsw = fcw = 0xffff;
196
197 cr0 = read_cr0();
198 cr0 &= ~(X86_CR0_TS | X86_CR0_EM);
199 write_cr0(cr0);
200
201 asm volatile("fninit ; fnstsw %0 ; fnstcw %1"
202 : "+m" (fsw), "+m" (fcw));
203
204 if (fsw == 0 && (fcw & 0x103f) == 0x003f)
205 set_cpu_cap(c, X86_FEATURE_FPU);
206 else
207 clear_cpu_cap(c, X86_FEATURE_FPU);
208
Ingo Molnar6a133202015-04-25 04:29:26 +0200209 /* The final cr0 value is set later, in fpu_init() */
210
211 fpstate_xstate_init_size();
Ingo Molnar146ed592015-04-22 11:36:14 +0200212}