[RFC PATCH 07/21] KVM: TDX: Add a helper for WBINVD on huge pages with TD's keyID

Yan Zhao posted 21 patches 7 months, 3 weeks ago
Only 20 patches received!
There is a newer version of this series
[RFC PATCH 07/21] KVM: TDX: Add a helper for WBINVD on huge pages with TD's keyID
Posted by Yan Zhao 7 months, 3 weeks ago
From: Xiaoyao Li <xiaoyao.li@intel.com>

After a guest page is removed from the S-EPT, KVM calls
tdh_phymem_page_wbinvd_hkid() to execute WBINVD on the page using the TD's
keyID.

Add a helper function that takes level information to perform WBINVD on a
huge page.

[Yan: split patch, added a helper, rebased to use struct page]
Signed-off-by: Xiaoyao Li <xiaoyao.li@intel.com>
Signed-off-by: Isaku Yamahata <isaku.yamahata@intel.com>
Signed-off-by: Yan Zhao <yan.y.zhao@intel.com>
---
 arch/x86/kvm/vmx/tdx.c | 24 +++++++++++++++++++-----
 1 file changed, 19 insertions(+), 5 deletions(-)

diff --git a/arch/x86/kvm/vmx/tdx.c b/arch/x86/kvm/vmx/tdx.c
index 69f3140928b5..355b21fc169f 100644
--- a/arch/x86/kvm/vmx/tdx.c
+++ b/arch/x86/kvm/vmx/tdx.c
@@ -1586,6 +1586,23 @@ int tdx_sept_set_private_spte(struct kvm *kvm, gfn_t gfn,
 	return tdx_mem_page_record_premap_cnt(kvm, level);
 }
 
