Commit bf9c912f authored by Ricardo Neri's avatar Ricardo Neri Committed by Borislav Petkov

x86/cpu: Use SERIALIZE in sync_core() when available

The SERIALIZE instruction gives software a way to force the processor to
complete all modifications to flags, registers and memory from previous
instructions and drain all buffered writes to memory before the next
instruction is fetched and executed. Thus, it serves the purpose of
sync_core(). Use it when available.
Suggested-by: default avatarAndy Lutomirski <luto@kernel.org>
Signed-off-by: default avatarRicardo Neri <ricardo.neri-calderon@linux.intel.com>
Signed-off-by: default avatarBorislav Petkov <bp@suse.de>
Reviewed-by: default avatarTony Luck <tony.luck@intel.com>
Link: https://lkml.kernel.org/r/20200807032833.17484-1-ricardo.neri-calderon@linux.intel.com
parent 9123e3a7
...@@ -234,6 +234,12 @@ static inline void clwb(volatile void *__p) ...@@ -234,6 +234,12 @@ static inline void clwb(volatile void *__p)
#define nop() asm volatile ("nop") #define nop() asm volatile ("nop")
static inline void serialize(void)
{
/* Instruction opcode for SERIALIZE; supported in binutils >= 2.35. */
asm volatile(".byte 0xf, 0x1, 0xe8" ::: "memory");
}
#endif /* __KERNEL__ */ #endif /* __KERNEL__ */
#endif /* _ASM_X86_SPECIAL_INSNS_H */ #endif /* _ASM_X86_SPECIAL_INSNS_H */
...@@ -5,6 +5,7 @@ ...@@ -5,6 +5,7 @@
#include <linux/preempt.h> #include <linux/preempt.h>
#include <asm/processor.h> #include <asm/processor.h>
#include <asm/cpufeature.h> #include <asm/cpufeature.h>
#include <asm/special_insns.h>
#ifdef CONFIG_X86_32 #ifdef CONFIG_X86_32
static inline void iret_to_self(void) static inline void iret_to_self(void)
...@@ -54,14 +55,23 @@ static inline void iret_to_self(void) ...@@ -54,14 +55,23 @@ static inline void iret_to_self(void)
static inline void sync_core(void) static inline void sync_core(void)
{ {
/* /*
* There are quite a few ways to do this. IRET-to-self is nice * The SERIALIZE instruction is the most straightforward way to
* because it works on every CPU, at any CPL (so it's compatible * do this but it not universally available.
* with paravirtualization), and it never exits to a hypervisor. */
* The only down sides are that it's a bit slow (it seems to be if (static_cpu_has(X86_FEATURE_SERIALIZE)) {
* a bit more than 2x slower than the fastest options) and that serialize();
* it unmasks NMIs. The "push %cs" is needed because, in return;
* paravirtual environments, __KERNEL_CS may not be a valid CS }
* value when we do IRET directly.
/*
* For all other processors, there are quite a few ways to do this.
* IRET-to-self is nice because it works on every CPU, at any CPL
* (so it's compatible with paravirtualization), and it never exits
* to a hypervisor. The only down sides are that it's a bit slow
* (it seems to be a bit more than 2x slower than the fastest
* options) and that it unmasks NMIs. The "push %cs" is needed
* because, in paravirtual environments, __KERNEL_CS may not be a
* valid CS value when we do IRET directly.
* *
* In case NMI unmasking or performance ever becomes a problem, * In case NMI unmasking or performance ever becomes a problem,
* the next best option appears to be MOV-to-CR2 and an * the next best option appears to be MOV-to-CR2 and an
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment