Re: [PATCH v3 05/16] x86/virt/tdx: Allocate reference counters for PAMT memory

Binbin Wu
2025-09-23T07:45:55Z

On 9/19/2025 7:22 AM, Rick Edgecombe wrote:
> From: "Kirill A. Shutemov" <kirill.shutemov@linux.intel.com>
>
> The PAMT memory holds metadata for TDX protected memory. With Dynamic
> PAMT, the 4KB range of PAMT is allocated on demand. The kernel supplies
> the TDX module with a page pair that covers 2MB of host physical memory.
>
> The kernel must provide this page pair before using pages from the range
> for TDX. If this is not done, any SEAMCALL that attempts to use the memory
> will fail.
>
> Allocate reference counters for every 2MB range to track PAMT memory usage.
> This is necessary to accurately determine when PAMT memory needs to be
> allocated and when it can be freed.
>
> This allocation will currently consume 2 MB for every 1 TB of address
> space from 0 to max_pfn (highest pfn of RAM). The allocation size will
> depend on how the ram is physically laid out. In a worse case scenario
> where the entire 52 address space is covered this would be 8GB. Then
^
52-bit
> the DPAMT refcount allocations could hypothetically exceed the savings
> from Dynamic PAMT, which is 4GB per TB. This is probably unlikely.
>
> However, future changes will reduce this refcount overhead to make DPAMT
> always a net win.
>
> Signed-off-by: Kirill A. Shutemov <kirill.shutemov@linux.intel.com>
> [Add feedback, update log]
> Signed-off-by: Rick Edgecombe <rick.p.edgecombe@intel.com>
> ---
> v3:
> - Split out lazily populate optimization to next patch (Dave)
> - Add comment around pamt_refcounts (Dave)
> - Improve log
> ---
> arch/x86/virt/vmx/tdx/tdx.c | 47 ++++++++++++++++++++++++++++++++++++-
> 1 file changed, 46 insertions(+), 1 deletion(-)
>
> diff --git a/arch/x86/virt/vmx/tdx/tdx.c b/arch/x86/virt/vmx/tdx/tdx.c
> index 4e4aa8927550..0ce4181ca352 100644
> --- a/arch/x86/virt/vmx/tdx/tdx.c
> +++ b/arch/x86/virt/vmx/tdx/tdx.c
> @@ -29,6 +29,7 @@
> #include <linux/acpi.h>
> #include <linux/suspend.h>
> #include <linux/idr.h>
> +#include <linux/vmalloc.h>
> #include <asm/page.h>
> #include <asm/special_insns.h>
> #include <asm/msr-index.h>
> @@ -50,6 +51,16 @@ static DEFINE_PER_CPU(bool, tdx_lp_initialized);
>
> static struct tdmr_info_list tdx_tdmr_list;
>
> +/*
> + * On a machine with Dynamic PAMT, the kernel maintains a reference counter
> + * for every 2M range. The counter indicates how many users there are for
> + * the PAMT memory of the 2M range.
> + *
> + * The kernel allocates PAMT memory when the first user arrives and
> + * frees it when the last user has left.
> + */
> +static atomic_t *pamt_refcounts;
> +
> static enum tdx_module_status_t tdx_module_status;
> static DEFINE_MUTEX(tdx_module_lock);
>
> @@ -183,6 +194,34 @@ int tdx_cpu_enable(void)
> }
> EXPORT_SYMBOL_GPL(tdx_cpu_enable);
>
> +/*
> + * Allocate PAMT reference counters for all physical memory.
> + *
> + * It consumes 2MiB for every 1TiB of physical memory.
> + */
> +static int init_pamt_metadata(void)
> +{
> + size_t size = max_pfn / PTRS_PER_PTE * sizeof(*pamt_refcounts);

Is there guarantee that max_pfn is PTRS_PER_PTE aligned?
If not, it should be rounded up.

> +
> + if (!tdx_supports_dynamic_pamt(&tdx_sysinfo))
> + return 0;
> +
> + pamt_refcounts = vmalloc(size);
> + if (!pamt_refcounts)
> + return -ENOMEM;
> +
> + return 0;
> +}
> +
> …