]> git.ipfire.org Git - thirdparty/kernel/stable.git/commitdiff
x86/sev: Evict cache lines during SNP memory validation
authorTom Lendacky <thomas.lendacky@amd.com>
Wed, 30 Jul 2025 14:12:37 +0000 (09:12 -0500)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Fri, 15 Aug 2025 14:39:33 +0000 (16:39 +0200)
Commit 7b306dfa326f70114312b320d083b21fa9481e1e upstream.

An SNP cache coherency vulnerability requires a cache line eviction
mitigation when validating memory after a page state change to private.
The specific mitigation is to touch the first and last byte of each 4K
page that is being validated. There is no need to perform the mitigation
when performing a page state change to shared and rescinding validation.

CPUID bit Fn8000001F_EBX[31] defines the COHERENCY_SFW_NO CPUID bit that,
when set, indicates that the software mitigation for this vulnerability is
not needed.

Implement the mitigation and invoke it when validating memory (making it
private) and the COHERENCY_SFW_NO bit is not set, indicating the SNP guest
is vulnerable.

Co-developed-by: Michael Roth <michael.roth@amd.com>
Signed-off-by: Michael Roth <michael.roth@amd.com>
Signed-off-by: Tom Lendacky <thomas.lendacky@amd.com>
Signed-off-by: Borislav Petkov (AMD) <bp@alien8.de>
Acked-by: Thomas Gleixner <tglx@linutronix.de>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
arch/x86/boot/cpuflags.c
arch/x86/boot/startup/sev-shared.c
arch/x86/coco/sev/core.c
arch/x86/include/asm/cpufeatures.h
arch/x86/include/asm/sev.h
arch/x86/kernel/cpu/scattered.c

index 916bac09b464da7132cd2cb81f713a2aca63ab1e..63e037e94e4c03cefb1628927009cc5c1fabec9d 100644 (file)
@@ -106,5 +106,18 @@ void get_cpuflags(void)
                        cpuid(0x80000001, &ignored, &ignored, &cpu.flags[6],
                              &cpu.flags[1]);
                }
+
+               if (max_amd_level >= 0x8000001f) {
+                       u32 ebx;
+
+                       /*
+                        * The X86_FEATURE_COHERENCY_SFW_NO feature bit is in
+                        * the virtualization flags entry (word 8) and set by
+                        * scattered.c, so the bit needs to be explicitly set.
+                        */
+                       cpuid(0x8000001f, &ignored, &ebx, &ignored, &ignored);
+                       if (ebx & BIT(31))
+                               set_bit(X86_FEATURE_COHERENCY_SFW_NO, cpu.flags);
+               }
        }
 }
index 7a706db87b932ffdc13b809fbc427216f0bfb295..ac7dfd21ddd4d5c307a7d91d5a39aa748dba2c22 100644 (file)
@@ -810,6 +810,13 @@ static void __head pvalidate_4k_page(unsigned long vaddr, unsigned long paddr,
                if (ret)
                        sev_es_terminate(SEV_TERM_SET_LINUX, GHCB_TERM_PVALIDATE);
        }
+
+       /*
+        * If validating memory (making it private) and affected by the
+        * cache-coherency vulnerability, perform the cache eviction mitigation.
+        */
+       if (validate && !has_cpuflag(X86_FEATURE_COHERENCY_SFW_NO))
+               sev_evict_cache((void *)vaddr, 1);
 }
 
 /*
index 7543a8b52c67c27bce382a4ff447a63d583aee53..eb80445e8e5d38f2aea48e4a98e0dee8a30a33b3 100644 (file)
@@ -358,10 +358,31 @@ static void svsm_pval_pages(struct snp_psc_desc *desc)
 
 static void pvalidate_pages(struct snp_psc_desc *desc)
 {
+       struct psc_entry *e;
+       unsigned int i;
+
        if (snp_vmpl)
                svsm_pval_pages(desc);
        else
                pval_pages(desc);
+
+       /*
+        * If not affected by the cache-coherency vulnerability there is no need
+        * to perform the cache eviction mitigation.
+        */
+       if (cpu_feature_enabled(X86_FEATURE_COHERENCY_SFW_NO))
+               return;
+
+       for (i = 0; i <= desc->hdr.end_entry; i++) {
+               e = &desc->entries[i];
+
+               /*
+                * If validating memory (making it private) perform the cache
+                * eviction mitigation.
+                */
+               if (e->operation == SNP_PAGE_STATE_PRIVATE)
+                       sev_evict_cache(pfn_to_kaddr(e->gfn), e->pagesize ? 512 : 1);
+       }
 }
 
 static int vmgexit_psc(struct ghcb *ghcb, struct snp_psc_desc *desc)
