From: Rick Edgecombe <rick.p.edgecombe@intel.com>
To: kas@kernel.org, bp@alien8.de, chao.gao@intel.com,
dave.hansen@linux.intel.com, isaku.yamahata@intel.com,
kai.huang@intel.com, kvm@vger.kernel.org,
linux-coco@lists.linux.dev, linux-kernel@vger.kernel.org,
mingo@redhat.com, pbonzini@redhat.com, seanjc@google.com,
tglx@linutronix.de, x86@kernel.org, yan.y.zhao@intel.com,
vannapurve@google.com
Cc: rick.p.edgecombe@intel.com
Subject: [PATCH v3 12/16] x86/virt/tdx: Add helpers to allow for pre-allocating pages
Date: Thu, 18 Sep 2025 16:22:20 -0700 [thread overview]
Message-ID: <20250918232224.2202592-13-rick.p.edgecombe@intel.com> (raw)
In-Reply-To: <20250918232224.2202592-1-rick.p.edgecombe@intel.com>
In the KVM fault path pagei, tables and private pages need to be
installed under a spin lock. This means that the operations around
installing PAMT pages for them will not be able to allocate pages.
Create a small structure to allow passing a list of pre-allocated pages
that PAMT operations can use. Have the structure keep a count such that
it can be stored on KVM's vCPU structure, and "topped up" for each fault.
This is consistent with how KVM manages similar caches and will fit better
than allocating and freeing all possible needed pages each time.
Adding this structure duplicates a fancier one that lives in KVM 'struct
kvm_mmu_memory_cache'. While the struct itself is easy to expose, the
functions that operate on it are a bit big to put in a header, which
would be needed to use them from the core kernel. So don't pursue this
option.
To avoid problem of needing the kernel to link to functionality in KVM,
a function pointer could be passed, however this makes the code
convoluted, when what is needed is barely more than a linked list. So
create a tiny, simpler version of KVM's kvm_mmu_memory_cache to use for
PAMT pages.
Signed-off-by: Rick Edgecombe <rick.p.edgecombe@intel.com>
---
arch/x86/include/asm/tdx.h | 43 ++++++++++++++++++++++++++++++++++++-
arch/x86/kvm/vmx/tdx.c | 16 +++++++++++---
arch/x86/kvm/vmx/tdx.h | 2 +-
arch/x86/virt/vmx/tdx/tdx.c | 22 +++++++++++++------
virt/kvm/kvm_main.c | 2 --
5 files changed, 72 insertions(+), 13 deletions(-)
diff --git a/arch/x86/include/asm/tdx.h b/arch/x86/include/asm/tdx.h
index 439dd5c5282e..e108b48af2c3 100644
--- a/arch/x86/include/asm/tdx.h
+++ b/arch/x86/include/asm/tdx.h
@@ -17,6 +17,7 @@
#include <uapi/asm/mce.h>
#include <asm/tdx_global_metadata.h>
#include <linux/pgtable.h>
+#include <linux/memory.h>
/*
* Used by the #VE exception handler to gather the #VE exception
@@ -116,7 +117,46 @@ int tdx_guest_keyid_alloc(void);
u32 tdx_get_nr_guest_keyids(void);
void tdx_guest_keyid_free(unsigned int keyid);
-int tdx_pamt_get(struct page *page);
+int tdx_dpamt_entry_pages(void);
+
+/*
+ * Simple structure for pre-allocating Dynamic
+ * PAMT pages outside of locks.
+ */
+struct tdx_prealloc {
+ struct list_head page_list;
+ int cnt;
+};
+
+static inline struct page *get_tdx_prealloc_page(struct tdx_prealloc *prealloc)
+{
+ struct page *page;
+
+ page = list_first_entry_or_null(&prealloc->page_list, struct page, lru);
+ if (page) {
+ list_del(&page->lru);
+ prealloc->cnt--;
+ }
+
+ return page;
+}
+
+static inline int topup_tdx_prealloc_page(struct tdx_prealloc *prealloc, unsigned int min_size)
+{
+ while (prealloc->cnt < min_size) {
+ struct page *page = alloc_page(GFP_KERNEL);
+
+ if (!page)
+ return -ENOMEM;
+
+ list_add(&page->lru, &prealloc->page_list);
+ prealloc->cnt++;
+ }
+
+ return 0;
+}
+
+int tdx_pamt_get(struct page *page, struct tdx_prealloc *prealloc);
void tdx_pamt_put(struct page *page);
struct page *tdx_alloc_page(void);
@@ -192,6 +232,7 @@ static inline int tdx_enable(void) { return -ENODEV; }
static inline u32 tdx_get_nr_guest_keyids(void) { return 0; }
static inline const char *tdx_dump_mce_info(struct mce *m) { return NULL; }
static inline const struct tdx_sys_info *tdx_get_sysinfo(void) { return NULL; }
+static inline int tdx_dpamt_entry_pages(void) { return 0; }
#endif /* CONFIG_INTEL_TDX_HOST */
#endif /* !__ASSEMBLER__ */
diff --git a/arch/x86/kvm/vmx/tdx.c b/arch/x86/kvm/vmx/tdx.c
index 6c9e11be9705..b274d350165c 100644
--- a/arch/x86/kvm/vmx/tdx.c
+++ b/arch/x86/kvm/vmx/tdx.c
@@ -1593,16 +1593,26 @@ static void tdx_unpin(struct kvm *kvm, struct page *page)
static void *tdx_alloc_external_fault_cache(struct kvm_vcpu *vcpu)
{
struct vcpu_tdx *tdx = to_tdx(vcpu);
+ struct page *page = get_tdx_prealloc_page(&tdx->prealloc);
- return kvm_mmu_memory_cache_alloc(&tdx->mmu_external_spt_cache);
+ if (!page)
+ return NULL;
+
+ return page_address(page);
}
static int tdx_topup_external_fault_cache(struct kvm_vcpu *vcpu)
{
struct vcpu_tdx *tdx = to_tdx(vcpu);
+ struct tdx_prealloc *prealloc = &tdx->prealloc;
+ int min_fault_cache_size;
- return kvm_mmu_topup_memory_cache(&tdx->mmu_external_spt_cache,
- PT64_ROOT_MAX_LEVEL);
+ /* External page tables */
+ min_fault_cache_size = PT64_ROOT_MAX_LEVEL;
+ /* Dynamic PAMT pages (if enabled) */
+ min_fault_cache_size += tdx_dpamt_entry_pages() * PT64_ROOT_MAX_LEVEL;
+
+ return topup_tdx_prealloc_page(prealloc, min_fault_cache_size);
}
static int tdx_mem_page_aug(struct kvm *kvm, gfn_t gfn,
diff --git a/arch/x86/kvm/vmx/tdx.h b/arch/x86/kvm/vmx/tdx.h
index cd7993ef056e..68bb841c1b6c 100644
--- a/arch/x86/kvm/vmx/tdx.h
+++ b/arch/x86/kvm/vmx/tdx.h
@@ -71,7 +71,7 @@ struct vcpu_tdx {
u64 map_gpa_next;
u64 map_gpa_end;
- struct kvm_mmu_memory_cache mmu_external_spt_cache;
+ struct tdx_prealloc prealloc;
};
void tdh_vp_rd_failed(struct vcpu_tdx *tdx, char *uclass, u32 field, u64 err);
diff --git a/arch/x86/virt/vmx/tdx/tdx.c b/arch/x86/virt/vmx/tdx/tdx.c
index c25e238931a7..b4edc3ee495c 100644
--- a/arch/x86/virt/vmx/tdx/tdx.c
+++ b/arch/x86/virt/vmx/tdx/tdx.c
@@ -1999,13 +1999,23 @@ u64 tdh_phymem_page_wbinvd_hkid(u64 hkid, struct page *page)
EXPORT_SYMBOL_GPL(tdh_phymem_page_wbinvd_hkid);
/* Number PAMT pages to be provided to TDX module per 2M region of PA */
-static int tdx_dpamt_entry_pages(void)
+int tdx_dpamt_entry_pages(void)
{
if (!tdx_supports_dynamic_pamt(&tdx_sysinfo))
return 0;
return tdx_sysinfo.tdmr.pamt_4k_entry_size * PTRS_PER_PTE / PAGE_SIZE;
}
+EXPORT_SYMBOL_GPL(tdx_dpamt_entry_pages);
+
+static struct page *alloc_dpamt_page(struct tdx_prealloc *prealloc)
+{
+ if (prealloc)
+ return get_tdx_prealloc_page(prealloc);
+
+ return alloc_page(GFP_KERNEL);
+}
+
/*
* The TDX spec treats the registers like an array, as they are ordered
@@ -2032,12 +2042,12 @@ static u64 *dpamt_args_array_ptr(struct tdx_module_args *args)
return (u64 *)((u8 *)args + offsetof(struct tdx_module_args, rdx));
}
-static int alloc_pamt_array(u64 *pa_array)
+static int alloc_pamt_array(u64 *pa_array, struct tdx_prealloc *prealloc)
{
struct page *page;
for (int i = 0; i < tdx_dpamt_entry_pages(); i++) {
- page = alloc_page(GFP_KERNEL);
+ page = alloc_dpamt_page(prealloc);
if (!page)
return -ENOMEM;
pa_array[i] = page_to_phys(page);
@@ -2111,7 +2121,7 @@ static u64 tdh_phymem_pamt_remove(unsigned long hpa, u64 *pamt_pa_array)
static DEFINE_SPINLOCK(pamt_lock);
/* Bump PAMT refcount for the given page and allocate PAMT memory if needed */
-int tdx_pamt_get(struct page *page)
+int tdx_pamt_get(struct page *page, struct tdx_prealloc *prealloc)
{
unsigned long hpa = ALIGN_DOWN(page_to_phys(page), PMD_SIZE);
u64 pamt_pa_array[MAX_DPAMT_ARG_SIZE];
@@ -2122,7 +2132,7 @@ int tdx_pamt_get(struct page *page)
if (!tdx_supports_dynamic_pamt(&tdx_sysinfo))
return 0;
- ret = alloc_pamt_array(pamt_pa_array);
+ ret = alloc_pamt_array(pamt_pa_array, prealloc);
if (ret)
return ret;
@@ -2228,7 +2238,7 @@ struct page *tdx_alloc_page(void)
if (!page)
return NULL;
- if (tdx_pamt_get(page)) {
+ if (tdx_pamt_get(page, NULL)) {
__free_page(page);
return NULL;
}
diff --git a/virt/kvm/kvm_main.c b/virt/kvm/kvm_main.c
index f05e6d43184b..fee108988028 100644
--- a/virt/kvm/kvm_main.c
+++ b/virt/kvm/kvm_main.c
@@ -404,7 +404,6 @@ int kvm_mmu_topup_memory_cache(struct kvm_mmu_memory_cache *mc, int min)
{
return __kvm_mmu_topup_memory_cache(mc, KVM_ARCH_NR_OBJS_PER_MEMORY_CACHE, min);
}
-EXPORT_SYMBOL_GPL(kvm_mmu_topup_memory_cache);
int kvm_mmu_memory_cache_nr_free_objects(struct kvm_mmu_memory_cache *mc)
{
@@ -437,7 +436,6 @@ void *kvm_mmu_memory_cache_alloc(struct kvm_mmu_memory_cache *mc)
BUG_ON(!p);
return p;
}
-EXPORT_SYMBOL_GPL(kvm_mmu_memory_cache_alloc);
#endif
static void kvm_vcpu_init(struct kvm_vcpu *vcpu, struct kvm *kvm, unsigned id)
--
2.51.0
next prev parent reply other threads:[~2025-09-18 23:23 UTC|newest]
Thread overview: 97+ messages / expand[flat|nested] mbox.gz Atom feed top
2025-09-18 23:22 [PATCH v3 00/16] TDX: Enable Dynamic PAMT Rick Edgecombe
2025-09-18 23:22 ` [PATCH v3 01/16] x86/tdx: Move all TDX error defines into <asm/shared/tdx_errno.h> Rick Edgecombe
2025-09-19 1:29 ` Huang, Kai
2025-09-25 23:23 ` Edgecombe, Rick P
2025-09-25 23:32 ` Huang, Kai
2025-09-23 5:49 ` Binbin Wu
2025-09-25 23:09 ` Edgecombe, Rick P
2025-09-26 5:36 ` Binbin Wu
2025-09-26 4:52 ` Xiaoyao Li
2025-09-26 19:53 ` Edgecombe, Rick P
2025-09-18 23:22 ` [PATCH v3 02/16] x86/tdx: Add helpers to check return status codes Rick Edgecombe
2025-09-19 1:26 ` Huang, Kai
2025-09-25 23:27 ` Edgecombe, Rick P
2025-09-23 6:19 ` Binbin Wu
2025-09-25 23:24 ` Edgecombe, Rick P
2025-09-26 6:32 ` Xiaoyao Li
2025-09-26 21:27 ` Edgecombe, Rick P
2025-09-18 23:22 ` [PATCH v3 03/16] x86/virt/tdx: Simplify tdmr_get_pamt_sz() Rick Edgecombe
2025-09-19 0:50 ` Huang, Kai
2025-09-19 19:26 ` Edgecombe, Rick P
2025-09-29 11:44 ` Xiaoyao Li
2025-09-29 17:47 ` Edgecombe, Rick P
2025-09-18 23:22 ` [PATCH v3 04/16] x86/virt/tdx: Allocate page bitmap for Dynamic PAMT Rick Edgecombe
2025-09-23 7:15 ` Binbin Wu
2025-09-25 23:28 ` Edgecombe, Rick P
2025-09-26 8:41 ` Xiaoyao Li
2025-09-26 21:57 ` Edgecombe, Rick P
2025-09-26 22:06 ` Dave Hansen
2025-10-06 19:34 ` Edgecombe, Rick P
2025-09-18 23:22 ` [PATCH v3 05/16] x86/virt/tdx: Allocate reference counters for PAMT memory Rick Edgecombe
2025-09-23 7:45 ` Binbin Wu
2025-09-29 17:41 ` Edgecombe, Rick P
2025-09-29 18:08 ` Dave Hansen
2025-09-30 1:04 ` Edgecombe, Rick P
2025-09-18 23:22 ` [PATCH v3 06/16] x86/virt/tdx: Improve PAMT refcounters allocation for sparse memory Rick Edgecombe
2025-09-19 7:25 ` Huang, Kai
2025-09-23 9:38 ` Binbin Wu
2025-09-24 6:50 ` Huang, Kai
2025-09-24 8:57 ` Binbin Wu
2025-10-01 0:32 ` Edgecombe, Rick P
2025-10-01 10:40 ` Huang, Kai
2025-10-01 19:00 ` Edgecombe, Rick P
2025-10-01 20:49 ` Huang, Kai
2025-10-15 1:35 ` Huang, Kai
2025-09-18 23:22 ` [PATCH v3 07/16] x86/virt/tdx: Add tdx_alloc/free_page() helpers Rick Edgecombe
2025-09-22 11:27 ` Huang, Kai
2025-09-26 22:41 ` Edgecombe, Rick P
2025-09-29 7:56 ` Yan Zhao
2025-09-29 17:19 ` Edgecombe, Rick P
2025-09-30 14:03 ` Xiaoyao Li
2025-09-30 17:38 ` Dave Hansen
2025-09-30 17:47 ` Edgecombe, Rick P
2025-09-30 15:25 ` Dave Hansen
2025-09-30 17:00 ` Edgecombe, Rick P
2025-09-18 23:22 ` [PATCH v3 08/16] x86/virt/tdx: Optimize " Rick Edgecombe
2025-09-19 9:39 ` Kiryl Shutsemau
2025-09-24 6:15 ` Binbin Wu
2025-09-18 23:22 ` [PATCH v3 09/16] KVM: TDX: Allocate PAMT memory for TD control structures Rick Edgecombe
2025-09-18 23:22 ` [PATCH v3 10/16] KVM: TDX: Allocate PAMT memory for vCPU " Rick Edgecombe
2025-09-18 23:22 ` [PATCH v3 11/16] KVM: TDX: Add x86 ops for external spt cache Rick Edgecombe
2025-09-19 9:44 ` Kiryl Shutsemau
2025-09-23 7:03 ` Yan Zhao
2025-09-26 22:10 ` Edgecombe, Rick P
2025-09-28 8:35 ` Yan Zhao
2025-09-24 7:58 ` Binbin Wu
2025-09-30 1:02 ` Yan Zhao
2025-09-30 17:54 ` Edgecombe, Rick P
2025-09-18 23:22 ` Rick Edgecombe [this message]
2025-09-19 9:55 ` [PATCH v3 12/16] x86/virt/tdx: Add helpers to allow for pre-allocating pages Kiryl Shutsemau
2025-10-01 19:48 ` Edgecombe, Rick P
2025-09-22 11:20 ` Huang, Kai
2025-09-26 23:47 ` Edgecombe, Rick P
2025-09-28 22:56 ` Huang, Kai
2025-09-29 12:10 ` Huang, Kai
2025-09-26 1:44 ` Yan Zhao
2025-09-26 22:05 ` Edgecombe, Rick P
2025-09-28 1:40 ` Yan Zhao
2025-09-26 15:19 ` Dave Hansen
2025-09-26 15:49 ` Edgecombe, Rick P
2025-09-18 23:22 ` [PATCH v3 13/16] KVM: TDX: Handle PAMT allocation in fault path Rick Edgecombe
2025-09-30 1:09 ` Yan Zhao
2025-09-30 18:11 ` Edgecombe, Rick P
2025-09-18 23:22 ` [PATCH v3 14/16] KVM: TDX: Reclaim PAMT memory Rick Edgecombe
2025-09-18 23:22 ` [PATCH v3 15/16] x86/virt/tdx: Enable Dynamic PAMT Rick Edgecombe
2025-09-18 23:22 ` [PATCH v3 16/16] Documentation/x86: Add documentation for TDX's " Rick Edgecombe
2025-09-26 2:28 ` [PATCH v3 00/16] TDX: Enable " Yan Zhao
2025-09-26 14:09 ` Dave Hansen
2025-09-26 16:02 ` Edgecombe, Rick P
2025-09-26 16:11 ` Dave Hansen
2025-09-26 19:00 ` Edgecombe, Rick P
2025-09-26 19:03 ` Dave Hansen
2025-09-26 19:52 ` Edgecombe, Rick P
2025-09-28 1:34 ` Yan Zhao
2025-09-29 11:17 ` Kiryl Shutsemau
2025-09-29 16:22 ` Dave Hansen
2025-09-29 16:58 ` Edgecombe, Rick P
2025-09-30 18:29 ` Edgecombe, Rick P
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20250918232224.2202592-13-rick.p.edgecombe@intel.com \
--to=rick.p.edgecombe@intel.com \
--cc=bp@alien8.de \
--cc=chao.gao@intel.com \
--cc=dave.hansen@linux.intel.com \
--cc=isaku.yamahata@intel.com \
--cc=kai.huang@intel.com \
--cc=kas@kernel.org \
--cc=kvm@vger.kernel.org \
--cc=linux-coco@lists.linux.dev \
--cc=linux-kernel@vger.kernel.org \
--cc=mingo@redhat.com \
--cc=pbonzini@redhat.com \
--cc=seanjc@google.com \
--cc=tglx@linutronix.de \
--cc=vannapurve@google.com \
--cc=x86@kernel.org \
--cc=yan.y.zhao@intel.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox
all inboxes | Powered by JetHome®