Re: [PATCH v4 02/17] x86/virt/tdx: Add a SEAMCALL wrapper to demote a 2MB huge page
From: Edgecombe, Rick P
Date: Thu Oct 22 2026 - 11:54:33 EST
On Thu, 2026-10-22 at 16:46 +0800, Yan Zhao wrote:
> u64 tdh_mem_page_demote_2mb(struct tdx_td *td, u64 gpa, kvm_pfn_t pfn, struct
> page *new_sept_pt,
> struct tdx_pamt_cache *pamt_cache, u64 *ext_err1,
> u64 *ext_err2)
> {
> struct tdx_module_args args = {
> .rcx = gpa | pg_level_to_tdx_sept_level(PG_LEVEL_2M),
> .rdx = tdx_tdr_pa(td),
> .r8 = page_to_phys(new_sept_pt),
> };
> struct page *dpamt_pages[TDX_DPAMT_ENTRY_PAGE_CNT];
> atomic_t *dpamt_refcount;
> u64 ret;
>
> /*
> * For implementation simplicity, only support demotion when
> * DPAMT is enabled.
> */
> WARN_ON_ONCE(!tdx_supports_dynamic_pamt(&tdx_sysinfo));
>
> /* A NULL pamt_cache is unexpected, so failure indicates a software
> error */
On the edge of unnecessary to me, but ok.
> ret = alloc_pamt_array(dpamt_pages, pamt_cache);
> if (ret) {
> *ext_err1 = 0;
> *ext_err2 = 0;
> return TDX_SW_ERROR;
> }
>
> dpamt_refcount = tdx_find_dpamt_refcount(pfn);
>
> args.r12 = page_to_phys(dpamt_pages[0]);
> args.r13 = page_to_phys(dpamt_pages[1]);
>
> /*
> * The dpamt_lock is used to avoid contention between the
> * TDH_MEM_PAGE_DEMOTE and TDH_PHYMEM_PAMT_{ADD/REMOVE} SEAMCALLs.
> */
> spin_lock(&dpamt_lock);
>
> ret = seamcall_saved_ret(TDH_MEM_PAGE_DEMOTE, &args);
> *ext_err1 = args.rcx;
> *ext_err2 = args.rdx;
>
> if (WARN_ON_ONCE(ret != TDX_SUCCESS))
> goto out_free;
>
> atomic_set(dpamt_refcount, PTRS_PER_PMD);
> spin_unlock(&dpamt_lock);
>
> return TDX_SUCCESS;
>
> out_free:
> spin_unlock(&dpamt_lock);
> free_pamt_array(pamt_cache, dpamt_pages);
>
> return ret;
> }
LGTM