From b78ea19ac22fd7b32d7828066cce3d8f2db5226a Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Tue, 4 Jun 2019 09:15:22 +0200 Subject: [PATCH 1/5] x86/fpu: Simplify kernel_fpu_end() Remove two little helpers and merge them into kernel_fpu_end() to streamline the function. Signed-off-by: Christoph Hellwig Signed-off-by: Borislav Petkov Acked-by: Sebastian Andrzej Siewior Cc: Dave Hansen Cc: "H. Peter Anvin" Cc: Ingo Molnar Cc: Nicolai Stange Cc: Rik van Riel Cc: Thomas Gleixner Cc: x86-ml Link: https://lkml.kernel.org/r/20190604071524.12835-2-hch@lst.de --- arch/x86/kernel/fpu/core.c | 15 +++------------ 1 file changed, 3 insertions(+), 12 deletions(-) diff --git a/arch/x86/kernel/fpu/core.c b/arch/x86/kernel/fpu/core.c index 649fbc3fcf9f..8e046068d20f 100644 --- a/arch/x86/kernel/fpu/core.c +++ b/arch/x86/kernel/fpu/core.c @@ -49,12 +49,6 @@ static void kernel_fpu_disable(void) this_cpu_write(in_kernel_fpu, true); } -static void kernel_fpu_enable(void) -{ - WARN_ON_FPU(!this_cpu_read(in_kernel_fpu)); - this_cpu_write(in_kernel_fpu, false); -} - static bool kernel_fpu_disabled(void) { return this_cpu_read(in_kernel_fpu); @@ -115,11 +109,6 @@ static void __kernel_fpu_begin(void) __cpu_invalidate_fpregs_state(); } -static void __kernel_fpu_end(void) -{ - kernel_fpu_enable(); -} - void kernel_fpu_begin(void) { preempt_disable(); @@ -129,7 +118,9 @@ EXPORT_SYMBOL_GPL(kernel_fpu_begin); void kernel_fpu_end(void) { - __kernel_fpu_end(); + WARN_ON_FPU(!this_cpu_read(in_kernel_fpu)); + + this_cpu_write(in_kernel_fpu, false); preempt_enable(); } EXPORT_SYMBOL_GPL(kernel_fpu_end); From 6d79d86f9600510e08ad45c72b9d7e664e439e62 Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Tue, 4 Jun 2019 09:15:23 +0200 Subject: [PATCH 2/5] x86/fpu: Simplify kernel_fpu_begin() Merge two helpers into the main function, remove a pointless local variable and flatten a conditional. Signed-off-by: Christoph Hellwig Signed-off-by: Borislav Petkov Acked-by: Sebastian Andrzej Siewior Cc: Dave Hansen Cc: "H. Peter Anvin" Cc: Ingo Molnar Cc: Nicolai Stange Cc: Rik van Riel Cc: Thomas Gleixner Cc: x86-ml Link: https://lkml.kernel.org/r/20190604071524.12835-3-hch@lst.de --- arch/x86/kernel/fpu/core.c | 44 ++++++++++++++------------------------ 1 file changed, 16 insertions(+), 28 deletions(-) diff --git a/arch/x86/kernel/fpu/core.c b/arch/x86/kernel/fpu/core.c index 8e046068d20f..3f92cfad88f0 100644 --- a/arch/x86/kernel/fpu/core.c +++ b/arch/x86/kernel/fpu/core.c @@ -43,12 +43,6 @@ static DEFINE_PER_CPU(bool, in_kernel_fpu); */ DEFINE_PER_CPU(struct fpu *, fpu_fpregs_owner_ctx); -static void kernel_fpu_disable(void) -{ - WARN_ON_FPU(this_cpu_read(in_kernel_fpu)); - this_cpu_write(in_kernel_fpu, true); -} - static bool kernel_fpu_disabled(void) { return this_cpu_read(in_kernel_fpu); @@ -88,31 +82,25 @@ bool irq_fpu_usable(void) } EXPORT_SYMBOL(irq_fpu_usable); -static void __kernel_fpu_begin(void) -{ - struct fpu *fpu = ¤t->thread.fpu; - - WARN_ON_FPU(!irq_fpu_usable()); - - kernel_fpu_disable(); - - if (!(current->flags & PF_KTHREAD)) { - if (!test_thread_flag(TIF_NEED_FPU_LOAD)) { - set_thread_flag(TIF_NEED_FPU_LOAD); - /* - * Ignore return value -- we don't care if reg state - * is clobbered. - */ - copy_fpregs_to_fpstate(fpu); - } - } - __cpu_invalidate_fpregs_state(); -} - void kernel_fpu_begin(void) { preempt_disable(); - __kernel_fpu_begin(); + + WARN_ON_FPU(!irq_fpu_usable()); + WARN_ON_FPU(this_cpu_read(in_kernel_fpu)); + + this_cpu_write(in_kernel_fpu, true); + + if (!(current->flags & PF_KTHREAD) && + !test_thread_flag(TIF_NEED_FPU_LOAD)) { + set_thread_flag(TIF_NEED_FPU_LOAD); + /* + * Ignore return value -- we don't care if reg state + * is clobbered. + */ + copy_fpregs_to_fpstate(¤t->thread.fpu); + } + __cpu_invalidate_fpregs_state(); } EXPORT_SYMBOL_GPL(kernel_fpu_begin); From 466329bf407cc5143c3211620faa2c132b9d9a06 Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Tue, 4 Jun 2019 09:15:24 +0200 Subject: [PATCH 3/5] x86/fpu: Remove the fpu__save() export This function is only use by the core FPU code. Signed-off-by: Christoph Hellwig Signed-off-by: Borislav Petkov Acked-by: Sebastian Andrzej Siewior Cc: Dave Hansen Cc: "H. Peter Anvin" Cc: Ingo Molnar Cc: Nicolai Stange Cc: Rik van Riel Cc: Thomas Gleixner Cc: x86-ml Link: https://lkml.kernel.org/r/20190604071524.12835-4-hch@lst.de --- arch/x86/kernel/fpu/core.c | 1 - 1 file changed, 1 deletion(-) diff --git a/arch/x86/kernel/fpu/core.c b/arch/x86/kernel/fpu/core.c index 3f92cfad88f0..12c70840980e 100644 --- a/arch/x86/kernel/fpu/core.c +++ b/arch/x86/kernel/fpu/core.c @@ -134,7 +134,6 @@ void fpu__save(struct fpu *fpu) trace_x86_fpu_after_save(fpu); fpregs_unlock(); } -EXPORT_SYMBOL_GPL(fpu__save); /* * Legacy x87 fpstate state init: From 9838e3bff0f92f23fcd50fe1ff1d4b3e91b8a448 Mon Sep 17 00:00:00 2001 From: Sebastian Andrzej Siewior Date: Wed, 3 Jul 2019 10:32:47 +0200 Subject: [PATCH 4/5] x86/fpu: Make 'no387' and 'nofxsr' command line options useful The command line option `no387' is designed to disable the FPU entirely. This only 'works' with CONFIG_MATH_EMULATION enabled. But on 64bit this cannot work because user space expects SSE to work which required basic FPU support. MATH_EMULATION does not help because SSE is not emulated. The command line option `nofxsr' should also be limited to 32bit because FXSR is part of the required flags on 64bit so turning it off is not possible. Clearing X86_FEATURE_FPU without emulation enabled will not work anyway and hang in fpu__init_system_early_generic() before the console is enabled. Setting additioal dependencies, ensures that the CPU still boots on a modern CPU. Otherwise, dropping FPU will leave FXSR enabled causing the kernel to crash early in fpu__init_system_mxcsr(). With XSAVE support it will crash in fpu__init_cpu_xstate(). The problem is that xsetbv() with XMM set and SSE cleared is not allowed. That means XSAVE has to be disabled. The XSAVE support is disabled in fpu__init_system_xstate_size_legacy() but it is too late. It can be removed, it has been added in commit 1f999ab5a1360 ("x86, xsave: Disable xsave in i387 emulation mode") to use `no387' on a CPU with XSAVE support. All this happens before console output. After hat, the next possible crash is in RAID6 detect code because MMX remained enabled. With a 3DNOW enabled config it will explode in memcpy() for instance due to kernel_fpu_begin() but this is unconditionally enabled. This is enough to boot a Debian Wheezy on a 32bit qemu "host" CPU which supports everything up to XSAVES, AVX2 without 3DNOW. Later, Debian increased the minimum requirements to i686 which means it does not boot userland atleast due to CMOV. After masking the additional features it still keeps SSE4A and 3DNOW* enabled (if present on the host) but those are unused in the kernel. Restrict `no387' and `nofxsr' otions to 32bit only. Add dependencies for FPU, FXSR to additionaly mask CMOV, MMX, XSAVE if FXSR or FPU is cleared. Reported-by: Vegard Nossum Signed-off-by: Sebastian Andrzej Siewior Signed-off-by: Thomas Gleixner Link: https://lkml.kernel.org/r/20190703083247.57kjrmlxkai3vpw3@linutronix.de --- arch/x86/kernel/cpu/cpuid-deps.c | 5 +++++ arch/x86/kernel/fpu/init.c | 17 +++++++---------- 2 files changed, 12 insertions(+), 10 deletions(-) diff --git a/arch/x86/kernel/cpu/cpuid-deps.c b/arch/x86/kernel/cpu/cpuid-deps.c index 2c0bd38a44ab..e794e3860fc8 100644 --- a/arch/x86/kernel/cpu/cpuid-deps.c +++ b/arch/x86/kernel/cpu/cpuid-deps.c @@ -20,6 +20,7 @@ struct cpuid_dep { * but it's difficult to tell that to the init reference checker. */ static const struct cpuid_dep cpuid_deps[] = { + { X86_FEATURE_FXSR, X86_FEATURE_FPU }, { X86_FEATURE_XSAVEOPT, X86_FEATURE_XSAVE }, { X86_FEATURE_XSAVEC, X86_FEATURE_XSAVE }, { X86_FEATURE_XSAVES, X86_FEATURE_XSAVE }, @@ -27,7 +28,11 @@ static const struct cpuid_dep cpuid_deps[] = { { X86_FEATURE_PKU, X86_FEATURE_XSAVE }, { X86_FEATURE_MPX, X86_FEATURE_XSAVE }, { X86_FEATURE_XGETBV1, X86_FEATURE_XSAVE }, + { X86_FEATURE_CMOV, X86_FEATURE_FXSR }, + { X86_FEATURE_MMX, X86_FEATURE_FXSR }, + { X86_FEATURE_MMXEXT, X86_FEATURE_MMX }, { X86_FEATURE_FXSR_OPT, X86_FEATURE_FXSR }, + { X86_FEATURE_XSAVE, X86_FEATURE_FXSR }, { X86_FEATURE_XMM, X86_FEATURE_FXSR }, { X86_FEATURE_XMM2, X86_FEATURE_XMM }, { X86_FEATURE_XMM3, X86_FEATURE_XMM2 }, diff --git a/arch/x86/kernel/fpu/init.c b/arch/x86/kernel/fpu/init.c index ef0030e3fe6b..5baae74af4f9 100644 --- a/arch/x86/kernel/fpu/init.c +++ b/arch/x86/kernel/fpu/init.c @@ -204,12 +204,6 @@ static void __init fpu__init_system_xstate_size_legacy(void) */ if (!boot_cpu_has(X86_FEATURE_FPU)) { - /* - * Disable xsave as we do not support it if i387 - * emulation is enabled. - */ - setup_clear_cpu_cap(X86_FEATURE_XSAVE); - setup_clear_cpu_cap(X86_FEATURE_XSAVEOPT); fpu_kernel_xstate_size = sizeof(struct swregs_state); } else { if (boot_cpu_has(X86_FEATURE_FXSR)) @@ -252,14 +246,17 @@ static void __init fpu__init_parse_early_param(void) char *argptr = arg; int bit; +#ifdef CONFIG_X86_32 if (cmdline_find_option_bool(boot_command_line, "no387")) +#ifdef CONFIG_MATH_EMULATION setup_clear_cpu_cap(X86_FEATURE_FPU); +#else + pr_err("Option 'no387' required CONFIG_MATH_EMULATION enabled.\n"); +#endif - if (cmdline_find_option_bool(boot_command_line, "nofxsr")) { + if (cmdline_find_option_bool(boot_command_line, "nofxsr")) setup_clear_cpu_cap(X86_FEATURE_FXSR); - setup_clear_cpu_cap(X86_FEATURE_FXSR_OPT); - setup_clear_cpu_cap(X86_FEATURE_XMM); - } +#endif if (cmdline_find_option_bool(boot_command_line, "noxsave")) fpu__xstate_clear_all_cpu_caps(); From 7891bc0ab739a31538b5f879a523232b8b07a0d3 Mon Sep 17 00:00:00 2001 From: Sebastian Andrzej Siewior Date: Thu, 4 Jul 2019 08:07:43 +0200 Subject: [PATCH 5/5] x86/fpu: Inline fpu__xstate_clear_all_cpu_caps() All fpu__xstate_clear_all_cpu_caps() does is to invoke one simple function since commit 73e3a7d2a7c3b ("x86/fpu: Remove the explicit clearing of XSAVE dependent features") so invoke that function directly and remove the wrapper. Signed-off-by: Sebastian Andrzej Siewior Signed-off-by: Thomas Gleixner Link: https://lkml.kernel.org/r/20190704060743.rvew4yrjd6n33uzx@linutronix.de --- arch/x86/include/asm/fpu/xstate.h | 1 - arch/x86/kernel/fpu/init.c | 2 +- arch/x86/kernel/fpu/xstate.c | 11 +---------- 3 files changed, 2 insertions(+), 12 deletions(-) diff --git a/arch/x86/include/asm/fpu/xstate.h b/arch/x86/include/asm/fpu/xstate.h index 7e42b285c856..c6136d79f8c0 100644 --- a/arch/x86/include/asm/fpu/xstate.h +++ b/arch/x86/include/asm/fpu/xstate.h @@ -47,7 +47,6 @@ extern u64 xstate_fx_sw_bytes[USER_XSTATE_FX_SW_WORDS]; extern void __init update_regset_xstate_info(unsigned int size, u64 xstate_mask); -void fpu__xstate_clear_all_cpu_caps(void); void *get_xsave_addr(struct xregs_state *xsave, int xfeature_nr); const void *get_xsave_field_ptr(int xfeature_nr); int using_compacted_format(void); diff --git a/arch/x86/kernel/fpu/init.c b/arch/x86/kernel/fpu/init.c index 5baae74af4f9..6ce7e0a23268 100644 --- a/arch/x86/kernel/fpu/init.c +++ b/arch/x86/kernel/fpu/init.c @@ -259,7 +259,7 @@ static void __init fpu__init_parse_early_param(void) #endif if (cmdline_find_option_bool(boot_command_line, "noxsave")) - fpu__xstate_clear_all_cpu_caps(); + setup_clear_cpu_cap(X86_FEATURE_XSAVE); if (cmdline_find_option_bool(boot_command_line, "noxsaveopt")) setup_clear_cpu_cap(X86_FEATURE_XSAVEOPT); diff --git a/arch/x86/kernel/fpu/xstate.c b/arch/x86/kernel/fpu/xstate.c index 3c36dd1784db..7b4c52aa929f 100644 --- a/arch/x86/kernel/fpu/xstate.c +++ b/arch/x86/kernel/fpu/xstate.c @@ -67,15 +67,6 @@ static unsigned int xstate_comp_offsets[sizeof(xfeatures_mask)*8]; */ unsigned int fpu_user_xstate_size; -/* - * Clear all of the X86_FEATURE_* bits that are unavailable - * when the CPU has no XSAVE support. - */ -void fpu__xstate_clear_all_cpu_caps(void) -{ - setup_clear_cpu_cap(X86_FEATURE_XSAVE); -} - /* * Return whether the system supports a given xfeature. * @@ -709,7 +700,7 @@ static void fpu__init_disable_system_xstate(void) { xfeatures_mask = 0; cr4_clear_bits(X86_CR4_OSXSAVE); - fpu__xstate_clear_all_cpu_caps(); + setup_clear_cpu_cap(X86_FEATURE_XSAVE); } /*