Skip to content

Commit a47dd5f

Browse files
bonziniKAGA-KOKO
authored andcommitted
x86/KVM/VMX: Add L1D flush algorithm
To mitigate the L1 Terminal Fault vulnerability it's required to flush L1D on VMENTER to prevent rogue guests from snooping host memory. CPUs will have a new control MSR via a microcode update to flush L1D with a single MSR write, but in the absence of microcode a fallback to a software based flush algorithm is required. Add a software flush loop which is based on code from Intel. [ tglx: Split out from combo patch ] [ bpetkov: Polish the asm code ] Signed-off-by: Paolo Bonzini <pbonzini@redhat.com> Signed-off-by: Konrad Rzeszutek Wilk <konrad.wilk@oracle.com> Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
1 parent a399477 commit a47dd5f

File tree

1 file changed

+66
-5
lines changed

1 file changed

+66
-5
lines changed

arch/x86/kvm/vmx.c

Lines changed: 66 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -9563,6 +9563,46 @@ static int vmx_handle_exit(struct kvm_vcpu *vcpu)
95639563
}
95649564
}
95659565

9566+
/*
9567+
* Software based L1D cache flush which is used when microcode providing
9568+
* the cache control MSR is not loaded.
9569+
*
9570+
* The L1D cache is 32 KiB on Nehalem and later microarchitectures, but to
9571+
* flush it is required to read in 64 KiB because the replacement algorithm
9572+
* is not exactly LRU. This could be sized at runtime via topology
9573+
* information but as all relevant affected CPUs have 32KiB L1D cache size
9574+
* there is no point in doing so.
9575+
*/
9576+
#define L1D_CACHE_ORDER 4
9577+
static void *vmx_l1d_flush_pages;
9578+
9579+
static void __maybe_unused vmx_l1d_flush(void)
9580+
{
9581+
int size = PAGE_SIZE << L1D_CACHE_ORDER;
9582+
9583+
asm volatile(
9584+
/* First ensure the pages are in the TLB */
9585+
"xorl %%eax, %%eax\n"
9586+
".Lpopulate_tlb:\n\t"
9587+
"movzbl (%[empty_zp], %%" _ASM_AX "), %%ecx\n\t"
9588+
"addl $4096, %%eax\n\t"
9589+
"cmpl %%eax, %[size]\n\t"
9590+
"jne .Lpopulate_tlb\n\t"
9591+
"xorl %%eax, %%eax\n\t"
9592+
"cpuid\n\t"
9593+
/* Now fill the cache */
9594+
"xorl %%eax, %%eax\n"
9595+
".Lfill_cache:\n"
9596+
"movzbl (%[empty_zp], %%" _ASM_AX "), %%ecx\n\t"
9597+
"addl $64, %%eax\n\t"
9598+
"cmpl %%eax, %[size]\n\t"
9599+
"jne .Lfill_cache\n\t"
9600+
"lfence\n"
9601+
:: [empty_zp] "r" (vmx_l1d_flush_pages),
9602+
[size] "r" (size)
9603+
: "eax", "ebx", "ecx", "edx");
9604+
}
9605+
95669606
static void update_cr8_intercept(struct kvm_vcpu *vcpu, int tpr, int irr)
95679607
{
95689608
struct vmcs12 *vmcs12 = get_vmcs12(vcpu);
@@ -13110,13 +13150,29 @@ static struct kvm_x86_ops vmx_x86_ops __ro_after_init = {
1311013150
.enable_smi_window = enable_smi_window,
1311113151
};
1311213152

13113-
static void __init vmx_setup_l1d_flush(void)
13153+
static int __init vmx_setup_l1d_flush(void)
1311413154
{
13155+
struct page *page;
13156+
1311513157
if (vmentry_l1d_flush == VMENTER_L1D_FLUSH_NEVER ||
1311613158
!boot_cpu_has_bug(X86_BUG_L1TF))
13117-
return;
13159+
return 0;
13160+
13161+
page = alloc_pages(GFP_KERNEL, L1D_CACHE_ORDER);
13162+
if (!page)
13163+
return -ENOMEM;
1311813164

13165+
vmx_l1d_flush_pages = page_address(page);
1311913166
static_branch_enable(&vmx_l1d_should_flush);
13167+
return 0;
13168+
}
13169+
13170+
static void vmx_free_l1d_flush_pages(void)
13171+
{
13172+
if (vmx_l1d_flush_pages) {
13173+
free_pages((unsigned long)vmx_l1d_flush_pages, L1D_CACHE_ORDER);
13174+
vmx_l1d_flush_pages = NULL;
13175+
}
1312013176
}
1312113177

1312213178
static int __init vmx_init(void)
@@ -13152,12 +13208,16 @@ static int __init vmx_init(void)
1315213208
}
1315313209
#endif
1315413210

13155-
vmx_setup_l1d_flush();
13211+
r = vmx_setup_l1d_flush();
13212+
if (r)
13213+
return r;
1315613214

1315713215
r = kvm_init(&vmx_x86_ops, sizeof(struct vcpu_vmx),
13158-
__alignof__(struct vcpu_vmx), THIS_MODULE);
13159-
if (r)
13216+
__alignof__(struct vcpu_vmx), THIS_MODULE);
13217+
if (r) {
13218+
vmx_free_l1d_flush_pages();
1316013219
return r;
13220+
}
1316113221

1316213222
#ifdef CONFIG_KEXEC_CORE
1316313223
rcu_assign_pointer(crash_vmclear_loaded_vmcss,
@@ -13199,6 +13259,7 @@ static void __exit vmx_exit(void)
1319913259
static_branch_disable(&enable_evmcs);
1320013260
}
1320113261
#endif
13262+
vmx_free_l1d_flush_pages();
1320213263
}
1320313264

1320413265
module_init(vmx_init)

0 commit comments

Comments
 (0)