From: "Edgecombe, Rick P" <rick.p.edgecombe@intel.com>
To: "Zhao, Yan Y" <yan.y.zhao@intel.com>
Cc: "Du, Fan" <fan.du@intel.com>,
"kvm@vger.kernel.org" <kvm@vger.kernel.org>,
"Huang, Kai" <kai.huang@intel.com>,
"Li, Xiaoyao" <xiaoyao.li@intel.com>,
"Hansen, Dave" <dave.hansen@intel.com>,
"thomas.lendacky@amd.com" <thomas.lendacky@amd.com>,
"tabba@google.com" <tabba@google.com>,
"vbabka@suse.cz" <vbabka@suse.cz>,
"david@kernel.org" <david@kernel.org>,
"kas@kernel.org" <kas@kernel.org>,
"binbin.wu@linux.intel.com" <binbin.wu@linux.intel.com>,
"seanjc@google.com" <seanjc@google.com>,
"pbonzini@redhat.com" <pbonzini@redhat.com>,
"Peng, Chao P" <chao.p.peng@intel.com>,
"ackerleytng@google.com" <ackerleytng@google.com>,
"michael.roth@amd.com" <michael.roth@amd.com>,
"nik.borisov@suse.com" <nik.borisov@suse.com>,
"linux-kernel@vger.kernel.org" <linux-kernel@vger.kernel.org>,
"sagis@google.com" <sagis@google.com>,
"Annapurve, Vishal" <vannapurve@google.com>,
"Chen, Farrah" <farrah.chen@intel.com>,
"Gao, Chao" <chao.gao@intel.com>,
"francescolavra.fl@gmail.com" <francescolavra.fl@gmail.com>,
"Miao, Jun" <jun.miao@intel.com>,
"jgross@suse.com" <jgross@suse.com>,
"pgonda@google.com" <pgonda@google.com>,
"x86@kernel.org" <x86@kernel.org>
Subject: Re: [PATCH v4 01/17] x86/virt/tdx: Enhance tdx_pamt_get/put() to support huge pages
Date: Thu, 15 Oct 2026 18:11:45 +0000 [thread overview]
Message-ID: <896585225b67cb215db0ce66dece20ba8fbb919f.camel@intel.com> (raw)
In-Reply-To: <atBLdGBCsPwMK7Sh@yzhao56-desk.sh.intel.com>
On Thu, 2026-10-15 at 11:41 +0800, Yan Zhao wrote:
> On Tue, Oct 13, 2026 at 07:18:15AM +0800, Edgecombe, Rick P wrote:
> > On Sat, 2026-10-10 at 18:18 +0800, Yan Zhao wrote:
> > > On Fri, Oct 02, 2026 at 07:02:40AM +0800, Edgecombe, Rick P wrote:
> > > > On Mon, 2026-09-28 at 17:08 +0800, Yan Zhao wrote:
> > > > > The TDX module uses PAMT to track metadata for every physical page (within
> > > > > TDMR) across three levels: 1GB, 2MB, and 4KB. The VMM is responsible for
> > > > > providing backing pages for the PAMT. Without Dynamic PAMT (DPAMT), all
> > > > > PAMT backing pages are allocated statically at system boot time. With DPAMT
> > > > > enabled, PAMT backing pages tracking physical pages at the 4KB level
> > > > > (referred to as DPAMT pages) are dynamically installed and uninstalled at
> > > > > runtime.
> > > > >
> > > > > Currently, the VMM invokes tdx_pamt_get()/tdx_pamt_put() to install and
> > > > > uninstall DPAMT pages under the assumption that all physical pages are
> > > > > tracked at 4KB level. However, when a guest page is mapped as a huge page
> > > > > in the S-EPT, the TDX module tracks it directly at the huge page level,
> > > > > meaning installation and uninstallation of DPAMT pages for huge pages is
> > > > > neither needed nor applicable.
> > > > >
> > > > > Add a "level" parameter to tdx_pamt_get()/tdx_pamt_put() so the helpers
> > > > > can skip DPAMT page installation and uninstallation for huge pages.
> > > >
> > > > I guess this means we need to make sure to get/put at the right level that the
> > > > TDX module is using it as. For example in this implementation, if a huge page
> > > > gets demoted, we can't call them like this:
> > > > 1. tdx_pamt_get(huge_pfn, PG_LEVEL_2MB)
> > > > 2. demote(huge_pfn)
> > > > 3. tdx_pamt_put(huge_pfn, PG_LEVEL_2MB)
> > > Actually, calling in this way is fine, since steps 1 & 3 are effectively no-ops.
> > > However, we can't call them like below.
> >
> > But step 2 incremented the refcounts. Then step 3 skips the decrement.
> > So don't you need?
> > 1. tdx_pamt_get(huge_pfn, PG_LEVEL_2MB)
> > 2. demote(huge_pfn)
> > 3. for (int i...) tdx_pamt_put(huge_pfn+i, PG_LEVEL_4KB);
> Oh, what I mean is there's no need for tdx_sept_split_leaf_spte() to invoke
> either 1 or 3. It only needs to invoke 2, though it doesn't break anything if
> tdx_sept_split_leaf_spte() incorrectly invokes
> tdx_pamt_{get/put}(huge_pfn, PG_LEVEL_2MB).
>
> tdx_pamt_put(pfn, PG_LEVEL_4KB) for each 4K page is done in
> tdx_sept_remove_leaf_spte().
>
> See more in the below contract.
>
> > > In DPAMT combined v5, Sean moved the level checking from KVM to
> > > tdx_pamt_{get/put}() [2].
> > > However, Sean's version introduced __tdx_pamt_{get/put}() for invocations where
> > > 4KB size is enforced.
> > >
> > > During our internal review, you said:
> > > "Can you also justify why to have two functions instead of page LEVEL_4K in a
> > > few places?"
> > >
> > > So, compared to passing level to tdx_pamt_{get/put}() while introducing
> > > __tdx_pamt_{get/put}() for the always-4KB invocations, I updated the patch to
> > > drop __tdx_pamt_{get/put}(), having KVM pass 4KB directly in the always-4KB
> > > invocations.
> > >
> > > I'm actually ok with any of these approaches. It seems they all require the
> > > caller to know about the right level size and whether to invoke PAMT get/put.
> >
> > Yea. That is kind of the problem. The caller needs to understand the impact of
> > the mapping level. The level arg isn't able wrap everything within the helpers.
> > So how the get/put helpers handle it is internal details that caller needs to
> > know. So there is abstraction leakage I think.
> >
> > So probably the most important thing is that it is clear how to use it. Then
> > whatever is the simplest code. It might be Kiryl's implementation. What do you
> > think?
> Hmm, I don't see checking level in KVM is better or simpler than passing the
> mapping level to tdx_pamt_{get/put}(). KVM still needs to know
> tdx_sept_split_leaf_spte() can't invoke tdx_pamt_get() for guest pages.
>
> So, what about explaining the contract as a comment to tdx_pamt_{get/put}()?
> That is:
>
> (1) KVM needs to invoke tdx_pamt_get() before it maps a new page (guest page or
> page table page).
>
> So, KVM needs to invoke tdx_pamt_get() in tdx_sept_map_leaf_spte() for
> guest pages, and tdx_sept_map_nonleaf_spte() for page table pages, and
> tdx_sept_split_leaf_spte() needs to invoke tdx_pamt_get() for the page table
> page.
> However, tdx_sept_split_leaf_spte() doesn't need to invoke tdx_pamt_get()
> for the guest page since the page has already been mapped.
>
> (2) KVM needs to invoke tdx_pamt_put() after it unmaps a page (guest page or page
> table page.
>
> So, KVM invokes tdx_pamt_put() in tdx_sept_remove_leaf_spte() and
> tdx_free_control_page() in tdx_sept_free_private_spt().
> It also needs to invoke tdx_pamt_put() when it fails to map a page.
>
> With the contract, it seems to be simpler for KVM to pass the level to
> tdx_pamt_{get/put}() ?
> The dpamt refcount adjustment are invisible to KVM.
>
> Do you think the contract is clear?
No, it doesn't seem clear. It's not clear which combination of args will update
the refcount or mapping level for different scenarios. The above seems to just
say what recipes will work, which only makes sense since you know all the
internal details. It doesn't describe a clear contact.
I think it is like - Pamt has a level, and three operations manipulate it. The
pamt level needs to match what TDX will map the page at.
The pamt get/put infra keeps refcounts for 4KB level page use. They may change
the mapping level, but they always update the refcount which is an explicit 4KB
level thing. So to me it makes much more sense if they stay 4KB level
operations.
Then the contract is simply:
There are only two possible mapping levels: 2MB and 4KB. There is a refcount
for each 2MB aligned range. The mapping level will be 4KB when there is any
refcount for 2MB aligned range.
tdx_pamt_get() increments the refcount
tdx_pamt_put() decrements the refcount
tdh_mem_page_demote() increments the refcount for each 4KB page
The mapping level will be determined by the refcount after each operation is
complete.
If you want to pass the level, somehow it has to be clear how the refcount and
mapping level will be adjusted for each combination of operations.
>
> > Or, hmm. It would be easy to catch misuse on the put side by (dpamt_refcount !=
> > 0 && level > PG_LEVEL_4K)? Then some comments to help user use the existing
> > design correctly? Either of those seem ok. But my concern was that this part of
> > the design wasn't clear. So most important is actually to explain the why of the
> > design with an argument of the benefits.
> If the above contract looks good to you, maybe I can explain the contract and
> design of the API in both the code comment and the patch log.
next prev parent reply other threads:[~2026-10-15 18:13 UTC|newest]
Thread overview: 68+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-09-28 9:07 [PATCH v4 00/17] KVM: TDX huge page support for private memory Yan Zhao
2026-09-28 9:08 ` [PATCH v4 01/17] x86/virt/tdx: Enhance tdx_pamt_get/put() to support huge pages Yan Zhao
2026-10-01 23:02 ` Edgecombe, Rick P
2026-10-10 10:18 ` Yan Zhao
2026-10-12 23:18 ` Edgecombe, Rick P
2026-10-15 3:41 ` Yan Zhao
2026-10-15 18:11 ` Edgecombe, Rick P [this message]
2026-09-28 9:08 ` [PATCH v4 02/17] x86/virt/tdx: Add a SEAMCALL wrapper to demote a 2MB huge page Yan Zhao
2026-10-02 0:54 ` Edgecombe, Rick P
2026-10-12 9:31 ` Yan Zhao
2026-10-12 22:16 ` Edgecombe, Rick P
2026-10-14 9:40 ` Yan Zhao
2026-10-14 18:32 ` Edgecombe, Rick P
2026-10-15 6:11 ` Yan Zhao
2026-10-15 9:28 ` Yan Zhao
2026-10-15 9:49 ` Yan Zhao
2026-10-15 18:30 ` Edgecombe, Rick P
2026-09-28 9:08 ` [PATCH v4 03/17] KVM: TDX: Reset private huge pages after S-EPT page removal Yan Zhao
2026-10-07 0:06 ` Edgecombe, Rick P
2026-10-10 9:22 ` Yan Zhao
2026-09-28 9:09 ` [PATCH v4 04/17] KVM: x86/mmu: Prevent huge page promotion for mirror roots in fault path Yan Zhao
2026-10-07 0:32 ` Edgecombe, Rick P
2026-09-28 9:09 ` [PATCH v4 05/17] KVM: x86/tdp_mmu: Alloc external_spt page for mirror page table splitting Yan Zhao
2026-10-07 0:33 ` Edgecombe, Rick P
2026-10-10 7:41 ` Yan Zhao
2026-09-28 9:10 ` [PATCH v4 06/17] KVM: x86/mmu: Allocate DPAMT pages for vCPU-induced page split Yan Zhao
2026-10-07 15:45 ` Edgecombe, Rick P
2026-10-10 6:37 ` Yan Zhao
2026-10-10 6:40 ` Yan Zhao
2026-10-12 16:41 ` Edgecombe, Rick P
2026-09-28 9:10 ` [PATCH v4 07/17] KVM: TDX: Add core support for splitting/demoting 2MB S-EPT mappings to 4KB Yan Zhao
2026-10-07 21:52 ` Edgecombe, Rick P
2026-10-10 6:34 ` Yan Zhao
2026-10-12 16:40 ` Edgecombe, Rick P
2026-10-14 5:39 ` Yan Zhao
2026-09-28 9:10 ` [PATCH v4 08/17] KVM: TDX: Adjust the topup count of DPAMT page pairs for splitting S-EPT Yan Zhao
2026-10-07 22:48 ` Edgecombe, Rick P
2026-10-08 1:16 ` Edgecombe, Rick P
2026-10-09 9:08 ` Yan Zhao
2026-10-09 22:12 ` Edgecombe, Rick P
2026-10-10 5:13 ` Yan Zhao
2026-10-12 16:36 ` Edgecombe, Rick P
2026-10-14 5:36 ` Yan Zhao
2026-10-14 18:34 ` Edgecombe, Rick P
2026-10-15 4:47 ` Yan Zhao
2026-10-15 17:21 ` Edgecombe, Rick P
2026-10-09 8:39 ` Yan Zhao
2026-10-09 22:11 ` Edgecombe, Rick P
2026-10-10 5:18 ` Yan Zhao
2026-09-28 9:10 ` [PATCH v4 09/17] KVM: x86/mmu: Introduce hugepage_set_guest_inhibit() Yan Zhao
2026-10-07 23:57 ` Edgecombe, Rick P
2026-10-10 6:00 ` Yan Zhao
2026-09-28 9:11 ` [PATCH v4 10/17] KVM: x86/mmu: Add a TDP MMU API to split huge pages for mirror roots Yan Zhao
2026-10-08 0:25 ` Edgecombe, Rick P
2026-09-28 9:11 ` [PATCH v4 11/17] KVM: TDX: Honor the guest's accept level contained in an EPT violation Yan Zhao
2026-10-08 1:05 ` Edgecombe, Rick P
2026-10-09 9:33 ` Yan Zhao
2026-10-09 22:00 ` Edgecombe, Rick P
2026-10-10 5:42 ` Yan Zhao
2026-10-12 16:14 ` Edgecombe, Rick P
2026-09-28 9:11 ` [PATCH v4 12/17] KVM: x86/mmu: Add support for splitting S-EPT entry under non-vCPU context Yan Zhao
2026-09-28 9:11 ` [PATCH v4 13/17] [GMEM-DEPENDENT] KVM: guest_memfd: Add helpers to get start/end gfns give gmem+slot+pgoff Yan Zhao
2026-10-08 23:16 ` Edgecombe, Rick P
2026-09-28 9:11 ` [PATCH v4 14/17] [GMEM-DEPENDENT] KVM: guest_memfd: Split kvm_gmem_invalidate_start() to start() and zap() Yan Zhao
2026-09-28 9:12 ` [PATCH v4 15/17] [GMEM-DEPENDENT] KVM: guest_memfd: Add a pre-zap hook .gmem_prezap() Yan Zhao
2026-10-14 7:01 ` Yan Zhao
2026-09-28 9:12 ` [PATCH v4 16/17] [GMEM-DEPENDENT] KVM: TDX: Implement .gmem_prezap() hook to split S-EPT Yan Zhao
2026-09-28 9:12 ` [PATCH v4 17/17] KVM: TDX: Turn on PG_LEVEL_2M 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=896585225b67cb215db0ce66dece20ba8fbb919f.camel@intel.com \
--to=rick.p.edgecombe@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=farrah.chen@intel.com \
--cc=francescolavra.fl@gmail.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=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 \
--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®