[PATCH v4 4/6] x86/virt/tdx: Support DPAMT when adding memory for the extensions

From: Xu Yilun

Date: Tue Oct 13 2026 - 12:51:30 EST


The TDX module uses Physical Address Metadata Table (PAMT) to track some
state for each page of physical memory that it might use. 3 levels of
PAMTs are used to track pages of different sizes - 1GB, 2MB and 4KB.
The Dynamic PAMT (DPAMT) feature allows saving memory by allocating
4KB-level PAMT dynamically, while the 1GB and 2MB levels remain
allocated on TDX module initialization.

A previous kernel change [1] enabled the DPAMT feature by default so
that the kernel must install DPAMT before adding any 4KB pages to the
TDX module.

Although the memory for the extensions is tens of megabytes and the
kernel allocates it in a large chunk, the TDX module accepts it at 4K
granularity. Thus the kernel has to install DPAMT for each page of it,
otherwise TDH.EXT.MEM.ADD would fail to execute.

The kernel has helpers to install DPAMT for a 4K page. Call
tdx_pamt_get() for each extension page before adding it to the TDX
module. Normally, these operations should not fail, and if they do,
intentionally keep the error handling as simple as before - leak all
pages, including the installed DPAMT.

AI was used under supervision to review code and workshop logs.

Signed-off-by: Xu Yilun <yilun.xu@xxxxxxxxxxxxxxx>
Reviewed-by: Kiryl Shutsemau (Meta) <kas@xxxxxxxxxx>
Link: https://lore.kernel.org/all/20260904215841.303070-1-rick.p.edgecombe@xxxxxxxxx/ # [1]
---
v4:
- Explain in changelog that TDH.EXT.MEM.ADD won't work without this
patch when DPAMT is on by default. (Tony)
- Move this patch right after the one that implements TDH.EXT.MEM.ADD
- Collect Reviewed-by tags

v3:
- New patch
---
arch/x86/virt/vmx/tdx/tdx.c | 9 ++++++++-
1 file changed, 8 insertions(+), 1 deletion(-)

diff --git a/arch/x86/virt/vmx/tdx/tdx.c b/arch/x86/virt/vmx/tdx/tdx.c
index 744ef95e448f..4908add631fa 100644
--- a/arch/x86/virt/vmx/tdx/tdx.c
+++ b/arch/x86/virt/vmx/tdx/tdx.c
@@ -1328,8 +1328,15 @@ static __init int tdx_ext_mem_setup(void)
struct page *chunk = page + added_pages;
unsigned int i;

- for (i = 0; i < chunk_pages; i++)
+ for (i = 0; i < chunk_pages; i++) {
+ ret = tdx_pamt_get(page_to_pfn(chunk + i), NULL);
+ if (ret) {
+ WARN(1, "DPAMT setup error for extensions, stranded all pages\n");
+ goto out_free_hpa_list;
+ }
+
hpa_list->phys[i] = page_to_phys(chunk + i);
+ }

ret = tdx_ext_mem_add(hpa_list, chunk_pages);
if (ret) {

--
2.25.1