]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
x86/tdx: Use PFN directly for mapping guest private memory
authorSean Christopherson <seanjc@google.com>
Thu, 30 Apr 2026 01:49:29 +0000 (09:49 +0800)
committerSean Christopherson <seanjc@google.com>
Tue, 26 May 2026 21:49:43 +0000 (14:49 -0700)
Remove struct page assumptions/constraints in the SEAMCALL wrapper APIs for
mapping guest private memory and have them take PFN directly.

Having core TDX make assumptions that guest private memory must be backed
by struct page (and/or folio) will create subtle dependencies on how
KVM/guest_memfd allocates/manages memory (e.g., whether it uses memory
allocated from core MM, if the memory is refcounted, or if the folio is
split) that are easily avoided. [1].

KVM's MMUs work with PFNs. This is very much an intentional design choice.
It ensures that the KVM MMUs remain flexible and are not too tied to the
regular CPU MMUs and the kernel code around them. Using 'struct page' for
TDX guest memory is not a good fit anywhere near the KVM MMU code [2].

Use "kvm_pfn_t pfn" for type safety. Using this KVM type is appropriate
since APIs tdh_mem_page_add() and tdh_mem_page_aug() are exported to KVM
only.

[ Yan: Replace "u64 pfn" with "kvm_pfn_t pfn" ]

Signed-off-by: Yan Zhao <yan.y.zhao@intel.com>
Link: https://lore.kernel.org/all/aWgyhmTJphGQqO0Y@google.com
Link: https://lore.kernel.org/all/ac7V0g2q2hN3dU5u@google.com
Acked-by: Kiryl Shutsemau <kas@kernel.org>
Reviewed-by: Xiaoyao Li <xiaoyao.li@intel.com>
Reviewed-by: Ackerley Tng <ackerleytng@google.com>
Acked-by: Dave Hansen <dave.hansen@linux.intel.com>
Link: https://patch.msgid.link/20260430014929.24210-1-yan.y.zhao@intel.com
Signed-off-by: Sean Christopherson <seanjc@google.com>
arch/x86/include/asm/tdx.h
arch/x86/kvm/vmx/tdx.c
arch/x86/virt/vmx/tdx/tdx.c

index c140ddde59ffe8b05dd26138853e8bf55c3b84a9..648d350616e46cd2cc4400f15de6b6c3e074aa6c 100644 (file)
@@ -6,6 +6,7 @@
 #include <linux/init.h>
 #include <linux/bits.h>
 #include <linux/mmzone.h>
+#include <linux/kvm_types.h>
 
 #include <asm/errno.h>
 #include <asm/ptrace.h>
@@ -189,10 +190,12 @@ static inline u64 mk_keyed_paddr(u16 hkid, struct page *page)
 
 u64 tdh_vp_enter(struct tdx_vp *vp, struct tdx_module_args *args);
 u64 tdh_mng_addcx(struct tdx_td *td, struct page *tdcs_page);
-u64 tdh_mem_page_add(struct tdx_td *td, u64 gpa, struct page *page, struct page *source, u64 *ext_err1, u64 *ext_err2);
+u64 tdh_mem_page_add(struct tdx_td *td, u64 gpa, kvm_pfn_t pfn, struct page *source,
+                    u64 *ext_err1, u64 *ext_err2);
 u64 tdh_mem_sept_add(struct tdx_td *td, u64 gpa, enum pg_level level, struct page *page, u64 *ext_err1, u64 *ext_err2);
 u64 tdh_vp_addcx(struct tdx_vp *vp, struct page *tdcx_page);
-u64 tdh_mem_page_aug(struct tdx_td *td, u64 gpa, enum pg_level level, struct page *page, u64 *ext_err1, u64 *ext_err2);
+u64 tdh_mem_page_aug(struct tdx_td *td, u64 gpa, enum pg_level level, kvm_pfn_t pfn,
+                    u64 *ext_err1, u64 *ext_err2);
 u64 tdh_mem_range_block(struct tdx_td *td, u64 gpa, enum pg_level level, u64 *ext_err1, u64 *ext_err2);
 u64 tdh_mng_key_config(struct tdx_td *td);
 u64 tdh_mng_create(struct tdx_td *td, u16 hkid);
index 72d916c957bc321e76feb183101bf76633ec8ea3..43bb9c492a4e38894e9151fd89437b6f64613547 100644 (file)
@@ -1624,8 +1624,8 @@ static int tdx_mem_page_add(struct kvm *kvm, gfn_t gfn, enum pg_level level,
            KVM_BUG_ON(!kvm_tdx->page_add_src, kvm))
                return -EIO;
 
