xref: /kernel/linux/linux-5.10/arch/x86/kernel/fpu/bugs.c (revision 8c2ecf20)
18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * x86 FPU bug checks:
48c2ecf20Sopenharmony_ci */
58c2ecf20Sopenharmony_ci#include <asm/fpu/internal.h>
68c2ecf20Sopenharmony_ci
78c2ecf20Sopenharmony_ci/*
88c2ecf20Sopenharmony_ci * Boot time CPU/FPU FDIV bug detection code:
98c2ecf20Sopenharmony_ci */
108c2ecf20Sopenharmony_ci
118c2ecf20Sopenharmony_cistatic double __initdata x = 4195835.0;
128c2ecf20Sopenharmony_cistatic double __initdata y = 3145727.0;
138c2ecf20Sopenharmony_ci
148c2ecf20Sopenharmony_ci/*
158c2ecf20Sopenharmony_ci * This used to check for exceptions..
168c2ecf20Sopenharmony_ci * However, it turns out that to support that,
178c2ecf20Sopenharmony_ci * the XMM trap handlers basically had to
188c2ecf20Sopenharmony_ci * be buggy. So let's have a correct XMM trap
198c2ecf20Sopenharmony_ci * handler, and forget about printing out
208c2ecf20Sopenharmony_ci * some status at boot.
218c2ecf20Sopenharmony_ci *
228c2ecf20Sopenharmony_ci * We should really only care about bugs here
238c2ecf20Sopenharmony_ci * anyway. Not features.
248c2ecf20Sopenharmony_ci */
258c2ecf20Sopenharmony_civoid __init fpu__init_check_bugs(void)
268c2ecf20Sopenharmony_ci{
278c2ecf20Sopenharmony_ci	s32 fdiv_bug;
288c2ecf20Sopenharmony_ci
298c2ecf20Sopenharmony_ci	/* kernel_fpu_begin/end() relies on patched alternative instructions. */
308c2ecf20Sopenharmony_ci	if (!boot_cpu_has(X86_FEATURE_FPU))
318c2ecf20Sopenharmony_ci		return;
328c2ecf20Sopenharmony_ci
338c2ecf20Sopenharmony_ci	kernel_fpu_begin();
348c2ecf20Sopenharmony_ci
358c2ecf20Sopenharmony_ci	/*
368c2ecf20Sopenharmony_ci	 * trap_init() enabled FXSR and company _before_ testing for FP
378c2ecf20Sopenharmony_ci	 * problems here.
388c2ecf20Sopenharmony_ci	 *
398c2ecf20Sopenharmony_ci	 * Test for the divl bug: http://en.wikipedia.org/wiki/Fdiv_bug
408c2ecf20Sopenharmony_ci	 */
418c2ecf20Sopenharmony_ci	__asm__("fninit\n\t"
428c2ecf20Sopenharmony_ci		"fldl %1\n\t"
438c2ecf20Sopenharmony_ci		"fdivl %2\n\t"
448c2ecf20Sopenharmony_ci		"fmull %2\n\t"
458c2ecf20Sopenharmony_ci		"fldl %1\n\t"
468c2ecf20Sopenharmony_ci		"fsubp %%st,%%st(1)\n\t"
478c2ecf20Sopenharmony_ci		"fistpl %0\n\t"
488c2ecf20Sopenharmony_ci		"fwait\n\t"
498c2ecf20Sopenharmony_ci		"fninit"
508c2ecf20Sopenharmony_ci		: "=m" (*&fdiv_bug)
518c2ecf20Sopenharmony_ci		: "m" (*&x), "m" (*&y));
528c2ecf20Sopenharmony_ci
538c2ecf20Sopenharmony_ci	kernel_fpu_end();
548c2ecf20Sopenharmony_ci
558c2ecf20Sopenharmony_ci	if (fdiv_bug) {
568c2ecf20Sopenharmony_ci		set_cpu_bug(&boot_cpu_data, X86_BUG_FDIV);
578c2ecf20Sopenharmony_ci		pr_warn("Hmm, FPU with FDIV bug\n");
588c2ecf20Sopenharmony_ci	}
598c2ecf20Sopenharmony_ci}
60