+static inline u64 tdx_wbinvd_page(struct kvm *kvm, u64 hkid, struct page *page, int level)
+{
+	unsigned long nr = KVM_PAGES_PER_HPAGE(level);
+	unsigned long idx = 0;
+	u64 err;
+
+	while (nr--) {
+		err = tdh_phymem_page_wbinvd_hkid(hkid, nth_page(page, idx++));
+
+		if (KVM_BUG_ON(err, kvm)) {
+			pr_tdx_error(TDH_PHYMEM_PAGE_WBINVD, err);
+			return err;
+		}
+	}
+	return err;
+}
+
 static int tdx_sept_drop_private_spte(struct kvm *kvm, gfn_t gfn,
 				      enum pg_level level, struct page *page)
 {
@@ -1625,12 +1642,9 @@ static int tdx_sept_drop_private_spte(struct kvm *kvm, gfn_t gfn,
 		return -EIO;
 	}
 
-	err = tdh_phymem_page_wbinvd_hkid((u16)kvm_tdx->hkid, page);
-
-	if (KVM_BUG_ON(err, kvm)) {
-		pr_tdx_error(TDH_PHYMEM_PAGE_WBINVD, err);
+	err = tdx_wbinvd_page(kvm, kvm_tdx->hkid, page, level);
+	if (err)
 		return -EIO;
-	}
 
 	tdx_clear_page(page, level);
 	tdx_unpin(kvm, page);
-- 
2.43.2
Re: [RFC PATCH 07/21] KVM: TDX: Add a helper for WBINVD on huge pages with TD's keyID
Posted by Edgecombe, Rick P 7 months ago
On Thu, 2025-04-24 at 11:05 +0800, Yan Zhao wrote:
> From: Xiaoyao Li <xiaoyao.li@intel.com>
> 
> After a guest page is removed from the S-EPT, KVM calls
> tdh_phymem_page_wbinvd_hkid() to execute WBINVD on the page using the TD's
> keyID.
> 
> Add a helper function that takes level information to perform WBINVD on a
> huge page.
> 
> [Yan: split patch, added a helper, rebased to use struct page]
> Signed-off-by: Xiaoyao Li <xiaoyao.li@intel.com>
> Signed-off-by: Isaku Yamahata <isaku.yamahata@intel.com>
> Signed-off-by: Yan Zhao <yan.y.zhao@intel.com>
> ---
>  arch/x86/kvm/vmx/tdx.c | 24 +++++++++++++++++++-----
>  1 file changed, 19 insertions(+), 5 deletions(-)
> 
> diff --git a/arch/x86/kvm/vmx/tdx.c b/arch/x86/kvm/vmx/tdx.c
> index 69f3140928b5..355b21fc169f 100644
> --- a/arch/x86/kvm/vmx/tdx.c
> +++ b/arch/x86/kvm/vmx/tdx.c
> @@ -1586,6 +1586,23 @@ int tdx_sept_set_private_spte(struct kvm *kvm, gfn_t gfn,
>  	return tdx_mem_page_record_premap_cnt(kvm, level);
>  }
>  
> +static inline u64 tdx_wbinvd_page(struct kvm *kvm, u64 hkid, struct page *page, int level)
> +{
> +	unsigned long nr = KVM_PAGES_PER_HPAGE(level);
> +	unsigned long idx = 0;
> +	u64 err;
> +
> +	while (nr--) {
> +		err = tdh_phymem_page_wbinvd_hkid(hkid, nth_page(page, idx++));
> +
> +		if (KVM_BUG_ON(err, kvm)) {
> +			pr_tdx_error(TDH_PHYMEM_PAGE_WBINVD, err);
> +			return err;
> +		}
> +	}
> +	return err;
> +}

Hmm, did you consider changing tdh_phymem_page_wbinvd_hkid()? It's the pattern
of KVM wrapping the SEAMCALL helpers to do some more work that needs to be
wrapped.

> +
>  static int tdx_sept_drop_private_spte(struct kvm *kvm, gfn_t gfn,
>  				      enum pg_level level, struct page *page)
>  {
> @@ -1625,12 +1642,9 @@ static int tdx_sept_drop_private_spte(struct kvm *kvm, gfn_t gfn,
>  		return -EIO;
>  	}
>  
> -	err = tdh_phymem_page_wbinvd_hkid((u16)kvm_tdx->hkid, page);
> -
> -	if (KVM_BUG_ON(err, kvm)) {
> -		pr_tdx_error(TDH_PHYMEM_PAGE_WBINVD, err);
> +	err = tdx_wbinvd_page(kvm, kvm_tdx->hkid, page, level);
> +	if (err)
>  		return -EIO;
> -	}
>  
>  	tdx_clear_page(page, level);
>  	tdx_unpin(kvm, page);

Re: [RFC PATCH 07/21] KVM: TDX: Add a helper for WBINVD on huge pages with TD's keyID
Posted by Yan Zhao 7 months ago
On Wed, May 14, 2025 at 03:29:00AM +0800, Edgecombe, Rick P wrote:
> On Thu, 2025-04-24 at 11:05 +0800, Yan Zhao wrote:
> > From: Xiaoyao Li <xiaoyao.li@intel.com>
> > 
> > After a guest page is removed from the S-EPT, KVM calls
> > tdh_phymem_page_wbinvd_hkid() to execute WBINVD on the page using the TD's
> > keyID.
> > 
> > Add a helper function that takes level information to perform WBINVD on a
> > huge page.
> > 
> > [Yan: split patch, added a helper, rebased to use struct page]
> > Signed-off-by: Xiaoyao Li <xiaoyao.li@intel.com>
> > Signed-off-by: Isaku Yamahata <isaku.yamahata@intel.com>
> > Signed-off-by: Yan Zhao <yan.y.zhao@intel.com>
> > ---
> >  arch/x86/kvm/vmx/tdx.c | 24 +++++++++++++++++++-----
> >  1 file changed, 19 insertions(+), 5 deletions(-)
> > 
> > diff --git a/arch/x86/kvm/vmx/tdx.c b/arch/x86/kvm/vmx/tdx.c
> > index 69f3140928b5..355b21fc169f 100644
> > --- a/arch/x86/kvm/vmx/tdx.c
> > +++ b/arch/x86/kvm/vmx/tdx.c
> > @@ -1586,6 +1586,23 @@ int tdx_sept_set_private_spte(struct kvm *kvm, gfn_t gfn,
> >  	return tdx_mem_page_record_premap_cnt(kvm, level);
> >  }
> >  
> > +static inline u64 tdx_wbinvd_page(struct kvm *kvm, u64 hkid, struct page *page, int level)
> > +{
> > +	unsigned long nr = KVM_PAGES_PER_HPAGE(level);
> > +	unsigned long idx = 0;
> > +	u64 err;
> > +
> > +	while (nr--) {
> > +		err = tdh_phymem_page_wbinvd_hkid(hkid, nth_page(page, idx++));
> > +
> > +		if (KVM_BUG_ON(err, kvm)) {
> > +			pr_tdx_error(TDH_PHYMEM_PAGE_WBINVD, err);
> > +			return err;
> > +		}
> > +	}
> > +	return err;
> > +}
> 
> Hmm, did you consider changing tdh_phymem_page_wbinvd_hkid()? It's the pattern
> of KVM wrapping the SEAMCALL helpers to do some more work that needs to be
> wrapped.
SEAMCALL TDH_PHYMEM_PAGE_WBINVD only accepts a 4KB page.
Will move the loop from KVM to the wrapper in x86 if you think it's better.


> >  static int tdx_sept_drop_private_spte(struct kvm *kvm, gfn_t gfn,
> >  				      enum pg_level level, struct page *page)
> >  {
> > @@ -1625,12 +1642,9 @@ static int tdx_sept_drop_private_spte(struct kvm *kvm, gfn_t gfn,
> >  		return -EIO;
> >  	}
> >  
> > -	err = tdh_phymem_page_wbinvd_hkid((u16)kvm_tdx->hkid, page);
> > -
> > -	if (KVM_BUG_ON(err, kvm)) {
> > -		pr_tdx_error(TDH_PHYMEM_PAGE_WBINVD, err);
> > +	err = tdx_wbinvd_page(kvm, kvm_tdx->hkid, page, level);
> > +	if (err)
> >  		return -EIO;
> > -	}
> >  
> >  	tdx_clear_page(page, level);
> >  	tdx_unpin(kvm, page);
>
Re: [RFC PATCH 07/21] KVM: TDX: Add a helper for WBINVD on huge pages with TD's keyID
Posted by Edgecombe, Rick P 7 months ago
On Fri, 2025-05-16 at 11:03 +0800, Yan Zhao wrote:
> > Hmm, did you consider changing tdh_phymem_page_wbinvd_hkid()? It's the
> > pattern
> > of KVM wrapping the SEAMCALL helpers to do some more work that needs to be
> > wrapped.
> SEAMCALL TDH_PHYMEM_PAGE_WBINVD only accepts a 4KB page.
> Will move the loop from KVM to the wrapper in x86 if you think it's better.

Don't wrap the wrappers was a suggestion from Dave. Let's try it.
Re: [RFC PATCH 07/21] KVM: TDX: Add a helper for WBINVD on huge pages with TD's keyID
Posted by Binbin Wu 7 months, 1 week ago

On 4/24/2025 11:05 AM, Yan Zhao wrote:
> From: Xiaoyao Li <xiaoyao.li@intel.com>
>
> After a guest page is removed from the S-EPT, KVM calls
> tdh_phymem_page_wbinvd_hkid() to execute WBINVD on the page using the TD's
> keyID.
>
> Add a helper function that takes level information to perform WBINVD on a
> huge page.
>
> [Yan: split patch, added a helper, rebased to use struct page]
> Signed-off-by: Xiaoyao Li <xiaoyao.li@intel.com>
> Signed-off-by: Isaku Yamahata <isaku.yamahata@intel.com>
> Signed-off-by: Yan Zhao <yan.y.zhao@intel.com>
> ---
>   arch/x86/kvm/vmx/tdx.c | 24 +++++++++++++++++++-----
>   1 file changed, 19 insertions(+), 5 deletions(-)
>
> diff --git a/arch/x86/kvm/vmx/tdx.c b/arch/x86/kvm/vmx/tdx.c
> index 69f3140928b5..355b21fc169f 100644
> --- a/arch/x86/kvm/vmx/tdx.c
> +++ b/arch/x86/kvm/vmx/tdx.c
> @@ -1586,6 +1586,23 @@ int tdx_sept_set_private_spte(struct kvm *kvm, gfn_t gfn,
>   	return tdx_mem_page_record_premap_cnt(kvm, level);
>   }
>   
> +static inline u64 tdx_wbinvd_page(struct kvm *kvm, u64 hkid, struct page *page, int level)
> +{
> +	unsigned long nr = KVM_PAGES_PER_HPAGE(level);
> +	unsigned long idx = 0;
> +	u64 err;
> +
> +	while (nr--) {
> +		err = tdh_phymem_page_wbinvd_hkid(hkid, nth_page(page, idx++));
> +
> +		if (KVM_BUG_ON(err, kvm)) {
> +			pr_tdx_error(TDH_PHYMEM_PAGE_WBINVD, err);
> +			return err;
> +		}
> +	}
> +	return err;
> +}
> +
>   static int tdx_sept_drop_private_spte(struct kvm *kvm, gfn_t gfn,
>   				      enum pg_level level, struct page *page)
>   {
> @@ -1625,12 +1642,9 @@ static int tdx_sept_drop_private_spte(struct kvm *kvm, gfn_t gfn,
>   		return -EIO;
>   	}
>   
> -	err = tdh_phymem_page_wbinvd_hkid((u16)kvm_tdx->hkid, page);
> -
> -	if (KVM_BUG_ON(err, kvm)) {
> -		pr_tdx_error(TDH_PHYMEM_PAGE_WBINVD, err);
> +	err = tdx_wbinvd_page(kvm, kvm_tdx->hkid, page, level);
> +	if (err)

It can add unlikely() here.
Also the err is not used after check, maybe it can be combined as:

if (unlikely(tdx_wbinvd_page(kvm, kvm_tdx->hkid, page, level)))
         return -EIO;


>   		return -EIO;
> -	}
>   
>   	tdx_clear_page(page, level);
>   	tdx_unpin(kvm, page);

Re: [RFC PATCH 07/21] KVM: TDX: Add a helper for WBINVD on huge pages with TD's keyID
Posted by Yan Zhao 7 months ago
On Tue, May 06, 2025 at 04:37:22PM +0800, Binbin Wu wrote:
> 
> 
> On 4/24/2025 11:05 AM, Yan Zhao wrote:
> > From: Xiaoyao Li <xiaoyao.li@intel.com>
> > 
> > After a guest page is removed from the S-EPT, KVM calls
> > tdh_phymem_page_wbinvd_hkid() to execute WBINVD on the page using the TD's
> > keyID.
> > 
> > Add a helper function that takes level information to perform WBINVD on a
> > huge page.
> > 
> > [Yan: split patch, added a helper, rebased to use struct page]
> > Signed-off-by: Xiaoyao Li <xiaoyao.li@intel.com>
> > Signed-off-by: Isaku Yamahata <isaku.yamahata@intel.com>
> > Signed-off-by: Yan Zhao <yan.y.zhao@intel.com>
> > ---
> >   arch/x86/kvm/vmx/tdx.c | 24 +++++++++++++++++++-----
> >   1 file changed, 19 insertions(+), 5 deletions(-)
> > 
> > diff --git a/arch/x86/kvm/vmx/tdx.c b/arch/x86/kvm/vmx/tdx.c
> > index 69f3140928b5..355b21fc169f 100644
> > --- a/arch/x86/kvm/vmx/tdx.c
> > +++ b/arch/x86/kvm/vmx/tdx.c
> > @@ -1586,6 +1586,23 @@ int tdx_sept_set_private_spte(struct kvm *kvm, gfn_t gfn,
> >   	return tdx_mem_page_record_premap_cnt(kvm, level);
> >   }
> > +static inline u64 tdx_wbinvd_page(struct kvm *kvm, u64 hkid, struct page *page, int level)
> > +{
> > +	unsigned long nr = KVM_PAGES_PER_HPAGE(level);
> > +	unsigned long idx = 0;
> > +	u64 err;
> > +
> > +	while (nr--) {
> > +		err = tdh_phymem_page_wbinvd_hkid(hkid, nth_page(page, idx++));
> > +
> > +		if (KVM_BUG_ON(err, kvm)) {
> > +			pr_tdx_error(TDH_PHYMEM_PAGE_WBINVD, err);
> > +			return err;
> > +		}
> > +	}
> > +	return err;
> > +}
> > +
> >   static int tdx_sept_drop_private_spte(struct kvm *kvm, gfn_t gfn,
> >   				      enum pg_level level, struct page *page)
> >   {
> > @@ -1625,12 +1642,9 @@ static int tdx_sept_drop_private_spte(struct kvm *kvm, gfn_t gfn,
> >   		return -EIO;
> >   	}
> > -	err = tdh_phymem_page_wbinvd_hkid((u16)kvm_tdx->hkid, page);
> > -
> > -	if (KVM_BUG_ON(err, kvm)) {
> > -		pr_tdx_error(TDH_PHYMEM_PAGE_WBINVD, err);
> > +	err = tdx_wbinvd_page(kvm, kvm_tdx->hkid, page, level);
> > +	if (err)
> 
> It can add unlikely() here.
> Also the err is not used after check, maybe it can be combined as:
> 
> if (unlikely(tdx_wbinvd_page(kvm, kvm_tdx->hkid, page, level)))
>         return -EIO;
That's better. Thanks!

> >   		return -EIO;
> > -	}
> >   	tdx_clear_page(page, level);
> >   	tdx_unpin(kvm, page);
>