Skip to content
Permalink
Browse files
x86/entry/64: Disallow RDPID in paranoid entry if KVM is enabled
Don't use RDPID in the paranoid entry flow if KVM is enabled as doing so
can consume a KVM guest's MSR_TSC_AUX value if an NMI arrives in KVM's
run loop.

As a performance optimization, KVM loads the guest's TSC_AUX when a CPU
first enters its run loop, and on AMD's SVM doesn't restore the host's
value until the CPU exits the run loop.  VMX is even more aggressive and
defers restoring the host's value until the CPU returns to userspace.
This optimization obviously relies on the kernel not consuming TSC_AUX,
which falls apart if an NMI arrives in the run loop.

Removing KVM's optimizaton would be painful, as both SVM and VMX would
need to context switch the MSR on every VM-Enter (2x WRMSR + 1x RDMSR),
whereas using LSL instead RDPID is a minor blip.

Fixes: eaad981 ("x86/entry/64: Introduce the FIND_PERCPU_BASE macro")
Cc: Dave Hansen <dave.hansen@intel.com>
Cc: Chang Seok Bae <chang.seok.bae@intel.com>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Sasha Levin <sashal@kernel.org>
Cc: Paolo Bonzini <pbonzini@redhat.com>
Cc: kvm@vger.kernel.org
Reported-by: Tom Lendacky <thomas.lendacky@amd.com>
Debugged-by: Tom Lendacky <thomas.lendacky@amd.com>
Suggested-by: Andy Lutomirski <luto@kernel.org>
Signed-off-by: Sean Christopherson <sean.j.christopherson@intel.com>
  • Loading branch information
Sean Christopherson authored and intel-lab-lkp committed Aug 21, 2020
1 parent a9bd3a9 commit bebb51882f9c18938e44b6a7b66fdf0452eea142
Show file tree
Hide file tree
Showing 2 changed files with 13 additions and 4 deletions.
@@ -342,9 +342,9 @@ For 32-bit we have the following conventions - kernel is built with
#endif
.endm

.macro SAVE_AND_SET_GSBASE scratch_reg:req save_reg:req
.macro SAVE_AND_SET_GSBASE scratch_reg:req save_reg:req no_rdpid=0
rdgsbase \save_reg
GET_PERCPU_BASE \scratch_reg
GET_PERCPU_BASE \scratch_reg \no_rdpid
wrgsbase \scratch_reg
.endm

@@ -375,11 +375,15 @@ For 32-bit we have the following conventions - kernel is built with
* We normally use %gs for accessing per-CPU data, but we are setting up
* %gs here and obviously can not use %gs itself to access per-CPU data.
*/
.macro GET_PERCPU_BASE reg:req
.macro GET_PERCPU_BASE reg:req no_rdpid=0
.if \no_rdpid
LOAD_CPU_AND_NODE_SEG_LIMIT \reg
.else
ALTERNATIVE \
"LOAD_CPU_AND_NODE_SEG_LIMIT \reg", \
"RDPID \reg", \
X86_FEATURE_RDPID
.endif
andq $VDSO_CPUNODE_MASK, \reg
movq __per_cpu_offset(, \reg, 8), \reg
.endm
@@ -842,8 +842,13 @@ SYM_CODE_START_LOCAL(paranoid_entry)
*
* The MSR write ensures that no subsequent load is based on a
* mispredicted GSBASE. No extra FENCE required.
*
* Disallow RDPID if KVM is enabled as it may consume a guest's TSC_AUX
* if an NMI arrives in KVM's run loop. KVM loads guest's TSC_AUX on
* VM-Enter and may not restore the host's value until the CPU returns
* to userspace, i.e. KVM depends on the kernel not using TSC_AUX.
*/
SAVE_AND_SET_GSBASE scratch_reg=%rax save_reg=%rbx
SAVE_AND_SET_GSBASE scratch_reg=%rax save_reg=%rbx no_rdpid=IS_ENABLED(CONFIG_KVM)
ret

.Lparanoid_entry_checkgs:

0 comments on commit bebb518

Please sign in to comment.