]> www.infradead.org Git - users/hch/block.git/commitdiff
KVM: Allow page-sized MMU caches to be initialized with custom 64-bit values
authorSean Christopherson <seanjc@google.com>
Mon, 22 Jan 2024 23:53:11 +0000 (15:53 -0800)
committerPaolo Bonzini <pbonzini@redhat.com>
Fri, 19 Apr 2024 16:15:18 +0000 (12:15 -0400)
Add support to MMU caches for initializing a page with a custom 64-bit
value, e.g. to pre-fill an entire page table with non-zero PTE values.
The functionality will be used by x86 to support Intel's TDX, which needs
to set bit 63 in all non-present PTEs in order to prevent !PRESENT page
faults from getting reflected into the guest (Intel's EPT Violation #VE
architecture made the less than brilliant decision of having the per-PTE
behavior be opt-out instead of opt-in).

Signed-off-by: Sean Christopherson <seanjc@google.com>
Signed-off-by: Isaku Yamahata <isaku.yamahata@intel.com>
Message-Id: <5919f685f109a1b0ebc6bd8fc4536ee94bcc172d.1705965635.git.isaku.yamahata@intel.com>
Reviewed-by: Xiaoyao Li <xiaoyao.li@intel.com>
Reviewed-by: Binbin Wu <binbin.wu@linux.intel.com>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
include/linux/kvm_types.h
virt/kvm/kvm_main.c

index d93f6522b2c34c2e5e33b80266f43cb2f7775bde..827ecc0b7e10a8ebfb2f27fbbc43f96127abf247 100644 (file)
@@ -86,6 +86,7 @@ struct gfn_to_pfn_cache {
 struct kvm_mmu_memory_cache {
        gfp_t gfp_zero;
        gfp_t gfp_custom;
+       u64 init_value;
        struct kmem_cache *kmem_cache;
        int capacity;
        int nobjs;
index 658581d4ad687559a320d1d62c3cfbed9462afb7..38b498669ef9cf6e0773213c79f692f42fe75614 100644 (file)
@@ -401,12 +401,17 @@ static void kvm_flush_shadow_all(struct kvm *kvm)
 static inline void *mmu_memory_cache_alloc_obj(struct kvm_mmu_memory_cache *mc,
                                               gfp_t gfp_flags)
 {
+       void *page;
+
        gfp_flags |= mc->gfp_zero;
 
        if (mc->kmem_cache)
                return kmem_cache_alloc(mc->kmem_cache, gfp_flags);
-       else
-               return (void *)__get_free_page(gfp_flags);
+
+       page = (void *)__get_free_page(gfp_flags);
+       if (page && mc->init_value)
+               memset64(page, mc->init_value, PAGE_SIZE / sizeof(u64));
+       return page;
 }
 
 int __kvm_mmu_topup_memory_cache(struct kvm_mmu_memory_cache *mc, int capacity, int min)
@@ -421,6 +426,13 @@ int __kvm_mmu_topup_memory_cache(struct kvm_mmu_memory_cache *mc, int capacity,
                if (WARN_ON_ONCE(!capacity))
                        return -EIO;
 
+               /*
+                * Custom init values can be used only for page allocations,
+                * and obviously conflict with __GFP_ZERO.
+                */
+               if (WARN_ON_ONCE(mc->init_value && (mc->kmem_cache || mc->gfp_zero)))
+                       return -EIO;
+
                mc->objects = kvmalloc_array(capacity, sizeof(void *), gfp);
                if (!mc->objects)
                        return -ENOMEM;