index 286d509f9363bc069587aae29762ad7051059787..4597ef6621220ed9c41b8d13b0042ea2bbe33faf 100644 (file)
 #define X86_FEATURE_FLEXPRIORITY       ( 8*32+ 1) /* "flexpriority" Intel FlexPriority */
 #define X86_FEATURE_EPT                        ( 8*32+ 2) /* "ept" Intel Extended Page Table */
 #define X86_FEATURE_VPID               ( 8*32+ 3) /* "vpid" Intel Virtual Processor ID */
+#define X86_FEATURE_COHERENCY_SFW_NO   ( 8*32+ 4) /* SNP cache coherency software work around not needed */
 
 #define X86_FEATURE_VMMCALL            ( 8*32+15) /* "vmmcall" Prefer VMMCALL to VMCALL */
 #define X86_FEATURE_XENPV              ( 8*32+16) /* Xen paravirtual guest */
index a631f7d7c0c0bc84f25a04cc43038900a2b03848..14d7e0719dd5ee35b53acedeb03440ca18ff2093 100644 (file)
@@ -621,6 +621,24 @@ int rmp_make_shared(u64 pfn, enum pg_level level);
 void snp_leak_pages(u64 pfn, unsigned int npages);
 void kdump_sev_callback(void);
 void snp_fixup_e820_tables(void);
+
+static inline void sev_evict_cache(void *va, int npages)
+{
+       volatile u8 val __always_unused;
+       u8 *bytes = va;
+       int page_idx;
+
+       /*
+        * For SEV guests, a read from the first/last cache-lines of a 4K page
+        * using the guest key is sufficient to cause a flush of all cache-lines
+        * associated with that 4K page without incurring all the overhead of a
+        * full CLFLUSH sequence.
+        */
+       for (page_idx = 0; page_idx < npages; page_idx++) {
+               val = bytes[page_idx * PAGE_SIZE];
+               val = bytes[page_idx * PAGE_SIZE + PAGE_SIZE - 1];
+       }
+}
 #else
 static inline bool snp_probe_rmptable_info(void) { return false; }
 static inline int snp_rmptable_init(void) { return -ENOSYS; }
@@ -636,6 +654,7 @@ static inline int rmp_make_shared(u64 pfn, enum pg_level level) { return -ENODEV
 static inline void snp_leak_pages(u64 pfn, unsigned int npages) {}
 static inline void kdump_sev_callback(void) { }
 static inline void snp_fixup_e820_tables(void) {}
+static inline void sev_evict_cache(void *va, int npages) {}
 #endif
 
 #endif
index b4a1f6732a3aad4d2dc760bb35f30cde27c9a759..6b868afb26c3198f0591690906141e9d46caf8b7 100644 (file)
@@ -48,6 +48,7 @@ static const struct cpuid_bit cpuid_bits[] = {
        { X86_FEATURE_PROC_FEEDBACK,            CPUID_EDX, 11, 0x80000007, 0 },
        { X86_FEATURE_AMD_FAST_CPPC,            CPUID_EDX, 15, 0x80000007, 0 },
        { X86_FEATURE_MBA,                      CPUID_EBX,  6, 0x80000008, 0 },
+       { X86_FEATURE_COHERENCY_SFW_NO,         CPUID_EBX, 31, 0x8000001f, 0 },
        { X86_FEATURE_SMBA,                     CPUID_EBX,  2, 0x80000020, 0 },
        { X86_FEATURE_BMEC,                     CPUID_EBX,  3, 0x80000020, 0 },
        { X86_FEATURE_TSA_SQ_NO,                CPUID_ECX,  1, 0x80000021, 0 },