Re: [PATCH v4 08/17] KVM: TDX: Adjust the topup count of DPAMT page pairs for splitting S-EPT
From: Yan Zhao
Date: Thu Oct 22 2026 - 03:26:11 EST
On Thu, Oct 22, 2026 at 06:28:16AM +0800, Edgecombe, Rick P wrote:
> On Mon, 2026-10-19 at 09:59 +0800, Yan Zhao wrote:
> > On Fri, Oct 16, 2026 at 01:21:14AM +0800, Edgecombe, Rick P wrote:
> > > On Thu, 2026-10-15 at 12:47 +0800, Yan Zhao wrote:
> > > > > The point of spelling it all out was to make the contact clear and the
> > > > > implementation doesn't have to assume anything about the callers.
> > > > Hmm, but it's hard for the caller to know if private_page is true.
> > > > We should avoid leaking TDX specific knowledge to KVM MMU, right?
> > >
> > > Wait, why won't the caller won't know if it might map a new private page? This
> > > is basically to cover the +1 part of the "+ 1 -1" in the calculation. I was
> > > thinking to set it to true for normal ept violation (like an accept) and false
> > > for split.
> > In TDX's .topup_external_cache() hook, tdx_topup_external_pamt_cache() always
> > needs to allocate DPAMT pages for guest private pages, even for the split case.
> >
> > However, from KVM MMU's perspective, it is unnatural to specify "private_page"
> > as true when tdp_mmu_alloc_sp_for_split() is preparing the mid-level page table
> > page.
> >
> > So, I think we should keep the current convention of just specifying
> > min_nr_spts, and let the TDX-specific tdx_topup_external_pamt_cache() account
> > for the +1 part for guest private pages, which is invisible and should not be
> > exposed to KVM MMU.
> >
> > So, what about
> >
> > topup(bool with_root_spt, int min_nr_spts) ?
>
> Hmm, ok I think I see what you are saying. Because each 4KB page will be
> confined to a 2MB aligned region, we need at most 1 extra page pair. Not 512.
> But the core MMU should not know this at all. Hmmm....
>
> Yea let's go with your suggestion. Can you share the implementation here first
> though so we can close it without risk of more respins?
Sure.
Here's how tdx_topup_external_pamt_cache() looks by the end of the series:
static int tdx_topup_external_pamt_cache(struct kvm *kvm, struct kvm_vcpu *vcpu,
bool with_root_spt, int min_nr_spts)
{
struct tdx_pamt_cache *pamt_cache;
int dpamt_pairs = min_nr_spts;
pamt_cache = tdx_get_pamt_cache(kvm, vcpu);
if (!pamt_cache)
return -EIO;
/* DPAMT page pair for the root SPT has already been installed */
if (with_root_spt)
dpamt_pairs -= 1;
/* +1 pair for 4KB guest private page */
dpamt_pairs += 1;
return tdx_topup_pamt_cache(pamt_cache, dpamt_pairs);
}
In the fault path, mmu_topup_memory_caches() calls:
r = kvm_x86_call(topup_external_cache)(vcpu->kvm, vcpu, true, PT64_ROOT_MAX_LEVEL);
In the split path, tdp_mmu_alloc_sp_for_split() calls:
kvm_x86_call(topup_external_cache)(kvm, kvm_get_running_vcpu(), false, 1);