From: Yan Zhao <yan.y.zhao@intel.com>
To: pbonzini@redhat.com, seanjc@google.com
Cc: linux-kernel@vger.kernel.org, kvm@vger.kernel.org,
x86@kernel.org, rick.p.edgecombe@intel.com,
dave.hansen@intel.com, kas@kernel.org, tabba@google.com,
ackerleytng@google.com, michael.roth@amd.com, david@kernel.org,
vannapurve@google.com, sagis@google.com, vbabka@suse.cz,
thomas.lendacky@amd.com, nik.borisov@suse.com, pgonda@google.com,
fan.du@intel.com, jun.miao@intel.com,
francescolavra.fl@gmail.com, jgross@suse.com,
ira.weiny@intel.com, isaku.yamahata@intel.com,
xiaoyao.li@intel.com, kai.huang@intel.com,
binbin.wu@linux.intel.com, chao.p.peng@intel.com,
chao.gao@intel.com, yan.y.zhao@intel.com
Subject: [PATCH v3 22/24] x86/tdx: Add/Remove DPAMT pages for guest private memory to demote
Date: Tue, 6 Jan 2026 18:24:13 +0800 [thread overview]
Message-ID: <20260106102413.25294-1-yan.y.zhao@intel.com> (raw)
In-Reply-To: <20260106101646.24809-1-yan.y.zhao@intel.com>
From: "Kirill A. Shutemov" <kirill.shutemov@linux.intel.com>
When Dynamic PAMT is enabled and splitting a 2MB mapping to 512 4KB
mappings, SEAMCALL TDH.MEM.PAGE.DEMOTE takes the Dynamic PAMT page pair in
registers R12 and R13. The Dynamic PAMT page pair is used to store physical
memory metadata for the 2MB guest private memory after its S-EPT mapping is
split to 4KB successfully.
Pass prealloc_split_cache (the per-VM split cache) to SEAMCALL wrapper
tdh_mem_page_demote() for dequeuing Dynamic PAMT pages from the cache.
Protect the cache dequeuing in KVM with prealloc_split_cache_lock.
Inside wrapper tdh_mem_page_demote(), dequeue the Dynamic PAMT pages into
the guest_memory_pamt_page array and copy the page address to R12 and R13.
Invoke SEAMCALL TDH_MEM_PAGE_DEMOTE using seamcall_saved_ret() to handle
registers above R11.
Free the Dynamic PAMT pages after SEAMCALL TDH_MEM_PAGE_DEMOTE fails since
the guest private memory is still mapped at 2MB level.
Opportunistically, rename dpamt_args_array_ptr() to
dpamt_args_array_ptr_rdx() for tdh_phymem_pamt_{add/remove} and invoke
dpamt_args_array_ptr_r12() in tdh_mem_page_demote() for populating
registers starting from R12.
Signed-off-by: Kirill A. Shutemov <kirill.shutemov@linux.intel.com>
Co-developed-by: Yan Zhao <yan.y.zhao@intel.com>
Signed-off-by: Yan Zhao <yan.y.zhao@intel.com>
---
v3:
- Split out as a new patch.
- Get pages from preallocate cache corresponding to DPAMT v4.
---
arch/x86/include/asm/tdx.h | 1 +
arch/x86/kvm/vmx/tdx.c | 5 ++-
arch/x86/virt/vmx/tdx/tdx.c | 76 ++++++++++++++++++++++++++-----------
3 files changed, 59 insertions(+), 23 deletions(-)
diff --git a/arch/x86/include/asm/tdx.h b/arch/x86/include/asm/tdx.h
index abe484045132..5fc7498392fd 100644
--- a/arch/x86/include/asm/tdx.h
+++ b/arch/x86/include/asm/tdx.h
@@ -251,6 +251,7 @@ u64 tdh_mng_create(struct tdx_td *td, u16 hkid);
u64 tdh_vp_create(struct tdx_td *td, struct tdx_vp *vp);
u64 tdh_mng_rd(struct tdx_td *td, u64 field, u64 *data);
u64 tdh_mem_page_demote(struct tdx_td *td, u64 gpa, int level, struct page *new_sept_page,
+ struct tdx_prealloc *prealloc,
u64 *ext_err1, u64 *ext_err2);
u64 tdh_mr_extend(struct tdx_td *td, u64 gpa, u64 *ext_err1, u64 *ext_err2);
u64 tdh_mr_finalize(struct tdx_td *td);
diff --git a/arch/x86/kvm/vmx/tdx.c b/arch/x86/kvm/vmx/tdx.c
index ec47bd799274..a11ff02a4f30 100644
--- a/arch/x86/kvm/vmx/tdx.c
+++ b/arch/x86/kvm/vmx/tdx.c
@@ -2021,8 +2021,11 @@ static int tdx_sept_split_private_spte(struct kvm *kvm, gfn_t gfn, enum pg_level
if (KVM_BUG_ON(ret, kvm))
return -EIO;
+ spin_lock(&kvm_tdx->prealloc_split_cache_lock);
err = tdh_do_no_vcpus(tdh_mem_page_demote, kvm, &kvm_tdx->td, gpa,
- tdx_level, new_sept_page, &entry, &level_state);
+ tdx_level, new_sept_page,
+ &kvm_tdx->prealloc_split_cache, &entry, &level_state);
+ spin_unlock(&kvm_tdx->prealloc_split_cache_lock);
if (TDX_BUG_ON_2(err, TDH_MEM_PAGE_DEMOTE, entry, level_state, kvm)) {
tdx_pamt_put(new_sept_page);
return -EIO;
diff --git a/arch/x86/virt/vmx/tdx/tdx.c b/arch/x86/virt/vmx/tdx/tdx.c
index 76963c563906..9917e4e7705f 100644
--- a/arch/x86/virt/vmx/tdx/tdx.c
+++ b/arch/x86/virt/vmx/tdx/tdx.c
@@ -1848,25 +1848,69 @@ u64 tdh_mng_rd(struct tdx_td *td, u64 field, u64 *data)
}
EXPORT_SYMBOL_GPL(tdh_mng_rd);
+static int alloc_pamt_array(u64 *pa_array, struct tdx_prealloc *prealloc);
+static void free_pamt_array(u64 *pa_array);
+/*
+ * The TDX spec treats the registers like an array, as they are ordered
+ * in the struct. The array size is limited by the number or registers,
+ * so define the max size it could be for worst case allocations and sanity
+ * checking.
+ */
+#define MAX_TDX_ARG_SIZE(reg) ((sizeof(struct tdx_module_args) - \
+ offsetof(struct tdx_module_args, reg)) / sizeof(u64))
+#define TDX_ARG_INDEX(reg) (offsetof(struct tdx_module_args, reg) / \
+ sizeof(u64))
+/*
+ * Treat struct the registers like an array that starts at R12, per
+ * TDX spec. Do some sanitychecks, and return an indexable type.
+ */
+static u64 *dpamt_args_array_ptr_r12(struct tdx_module_array_args *args)
+{
+ WARN_ON_ONCE(tdx_dpamt_entry_pages() > MAX_TDX_ARG_SIZE(r12));
+
+ return &args->args_array[TDX_ARG_INDEX(r12)];
+}
+
u64 tdh_mem_page_demote(struct tdx_td *td, u64 gpa, int level, struct page *new_sept_page,
+ struct tdx_prealloc *prealloc,
u64 *ext_err1, u64 *ext_err2)
{
- struct tdx_module_args args = {
- .rcx = gpa | level,
- .rdx = tdx_tdr_pa(td),
- .r8 = page_to_phys(new_sept_page),
+ bool dpamt = tdx_supports_dynamic_pamt(&tdx_sysinfo) && level == TDX_PS_2M;
+ u64 guest_memory_pamt_page[MAX_TDX_ARG_SIZE(r12)];
+ struct tdx_module_array_args args = {
+ .args.rcx = gpa | level,
+ .args.rdx = tdx_tdr_pa(td),
+ .args.r8 = page_to_phys(new_sept_page),
};
u64 ret;
if (!tdx_supports_demote_nointerrupt(&tdx_sysinfo))
return TDX_SW_ERROR;
+ if (dpamt) {
+ u64 *args_array = dpamt_args_array_ptr_r12(&args);
+
+ if (alloc_pamt_array(guest_memory_pamt_page, prealloc))
+ return TDX_SW_ERROR;
+
+ /*
+ * Copy PAMT page PAs of the guest memory into the struct per the
+ * TDX ABI
+ */
+ memcpy(args_array, guest_memory_pamt_page,
+ tdx_dpamt_entry_pages() * sizeof(*args_array));
+ }
+
/* Flush the new S-EPT page to be added */
tdx_clflush_page(new_sept_page);
- ret = seamcall_ret(TDH_MEM_PAGE_DEMOTE, &args);
- *ext_err1 = args.rcx;
- *ext_err2 = args.rdx;
+ ret = seamcall_saved_ret(TDH_MEM_PAGE_DEMOTE, &args.args);
+
+ *ext_err1 = args.args.rcx;
+ *ext_err2 = args.args.rdx;
+
+ if (dpamt && ret)
+ free_pamt_array(guest_memory_pamt_page);
return ret;
}
@@ -2104,23 +2148,11 @@ static struct page *alloc_dpamt_page(struct tdx_prealloc *prealloc)
return alloc_page(GFP_KERNEL_ACCOUNT);
}
-
-/*
- * The TDX spec treats the registers like an array, as they are ordered
- * in the struct. The array size is limited by the number or registers,
- * so define the max size it could be for worst case allocations and sanity
- * checking.
- */
-#define MAX_TDX_ARG_SIZE(reg) (sizeof(struct tdx_module_args) - \
- offsetof(struct tdx_module_args, reg))
-#define TDX_ARG_INDEX(reg) (offsetof(struct tdx_module_args, reg) / \
- sizeof(u64))
-
/*
* Treat struct the registers like an array that starts at RDX, per
* TDX spec. Do some sanitychecks, and return an indexable type.
*/
-static u64 *dpamt_args_array_ptr(struct tdx_module_array_args *args)
+static u64 *dpamt_args_array_ptr_rdx(struct tdx_module_array_args *args)
{
WARN_ON_ONCE(tdx_dpamt_entry_pages() > MAX_TDX_ARG_SIZE(rdx));
@@ -2188,7 +2220,7 @@ static u64 tdh_phymem_pamt_add(struct page *page, u64 *pamt_pa_array)
struct tdx_module_array_args args = {
.args.rcx = pamt_2mb_arg(page)
};
- u64 *dpamt_arg_array = dpamt_args_array_ptr(&args);
+ u64 *dpamt_arg_array = dpamt_args_array_ptr_rdx(&args);
/* Copy PAMT page PA's into the struct per the TDX ABI */
memcpy(dpamt_arg_array, pamt_pa_array,
@@ -2216,7 +2248,7 @@ static u64 tdh_phymem_pamt_remove(struct page *page, u64 *pamt_pa_array)
struct tdx_module_array_args args = {
.args.rcx = pamt_2mb_arg(page),
};
- u64 *args_array = dpamt_args_array_ptr(&args);
+ u64 *args_array = dpamt_args_array_ptr_rdx(&args);
u64 ret;
ret = seamcall_ret(TDH_PHYMEM_PAMT_REMOVE, &args.args);
--
2.43.2
next prev parent reply other threads:[~2026-01-06 10:26 UTC|newest]
Thread overview: 127+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-01-06 10:16 [PATCH v3 00/24] KVM: TDX huge page support for private memory Yan Zhao
2026-01-06 10:18 ` [PATCH v3 01/24] x86/tdx: Enhance tdh_mem_page_aug() to support huge pages Yan Zhao
2026-01-06 21:08 ` Dave Hansen
2026-01-07 9:12 ` Yan Zhao
2026-01-07 16:39 ` Dave Hansen
2026-01-08 19:05 ` Ackerley Tng
2026-01-08 19:24 ` Dave Hansen
2026-01-09 16:21 ` Vishal Annapurve
2026-01-09 3:08 ` Yan Zhao
2026-01-09 18:29 ` Ackerley Tng
2026-01-12 2:41 ` Yan Zhao
2026-01-13 16:50 ` Vishal Annapurve
2026-01-14 1:48 ` Yan Zhao
2026-01-06 10:18 ` [PATCH v3 02/24] x86/virt/tdx: Add SEAMCALL wrapper tdh_mem_page_demote() Yan Zhao
2026-01-16 1:00 ` Huang, Kai
2026-01-16 8:35 ` Yan Zhao
2026-01-16 11:10 ` Huang, Kai
2026-01-16 11:22 ` Huang, Kai
2026-01-19 6:18 ` Yan Zhao
2026-01-19 6:15 ` Yan Zhao
2026-01-16 11:22 ` Huang, Kai
2026-01-19 5:55 ` Yan Zhao
2026-01-28 22:49 ` Sean Christopherson
2026-01-06 10:19 ` [PATCH v3 03/24] x86/tdx: Enhance tdh_phymem_page_wbinvd_hkid() to invalidate huge pages Yan Zhao
2026-01-06 10:19 ` [PATCH v3 04/24] x86/tdx: Introduce tdx_quirk_reset_folio() to reset private " Yan Zhao
2026-01-06 10:20 ` [PATCH v3 05/24] x86/virt/tdx: Enhance tdh_phymem_page_reclaim() to support " Yan Zhao
2026-01-06 10:20 ` [PATCH v3 06/24] KVM: x86/mmu: Disallow page merging (huge page adjustment) for mirror root Yan Zhao
2026-01-15 22:49 ` Sean Christopherson
2026-01-16 7:54 ` Yan Zhao
2026-01-26 16:08 ` Sean Christopherson
2026-01-27 3:40 ` Yan Zhao
2026-01-28 19:51 ` Sean Christopherson
2026-01-06 10:20 ` [PATCH v3 07/24] KVM: x86/tdp_mmu: Introduce split_external_spte() under write mmu_lock Yan Zhao
2026-01-28 22:38 ` Sean Christopherson
2026-01-06 10:20 ` [PATCH v3 08/24] KVM: TDX: Enable huge page splitting " Yan Zhao
2026-01-06 10:21 ` [PATCH v3 09/24] KVM: x86: Reject splitting huge pages under shared mmu_lock in TDX Yan Zhao
2026-01-06 10:21 ` [PATCH v3 10/24] KVM: x86/tdp_mmu: Alloc external_spt page for mirror page table splitting Yan Zhao
2026-01-06 10:21 ` [PATCH v3 11/24] KVM: x86/mmu: Introduce kvm_split_cross_boundary_leafs() Yan Zhao
2026-01-15 12:25 ` Huang, Kai
2026-01-16 23:39 ` Sean Christopherson
2026-01-19 1:28 ` Yan Zhao
2026-01-19 8:35 ` Huang, Kai
2026-01-19 8:49 ` Huang, Kai
2026-01-19 10:11 ` Yan Zhao
2026-01-19 10:40 ` Huang, Kai
2026-01-19 11:06 ` Yan Zhao
2026-01-19 12:32 ` Yan Zhao
2026-01-29 14:36 ` Sean Christopherson
2026-01-20 17:51 ` Sean Christopherson
2026-01-22 6:27 ` Yan Zhao
2026-01-20 17:57 ` Vishal Annapurve
2026-01-20 18:02 ` Sean Christopherson
2026-01-22 6:33 ` Yan Zhao
2026-01-29 14:51 ` Sean Christopherson
2026-01-06 10:21 ` [PATCH v3 12/24] KVM: x86: Introduce hugepage_set_guest_inhibit() Yan Zhao
2026-01-06 10:22 ` [PATCH v3 13/24] KVM: TDX: Honor the guest's accept level contained in an EPT violation Yan Zhao
2026-01-06 10:22 ` [PATCH v3 14/24] KVM: Change the return type of gfn_handler_t() from bool to int Yan Zhao
2026-01-16 0:21 ` Sean Christopherson
2026-01-16 6:42 ` Yan Zhao
2026-01-06 10:22 ` [PATCH v3 15/24] KVM: x86: Split cross-boundary mirror leafs for KVM_SET_MEMORY_ATTRIBUTES Yan Zhao
2026-01-06 10:22 ` [PATCH v3 16/24] KVM: guest_memfd: Split for punch hole and private-to-shared conversion Yan Zhao
2026-01-28 22:39 ` Sean Christopherson
2026-01-06 10:23 ` [PATCH v3 17/24] KVM: TDX: Get/Put DPAMT page pair only when mapping size is 4KB Yan Zhao
2026-01-06 10:23 ` [PATCH v3 18/24] x86/virt/tdx: Add loud warning when tdx_pamt_put() fails Yan Zhao
2026-01-06 10:23 ` [PATCH v3 19/24] KVM: x86: Introduce per-VM external cache for splitting Yan Zhao
2026-01-21 1:54 ` Huang, Kai
2026-01-21 17:30 ` Sean Christopherson
2026-01-21 19:39 ` Edgecombe, Rick P
2026-01-21 23:01 ` Huang, Kai
2026-01-22 7:03 ` Yan Zhao
2026-01-22 7:30 ` Huang, Kai
2026-01-22 7:49 ` Yan Zhao
2026-01-22 10:33 ` Huang, Kai
2026-01-06 10:23 ` [PATCH v3 20/24] KVM: TDX: Implement per-VM external cache for splitting in TDX Yan Zhao
2026-01-06 10:23 ` [PATCH v3 21/24] KVM: TDX: Add/Remove DPAMT pages for the new S-EPT page for splitting Yan Zhao
2026-01-06 10:24 ` Yan Zhao [this message]
2026-01-19 10:52 ` [PATCH v3 22/24] x86/tdx: Add/Remove DPAMT pages for guest private memory to demote Huang, Kai
2026-01-19 11:11 ` Yan Zhao
2026-01-06 10:24 ` [PATCH v3 23/24] x86/tdx: Pass guest memory's PFN info to demote for updating pamt_refcount Yan Zhao
2026-01-06 10:24 ` [PATCH v3 24/24] KVM: TDX: Turn on PG_LEVEL_2M Yan Zhao
2026-01-06 17:47 ` [PATCH v3 00/24] KVM: TDX huge page support for private memory Vishal Annapurve
2026-01-06 21:26 ` Ackerley Tng
2026-01-06 21:38 ` Sean Christopherson
2026-01-06 22:04 ` Ackerley Tng
2026-01-06 23:43 ` Sean Christopherson
2026-01-07 9:03 ` Yan Zhao
2026-01-08 20:11 ` Ackerley Tng
2026-01-09 9:18 ` Yan Zhao
2026-01-09 16:12 ` Vishal Annapurve
2026-01-09 17:16 ` Vishal Annapurve
2026-01-09 18:07 ` Ackerley Tng
2026-01-12 1:39 ` Yan Zhao
2026-01-12 2:12 ` Yan Zhao
2026-01-12 19:56 ` Ackerley Tng
2026-01-13 6:10 ` Yan Zhao
2026-01-13 16:40 ` Vishal Annapurve
2026-01-14 9:32 ` Yan Zhao
2026-01-07 19:22 ` Edgecombe, Rick P
2026-01-07 20:27 ` Sean Christopherson
2026-01-12 20:15 ` Ackerley Tng
2026-01-14 0:33 ` Yan Zhao
2026-01-14 1:24 ` Sean Christopherson
2026-01-14 9:23 ` Yan Zhao
2026-01-14 15:26 ` Sean Christopherson
2026-01-14 18:45 ` Ackerley Tng
2026-01-15 3:08 ` Yan Zhao
2026-01-15 18:13 ` Ackerley Tng
2026-01-14 18:56 ` Dave Hansen
2026-01-15 0:19 ` Sean Christopherson
2026-01-16 15:45 ` Edgecombe, Rick P
2026-01-16 16:31 ` Sean Christopherson
2026-01-16 16:58 ` Edgecombe, Rick P
2026-01-19 5:53 ` Yan Zhao
2026-01-30 15:32 ` Sean Christopherson
2026-02-03 9:18 ` Yan Zhao
2026-02-09 17:01 ` Sean Christopherson
2026-01-16 16:57 ` Dave Hansen
2026-01-16 17:14 ` Sean Christopherson
2026-01-16 17:45 ` Dave Hansen
2026-01-16 19:59 ` Sean Christopherson
2026-01-16 22:25 ` Dave Hansen
2026-01-15 1:41 ` Yan Zhao
2026-01-15 16:26 ` Sean Christopherson
2026-01-16 0:28 ` Sean Christopherson
2026-01-16 11:25 ` Yan Zhao
2026-01-16 14:46 ` Sean Christopherson
2026-01-19 1:25 ` Yan Zhao
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=20260106102413.25294-1-yan.y.zhao@intel.com \
--to=yan.y.zhao@intel.com \
--cc=ackerleytng@google.com \
--cc=binbin.wu@linux.intel.com \
--cc=chao.gao@intel.com \
--cc=chao.p.peng@intel.com \
--cc=dave.hansen@intel.com \
--cc=david@kernel.org \
--cc=fan.du@intel.com \
--cc=francescolavra.fl@gmail.com \
--cc=ira.weiny@intel.com \
--cc=isaku.yamahata@intel.com \
--cc=jgross@suse.com \
--cc=jun.miao@intel.com \
--cc=kai.huang@intel.com \
--cc=kas@kernel.org \
--cc=kvm@vger.kernel.org \
--cc=linux-kernel@vger.kernel.org \
--cc=michael.roth@amd.com \
--cc=nik.borisov@suse.com \
--cc=pbonzini@redhat.com \
--cc=pgonda@google.com \
--cc=rick.p.edgecombe@intel.com \
--cc=sagis@google.com \
--cc=seanjc@google.com \
--cc=tabba@google.com \
--cc=thomas.lendacky@amd.com \
--cc=vannapurve@google.com \
--cc=vbabka@suse.cz \
--cc=x86@kernel.org \
--cc=xiaoyao.li@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®