-       err = tdh_mem_page_add(&kvm_tdx->td, gpa, pfn_to_page(pfn),
-                              kvm_tdx->page_add_src, &entry, &level_state);
+       err = tdh_mem_page_add(&kvm_tdx->td, gpa, pfn, kvm_tdx->page_add_src,
+                              &entry, &level_state);
        if (unlikely(tdx_operand_busy(err)))
                return -EBUSY;
 
@@ -1639,12 +1639,11 @@ static int tdx_mem_page_aug(struct kvm *kvm, gfn_t gfn,
                            enum pg_level level, kvm_pfn_t pfn)
 {
        struct kvm_tdx *kvm_tdx = to_kvm_tdx(kvm);
-       struct page *page = pfn_to_page(pfn);
        gpa_t gpa = gfn_to_gpa(gfn);
        u64 entry, level_state;
        u64 err;
 
-       err = tdh_mem_page_aug(&kvm_tdx->td, gpa, level, page, &entry, &level_state);
+       err = tdh_mem_page_aug(&kvm_tdx->td, gpa, level, pfn, &entry, &level_state);
        if (unlikely(tdx_operand_busy(err)))
                return -EBUSY;
 
index a6e77afafa7904cdb580c24abe2b82ae1ac9cef9..b24b81cea5eaefb7c8d68f6c70910398950895b9 100644 (file)
@@ -30,7 +30,6 @@
 #include <linux/suspend.h>
 #include <linux/syscore_ops.h>
 #include <linux/idr.h>
-#include <linux/kvm_types.h>
 #include <asm/page.h>
 #include <asm/special_insns.h>
 #include <asm/msr-index.h>
@@ -1568,6 +1567,11 @@ static void tdx_clflush_page(struct page *page)
        clflush_cache_range(page_to_virt(page), PAGE_SIZE);
 }
 
+static void tdx_clflush_pfn(kvm_pfn_t pfn)
+{
+       clflush_cache_range(__va(PFN_PHYS(pfn)), PAGE_SIZE);
+}
+
 static int pg_level_to_tdx_sept_level(enum pg_level level)
 {
        WARN_ON_ONCE(level == PG_LEVEL_NONE);
@@ -1594,17 +1598,18 @@ u64 tdh_mng_addcx(struct tdx_td *td, struct page *tdcs_page)
 }
 EXPORT_SYMBOL_FOR_KVM(tdh_mng_addcx);
 
-u64 tdh_mem_page_add(struct tdx_td *td, u64 gpa, struct page *page, struct page *source, u64 *ext_err1, u64 *ext_err2)
+u64 tdh_mem_page_add(struct tdx_td *td, u64 gpa, kvm_pfn_t pfn, struct page *source,
+                    u64 *ext_err1, u64 *ext_err2)
 {
        struct tdx_module_args args = {
                .rcx = gpa,
                .rdx = tdx_tdr_pa(td),
-               .r8 = page_to_phys(page),
+               .r8 = PFN_PHYS(pfn),
                .r9 = page_to_phys(source),
        };
        u64 ret;
 
-       tdx_clflush_page(page);
+       tdx_clflush_pfn(pfn);
        ret = seamcall_ret(TDH_MEM_PAGE_ADD, &args);
 
        *ext_err1 = args.rcx;
@@ -1647,16 +1652,16 @@ u64 tdh_vp_addcx(struct tdx_vp *vp, struct page *tdcx_page)
 EXPORT_SYMBOL_FOR_KVM(tdh_vp_addcx);
 
 u64 tdh_mem_page_aug(struct tdx_td *td, u64 gpa, enum pg_level level,
-                    struct page *page, u64 *ext_err1, u64 *ext_err2)
+                    kvm_pfn_t pfn, u64 *ext_err1, u64 *ext_err2)
 {
        struct tdx_module_args args = {
                .rcx = gpa | pg_level_to_tdx_sept_level(level),
                .rdx = tdx_tdr_pa(td),
-               .r8 = page_to_phys(page),
+               .r8 = PFN_PHYS(pfn),
        };
        u64 ret;
 
-       tdx_clflush_page(page);
+       tdx_clflush_pfn(pfn);
        ret = seamcall_ret(TDH_MEM_PAGE_AUG, &args);
 
        *ext_err1 = args.rcx;