Linux Confidential Computing Development
 help / color / mirror / Atom feed
* Re: [PATCH v2 5/5] KVM: guest_memfd: GUP source pages prior to populating guest memory
From: Yan Zhao @ 2025-12-26  3:09 UTC (permalink / raw)
  To: Michael Roth, kvm, linux-coco, linux-mm, linux-kernel,
	thomas.lendacky, pbonzini, seanjc, vbabka, ashish.kalra,
	liam.merwick, david, vannapurve, ackerleytng, aik, ira.weiny
In-Reply-To: <aU33Y56qBXgrL5/3@yzhao56-desk.sh.intel.com>

On Fri, Dec 26, 2025 at 10:48:03AM +0800, Yan Zhao wrote:
> > @@ -842,47 +881,38 @@ long kvm_gmem_populate(struct kvm *kvm, gfn_t start_gfn, void __user *src, long
> >  	if (!file)
> >  		return -EFAULT;
> >  
> > -	filemap_invalidate_lock(file->f_mapping);
> > -
> >  	npages = min_t(ulong, slot->npages - (start_gfn - slot->base_gfn), npages);
> >  	for (i = 0; i < npages; i++) {
> > -		struct folio *folio;
> > -		gfn_t gfn = start_gfn + i;
> > -		pgoff_t index = kvm_gmem_get_index(slot, gfn);
> > -		kvm_pfn_t pfn;
> > +		struct page *src_page = NULL;
> > +		void __user *p;
> >  
> >  		if (signal_pending(current)) {
> >  			ret = -EINTR;
> >  			break;
> >  		}
> >  
> > -		folio = __kvm_gmem_get_pfn(file, slot, index, &pfn, NULL);
> > -		if (IS_ERR(folio)) {
> > -			ret = PTR_ERR(folio);
> > -			break;
> > -		}
> > +		p = src ? src + i * PAGE_SIZE : NULL;
> >  
> > -		folio_unlock(folio);
> > +		if (p) {
> > +			ret = get_user_pages_fast((unsigned long)p, 1, 0, &src_page);
> > +			if (ret < 0)
> > +				break;
> > +			if (ret != 1) {
> Put pages in this case? e.g.,
> 
> --- a/virt/kvm/guest_memfd.c
> +++ b/virt/kvm/guest_memfd.c
> @@ -1645,6 +1645,9 @@ long kvm_gmem_populate(struct kvm *kvm, gfn_t start_gfn, void __user *src, long
>                         if (ret < 0)
>                                 break;
>                         if (ret != 1) {
> +                               while (ret--)
Oops. Need to check if ret == 0, and looks put_page() is not required in this
case given nr_pages == 1.
So, please ignore this comment.
> +                                       put_page(src_page++);
> +
>                                 ret = -ENOMEM;
>                                 break;
>                         }
> 
> 
> 
> 
> > +				ret = -ENOMEM;
> > +				break;
> > +			}
> > +		}
> >  
> > -		ret = -EINVAL;
> > -		if (!kvm_range_has_memory_attributes(kvm, gfn, gfn + 1,
> > -						     KVM_MEMORY_ATTRIBUTE_PRIVATE,
> > -						     KVM_MEMORY_ATTRIBUTE_PRIVATE))
> > -			goto put_folio_and_exit;
> > +		ret = __kvm_gmem_populate(kvm, slot, file, start_gfn + i, src_page,
> > +					  post_populate, opaque);
> >  
> > -		p = src ? src + i * PAGE_SIZE : NULL;
> > -		ret = post_populate(kvm, gfn, pfn, p, opaque);
> > -		if (!ret)
> > -			folio_mark_uptodate(folio);
> > +		if (src_page)
> > +			put_page(src_page);
> >  
> > -put_folio_and_exit:
> > -		folio_put(folio);
> >  		if (ret)
> >  			break;
> >  	}
> >  
> > -	filemap_invalidate_unlock(file->f_mapping);
> > -
> >  	return ret && !i ? ret : i;
> >  }
> >  EXPORT_SYMBOL_FOR_KVM_INTERNAL(kvm_gmem_populate);
> > -- 
> > 2.25.1
> > 

^ permalink raw reply

* Re: [PATCH v2 1/5] KVM: guest_memfd: Remove partial hugepage handling from kvm_gmem_populate()
From: Yan Zhao @ 2025-12-26  2:49 UTC (permalink / raw)
  To: Michael Roth
  Cc: kvm@vger.kernel.org, linux-coco@lists.linux.dev,
	linux-mm@kvack.org, linux-kernel@vger.kernel.org,
	thomas.lendacky@amd.com, pbonzini@redhat.com, seanjc@google.com,
	vbabka@suse.cz, ashish.kalra@amd.com, liam.merwick@oracle.com,
	david@redhat.com, Annapurve, Vishal, ackerleytng@google.com,
	aik@amd.com, Weiny, Ira
In-Reply-To: <20251215153411.3613928-2-michael.roth@amd.com>

> -static int sev_gmem_post_populate(struct kvm *kvm, gfn_t gfn_start, kvm_pfn_t pfn,
> -				  void __user *src, int order, void *opaque)
> +static int sev_gmem_post_populate(struct kvm *kvm, gfn_t gfn, kvm_pfn_t pfn,
> +				  void __user *src, void *opaque)
>  {
>  	struct sev_gmem_populate_args *sev_populate_args = opaque;
> +	struct sev_data_snp_launch_update fw_args = {0};
>  	struct kvm_sev_info *sev = to_kvm_sev_info(kvm);
> -	int n_private = 0, ret, i;
> -	int npages = (1 << order);
> -	gfn_t gfn;
> +	bool assigned = false;
> +	int level;
> +	int ret;
>  
>  	if (WARN_ON_ONCE(sev_populate_args->type != KVM_SEV_SNP_PAGE_TYPE_ZERO && !src))
>  		return -EINVAL;
>  
> -	for (gfn = gfn_start, i = 0; gfn < gfn_start + npages; gfn++, i++) {
> -		struct sev_data_snp_launch_update fw_args = {0};
> -		bool assigned = false;
> -		int level;
> -
> -		ret = snp_lookup_rmpentry((u64)pfn + i, &assigned, &level);
> -		if (ret || assigned) {
> -			pr_debug("%s: Failed to ensure GFN 0x%llx RMP entry is initial shared state, ret: %d assigned: %d\n",
> -				 __func__, gfn, ret, assigned);
> -			ret = ret ? -EINVAL : -EEXIST;
> -			goto err;
> -		}
> +	ret = snp_lookup_rmpentry((u64)pfn, &assigned, &level);
> +	if (ret || assigned) {
> +		pr_debug("%s: Failed to ensure GFN 0x%llx RMP entry is initial shared state, ret: %d assigned: %d\n",
> +			 __func__, gfn, ret, assigned);
> +		ret = ret ? -EINVAL : -EEXIST;
> +		goto out;
> +	}
>  
> -		if (src) {
> -			void *vaddr = kmap_local_pfn(pfn + i);
> +	if (src) {
> +		void *vaddr = kmap_local_pfn(pfn);
>  
> -			if (copy_from_user(vaddr, src + i * PAGE_SIZE, PAGE_SIZE)) {
> -				ret = -EFAULT;
> -				goto err;
Please consider apply the following fix before this patch. Thanks!

commit 2714522d42263e0e250f21a0b171c10c4bb17ed3
Author: Yan Zhao <yan.y.zhao@intel.com>
Date:   Mon Nov 10 11:22:28 2025 +0800

    KVM: SVM: Fix a missing kunmap_local() in sev_gmem_post_populate()
    
    sev_gmem_post_populate() needs to unmap the target vaddr after
    copy_from_user() to the vaddr fails.
    
    Fixes: dee5a47cc7a4 ("KVM: SEV: Add KVM_SEV_SNP_LAUNCH_UPDATE command")
    Signed-off-by: Yan Zhao <yan.y.zhao@intel.com>

diff --git a/arch/x86/kvm/svm/sev.c b/arch/x86/kvm/svm/sev.c
index f59c65abe3cf..261d9ef8631b 100644
--- a/arch/x86/kvm/svm/sev.c
+++ b/arch/x86/kvm/svm/sev.c
@@ -2296,6 +2296,7 @@ static int sev_gmem_post_populate(struct kvm *kvm, gfn_t gfn_start, kvm_pfn_t pf
                        void *vaddr = kmap_local_pfn(pfn + i);
 
                        if (copy_from_user(vaddr, src + i * PAGE_SIZE, PAGE_SIZE)) {
+                               kunmap_local(vaddr);
                                ret = -EFAULT;
                                goto err;
                        }



> -			}
> -			kunmap_local(vaddr);
> +		if (copy_from_user(vaddr, src, PAGE_SIZE)) {
> +			ret = -EFAULT;
> +			goto out;
>  		}
> -
> -		ret = rmp_make_private(pfn + i, gfn << PAGE_SHIFT, PG_LEVEL_4K,
> -				       sev_get_asid(kvm), true);
> -		if (ret)
> -			goto err;
> -
> -		n_private++;
> -
> -		fw_args.gctx_paddr = __psp_pa(sev->snp_context);
> -		fw_args.address = __sme_set(pfn_to_hpa(pfn + i));
> -		fw_args.page_size = PG_LEVEL_TO_RMP(PG_LEVEL_4K);
> -		fw_args.page_type = sev_populate_args->type;
> -
> -		ret = __sev_issue_cmd(sev_populate_args->sev_fd, SEV_CMD_SNP_LAUNCH_UPDATE,
> -				      &fw_args, &sev_populate_args->fw_error);
> -		if (ret)
> -			goto fw_err;
> +		kunmap_local(vaddr);
>  	}
>  
> -	return 0;
> +	ret = rmp_make_private(pfn, gfn << PAGE_SHIFT, PG_LEVEL_4K,
> +			       sev_get_asid(kvm), true);
> +	if (ret)
> +		goto out;
> +
> +	fw_args.gctx_paddr = __psp_pa(sev->snp_context);
> +	fw_args.address = __sme_set(pfn_to_hpa(pfn));
> +	fw_args.page_size = PG_LEVEL_TO_RMP(PG_LEVEL_4K);
> +	fw_args.page_type = sev_populate_args->type;
>  
> -fw_err:
> +	ret = __sev_issue_cmd(sev_populate_args->sev_fd, SEV_CMD_SNP_LAUNCH_UPDATE,
> +			      &fw_args, &sev_populate_args->fw_error);
>  	/*
>  	 * If the firmware command failed handle the reclaim and cleanup of that
> -	 * PFN specially vs. prior pages which can be cleaned up below without
> -	 * needing to reclaim in advance.
> +	 * PFN before reporting an error.
>  	 *
>  	 * Additionally, when invalid CPUID function entries are detected,
>  	 * firmware writes the expected values into the page and leaves it
> @@ -2336,26 +2322,20 @@ static int sev_gmem_post_populate(struct kvm *kvm, gfn_t gfn_start, kvm_pfn_t pf
>  	 * information to provide information on which CPUID leaves/fields
>  	 * failed CPUID validation.
>  	 */
> -	if (!snp_page_reclaim(kvm, pfn + i) &&
> +	if (ret && !snp_page_reclaim(kvm, pfn) &&
>  	    sev_populate_args->type == KVM_SEV_SNP_PAGE_TYPE_CPUID &&
>  	    sev_populate_args->fw_error == SEV_RET_INVALID_PARAM) {
> -		void *vaddr = kmap_local_pfn(pfn + i);
> +		void *vaddr = kmap_local_pfn(pfn);
>  
> -		if (copy_to_user(src + i * PAGE_SIZE, vaddr, PAGE_SIZE))
> +		if (copy_to_user(src, vaddr, PAGE_SIZE))
>  			pr_debug("Failed to write CPUID page back to userspace\n");
>  
>  		kunmap_local(vaddr);
>  	}
>  
> -	/* pfn + i is hypervisor-owned now, so skip below cleanup for it. */
> -	n_private--;
> -
> -err:
> -	pr_debug("%s: exiting with error ret %d (fw_error %d), restoring %d gmem PFNs to shared.\n",
> -		 __func__, ret, sev_populate_args->fw_error, n_private);
> -	for (i = 0; i < n_private; i++)
> -		kvm_rmp_make_shared(kvm, pfn + i, PG_LEVEL_4K);
> -
> +out:
> +	pr_debug("%s: exiting with return code %d (fw_error %d)\n",
> +		 __func__, ret, sev_populate_args->fw_error);
>  	return ret;
>  }
 

^ permalink raw reply related

* Re: [PATCH v2 5/5] KVM: guest_memfd: GUP source pages prior to populating guest memory
From: Yan Zhao @ 2025-12-26  2:48 UTC (permalink / raw)
  To: Michael Roth
  Cc: kvm, linux-coco, linux-mm, linux-kernel, thomas.lendacky,
	pbonzini, seanjc, vbabka, ashish.kalra, liam.merwick, david,
	vannapurve, ackerleytng, aik, ira.weiny
In-Reply-To: <20251215153411.3613928-6-michael.roth@amd.com>

On Mon, Dec 15, 2025 at 09:34:11AM -0600, Michael Roth wrote:
> diff --git a/arch/x86/kvm/vmx/tdx.c b/arch/x86/kvm/vmx/tdx.c
> index 4fb042ce8ed1..3eb597c0e79f 100644
> --- a/arch/x86/kvm/vmx/tdx.c
> +++ b/arch/x86/kvm/vmx/tdx.c
> @@ -3118,34 +3118,21 @@ struct tdx_gmem_post_populate_arg {
>  };
>  
>  static int tdx_gmem_post_populate(struct kvm *kvm, gfn_t gfn, kvm_pfn_t pfn,
> -				  void __user *src, void *_arg)
> +				  struct page *src_page, void *_arg)
>  {
>  	struct tdx_gmem_post_populate_arg *arg = _arg;
>  	struct kvm_tdx *kvm_tdx = to_kvm_tdx(kvm);
>  	u64 err, entry, level_state;
>  	gpa_t gpa = gfn_to_gpa(gfn);
> -	struct page *src_page;
>  	int ret, i;
>  
>  	if (KVM_BUG_ON(kvm_tdx->page_add_src, kvm))
>  		return -EIO;
Check if src_page is NULL.

diff --git a/arch/x86/kvm/vmx/tdx.c b/arch/x86/kvm/vmx/tdx.c
index f9dc59a39eb8..98ff84bc83f2 100644
--- a/arch/x86/kvm/vmx/tdx.c
+++ b/arch/x86/kvm/vmx/tdx.c
@@ -3190,6 +3190,9 @@ static int tdx_gmem_post_populate(struct kvm *kvm, gfn_t gfn, kvm_pfn_t pfn,
        if (KVM_BUG_ON(kvm_tdx->page_add_src, kvm))
                return -EIO;
 
+       if (!src_page)
+               return -EOPNOTSUPP;
+
        kvm_tdx->page_add_src = src_page;
        ret = kvm_tdp_mmu_map_private_pfn(arg->vcpu, gfn, pfn);
        kvm_tdx->page_add_src = NULL;

> -	/*
> -	 * Get the source page if it has been faulted in. Return failure if the
> -	 * source page has been swapped out or unmapped in primary memory.
> -	 */
> -	ret = get_user_pages_fast((unsigned long)src, 1, 0, &src_page);
> -	if (ret < 0)
> -		return ret;
> -	if (ret != 1)
> -		return -ENOMEM;
> -
>  	kvm_tdx->page_add_src = src_page;
>  	ret = kvm_tdp_mmu_map_private_pfn(arg->vcpu, gfn, pfn);
>  	kvm_tdx->page_add_src = NULL;
>  
> -	put_page(src_page);
> -
>  	if (ret || !(arg->flags & KVM_TDX_MEASURE_MEMORY_REGION))
>  		return ret;
>  
...
>  long kvm_gmem_populate(struct kvm *kvm, gfn_t start_gfn, void __user *src, long npages,
>  		       kvm_gmem_populate_cb post_populate, void *opaque)
>  {
>  	struct kvm_memory_slot *slot;
> -	void __user *p;
> -
>  	int ret = 0;
>  	long i;
>  
> @@ -834,6 +870,9 @@ long kvm_gmem_populate(struct kvm *kvm, gfn_t start_gfn, void __user *src, long
>  	if (WARN_ON_ONCE(npages <= 0))
>  		return -EINVAL;
>  
> +	if (WARN_ON_ONCE(!PAGE_ALIGNED(src)))
> +		return -EINVAL;
> +
>  	slot = gfn_to_memslot(kvm, start_gfn);
>  	if (!kvm_slot_has_gmem(slot))
>  		return -EINVAL;
> @@ -842,47 +881,38 @@ long kvm_gmem_populate(struct kvm *kvm, gfn_t start_gfn, void __user *src, long
>  	if (!file)
>  		return -EFAULT;
>  
> -	filemap_invalidate_lock(file->f_mapping);
> -
>  	npages = min_t(ulong, slot->npages - (start_gfn - slot->base_gfn), npages);
>  	for (i = 0; i < npages; i++) {
> -		struct folio *folio;
> -		gfn_t gfn = start_gfn + i;
> -		pgoff_t index = kvm_gmem_get_index(slot, gfn);
> -		kvm_pfn_t pfn;
> +		struct page *src_page = NULL;
> +		void __user *p;
>  
>  		if (signal_pending(current)) {
>  			ret = -EINTR;
>  			break;
>  		}
>  
> -		folio = __kvm_gmem_get_pfn(file, slot, index, &pfn, NULL);
> -		if (IS_ERR(folio)) {
> -			ret = PTR_ERR(folio);
> -			break;
> -		}
> +		p = src ? src + i * PAGE_SIZE : NULL;
>  
> -		folio_unlock(folio);
> +		if (p) {
> +			ret = get_user_pages_fast((unsigned long)p, 1, 0, &src_page);
> +			if (ret < 0)
> +				break;
> +			if (ret != 1) {
Put pages in this case? e.g.,

--- a/virt/kvm/guest_memfd.c
+++ b/virt/kvm/guest_memfd.c
@@ -1645,6 +1645,9 @@ long kvm_gmem_populate(struct kvm *kvm, gfn_t start_gfn, void __user *src, long
                        if (ret < 0)
                                break;
                        if (ret != 1) {
+                               while (ret--)
+                                       put_page(src_page++);
+
                                ret = -ENOMEM;
                                break;
                        }




> +				ret = -ENOMEM;
> +				break;
> +			}
> +		}
>  
> -		ret = -EINVAL;
> -		if (!kvm_range_has_memory_attributes(kvm, gfn, gfn + 1,
> -						     KVM_MEMORY_ATTRIBUTE_PRIVATE,
> -						     KVM_MEMORY_ATTRIBUTE_PRIVATE))
> -			goto put_folio_and_exit;
> +		ret = __kvm_gmem_populate(kvm, slot, file, start_gfn + i, src_page,
> +					  post_populate, opaque);
>  
> -		p = src ? src + i * PAGE_SIZE : NULL;
> -		ret = post_populate(kvm, gfn, pfn, p, opaque);
> -		if (!ret)
> -			folio_mark_uptodate(folio);
> +		if (src_page)
> +			put_page(src_page);
>  
> -put_folio_and_exit:
> -		folio_put(folio);
>  		if (ret)
>  			break;
>  	}
>  
> -	filemap_invalidate_unlock(file->f_mapping);
> -
>  	return ret && !i ? ret : i;
>  }
>  EXPORT_SYMBOL_FOR_KVM_INTERNAL(kvm_gmem_populate);
> -- 
> 2.25.1
> 

^ permalink raw reply related

* Re: [PATCH v2 2/7] KVM: x86: Extract VMXON and EFER.SVME enablement to kernel
From: Xu Yilun @ 2025-12-24 11:07 UTC (permalink / raw)
  To: Sean Christopherson
  Cc: dan.j.williams, Thomas Gleixner, Ingo Molnar, Borislav Petkov,
	Dave Hansen, x86, Kiryl Shutsemau, Paolo Bonzini, linux-kernel,
	linux-coco, kvm, Chao Gao
In-Reply-To: <aTmBobJJo_sFbre9@google.com>

On Wed, Dec 10, 2025 at 06:20:17AM -0800, Sean Christopherson wrote:
> On Wed, Dec 10, 2025, dan.j.williams@intel.com wrote:
> > Sean Christopherson wrote:
> > > On Sat, Dec 06, 2025, dan.j.williams@intel.com wrote:
> > > I don't think we need anything at this time.  INTEL_TDX_HOST depends on KVM_INTEL,
> > > and so without a user that needs VMXON without KVM_INTEL, I think we're good as-is.
> > > 
> > >  config INTEL_TDX_HOST
> > > 	bool "Intel Trust Domain Extensions (TDX) host support"
> > > 	depends on CPU_SUP_INTEL
> > > 	depends on X86_64
> > > 	depends on KVM_INTEL
> > 
> > ...but INTEL_TDX_HOST, it turns out, does not have any functional
> > dependencies on KVM_INTEL. At least, not since I last checked. Yes, it
> > would be silly and result in dead code today to do a build with:
> > 
> > CONFIG_INTEL_TDX_HOST=y
> > CONFIG_KVM_INTEL=n
> > 
> > However, when the TDX Connect support arrives you could have:
> > 
> > CONFIG_INTEL_TDX_HOST=y
> > CONFIG_KVM_INTEL=n
> > CONFIG_TDX_HOST_SERVICES=y
> > 
> > Where "TDX Host Services" is a driver for PCIe Link Encryption and TDX
> > Module update. Whether such configuration freedom has any practical
> > value is a separate question.
> > 
> > I am ok if the answer is, "wait until someone shows up who really wants
> > PCIe Link Encryption without KVM".
> 
> Ya, that's my answer.  At the very least, wait until TDX_HOST_SERVICES comes
> along.

I've tested the PCIe Link Encryption without KVM, with the kernel
config:

  CONFIG_INTEL_TDX_HOST=y
  CONFIG_KVM_INTEL=n
  CONFIG_TDX_HOST_SERVICES=y

and

--- /dev/null
+++ b/drivers/virt/coco/tdx-host/Kconfig
@@ -0,0 +1,10 @@
+config TDX_HOST_SERVICES
+       tristate "TDX Host Services Driver"
+       depends on INTEL_TDX_HOST
+       default m

Finally I enabled the combination successfully with a patch below, do we
need the change when TDX_HOST_SERVICES comes?

------------8<----------------------

diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig
index 80527299f859..e3e90d1fcad3 100644
--- a/arch/x86/Kconfig
+++ b/arch/x86/Kconfig
@@ -1898,7 +1898,6 @@ config INTEL_TDX_HOST
        bool "Intel Trust Domain Extensions (TDX) host support"
        depends on CPU_SUP_INTEL
        depends on X86_64
-       depends on KVM_INTEL
        depends on X86_X2APIC
        select ARCH_KEEP_MEMBLOCK
        depends on CONTIG_ALLOC
diff --git a/arch/x86/include/asm/virt.h b/arch/x86/include/asm/virt.h
index 77a366afd9f7..26bbf0f21575 100644
--- a/arch/x86/include/asm/virt.h
+++ b/arch/x86/include/asm/virt.h
@@ -6,7 +6,7 @@

 typedef void (cpu_emergency_virt_cb)(void);

-#if IS_ENABLED(CONFIG_KVM_X86)
+#if IS_ENABLED(CONFIG_KVM_X86) || IS_ENABLED(CONFIG_INTEL_TDX_HOST)
 extern bool virt_rebooting;

 void __init x86_virt_init(void);
diff --git a/arch/x86/kvm/Kconfig b/arch/x86/kvm/Kconfig
index 278f08194ec8..28fe309093ed 100644
--- a/arch/x86/kvm/Kconfig
+++ b/arch/x86/kvm/Kconfig
@@ -134,7 +134,7 @@ config X86_SGX_KVM
 config KVM_INTEL_TDX
        bool "Intel Trust Domain Extensions (TDX) support"
        default y
-       depends on INTEL_TDX_HOST
+       depends on INTEL_TDX_HOST && KVM_INTEL
        select KVM_GENERIC_MEMORY_ATTRIBUTES
        select HAVE_KVM_ARCH_GMEM_POPULATE
        help
diff --git a/arch/x86/virt/Makefile b/arch/x86/virt/Makefile
index 6e485751650c..85ed7a06ed88 100644
--- a/arch/x86/virt/Makefile
+++ b/arch/x86/virt/Makefile
@@ -1,4 +1,5 @@
 # SPDX-License-Identifier: GPL-2.0-only
 obj-y  += svm/ vmx/

-obj-$(subst m,y,$(CONFIG_KVM_X86)) += hw.o
\ No newline at end of file
+obj-$(CONFIG_INTEL_TDX_HOST) += hw.o
+obj-$(subst m,y,$(CONFIG_KVM_X86)) += hw.o
diff --git a/arch/x86/virt/hw.c b/arch/x86/virt/hw.c
index 986e780cf438..31ea89069a93 100644
--- a/arch/x86/virt/hw.c
+++ b/arch/x86/virt/hw.c
@@ -48,7 +48,7 @@ static void x86_virt_invoke_kvm_emergency_callback(void)
                kvm_callback();
 }

-#if IS_ENABLED(CONFIG_KVM_INTEL)
+#if IS_ENABLED(CONFIG_KVM_INTEL) || IS_ENABLED(CONFIG_INTEL_TDX_HOST)
 static DEFINE_PER_CPU(struct vmcs *, root_vmcs);

 static int x86_virt_cpu_vmxon(void)
@@ -257,7 +257,8 @@ static __init int x86_svm_init(void) { return -EOPNOTSUPP; }
 ({                                                     \
        int __r;                                        \
                                                        \
-       if (IS_ENABLED(CONFIG_KVM_INTEL) &&             \
+       if ((IS_ENABLED(CONFIG_KVM_INTEL) ||            \
+            IS_ENABLED(CONFIG_INTEL_TDX_HOST)) &&      \
            cpu_feature_enabled(X86_FEATURE_VMX))       \
                __r = x86_vmx_##fn();                   \
        else if (IS_ENABLED(CONFIG_KVM_AMD) &&          \

> 

^ permalink raw reply related

* Re: [PATCH v4 04/16] x86/virt/tdx: Allocate page bitmap for Dynamic PAMT
From: Xu Yilun @ 2025-12-24  9:10 UTC (permalink / raw)
  To: Rick Edgecombe
  Cc: bp, chao.gao, dave.hansen, isaku.yamahata, kai.huang, kas, kvm,
	linux-coco, linux-kernel, mingo, pbonzini, seanjc, tglx,
	vannapurve, x86, yan.y.zhao, xiaoyao.li, binbin.wu,
	Kirill A. Shutemov
In-Reply-To: <20251121005125.417831-5-rick.p.edgecombe@intel.com>

> diff --git a/arch/x86/virt/vmx/tdx/tdx_global_metadata.c b/arch/x86/virt/vmx/tdx/tdx_global_metadata.c
> index 13ad2663488b..00ab0e550636 100644
> --- a/arch/x86/virt/vmx/tdx/tdx_global_metadata.c
> +++ b/arch/x86/virt/vmx/tdx/tdx_global_metadata.c
> @@ -33,6 +33,13 @@ static int get_tdx_sys_info_tdmr(struct tdx_sys_info_tdmr *sysinfo_tdmr)
>  		sysinfo_tdmr->pamt_2m_entry_size = val;
>  	if (!ret && !(ret = read_sys_metadata_field(0x9100000100000012, &val)))
>  		sysinfo_tdmr->pamt_1g_entry_size = val;
> +	/*
> +	 * Don't fail here if tdx_supports_dynamic_pamt() isn't supported. The
> +	 * TDX code can fallback to normal PAMT if it's not supported.
> +	 */
> +	if (!ret && tdx_supports_dynamic_pamt(&tdx_sysinfo) &&
> +	    !(ret = read_sys_metadata_field(0x9100000100000013, &val)))
> +		sysinfo_tdmr->pamt_page_bitmap_entry_bits = val;

Is it better we seal the awkward pattern inside the if (dpamt supported)  block:

	if (tdx_support_dynamic_pamt(&tdx_sysinfo))
		if (!ret && !(ret = read_sys_metadata_field(0x9100000100000013, &val)))
			sysinfo_tdmr->pamt_page_bitmap_entry_bits = val;

so we don't have to get used to another variant of the awkward pattern :)

Thanks,
Yilun

>  
>  	return ret;
>  }
> -- 
> 2.51.2
> 
> 

^ permalink raw reply

* Re: [PATCH] PCI/IDE: Fix duplicate stream symlink names for TSM class devices
From: Xu Yilun @ 2025-12-24  1:00 UTC (permalink / raw)
  To: Bjorn Helgaas
  Cc: linux-coco, linux-pci, dan.j.williams, yilun.xu, baolu.lu,
	zhenzhong.duan, linux-kernel, yi1.lai
In-Reply-To: <20251223173157.GA4025076@bhelgaas>

On Tue, Dec 23, 2025 at 11:31:57AM -0600, Bjorn Helgaas wrote:
> On Tue, Dec 23, 2025 at 04:56:01PM +0800, Xu Yilun wrote:
> > The symlink name streamH.R.E is unique within a specific host bridge but
> > not across the system. Error occurs e.g. when creating the first stream
> > on a second host bridge:
> > 
> > [ 1244.034755] sysfs: cannot create duplicate filename '/devices/faux/tdx_host/tsm/tsm0/stream0.0.0'
> 
> Drop timestamp because it's no relevant.  Indent quoted material two
> spaces.

Yes.

> 
> > Fix this by adding host bridge name into symlink name for TSM class
> > devices. It should be OK to change the uAPI to
> > /sys/class/tsm/tsmN/pciDDDD:BB:streamH.R.E since it's new and has few
> > users.
> 
> Looks like this adds "pciDDDD:BB:" to one name, which is described
> here and in the Documentation/ABI change.
> 
> > Internally in the IDE library, store the full name in struct pci_ide
> > so TSM symlinks can use it directly, while PCI host bridge symlinks
> > can skip the host bridge name to keep concise.
> 
> And shortens this name, but no example or doc update?  Or maybe the
> shortening just strips the "pciDDDD:BB" to preserve the existing names
> somewhere else?

The later. The shortening is the internal code change, aims to preserve
the existing name /sys/devices/pciDDDD:BB/streamH.R.E, which is
described in:

  Documentation/ABI/testing/sysfs-devices-pci-host-bridge

  What:		pciDDDD:BB/streamH.R.E

I don't want repeat the host bridge name in host bridge context.

> 
> I'm just confused about which symlinks are changing (adding
> "pciDDDD:BB") and which are being kept concise (either by staying the
> same or being shortened).

I should have clearly listed the changed & preserved symlinks. Will
improve in v2.

Thanks,
Yilun

> 
> > Fixes: a4438f06b1db ("PCI/TSM: Report active IDE streams")
> > Reported-by: Yi Lai <yi1.lai@intel.com>
> > Signed-off-by: Xu Yilun <yilun.xu@linux.intel.com>
> > ---
> >  Documentation/ABI/testing/sysfs-class-tsm |  2 +-
> >  drivers/pci/ide.c                         | 12 +++++++++---
> >  2 files changed, 10 insertions(+), 4 deletions(-)
> > 
> > diff --git a/Documentation/ABI/testing/sysfs-class-tsm b/Documentation/ABI/testing/sysfs-class-tsm
> > index 6fc1a5ac6da1..eff71e42c60e 100644
> > --- a/Documentation/ABI/testing/sysfs-class-tsm
> > +++ b/Documentation/ABI/testing/sysfs-class-tsm
> > @@ -8,7 +8,7 @@ Description:
> >  		link encryption and other device-security features coordinated
> >  		through a platform tsm.
> >  
> > -What:		/sys/class/tsm/tsmN/streamH.R.E
> > +What:		/sys/class/tsm/tsmN/pciDDDD:BB:streamH.R.E
> >  Contact:	linux-pci@vger.kernel.org
> >  Description:
> >  		(RO) When a host bridge has established a secure connection via
> > diff --git a/drivers/pci/ide.c b/drivers/pci/ide.c
> > index f0ef474e1a0d..db1c7423bf39 100644
> > --- a/drivers/pci/ide.c
> > +++ b/drivers/pci/ide.c
> > @@ -425,6 +425,7 @@ int pci_ide_stream_register(struct pci_ide *ide)
> >  	struct pci_host_bridge *hb = pci_find_host_bridge(pdev->bus);
> >  	struct pci_ide_stream_id __sid;
> >  	u8 ep_stream, rp_stream;
> > +	const char *short_name;
> >  	int rc;
> >  
> >  	if (ide->stream_id < 0 || ide->stream_id > U8_MAX) {
> > @@ -441,13 +442,16 @@ int pci_ide_stream_register(struct pci_ide *ide)
> >  
> >  	ep_stream = ide->partner[PCI_IDE_EP].stream_index;
> >  	rp_stream = ide->partner[PCI_IDE_RP].stream_index;
> > -	const char *name __free(kfree) = kasprintf(GFP_KERNEL, "stream%d.%d.%d",
> > +	const char *name __free(kfree) = kasprintf(GFP_KERNEL, "%s:stream%d.%d.%d",
> > +						   dev_name(&hb->dev),
> >  						   ide->host_bridge_stream,
> >  						   rp_stream, ep_stream);
> >  	if (!name)
> >  		return -ENOMEM;
> >  
> > -	rc = sysfs_create_link(&hb->dev.kobj, &pdev->dev.kobj, name);
> > +	/* Skip host bridge name in the host bridge context */
> > +	short_name = name + strlen(dev_name(&hb->dev)) + 1;
> > +	rc = sysfs_create_link(&hb->dev.kobj, &pdev->dev.kobj, short_name);
> >  	if (rc)
> >  		return rc;
> >  
> > @@ -471,8 +475,10 @@ void pci_ide_stream_unregister(struct pci_ide *ide)
> >  {
> >  	struct pci_dev *pdev = ide->pdev;
> >  	struct pci_host_bridge *hb = pci_find_host_bridge(pdev->bus);
> > +	const char *short_name;
> >  
> > -	sysfs_remove_link(&hb->dev.kobj, ide->name);
> > +	short_name = ide->name + strlen(dev_name(&hb->dev)) + 1;
> > +	sysfs_remove_link(&hb->dev.kobj, short_name);
> >  	kfree(ide->name);
> >  	ida_free(&hb->ide_stream_ids_ida, ide->stream_id);
> >  	ide->name = NULL;
> > 
> > base-commit: 8f0b4cce4481fb22653697cced8d0d04027cb1e8
> > -- 
> > 2.25.1
> > 

^ permalink raw reply

* Re: [RFC PATCH v2 0/1] firmware: smccc: Add support for Live Firmware Activation (LFA)
From: Vedashree Vidwans @ 2025-12-23 23:01 UTC (permalink / raw)
  To: salman.nabi
  Cc: andre.przywara, ardb, chao.gao, linux-arm-kernel, linux-coco,
	linux-kernel, lpieralisi, mark.rutland, sdonthineni, sudeep.holla,
	vsethi, vwadekar, Vedashree Vidwans
In-Reply-To: <20250926123145.268728-1-salman.nabi@arm.com>

Hello Salman,

Thank you for the patch. As you might know, I am implementing the
interrupt interface for LFA driver. The LFA usecase I am working
with will validate both interrupt and sysfs interfaces of the LFA
driver. Hence, I would like to extend the driver posted here with
required changes. Please find the extended driver patches posted
at [1].
While working on this code, I realized that LFA driver should
use SMCCC 1.2+ version as per the LFA specification. And I have
included a patch to upgrade SMCCC version in the code.
As the initial LFA driver in this thread isn't merged yet, I would
like to request modification to this original patch based on
a review comment on my patch series.

Could we please come up with a strategy to incorporate the changes?
We are aiming to merge LFA patches to Linux kernel as soon as
possible. Since I am actively working on this driver, I will be
happy to revise the initial patch(with authors intact) and post
a fresh series for review.

Regards,
Veda

[1] https://lore.kernel.org/linux-arm-kernel/20251208221319.1524888-1-vvidwans@nvidia.com/

^ permalink raw reply

* Re: [PATCH v2 3/4] coco: host: arm64: Handle hostconf RHI calls in kernel
From: Suzuki K Poulose @ 2025-12-23 19:56 UTC (permalink / raw)
  To: Aneesh Kumar K.V, linux-kernel, iommu, linux-coco
  Cc: Catalin Marinas, will, maz, tglx, robin.murphy, akpm, jgg,
	steven.price
In-Reply-To: <yq5ased2twfh.fsf@kernel.org>

On 22/12/2025 14:37, Aneesh Kumar K.V wrote:
> Suzuki K Poulose <suzuki.poulose@arm.com> writes:
> 
>> On 21/12/2025 16:09, Aneesh Kumar K.V (Arm) wrote:
>>>    - Mark hostconf RHI SMC IDs as handled in the SMCCC filter.
>>>    - Return version/features plus PAGE_SIZE alignment for guest queries.
>>>    - Drop the 4K page-size guard in RMI init now that realm can query IPA
>>>      change alignment size via the hostconf RHI
>>>
>>> Signed-off-by: Aneesh Kumar K.V (Arm) <aneesh.kumar@kernel.org>
>>> ---
>>>    arch/arm64/kvm/hypercalls.c | 23 ++++++++++++++++++++++-
>>>    arch/arm64/kvm/rmi.c        |  4 ----
>>>    2 files changed, 22 insertions(+), 5 deletions(-)
>>>
>>> diff --git a/arch/arm64/kvm/hypercalls.c b/arch/arm64/kvm/hypercalls.c
>>> index 70ac7971416c..2861ca9063dd 100644
>>> --- a/arch/arm64/kvm/hypercalls.c
>>> +++ b/arch/arm64/kvm/hypercalls.c
>>> @@ -8,6 +8,7 @@
>>>    
>>>    #include <kvm/arm_hypercalls.h>
>>>    #include <kvm/arm_psci.h>
>>> +#include <asm/rhi.h>
>>>    
>>>    #define KVM_ARM_SMCCC_STD_FEATURES				\
>>>    	GENMASK(KVM_REG_ARM_STD_BMAP_BIT_COUNT - 1, 0)
>>> @@ -77,6 +78,9 @@ static bool kvm_smccc_default_allowed(u32 func_id)
>>>    	 */
>>>    	case ARM_SMCCC_VERSION_FUNC_ID:
>>>    	case ARM_SMCCC_ARCH_FEATURES_FUNC_ID:
>>> +	case RHI_HOSTCONF_VERSION:
>>> +	case RHI_HOSTCONF_FEATURES:
>>> +	case RHI_HOSTCONF_GET_IPA_CHANGE_ALIGNMENT:
>>>    		return true;
>>>    	default:
>>>    		/* PSCI 0.2 and up is in the 0:0x1f range */
>>> @@ -157,7 +161,15 @@ static int kvm_smccc_filter_insert_reserved(struct kvm *kvm)
>>>    			       GFP_KERNEL_ACCOUNT);
>>>    	if (r)
>>>    		goto out_destroy;
>>> -
>>> +	/*
>>> +	 * Don't forward RHI_HOST_CONF related RHI calls
>>> +	 */
>>> +	r = mtree_insert_range(&kvm->arch.smccc_filter,
>>> +			       RHI_HOSTCONF_VERSION, RHI_HOSTCONF_GET_IPA_CHANGE_ALIGNMENT,
>>> +			       xa_mk_value(KVM_SMCCC_FILTER_HANDLE),
>>> +			       GFP_KERNEL_ACCOUNT);
>>
>> minor nit: this is needed only for the Realms ?
>>
> 
> 
> That is the kvm forwarding of the RHI hostcalls to VMM. We are updating
> smccc filter that the SMCCC FID range [RHI_HOSTCONF_VERSION, RHI_HOSTCONF_GET_IPA_CHANGE_ALIGNMENT]
> will be handled by the kernel. This is needed because it is the kernel
> that is dropping the below check in kvm_init_rmi().

I don't see why that is related to kvm_init_rmi(). My point is,
for non-CCA VMs, RHI_HOST_* are not expected. And given this
filtering is per KVM, we could skip this step for !kvm_is_realm(kvm).



> 
>   	/* Only 4k page size on the host is supported */
> 	if (PAGE_SIZE != SZ_4K)
>   		return;
> 
> We want to make sure RHI support and dropping of the above check happens
> in the same patch and is part of the kernel.


Not necessarily, the guest won't run without the above changes. So, all 
your RHI host changes can go in and the final step can be the above
change.(similar to what we do for "enable a Kconfig" once we have put
in all the infrastructure for the feature).

Suzuki

> 
>>
>>> +	if (r)
>>> +		goto out_destroy;
>>>    	return 0;
>>>    out_destroy:
>>>    	mtree_destroy(&kvm->arch.smccc_filter);
>>> @@ -376,6 +388,15 @@ int kvm_smccc_call_handler(struct kvm_vcpu *vcpu)
>>>    	case ARM_SMCCC_TRNG_RND32:
>>>    	case ARM_SMCCC_TRNG_RND64:
>>>    		return kvm_trng_call(vcpu);
>>> +	case RHI_HOSTCONF_VERSION:
>>> +		val[0] = RHI_HOSTCONF_VER_1_0;
>>> +		break;
>>> +	case RHI_HOSTCONF_FEATURES:
>>> +		val[0] = __RHI_HOSTCONF_GET_IPA_CHANGE_ALIGNMENT;
>>> +		break;
>>> +	case RHI_HOSTCONF_GET_IPA_CHANGE_ALIGNMENT:
>>> +		val[0] = PAGE_SIZE;
>>> +		break;
>>>    	default:
>>>    		return kvm_psci_call(vcpu);
>>>    	}
>>> diff --git a/arch/arm64/kvm/rmi.c b/arch/arm64/kvm/rmi.c
>>> index 9957a71d21b1..bd345e051a24 100644
>>> --- a/arch/arm64/kvm/rmi.c
>>> +++ b/arch/arm64/kvm/rmi.c
>>> @@ -1935,10 +1935,6 @@ EXPORT_SYMBOL_GPL(kvm_has_da_feature);
>>>    
>>>    void kvm_init_rmi(void)
>>>    {
>>> -	/* Only 4k page size on the host is supported */
>>> -	if (PAGE_SIZE != SZ_4K)
>>> -		return;
>>
>> For the record, these patches doesn't necessarily solve the Host support
>> fully. The KVM still needs to support splitting pages for RMM's 4K.
>>
> 
> We already delegate RMM granules and setup stage 2 in rmm with
> RMM_PAGE_SIZE. ie, the shared patchset can be used to setup a 64K host

Do you mean the branch that you are basing these changes on ? I thought
we dropped most of those changes from the KVM support. Yes, there are
some left overs from the changes, but we can't run with 64K yet.

> with 4K Realm running on a RMM using 4K RMM granule size.
> 
>>
>> That said, this can be ignored as we rebase the KVM to only support
>> RMM v2.0, where the Host can set the RMM's Stage2 page size.
>>
>> Suzuki
>>
> 
> -aneesh


^ permalink raw reply

* Re: [PATCH] PCI/IDE: Fix duplicate stream symlink names for TSM class devices
From: Bjorn Helgaas @ 2025-12-23 17:31 UTC (permalink / raw)
  To: Xu Yilun
  Cc: linux-coco, linux-pci, dan.j.williams, yilun.xu, baolu.lu,
	zhenzhong.duan, linux-kernel, yi1.lai
In-Reply-To: <20251223085601.2607455-1-yilun.xu@linux.intel.com>

On Tue, Dec 23, 2025 at 04:56:01PM +0800, Xu Yilun wrote:
> The symlink name streamH.R.E is unique within a specific host bridge but
> not across the system. Error occurs e.g. when creating the first stream
> on a second host bridge:
> 
> [ 1244.034755] sysfs: cannot create duplicate filename '/devices/faux/tdx_host/tsm/tsm0/stream0.0.0'

Drop timestamp because it's no relevant.  Indent quoted material two
spaces.

> Fix this by adding host bridge name into symlink name for TSM class
> devices. It should be OK to change the uAPI to
> /sys/class/tsm/tsmN/pciDDDD:BB:streamH.R.E since it's new and has few
> users.

Looks like this adds "pciDDDD:BB:" to one name, which is described
here and in the Documentation/ABI change.

> Internally in the IDE library, store the full name in struct pci_ide
> so TSM symlinks can use it directly, while PCI host bridge symlinks
> can skip the host bridge name to keep concise.

And shortens this name, but no example or doc update?  Or maybe the
shortening just strips the "pciDDDD:BB" to preserve the existing names
somewhere else?

I'm just confused about which symlinks are changing (adding
"pciDDDD:BB") and which are being kept concise (either by staying the
same or being shortened).

> Fixes: a4438f06b1db ("PCI/TSM: Report active IDE streams")
> Reported-by: Yi Lai <yi1.lai@intel.com>
> Signed-off-by: Xu Yilun <yilun.xu@linux.intel.com>
> ---
>  Documentation/ABI/testing/sysfs-class-tsm |  2 +-
>  drivers/pci/ide.c                         | 12 +++++++++---
>  2 files changed, 10 insertions(+), 4 deletions(-)
> 
> diff --git a/Documentation/ABI/testing/sysfs-class-tsm b/Documentation/ABI/testing/sysfs-class-tsm
> index 6fc1a5ac6da1..eff71e42c60e 100644
> --- a/Documentation/ABI/testing/sysfs-class-tsm
> +++ b/Documentation/ABI/testing/sysfs-class-tsm
> @@ -8,7 +8,7 @@ Description:
>  		link encryption and other device-security features coordinated
>  		through a platform tsm.
>  
> -What:		/sys/class/tsm/tsmN/streamH.R.E
> +What:		/sys/class/tsm/tsmN/pciDDDD:BB:streamH.R.E
>  Contact:	linux-pci@vger.kernel.org
>  Description:
>  		(RO) When a host bridge has established a secure connection via
> diff --git a/drivers/pci/ide.c b/drivers/pci/ide.c
> index f0ef474e1a0d..db1c7423bf39 100644
> --- a/drivers/pci/ide.c
> +++ b/drivers/pci/ide.c
> @@ -425,6 +425,7 @@ int pci_ide_stream_register(struct pci_ide *ide)
>  	struct pci_host_bridge *hb = pci_find_host_bridge(pdev->bus);
>  	struct pci_ide_stream_id __sid;
>  	u8 ep_stream, rp_stream;
> +	const char *short_name;
>  	int rc;
>  
>  	if (ide->stream_id < 0 || ide->stream_id > U8_MAX) {
> @@ -441,13 +442,16 @@ int pci_ide_stream_register(struct pci_ide *ide)
>  
>  	ep_stream = ide->partner[PCI_IDE_EP].stream_index;
>  	rp_stream = ide->partner[PCI_IDE_RP].stream_index;
> -	const char *name __free(kfree) = kasprintf(GFP_KERNEL, "stream%d.%d.%d",
> +	const char *name __free(kfree) = kasprintf(GFP_KERNEL, "%s:stream%d.%d.%d",
> +						   dev_name(&hb->dev),
>  						   ide->host_bridge_stream,
>  						   rp_stream, ep_stream);
>  	if (!name)
>  		return -ENOMEM;
>  
> -	rc = sysfs_create_link(&hb->dev.kobj, &pdev->dev.kobj, name);
> +	/* Skip host bridge name in the host bridge context */
> +	short_name = name + strlen(dev_name(&hb->dev)) + 1;
> +	rc = sysfs_create_link(&hb->dev.kobj, &pdev->dev.kobj, short_name);
>  	if (rc)
>  		return rc;
>  
> @@ -471,8 +475,10 @@ void pci_ide_stream_unregister(struct pci_ide *ide)
>  {
>  	struct pci_dev *pdev = ide->pdev;
>  	struct pci_host_bridge *hb = pci_find_host_bridge(pdev->bus);
> +	const char *short_name;
>  
> -	sysfs_remove_link(&hb->dev.kobj, ide->name);
> +	short_name = ide->name + strlen(dev_name(&hb->dev)) + 1;
> +	sysfs_remove_link(&hb->dev.kobj, short_name);
>  	kfree(ide->name);
>  	ida_free(&hb->ide_stream_ids_ida, ide->stream_id);
>  	ide->name = NULL;
> 
> base-commit: 8f0b4cce4481fb22653697cced8d0d04027cb1e8
> -- 
> 2.25.1
> 

^ permalink raw reply

* Re: [PATCH v1 26/26] coco/tdx-host: Finally enable SPDM session and IDE Establishment
From: Xu Yilun @ 2025-12-23 10:45 UTC (permalink / raw)
  To: Jonathan Cameron
  Cc: linux-coco, linux-pci, chao.gao, dave.jiang, baolu.lu, yilun.xu,
	zhenzhong.duan, kvm, rick.p.edgecombe, dave.hansen,
	dan.j.williams, kas, x86
In-Reply-To: <20251219120616.00000890@huawei.com>

On Fri, Dec 19, 2025 at 12:06:16PM +0000, Jonathan Cameron wrote:
> On Mon, 17 Nov 2025 10:23:10 +0800
> Xu Yilun <yilun.xu@linux.intel.com> wrote:
> 
> > The basic SPDM session and IDE functionalities are all implemented,
> > enable them.
> > 
> > Signed-off-by: Xu Yilun <yilun.xu@linux.intel.com>
> Hard to disagree with this one :)
> Reviewed-by: Jonathan Cameron <jonathan.cameron@huawei.com>

Thanks for all your review, tagged them in my v2.

^ permalink raw reply

* Re: [PATCH v1 14/26] mm: Add __free() support for folio_put()
From: Xu Yilun @ 2025-12-23 10:44 UTC (permalink / raw)
  To: Jonathan Cameron
  Cc: linux-coco, linux-pci, chao.gao, dave.jiang, baolu.lu, yilun.xu,
	zhenzhong.duan, kvm, rick.p.edgecombe, dave.hansen,
	dan.j.williams, kas, x86
In-Reply-To: <20251219115507.00002848@huawei.com>

On Fri, Dec 19, 2025 at 11:55:07AM +0000, Jonathan Cameron wrote:
> On Mon, 17 Nov 2025 10:22:58 +0800
> Xu Yilun <yilun.xu@linux.intel.com> wrote:
> 
> > Allow for the declaration of struct folio * variables that trigger
> > folio_put() when they go out of scope.
> > 
> > Signed-off-by: Xu Yilun <yilun.xu@linux.intel.com>
> > ---
> >  include/linux/mm.h | 2 ++
> >  1 file changed, 2 insertions(+)
> > 
> > diff --git a/include/linux/mm.h b/include/linux/mm.h
> > index d16b33bacc32..2456bb775e27 100644
> > --- a/include/linux/mm.h
> > +++ b/include/linux/mm.h
> > @@ -1425,6 +1425,8 @@ static inline void folio_put(struct folio *folio)
> >  		__folio_put(folio);
> >  }
> >  
> > +DEFINE_FREE(folio_put, struct folio *, if (_T) folio_put(_T))
> 
> Seems like a reasonable addition to me.
> Reviewed-by: Jonathan Cameron <jonathan.cameron@huawei.com>

Sorry I'll also drop this one cause I'll drop __free() in tdx core.

> 
> > +
> >  /**
> >   * folio_put_refs - Reduce the reference count on a folio.
> >   * @folio: The folio.
> 

^ permalink raw reply

* Re: [PATCH v1 12/26] iommu/vt-d: Reserve the MSB domain ID bit for the TDX module
From: Xu Yilun @ 2025-12-23 10:39 UTC (permalink / raw)
  To: Jonathan Cameron
  Cc: linux-coco, linux-pci, chao.gao, dave.jiang, baolu.lu, yilun.xu,
	zhenzhong.duan, kvm, rick.p.edgecombe, dave.hansen,
	dan.j.williams, kas, x86
In-Reply-To: <20251219115115.00000922@huawei.com>

On Fri, Dec 19, 2025 at 11:51:15AM +0000, Jonathan Cameron wrote:
> On Mon, 17 Nov 2025 10:22:56 +0800
> Xu Yilun <yilun.xu@linux.intel.com> wrote:
> 
> > From: Lu Baolu <baolu.lu@linux.intel.com>
> > 
> > The Intel TDX Connect Architecture Specification defines some enhancements
> > for the VT-d architecture to introduce IOMMU support for TEE-IO requests.
> > Section 2.2, 'Trusted DMA' states that:
> > 
> > "I/O TLB and DID Isolation – When IOMMU is enabled to support TDX
> > Connect, the IOMMU restricts the VMM’s DID setting, reserving the MSB bit
> > for the TDX module. The TDX module always sets this reserved bit on the
> > trusted DMA table. IOMMU tags IOTLB, PASID cache, and context entries to
> > indicate whether they were created from TEE-IO transactions, ensuring
> > isolation between TEE and non-TEE requests in translation caches."
> > 
> > Reserve the MSB in the domain ID for the TDX module's use if the
> > enhancement is required, which is detected if the ECAP.TDXCS bit in the
> > VT-d extended capability register is set and the TVM Usable field of the
> > ACPI KEYP table is set.
> > 
> > Signed-off-by: Lu Baolu <baolu.lu@linux.intel.com>
> Hi,
> One comment inline.
> 
> Thanks,
> 
> Jonathan
> 
> > diff --git a/drivers/iommu/intel/dmar.c b/drivers/iommu/intel/dmar.c
> > index a54934c0536f..e9d65b26ad64 100644
> > --- a/drivers/iommu/intel/dmar.c
> > +++ b/drivers/iommu/intel/dmar.c
> > @@ -1033,6 +1033,56 @@ static int map_iommu(struct intel_iommu *iommu, struct dmar_drhd_unit *drhd)
> >  	return err;
> >  }
> >  
> > +static int keyp_config_unit_tvm_usable(union acpi_subtable_headers *header,
> > +				       void *arg, const unsigned long end)
> > +{
> > +	struct acpi_keyp_config_unit *acpi_cu =
> > +		(struct acpi_keyp_config_unit *)&header->keyp;
> > +	int *tvm_usable = arg;
> > +
> > +	if (acpi_cu->flags & ACPI_KEYP_F_TVM_USABLE)
> > +		*tvm_usable = true;
> As below. Be consistent on int vs bool as otherwise the subtle use of -1 is very confusing.
> > +
> > +	return 0;
> > +}
> > +
> > +static bool platform_is_tdxc_enhanced(void)
> > +{
> > +	static int tvm_usable = -1;
> > +	int ret;
> > +
> > +	/* only need to parse once */
> > +	if (tvm_usable != -1)
> > +		return tvm_usable;
> > +
> > +	tvm_usable = false;
> 
> This is flipping between an int and a bool which seems odd.
> I'd stick to an integer then make it a bool only at return.

I agree. My change below:

> 
> > +	ret = acpi_table_parse_keyp(ACPI_KEYP_TYPE_CONFIG_UNIT,
> > +				    keyp_config_unit_tvm_usable, &tvm_usable);
> > +	if (ret < 0)
> > +		tvm_usable = false;
> > +
> > +	return tvm_usable;
> > +}

-----------8<----------------------

diff --git a/drivers/iommu/intel/dmar.c b/drivers/iommu/intel/dmar.c
index 645b72270967..fd14de8775b6 100644
--- a/drivers/iommu/intel/dmar.c
+++ b/drivers/iommu/intel/dmar.c
@@ -1041,7 +1041,7 @@ static int keyp_config_unit_tvm_usable(union acpi_subtable_headers *header,
        int *tvm_usable = arg;

        if (acpi_cu->flags & ACPI_KEYP_F_TVM_USABLE)
-               *tvm_usable = true;
+               *tvm_usable = 1;

        return 0;
 }
@@ -1053,15 +1053,15 @@ static bool platform_is_tdxc_enhanced(void)

        /* only need to parse once */
        if (tvm_usable != -1)
-               return tvm_usable;
+               return !!tvm_usable;

-       tvm_usable = false;
+       tvm_usable = 0;
        ret = acpi_table_parse_keyp(ACPI_KEYP_TYPE_CONFIG_UNIT,
                                    keyp_config_unit_tvm_usable, &tvm_usable);
        if (ret < 0)
-               tvm_usable = false;
+               tvm_usable = 0;

-       return tvm_usable;
+       return !!tvm_usable;
 }


> 
> 
> 

^ permalink raw reply related

* Re: [PATCH v1 11/26] iommu/vt-d: Cache max domain ID to avoid redundant calculation
From: Xu Yilun @ 2025-12-23 10:09 UTC (permalink / raw)
  To: Jonathan Cameron
  Cc: linux-coco, linux-pci, chao.gao, dave.jiang, baolu.lu, yilun.xu,
	zhenzhong.duan, kvm, rick.p.edgecombe, dave.hansen,
	dan.j.williams, kas, x86
In-Reply-To: <20251219115309.00001727@huawei.com>

On Fri, Dec 19, 2025 at 11:53:09AM +0000, Jonathan Cameron wrote:
> On Mon, 17 Nov 2025 10:22:55 +0800
> Xu Yilun <yilun.xu@linux.intel.com> wrote:
> 
> > From: Lu Baolu <baolu.lu@linux.intel.com>
> > 
> > The cap_ndoms() helper calculates the maximum available domain ID from
> > the value of capability register, which can be inefficient if called
> > repeatedly. Cache the maximum supported domain ID in max_domain_id field
> > during initialization to avoid redundant calls to cap_ndoms() throughout
> > the IOMMU driver.
> > 
> > No functionality change.
> > 
> > Signed-off-by: Lu Baolu <baolu.lu@linux.intel.com>
> > Signed-off-by: Dan Williams <dan.j.williams@intel.com>
> Missing sign off of the last person to handle the patch. Xu Yilun.
> That makes this unmergeable :(

Will add my Sign off in v2, thanks.

^ permalink raw reply

* Re: [PATCH v1 06/26] x86/virt/tdx: Add tdx_page_array helpers for new TDX Module objects
From: Xu Yilun @ 2025-12-23 10:07 UTC (permalink / raw)
  To: Jonathan Cameron
  Cc: linux-coco, linux-pci, chao.gao, dave.jiang, baolu.lu, yilun.xu,
	zhenzhong.duan, kvm, rick.p.edgecombe, dave.hansen,
	dan.j.williams, kas, x86
In-Reply-To: <20251219113249.000040b1@huawei.com>

> > +static bool tdx_page_array_validate_release(struct tdx_page_array *array,
> > +					    unsigned int offset,
> > +					    unsigned int nr_released,
> > +					    u64 released_hpa)
> > +{
> > +	unsigned int nents;
> > +	u64 *entries;
> > +	int i;
> > +
> > +	if (offset >= array->nr_pages)
> > +		return false;
> > +
> > +	nents = umin(array->nr_pages - offset, TDX_PAGE_ARRAY_MAX_NENTS);
> > +
> > +	if (nents != nr_released) {
> > +		pr_err("%s nr_released [%d] doesn't match page array nents [%d]\n",
> > +		       __func__, nr_released, nents);
> > +		return false;
> > +	}
> > +
> > +	/*
> > +	 * Unfortunately TDX has multiple page allocation protocols, check the
> > +	 * "singleton" case required for HPA_ARRAY_T.
> > +	 */
> > +	if (page_to_phys(array->pages[0]) == released_hpa &&
> > +	    array->nr_pages == 1)
> > +		return true;
> > +
> > +	/* Then check the "non-singleton" case */
> > +	if (page_to_phys(array->root) == released_hpa) {
> > +		entries = (u64 *)page_address(array->root);
> 
> page_address() returns a void * so the cast here isn't needed and (to me
> at least) doesn't add value from readability point of view.

These casts disappear during the refactoring from alloc_page() to
kzalloc(PAGE_SIZE, ...) for my v2.

> 
> I haven't checked later patches, but if this code doesn't change to use
> entries outside this scope then,
> 		u64 *entries = page_address(array->root);
> would be nice to restrict the scope and make the type here immediately
> visible.

Yes. Also for int i.

Thanks,
Yilun

> 
> > +		for (i = 0; i < nents; i++) {
> > +			struct page *page = array->pages[offset + i];
> > +			u64 val = page_to_phys(page);
> > +
> > +			if (val != entries[i]) {
> > +				pr_err("%s entry[%d] [0x%llx] doesn't match page hpa [0x%llx]\n",
> > +				       __func__, i, entries[i], val);
> > +				return false;
> > +			}
> > +		}
> > +
> > +		return true;
> > +	}
> > +
> > +	pr_err("%s failed to validate, released_hpa [0x%llx], root page hpa [0x%llx], page0 hpa [%#llx], number pages %u\n",
> > +	       __func__, released_hpa, page_to_phys(array->root),
> > +	       page_to_phys(array->pages[0]), array->nr_pages);
> > +
> > +	return false;
> > +}
> 
> 

^ permalink raw reply

* Re: [PATCH v1 05/26] mm: Add __free() support for __free_page()
From: Xu Yilun @ 2025-12-23  9:41 UTC (permalink / raw)
  To: Jonathan Cameron
  Cc: linux-coco, linux-pci, chao.gao, dave.jiang, baolu.lu, yilun.xu,
	zhenzhong.duan, kvm, rick.p.edgecombe, dave.hansen,
	dan.j.williams, kas, x86
In-Reply-To: <20251219112220.00003adc@huawei.com>

On Fri, Dec 19, 2025 at 11:22:20AM +0000, Jonathan Cameron wrote:
> On Mon, 17 Nov 2025 10:22:49 +0800
> Xu Yilun <yilun.xu@linux.intel.com> wrote:
> 
> > Allow for the declaration of struct page * variables that trigger
> > __free_page() when they go out of scope.
> > 
> > Signed-off-by: Xu Yilun <yilun.xu@linux.intel.com>
> 
> Reviewed-by: Jonathan Cameron <jonathan.cameron@huawei.com>

Sorry I will drop this patch on v2 cause I'll use

  kzalloc(PAGE_SIZE, ...) for all single page allocation in this series.

Thanks,
Yilun

^ permalink raw reply

* [PATCH] PCI/IDE: Fix duplicate stream symlink names for TSM class devices
From: Xu Yilun @ 2025-12-23  8:56 UTC (permalink / raw)
  To: linux-coco, linux-pci, dan.j.williams
  Cc: yilun.xu, yilun.xu, baolu.lu, zhenzhong.duan, linux-kernel,
	yi1.lai

The symlink name streamH.R.E is unique within a specific host bridge but
not across the system. Error occurs e.g. when creating the first stream
on a second host bridge:

[ 1244.034755] sysfs: cannot create duplicate filename '/devices/faux/tdx_host/tsm/tsm0/stream0.0.0'

Fix this by adding host bridge name into symlink name for TSM class
devices. It should be OK to change the uAPI to
/sys/class/tsm/tsmN/pciDDDD:BB:streamH.R.E since it's new and has few
users.

Internally in the IDE library, store the full name in struct pci_ide
so TSM symlinks can use it directly, while PCI host bridge symlinks
can skip the host bridge name to keep concise.

Fixes: a4438f06b1db ("PCI/TSM: Report active IDE streams")
Reported-by: Yi Lai <yi1.lai@intel.com>
Signed-off-by: Xu Yilun <yilun.xu@linux.intel.com>
---
 Documentation/ABI/testing/sysfs-class-tsm |  2 +-
 drivers/pci/ide.c                         | 12 +++++++++---
 2 files changed, 10 insertions(+), 4 deletions(-)

diff --git a/Documentation/ABI/testing/sysfs-class-tsm b/Documentation/ABI/testing/sysfs-class-tsm
index 6fc1a5ac6da1..eff71e42c60e 100644
--- a/Documentation/ABI/testing/sysfs-class-tsm
+++ b/Documentation/ABI/testing/sysfs-class-tsm
@@ -8,7 +8,7 @@ Description:
 		link encryption and other device-security features coordinated
 		through a platform tsm.
 
-What:		/sys/class/tsm/tsmN/streamH.R.E
+What:		/sys/class/tsm/tsmN/pciDDDD:BB:streamH.R.E
 Contact:	linux-pci@vger.kernel.org
 Description:
 		(RO) When a host bridge has established a secure connection via
diff --git a/drivers/pci/ide.c b/drivers/pci/ide.c
index f0ef474e1a0d..db1c7423bf39 100644
--- a/drivers/pci/ide.c
+++ b/drivers/pci/ide.c
@@ -425,6 +425,7 @@ int pci_ide_stream_register(struct pci_ide *ide)
 	struct pci_host_bridge *hb = pci_find_host_bridge(pdev->bus);
 	struct pci_ide_stream_id __sid;
 	u8 ep_stream, rp_stream;
+	const char *short_name;
 	int rc;
 
 	if (ide->stream_id < 0 || ide->stream_id > U8_MAX) {
@@ -441,13 +442,16 @@ int pci_ide_stream_register(struct pci_ide *ide)
 
 	ep_stream = ide->partner[PCI_IDE_EP].stream_index;
 	rp_stream = ide->partner[PCI_IDE_RP].stream_index;
-	const char *name __free(kfree) = kasprintf(GFP_KERNEL, "stream%d.%d.%d",
+	const char *name __free(kfree) = kasprintf(GFP_KERNEL, "%s:stream%d.%d.%d",
+						   dev_name(&hb->dev),
 						   ide->host_bridge_stream,
 						   rp_stream, ep_stream);
 	if (!name)
 		return -ENOMEM;
 
-	rc = sysfs_create_link(&hb->dev.kobj, &pdev->dev.kobj, name);
+	/* Skip host bridge name in the host bridge context */
+	short_name = name + strlen(dev_name(&hb->dev)) + 1;
+	rc = sysfs_create_link(&hb->dev.kobj, &pdev->dev.kobj, short_name);
 	if (rc)
 		return rc;
 
@@ -471,8 +475,10 @@ void pci_ide_stream_unregister(struct pci_ide *ide)
 {
 	struct pci_dev *pdev = ide->pdev;
 	struct pci_host_bridge *hb = pci_find_host_bridge(pdev->bus);
+	const char *short_name;
 
-	sysfs_remove_link(&hb->dev.kobj, ide->name);
+	short_name = ide->name + strlen(dev_name(&hb->dev)) + 1;
+	sysfs_remove_link(&hb->dev.kobj, short_name);
 	kfree(ide->name);
 	ida_free(&hb->ide_stream_ids_ida, ide->stream_id);
 	ide->name = NULL;

base-commit: 8f0b4cce4481fb22653697cced8d0d04027cb1e8
-- 
2.25.1


^ permalink raw reply related

* Re: [PATCH v2 4/4] dma: direct: set decrypted flag for remapped dma allocations
From: Aneesh Kumar K.V @ 2025-12-23  8:18 UTC (permalink / raw)
  To: Suzuki K Poulose, linux-kernel, iommu, linux-coco
  Cc: Catalin Marinas, will, maz, tglx, robin.murphy, akpm, jgg,
	steven.price
In-Reply-To: <5820e8f3-9cf8-423f-89df-0df7ca78a84b@arm.com>

Suzuki K Poulose <suzuki.poulose@arm.com> writes:

> On 21/12/2025 16:09, Aneesh Kumar K.V (Arm) wrote:
>> Devices that are DMA non-coherent and need a remap were skipping
>> dma_set_decrypted(), leaving buffers encrypted even when the device
>> requires unencrypted access. Move the call after the remap
>> branch so both paths mark the allocation decrypted (or fail cleanly)
>> before use.
>> 
>> Fixes: f3c962226dbe ("dma-direct: clean up the remapping checks in dma_direct_alloc")
>> Signed-off-by: Aneesh Kumar K.V (Arm) <aneesh.kumar@kernel.org>
>> ---
>>   kernel/dma/direct.c | 8 +++-----
>>   1 file changed, 3 insertions(+), 5 deletions(-)
>> 
>> diff --git a/kernel/dma/direct.c b/kernel/dma/direct.c
>> index 3448d877c7c6..a62dc25524cc 100644
>> --- a/kernel/dma/direct.c
>> +++ b/kernel/dma/direct.c
>> @@ -271,9 +271,6 @@ void *dma_direct_alloc(struct device *dev, size_t size,
>>   	if (remap) {
>>   		pgprot_t prot = dma_pgprot(dev, PAGE_KERNEL, attrs);
>>   
>> -		if (force_dma_unencrypted(dev))
>> -			prot = pgprot_decrypted(prot);
>
> This would be problematic, isn't it ? We don't support decrypted on a
> vmap area for arm64. If we move this down, we might actually use the
> vmapped area. Not sure if other archs are fine with "decrypting" a
> "vmap" address.
>
> If we map the "vmap" address with pgprot_decrypted, we could go ahead
> and further map the linear map (i.e., page_address(page)) decrypted
> and get everything working.

We still have the problem w.r.t free

dma_direct_free():

	if (is_vmalloc_addr(cpu_addr)) {
		vunmap(cpu_addr);
	} else {
		if (dma_set_encrypted(dev, cpu_addr, size))
			return;
	}

-aneesh

^ permalink raw reply

* [PATCH 0/8] KVM: VMX: Introduce Intel Mode-Based Execute Control (MBEC)
From: Jon Kohler @ 2025-12-23  5:47 UTC (permalink / raw)
  To: seanjc, pbonzini, tglx, mingo, bp, dave.hansen, x86, hpa, kvm,
	linux-kernel, Kiryl Shutsemau, Rick Edgecombe,
	open list:X86 TRUST DOMAIN EXTENSIONS (TDX):Keyword:b(tdx)
  Cc: ken, Alexander.Grest, chao.gao, madvenka, mic, nsaenz, tao1.su,
	xiaoyao.li, zhao1.liu, Jon Kohler

## Summary
This series introduces support for Intel Mode-Based Execute Control
(MBEC) to KVM and nested VMX virtualization. By exposing MBEC to L2
guests, it enables a dramatic reduction in VMexits (up to 24x) for
Windows guests running with Hypervisor-Protected Code Integrity (HVCI),
significantly improving virtualization performance.

## What?
Intel MBEC is a hardware feature, introduced in the Kabylake
generation, that allows for more granular control over execution
permissions. MBEC enables the separation and tracking of execution
permissions for supervisor (kernel) and user-mode code. It is used as
an accelerator for Microsoft's Memory Integrity [1] (also known as
hypervisor-protected code integrity or HVCI).

## Why?
The primary reason for this feature is performance.

Without hardware-level MBEC, enabling Windows HVCI runs a 'software
MBEC' known as Restricted User Mode, which imposes a runtime overhead
due to increased state transitions between the guest's L2 root
partition and the L2 secure partition for running kernel mode code
integrity operations.

In practice, this results in a significant number of exits. For
example, playing a YouTube video within the Edge Browser produces
roughly 1.2 million VMexits/second across an 8 vCPU Windows 11 guest.

Most of these exits are VMREAD/VMWRITE operations, which can be
emulated with Enlightened VMCS (eVMCS). However, even with eVMCS, this
configuration still produces around 200,000 VMexits/second.

With MBEC exposed to the L1 Windows Hypervisor, the same scenario
results in approximately 50,000 VMexits/second, a *24x* reduction from
the baseline.

Not a typo, 24x reduction in VMexits.

## How?
This series implements core KVM support for exposing the MBEC bit in
secondary execution controls (bit 22) to L2 nested guests, based on
configuration from user space. The inspiration for this series started
with Mickaël's series for Heki [3], where we've extracted, refactored,
and completely reworked the MBEC-specific use case to be general-purpose.

MBEC splits the EPT execute permission into two independent bits. When
secondary execution control bit 22 ("mode-based execute control for EPT")
is set for the L2 guest, EPT PTE bit 2 controls execute permission for
supervisor-mode linear addresses, while bit 10 controls execute permission
for user-mode linear addresses.

The semantics for EPT violation qualifications also change when MBEC
is enabled, with bit 5 reflecting supervisor/kernel mode execute
permissions and bit 6 reflecting user mode execute permissions.
This ultimately serves to expose this feature to the L1 hypervisor,
which consumes MBEC and informs the L2 partitions not to use the
software MBEC by removing bit 13 in 0x40000004 EAX [4].

## Where?
The implementation spans multiple components:
- KVM MMU code: Teach the shadow MMU about MBEC execution modes
- KVM VMX code: Handle EPT violations and VMX controls for MBEC
- User space VMM: Pass secondary execution control bit 22 to enable MBEC
  for L2 guests 

A trivial enablement patch for QEMU enablement is available [5].

A GitHub mirror of this series is also available [6].

## Performance Impact
Testing shows dramatic performance improvements for Windows HVCI workloads:
- 24x reduction in VMexits for typical browser usage
- From ~1.2M VMexits/second to ~50K VMexits/second
- Enables hardware acceleration of Windows Memory Integrity

The implementation adds minimal overhead when MBEC is not used, especially
when combined with EVMCS to elide nested VMREAD/VMWRITE vmexits.

## Testing
Initial testing has been on done on 6.18-based code with:
  Guests
    - Windows 11 24H2 26100.2894
    - Windows Server 2025 24H2 26100.2894
    - Windows Server 2022 W1H2 20348.825
  Processors:
    - Intel Skylake 6154
    - Intel Sapphire Rapids 6444Y
  Unit Tests
    - KVM Unit Tests [7]

## Changelog
RFC -> V1:
- Fix incorrect bit reference in cover letter (Adrian-Ken)
- Remove module parameters (Sean, Amit)
- Remove redundant arch-level tracking boolean (Sean)
- Update is_present_gpte to account for MBEC bit 10 (Chao)
- Move MBEC enablement tracking to MMU role (Sean)
- Restrict MBEC advertisement to nested virtualization only (Sean)
- Consolidate preparatory patches into main implementation (Sean)
- Add permission mask refactoring preparation (Sean)
- Implement TDP-aware executable permission checking (Sean)

[1] https://learn.microsoft.com/en-us/windows/security/hardware-security/enable-virtualization-based-protection-of-code-integrity
[2] https://learn.microsoft.com/en-us/virtualization/hyper-v-on-windows/tlfs/nested-virtualization#enlightened-vmcs-intel
[3] https://patchwork.kernel.org/project/kvm/patch/20231113022326.24388-6-mic@digikod.net/
[4] https://learn.microsoft.com/en-us/virtualization/hyper-v-on-windows/tlfs/feature-discovery#implementation-recommendations---0x40000004
[5] https://github.com/JonKohler/qemu/tree/mbec-v1
[6] https://github.com/JonKohler/linux/tree/mbec-v1-6.18
[7] https://github.com/JonKohler/kvm-unit-tests/tree/mbec-v1

Cc: "Adrian-Ken Rueegsegger" <ken@codelabs.ch>
Cc: "Alexander Grest" <Alexander.Grest@microsoft.com>
Cc: "Chao Gao" <chao.gao@intel.com>
Cc: "Madhavan T . Venkataraman" <madvenka@linux.microsoft.com>
Cc: "Mickaël Salaün" <mic@digikod.net>
Cc: "Nicolas Saenz Julienne" <nsaenz@amazon.es>
Cc: "Tao Su" <tao1.su@linux.intel.com>
Cc: "Xiaoyao Li" <xiaoyao.li@intel.com>
Cc: "Zhao Liu" <zhao1.liu@intel.com>

Jon Kohler (8):
  KVM: TDX/VMX: rework EPT_VIOLATION_EXEC_FOR_RING3_LIN into PROT_MASK
  KVM: x86/mmu: remove SPTE_PERM_MASK
  KVM: x86/mmu: adjust MMIO generation bit allocation and allowed mask
  KVM: x86/mmu: update access permissions from ACC_ALL to ACC_RWX
  KVM: x86/mmu: bootstrap support for Intel MBEC
  KVM: VMX: enhance EPT violation handler for MBEC
  KVM: VMX: allow MBEC with EVMCS
  KVM: nVMX: advertise MBEC and setup mmu has_mbec

 Documentation/virt/kvm/x86/mmu.rst |  9 +++-
 arch/x86/include/asm/kvm_host.h    | 19 +++++---
 arch/x86/include/asm/vmx.h         |  9 +++-
 arch/x86/kvm/mmu.h                 | 15 +++++-
 arch/x86/kvm/mmu/mmu.c             | 74 ++++++++++++++++++++++++++--
 arch/x86/kvm/mmu/mmutrace.h        | 23 ++++++---
 arch/x86/kvm/mmu/paging_tmpl.h     | 24 ++++++---
 arch/x86/kvm/mmu/spte.c            | 65 +++++++++++++++++++------
 arch/x86/kvm/mmu/spte.h            | 78 ++++++++++++++++++++++++------
 arch/x86/kvm/mmu/tdp_mmu.c         | 12 +++--
 arch/x86/kvm/vmx/capabilities.h    |  6 +++
 arch/x86/kvm/vmx/common.h          | 15 ++++--
 arch/x86/kvm/vmx/hyperv_evmcs.h    |  1 +
 arch/x86/kvm/vmx/nested.c          |  6 +++
 arch/x86/kvm/vmx/tdx.c             |  2 +-
 arch/x86/kvm/vmx/vmx.c             | 10 +++-
 arch/x86/kvm/vmx/vmx.h             |  1 +
 17 files changed, 301 insertions(+), 68 deletions(-)

-- 
2.43.0


^ permalink raw reply

* [PATCH 1/8] KVM: TDX/VMX: rework EPT_VIOLATION_EXEC_FOR_RING3_LIN into PROT_MASK
From: Jon Kohler @ 2025-12-23  5:47 UTC (permalink / raw)
  To: seanjc, pbonzini, tglx, mingo, bp, dave.hansen, x86, hpa, kvm,
	linux-kernel, Kiryl Shutsemau, Rick Edgecombe,
	open list:X86 TRUST DOMAIN EXTENSIONS (TDX)
  Cc: ken, Alexander.Grest, chao.gao, madvenka, mic, nsaenz, tao1.su,
	xiaoyao.li, zhao1.liu, Jon Kohler
In-Reply-To: <20251223054806.1611168-1-jon@nutanix.com>

EPT exit qualification bit 6 is used when mode-based execute control
is enabled, and reflects user executable addresses. Rework name to
reflect the intention and add to EPT_VIOLATION_PROT_MASK, which allows
simplifying the return evaluation in
tdx_is_sept_violation_unexpected_pending a pinch.

Rework handling in __vmx_handle_ept_violation to unconditionally clear
EPT_VIOLATION_PROT_USER_EXEC until MBEC is implemented, as suggested by
Sean [1].

Note: Intel SDM Table 29-7 defines bit 6 as:
  If the “mode-based execute control” VM-execution control is 0, the
  value of this bit is undefined. If that control is 1, this bit is the
  logical-AND of bit 10 in the EPT paging-structure entries used to
  translate the guest-physical address of the access causing the EPT
  violation. In this case, it indicates whether the guest-physical
  address was executable for user-mode linear addresses.

[1] https://lore.kernel.org/all/aCJDzU1p_SFNRIJd@google.com/

Suggested-by: Sean Christopherson <seanjc@google.com>
Signed-off-by: Jon Kohler <jon@nutanix.com>
---
 arch/x86/include/asm/vmx.h | 5 +++--
 arch/x86/kvm/vmx/common.h  | 9 +++++++--
 arch/x86/kvm/vmx/tdx.c     | 2 +-
 3 files changed, 11 insertions(+), 5 deletions(-)

diff --git a/arch/x86/include/asm/vmx.h b/arch/x86/include/asm/vmx.h
index c85c50019523..de3abec84fe5 100644
--- a/arch/x86/include/asm/vmx.h
+++ b/arch/x86/include/asm/vmx.h
@@ -596,10 +596,11 @@ enum vm_entry_failure_code {
 #define EPT_VIOLATION_PROT_READ		BIT(3)
 #define EPT_VIOLATION_PROT_WRITE	BIT(4)
 #define EPT_VIOLATION_PROT_EXEC		BIT(5)
-#define EPT_VIOLATION_EXEC_FOR_RING3_LIN BIT(6)
+#define EPT_VIOLATION_PROT_USER_EXEC	BIT(6)
 #define EPT_VIOLATION_PROT_MASK		(EPT_VIOLATION_PROT_READ  | \
 					 EPT_VIOLATION_PROT_WRITE | \
-					 EPT_VIOLATION_PROT_EXEC)
+					 EPT_VIOLATION_PROT_EXEC  | \
+					 EPT_VIOLATION_PROT_USER_EXEC)
 #define EPT_VIOLATION_GVA_IS_VALID	BIT(7)
 #define EPT_VIOLATION_GVA_TRANSLATED	BIT(8)
 
diff --git a/arch/x86/kvm/vmx/common.h b/arch/x86/kvm/vmx/common.h
index 412d0829d7a2..adf925500b9e 100644
--- a/arch/x86/kvm/vmx/common.h
+++ b/arch/x86/kvm/vmx/common.h
@@ -94,8 +94,13 @@ static inline int __vmx_handle_ept_violation(struct kvm_vcpu *vcpu, gpa_t gpa,
 	/* Is it a fetch fault? */
 	error_code |= (exit_qualification & EPT_VIOLATION_ACC_INSTR)
 		      ? PFERR_FETCH_MASK : 0;
-	/* ept page table entry is present? */
-	error_code |= (exit_qualification & EPT_VIOLATION_PROT_MASK)
+	/*
+	 * ept page table entry is present?
+	 * note: unconditionally clear USER_EXEC until mode-based
+	 * execute control is implemented
+	 */
+	error_code |= (exit_qualification &
+		       (EPT_VIOLATION_PROT_MASK & ~EPT_VIOLATION_PROT_USER_EXEC))
 		      ? PFERR_PRESENT_MASK : 0;
 
 	if (exit_qualification & EPT_VIOLATION_GVA_IS_VALID)
diff --git a/arch/x86/kvm/vmx/tdx.c b/arch/x86/kvm/vmx/tdx.c
index 0a49c863c811..61185c30a40e 100644
--- a/arch/x86/kvm/vmx/tdx.c
+++ b/arch/x86/kvm/vmx/tdx.c
@@ -1922,7 +1922,7 @@ static inline bool tdx_is_sept_violation_unexpected_pending(struct kvm_vcpu *vcp
 	if (eeq_type != TDX_EXT_EXIT_QUAL_TYPE_PENDING_EPT_VIOLATION)
 		return false;
 
-	return !(eq & EPT_VIOLATION_PROT_MASK) && !(eq & EPT_VIOLATION_EXEC_FOR_RING3_LIN);
+	return !(eq & EPT_VIOLATION_PROT_MASK);
 }
 
 static int tdx_handle_ept_violation(struct kvm_vcpu *vcpu)
-- 
2.43.0


^ permalink raw reply related

* Re: [PATCH v2 1/4] swiotlb: dma: its: Enforce host page-size alignment for shared buffers
From: Aneesh Kumar K.V @ 2025-12-22 15:42 UTC (permalink / raw)
  To: Steven Price, linux-kernel, iommu, linux-coco
  Cc: Catalin Marinas, will, maz, tglx, robin.murphy, suzuki.poulose,
	akpm, jgg
In-Reply-To: <4a34ed21-f1e0-4991-a367-d6d2f9ad705f@arm.com>

Steven Price <steven.price@arm.com> writes:

> On 21/12/2025 16:09, Aneesh Kumar K.V (Arm) wrote:
>> When running private-memory guests, the guest kernel must apply
>> additional constraints when allocating buffers that are shared with the
>> hypervisor.
>> 
>> These shared buffers are also accessed by the host kernel and therefore
>> must be aligned to the host’s page size.
>> 
>> On non-secure hosts, set_guest_memory_attributes() tracks memory at the
>> host PAGE_SIZE granularity. This creates a mismatch when the guest
>> applies attributes at 4K boundaries while the host uses 64K pages. In
>> such cases, the call returns -EINVAL, preventing the conversion of
>> memory regions from private to shared.
>> 
>> Architectures such as Arm can tolerate realm physical address space PFNs
>> being mapped as shared memory, as incorrect accesses are detected and
>> reported as GPC faults. However, relying on this mechanism is unsafe and
>> can still lead to kernel crashes.
>> 
>> This is particularly likely when guest_memfd allocations are mmapped and
>> accessed from userspace. Once exposed to userspace, we cannot guarantee
>> that applications will only access the intended 4K shared region rather
>> than the full 64K page mapped into their address space. Such userspace
>> addresses may also be passed back into the kernel and accessed via the
>> linear map, resulting in a GPC fault and a kernel crash.
>> 
>> With CCA, although Stage-2 mappings managed by the RMM still operate at
>> a 4K granularity, shared pages must nonetheless be aligned to the
>> host-managed page size to avoid the issues described above.
>> 
>> Introduce a new helper, mem_encryp_align(), to allow callers to enforce
>> the required alignment for shared buffers.
>> 
>> The architecture-specific implementation of mem_encrypt_align() will be
>> provided in a follow-up patch.
>> 
>> Signed-off-by: Aneesh Kumar K.V (Arm) <aneesh.kumar@kernel.org>
>> ---
>>  arch/arm64/include/asm/mem_encrypt.h |  6 ++++++
>>  arch/arm64/mm/mem_encrypt.c          |  6 ++++++
>>  drivers/irqchip/irq-gic-v3-its.c     |  7 ++++---
>>  include/linux/mem_encrypt.h          |  7 +++++++
>>  kernel/dma/contiguous.c              | 10 ++++++++++
>>  kernel/dma/direct.c                  |  6 ++++++
>>  kernel/dma/pool.c                    |  6 ++++--
>>  kernel/dma/swiotlb.c                 | 18 ++++++++++++------
>>  8 files changed, 55 insertions(+), 11 deletions(-)
>> 
>> diff --git a/arch/arm64/include/asm/mem_encrypt.h b/arch/arm64/include/asm/mem_encrypt.h
>> index d77c10cd5b79..b7ac143b81ce 100644
>> --- a/arch/arm64/include/asm/mem_encrypt.h
>> +++ b/arch/arm64/include/asm/mem_encrypt.h
>> @@ -17,6 +17,12 @@ int set_memory_encrypted(unsigned long addr, int numpages);
>>  int set_memory_decrypted(unsigned long addr, int numpages);
>>  bool force_dma_unencrypted(struct device *dev);
>>  
>> +#define mem_encrypt_align mem_encrypt_align
>> +static inline size_t mem_encrypt_align(size_t size)
>> +{
>> +	return size;
>> +}
>> +
>>  int realm_register_memory_enc_ops(void);
>>  
>>  /*
>> diff --git a/arch/arm64/mm/mem_encrypt.c b/arch/arm64/mm/mem_encrypt.c
>> index 645c099fd551..deb364eadd47 100644
>> --- a/arch/arm64/mm/mem_encrypt.c
>> +++ b/arch/arm64/mm/mem_encrypt.c
>> @@ -46,6 +46,12 @@ int set_memory_decrypted(unsigned long addr, int numpages)
>>  	if (likely(!crypt_ops) || WARN_ON(!PAGE_ALIGNED(addr)))
>>  		return 0;
>>  
>> +	if (WARN_ON(!IS_ALIGNED(addr, mem_encrypt_align(PAGE_SIZE))))
>> +		return 0;
>> +
>> +	if (WARN_ON(!IS_ALIGNED(numpages << PAGE_SHIFT, mem_encrypt_align(PAGE_SIZE))))
>> +		return 0;
>> +
>>  	return crypt_ops->decrypt(addr, numpages);
>>  }
>>  EXPORT_SYMBOL_GPL(set_memory_decrypted);
>> diff --git a/drivers/irqchip/irq-gic-v3-its.c b/drivers/irqchip/irq-gic-v3-its.c
>> index 467cb78435a9..ffb8ef3a1eb3 100644
>> --- a/drivers/irqchip/irq-gic-v3-its.c
>> +++ b/drivers/irqchip/irq-gic-v3-its.c
>> @@ -213,16 +213,17 @@ static gfp_t gfp_flags_quirk;
>>  static struct page *its_alloc_pages_node(int node, gfp_t gfp,
>>  					 unsigned int order)
>>  {
>> +	unsigned int new_order;
>>  	struct page *page;
>>  	int ret = 0;
>>  
>> -	page = alloc_pages_node(node, gfp | gfp_flags_quirk, order);
>> -
>> +	new_order = get_order(mem_encrypt_align((PAGE_SIZE << order)));
>> +	page = alloc_pages_node(node, gfp | gfp_flags_quirk, new_order);
>>  	if (!page)
>>  		return NULL;
>>  
>>  	ret = set_memory_decrypted((unsigned long)page_address(page),
>> -				   1 << order);
>> +				   1 << new_order);
>>  	/*
>>  	 * If set_memory_decrypted() fails then we don't know what state the
>>  	 * page is in, so we can't free it. Instead we leak it.
>
> Don't you also need to update its_free_pages() in a similar manner so
> that the set_memory_encrypted()/free_pages() calls are done with the
> same order argument?
>

Yes, agreed — good point. The free path needs to mirror the allocation
path, so its_free_pages() should use the same order when calling
set_memory_encrypted()/decrypted() and free_pages(). I’ll update it
accordingly to keep the behavior symmetric and consistent. I also
noticed that swiotlb also need similar change.

-aneesh


^ permalink raw reply

* Re: [PATCH v2 4/4] dma: direct: set decrypted flag for remapped dma allocations
From: Suzuki K Poulose @ 2025-12-22 15:05 UTC (permalink / raw)
  To: Aneesh Kumar K.V (Arm), linux-kernel, iommu, linux-coco
  Cc: Catalin Marinas, will, maz, tglx, robin.murphy, akpm, jgg,
	steven.price
In-Reply-To: <20251221160920.297689-5-aneesh.kumar@kernel.org>

On 21/12/2025 16:09, Aneesh Kumar K.V (Arm) wrote:
> Devices that are DMA non-coherent and need a remap were skipping
> dma_set_decrypted(), leaving buffers encrypted even when the device
> requires unencrypted access. Move the call after the remap
> branch so both paths mark the allocation decrypted (or fail cleanly)
> before use.
> 
> Fixes: f3c962226dbe ("dma-direct: clean up the remapping checks in dma_direct_alloc")
> Signed-off-by: Aneesh Kumar K.V (Arm) <aneesh.kumar@kernel.org>
> ---
>   kernel/dma/direct.c | 8 +++-----
>   1 file changed, 3 insertions(+), 5 deletions(-)
> 
> diff --git a/kernel/dma/direct.c b/kernel/dma/direct.c
> index 3448d877c7c6..a62dc25524cc 100644
> --- a/kernel/dma/direct.c
> +++ b/kernel/dma/direct.c
> @@ -271,9 +271,6 @@ void *dma_direct_alloc(struct device *dev, size_t size,
>   	if (remap) {
>   		pgprot_t prot = dma_pgprot(dev, PAGE_KERNEL, attrs);
>   
> -		if (force_dma_unencrypted(dev))
> -			prot = pgprot_decrypted(prot);

This would be problematic, isn't it ? We don't support decrypted on a
vmap area for arm64. If we move this down, we might actually use the
vmapped area. Not sure if other archs are fine with "decrypting" a
"vmap" address.

If we map the "vmap" address with pgprot_decrypted, we could go ahead
and further map the linear map (i.e., page_address(page)) decrypted
and get everything working.

Suzuki


> -
>   		/* remove any dirty cache lines on the kernel alias */
>   		arch_dma_prep_coherent(page, size);
>   
> @@ -284,10 +281,11 @@ void *dma_direct_alloc(struct device *dev, size_t size,
>   			goto out_free_pages;
>   	} else {
>   		ret = page_address(page);
> -		if (dma_set_decrypted(dev, ret, size))
> -			goto out_leak_pages;
>   	}
>   
> +	if (dma_set_decrypted(dev, ret, size))
> +		goto out_leak_pages;
> +
>   	memset(ret, 0, size);
>   
>   	if (set_uncached) {


^ permalink raw reply

* Re: [PATCH v2 1/4] swiotlb: dma: its: Enforce host page-size alignment for shared buffers
From: Steven Price @ 2025-12-22 14:49 UTC (permalink / raw)
  To: Aneesh Kumar K.V (Arm), linux-kernel, iommu, linux-coco
  Cc: Catalin Marinas, will, maz, tglx, robin.murphy, suzuki.poulose,
	akpm, jgg
In-Reply-To: <20251221160920.297689-2-aneesh.kumar@kernel.org>

On 21/12/2025 16:09, Aneesh Kumar K.V (Arm) wrote:
> When running private-memory guests, the guest kernel must apply
> additional constraints when allocating buffers that are shared with the
> hypervisor.
> 
> These shared buffers are also accessed by the host kernel and therefore
> must be aligned to the host’s page size.
> 
> On non-secure hosts, set_guest_memory_attributes() tracks memory at the
> host PAGE_SIZE granularity. This creates a mismatch when the guest
> applies attributes at 4K boundaries while the host uses 64K pages. In
> such cases, the call returns -EINVAL, preventing the conversion of
> memory regions from private to shared.
> 
> Architectures such as Arm can tolerate realm physical address space PFNs
> being mapped as shared memory, as incorrect accesses are detected and
> reported as GPC faults. However, relying on this mechanism is unsafe and
> can still lead to kernel crashes.
> 
> This is particularly likely when guest_memfd allocations are mmapped and
> accessed from userspace. Once exposed to userspace, we cannot guarantee
> that applications will only access the intended 4K shared region rather
> than the full 64K page mapped into their address space. Such userspace
> addresses may also be passed back into the kernel and accessed via the
> linear map, resulting in a GPC fault and a kernel crash.
> 
> With CCA, although Stage-2 mappings managed by the RMM still operate at
> a 4K granularity, shared pages must nonetheless be aligned to the
> host-managed page size to avoid the issues described above.
> 
> Introduce a new helper, mem_encryp_align(), to allow callers to enforce
> the required alignment for shared buffers.
> 
> The architecture-specific implementation of mem_encrypt_align() will be
> provided in a follow-up patch.
> 
> Signed-off-by: Aneesh Kumar K.V (Arm) <aneesh.kumar@kernel.org>
> ---
>  arch/arm64/include/asm/mem_encrypt.h |  6 ++++++
>  arch/arm64/mm/mem_encrypt.c          |  6 ++++++
>  drivers/irqchip/irq-gic-v3-its.c     |  7 ++++---
>  include/linux/mem_encrypt.h          |  7 +++++++
>  kernel/dma/contiguous.c              | 10 ++++++++++
>  kernel/dma/direct.c                  |  6 ++++++
>  kernel/dma/pool.c                    |  6 ++++--
>  kernel/dma/swiotlb.c                 | 18 ++++++++++++------
>  8 files changed, 55 insertions(+), 11 deletions(-)
> 
> diff --git a/arch/arm64/include/asm/mem_encrypt.h b/arch/arm64/include/asm/mem_encrypt.h
> index d77c10cd5b79..b7ac143b81ce 100644
> --- a/arch/arm64/include/asm/mem_encrypt.h
> +++ b/arch/arm64/include/asm/mem_encrypt.h
> @@ -17,6 +17,12 @@ int set_memory_encrypted(unsigned long addr, int numpages);
>  int set_memory_decrypted(unsigned long addr, int numpages);
>  bool force_dma_unencrypted(struct device *dev);
>  
> +#define mem_encrypt_align mem_encrypt_align
> +static inline size_t mem_encrypt_align(size_t size)
> +{
> +	return size;
> +}
> +
>  int realm_register_memory_enc_ops(void);
>  
>  /*
> diff --git a/arch/arm64/mm/mem_encrypt.c b/arch/arm64/mm/mem_encrypt.c
> index 645c099fd551..deb364eadd47 100644
> --- a/arch/arm64/mm/mem_encrypt.c
> +++ b/arch/arm64/mm/mem_encrypt.c
> @@ -46,6 +46,12 @@ int set_memory_decrypted(unsigned long addr, int numpages)
>  	if (likely(!crypt_ops) || WARN_ON(!PAGE_ALIGNED(addr)))
>  		return 0;
>  
> +	if (WARN_ON(!IS_ALIGNED(addr, mem_encrypt_align(PAGE_SIZE))))
> +		return 0;
> +
> +	if (WARN_ON(!IS_ALIGNED(numpages << PAGE_SHIFT, mem_encrypt_align(PAGE_SIZE))))
> +		return 0;
> +
>  	return crypt_ops->decrypt(addr, numpages);
>  }
>  EXPORT_SYMBOL_GPL(set_memory_decrypted);
> diff --git a/drivers/irqchip/irq-gic-v3-its.c b/drivers/irqchip/irq-gic-v3-its.c
> index 467cb78435a9..ffb8ef3a1eb3 100644
> --- a/drivers/irqchip/irq-gic-v3-its.c
> +++ b/drivers/irqchip/irq-gic-v3-its.c
> @@ -213,16 +213,17 @@ static gfp_t gfp_flags_quirk;
>  static struct page *its_alloc_pages_node(int node, gfp_t gfp,
>  					 unsigned int order)
>  {
> +	unsigned int new_order;
>  	struct page *page;
>  	int ret = 0;
>  
> -	page = alloc_pages_node(node, gfp | gfp_flags_quirk, order);
> -
> +	new_order = get_order(mem_encrypt_align((PAGE_SIZE << order)));
> +	page = alloc_pages_node(node, gfp | gfp_flags_quirk, new_order);
>  	if (!page)
>  		return NULL;
>  
>  	ret = set_memory_decrypted((unsigned long)page_address(page),
> -				   1 << order);
> +				   1 << new_order);
>  	/*
>  	 * If set_memory_decrypted() fails then we don't know what state the
>  	 * page is in, so we can't free it. Instead we leak it.

Don't you also need to update its_free_pages() in a similar manner so
that the set_memory_encrypted()/free_pages() calls are done with the
same order argument?

Thanks,
Steve

> diff --git a/include/linux/mem_encrypt.h b/include/linux/mem_encrypt.h
> index 07584c5e36fb..a0b9f6fe5d1a 100644
> --- a/include/linux/mem_encrypt.h
> +++ b/include/linux/mem_encrypt.h
> @@ -54,6 +54,13 @@
>  #define dma_addr_canonical(x)		(x)
>  #endif
>  
> +#ifndef mem_encrypt_align
> +static inline size_t mem_encrypt_align(size_t size)
> +{
> +	return size;
> +}
> +#endif
> +
>  #endif	/* __ASSEMBLY__ */
>  
>  #endif	/* __MEM_ENCRYPT_H__ */
> diff --git a/kernel/dma/contiguous.c b/kernel/dma/contiguous.c
> index d9b9dcba6ff7..35f738c9eee2 100644
> --- a/kernel/dma/contiguous.c
> +++ b/kernel/dma/contiguous.c
> @@ -45,6 +45,7 @@
>  #include <linux/dma-map-ops.h>
>  #include <linux/cma.h>
>  #include <linux/nospec.h>
> +#include <linux/dma-direct.h>
>  
>  #ifdef CONFIG_CMA_SIZE_MBYTES
>  #define CMA_SIZE_MBYTES CONFIG_CMA_SIZE_MBYTES
> @@ -356,6 +357,15 @@ struct page *dma_alloc_contiguous(struct device *dev, size_t size, gfp_t gfp)
>  	int nid = dev_to_node(dev);
>  #endif
>  
> +	/*
> +	 * for untrusted device, we require the dma buffers to be aligned to
> +	 * the size of allocation. if we can't do that with cma allocation, fail
> +	 * cma allocation early.
> +	 */
> +	if (force_dma_unencrypted(dev))
> +		if (get_order(size) > CONFIG_CMA_ALIGNMENT)
> +			return NULL;
> +
>  	/* CMA can be used only in the context which permits sleeping */
>  	if (!gfpflags_allow_blocking(gfp))
>  		return NULL;
> diff --git a/kernel/dma/direct.c b/kernel/dma/direct.c
> index 1f9ee9759426..3448d877c7c6 100644
> --- a/kernel/dma/direct.c
> +++ b/kernel/dma/direct.c
> @@ -250,6 +250,9 @@ void *dma_direct_alloc(struct device *dev, size_t size,
>  	    dma_direct_use_pool(dev, gfp))
>  		return dma_direct_alloc_from_pool(dev, size, dma_handle, gfp);
>  
> +	if (force_dma_unencrypted(dev))
> +		size = mem_encrypt_align(size);
> +
>  	/* we always manually zero the memory once we are done */
>  	page = __dma_direct_alloc_pages(dev, size, gfp & ~__GFP_ZERO, true);
>  	if (!page)
> @@ -359,6 +362,9 @@ struct page *dma_direct_alloc_pages(struct device *dev, size_t size,
>  	if (force_dma_unencrypted(dev) && dma_direct_use_pool(dev, gfp))
>  		return dma_direct_alloc_from_pool(dev, size, dma_handle, gfp);
>  
> +	if (force_dma_unencrypted(dev))
> +		size = mem_encrypt_align(size);
> +
>  	page = __dma_direct_alloc_pages(dev, size, gfp, false);
>  	if (!page)
>  		return NULL;
> diff --git a/kernel/dma/pool.c b/kernel/dma/pool.c
> index ee45dee33d49..86615e088240 100644
> --- a/kernel/dma/pool.c
> +++ b/kernel/dma/pool.c
> @@ -80,12 +80,13 @@ static int atomic_pool_expand(struct gen_pool *pool, size_t pool_size,
>  			      gfp_t gfp)
>  {
>  	unsigned int order;
> +	unsigned int min_encrypt_order = get_order(mem_encrypt_align(PAGE_SIZE));
>  	struct page *page = NULL;
>  	void *addr;
>  	int ret = -ENOMEM;
>  
>  	/* Cannot allocate larger than MAX_PAGE_ORDER */
> -	order = min(get_order(pool_size), MAX_PAGE_ORDER);
> +	order = min(get_order(mem_encrypt_align(pool_size)), MAX_PAGE_ORDER);
>  
>  	do {
>  		pool_size = 1 << (PAGE_SHIFT + order);
> @@ -94,7 +95,7 @@ static int atomic_pool_expand(struct gen_pool *pool, size_t pool_size,
>  							 order, false);
>  		if (!page)
>  			page = alloc_pages(gfp, order);
> -	} while (!page && order-- > 0);
> +	} while (!page && order-- > min_encrypt_order);
>  	if (!page)
>  		goto out;
>  
> @@ -196,6 +197,7 @@ static int __init dma_atomic_pool_init(void)
>  		unsigned long pages = totalram_pages() / (SZ_1G / SZ_128K);
>  		pages = min_t(unsigned long, pages, MAX_ORDER_NR_PAGES);
>  		atomic_pool_size = max_t(size_t, pages << PAGE_SHIFT, SZ_128K);
> +		WARN_ON(!IS_ALIGNED(atomic_pool_size, mem_encrypt_align(PAGE_SIZE)));
>  	}
>  	INIT_WORK(&atomic_pool_work, atomic_pool_work_fn);
>  
> diff --git a/kernel/dma/swiotlb.c b/kernel/dma/swiotlb.c
> index 0d37da3d95b6..db53dc7bff6a 100644
> --- a/kernel/dma/swiotlb.c
> +++ b/kernel/dma/swiotlb.c
> @@ -319,8 +319,8 @@ static void __init *swiotlb_memblock_alloc(unsigned long nslabs,
>  		unsigned int flags,
>  		int (*remap)(void *tlb, unsigned long nslabs))
>  {
> -	size_t bytes = PAGE_ALIGN(nslabs << IO_TLB_SHIFT);
>  	void *tlb;
> +	size_t bytes = mem_encrypt_align(nslabs << IO_TLB_SHIFT);
>  
>  	/*
>  	 * By default allocate the bounce buffer memory from low memory, but
> @@ -328,9 +328,9 @@ static void __init *swiotlb_memblock_alloc(unsigned long nslabs,
>  	 * memory encryption.
>  	 */
>  	if (flags & SWIOTLB_ANY)
> -		tlb = memblock_alloc(bytes, PAGE_SIZE);
> +		tlb = memblock_alloc(bytes, mem_encrypt_align(PAGE_SIZE));
>  	else
> -		tlb = memblock_alloc_low(bytes, PAGE_SIZE);
> +		tlb = memblock_alloc_low(bytes, mem_encrypt_align(PAGE_SIZE));
>  
>  	if (!tlb) {
>  		pr_warn("%s: Failed to allocate %zu bytes tlb structure\n",
> @@ -339,7 +339,7 @@ static void __init *swiotlb_memblock_alloc(unsigned long nslabs,
>  	}
>  
>  	if (remap && remap(tlb, nslabs) < 0) {
> -		memblock_free(tlb, PAGE_ALIGN(bytes));
> +		memblock_free(tlb, bytes);
>  		pr_warn("%s: Failed to remap %zu bytes\n", __func__, bytes);
>  		return NULL;
>  	}
> @@ -461,15 +461,21 @@ int swiotlb_init_late(size_t size, gfp_t gfp_mask,
>  		swiotlb_adjust_nareas(num_possible_cpus());
>  
>  retry:
> -	order = get_order(nslabs << IO_TLB_SHIFT);
> +	order = get_order(mem_encrypt_align(nslabs << IO_TLB_SHIFT));
>  	nslabs = SLABS_PER_PAGE << order;
>  
> +	WARN_ON(!IS_ALIGNED(order << PAGE_SHIFT, mem_encrypt_align(PAGE_SIZE)));
> +	WARN_ON(!IS_ALIGNED(default_nslabs << IO_TLB_SHIFT, mem_encrypt_align(PAGE_SIZE)));
> +	WARN_ON(!IS_ALIGNED(IO_TLB_MIN_SLABS << IO_TLB_SHIFT, mem_encrypt_align(PAGE_SIZE)));
> +
>  	while ((SLABS_PER_PAGE << order) > IO_TLB_MIN_SLABS) {
>  		vstart = (void *)__get_free_pages(gfp_mask | __GFP_NOWARN,
>  						  order);
>  		if (vstart)
>  			break;
>  		order--;
> +		if (order < get_order(mem_encrypt_align(PAGE_SIZE)))
> +			break;
>  		nslabs = SLABS_PER_PAGE << order;
>  		retried = true;
>  	}
> @@ -573,7 +579,7 @@ void __init swiotlb_exit(void)
>   */
>  static struct page *alloc_dma_pages(gfp_t gfp, size_t bytes, u64 phys_limit)
>  {
> -	unsigned int order = get_order(bytes);
> +	unsigned int order = get_order(mem_encrypt_align(bytes));
>  	struct page *page;
>  	phys_addr_t paddr;
>  	void *vaddr;


^ permalink raw reply

* Re: [PATCH v2 3/4] coco: host: arm64: Handle hostconf RHI calls in kernel
From: Aneesh Kumar K.V @ 2025-12-22 14:37 UTC (permalink / raw)
  To: Suzuki K Poulose, linux-kernel, iommu, linux-coco
  Cc: Catalin Marinas, will, maz, tglx, robin.murphy, akpm, jgg,
	steven.price
In-Reply-To: <c40414b5-ade9-4d2f-bd73-2167e923b3d6@arm.com>

Suzuki K Poulose <suzuki.poulose@arm.com> writes:

> On 21/12/2025 16:09, Aneesh Kumar K.V (Arm) wrote:
>>   - Mark hostconf RHI SMC IDs as handled in the SMCCC filter.
>>   - Return version/features plus PAGE_SIZE alignment for guest queries.
>>   - Drop the 4K page-size guard in RMI init now that realm can query IPA
>>     change alignment size via the hostconf RHI
>> 
>> Signed-off-by: Aneesh Kumar K.V (Arm) <aneesh.kumar@kernel.org>
>> ---
>>   arch/arm64/kvm/hypercalls.c | 23 ++++++++++++++++++++++-
>>   arch/arm64/kvm/rmi.c        |  4 ----
>>   2 files changed, 22 insertions(+), 5 deletions(-)
>> 
>> diff --git a/arch/arm64/kvm/hypercalls.c b/arch/arm64/kvm/hypercalls.c
>> index 70ac7971416c..2861ca9063dd 100644
>> --- a/arch/arm64/kvm/hypercalls.c
>> +++ b/arch/arm64/kvm/hypercalls.c
>> @@ -8,6 +8,7 @@
>>   
>>   #include <kvm/arm_hypercalls.h>
>>   #include <kvm/arm_psci.h>
>> +#include <asm/rhi.h>
>>   
>>   #define KVM_ARM_SMCCC_STD_FEATURES				\
>>   	GENMASK(KVM_REG_ARM_STD_BMAP_BIT_COUNT - 1, 0)
>> @@ -77,6 +78,9 @@ static bool kvm_smccc_default_allowed(u32 func_id)
>>   	 */
>>   	case ARM_SMCCC_VERSION_FUNC_ID:
>>   	case ARM_SMCCC_ARCH_FEATURES_FUNC_ID:
>> +	case RHI_HOSTCONF_VERSION:
>> +	case RHI_HOSTCONF_FEATURES:
>> +	case RHI_HOSTCONF_GET_IPA_CHANGE_ALIGNMENT:
>>   		return true;
>>   	default:
>>   		/* PSCI 0.2 and up is in the 0:0x1f range */
>> @@ -157,7 +161,15 @@ static int kvm_smccc_filter_insert_reserved(struct kvm *kvm)
>>   			       GFP_KERNEL_ACCOUNT);
>>   	if (r)
>>   		goto out_destroy;
>> -
>> +	/*
>> +	 * Don't forward RHI_HOST_CONF related RHI calls
>> +	 */
>> +	r = mtree_insert_range(&kvm->arch.smccc_filter,
>> +			       RHI_HOSTCONF_VERSION, RHI_HOSTCONF_GET_IPA_CHANGE_ALIGNMENT,
>> +			       xa_mk_value(KVM_SMCCC_FILTER_HANDLE),
>> +			       GFP_KERNEL_ACCOUNT);
>
> minor nit: this is needed only for the Realms ?
>


That is the kvm forwarding of the RHI hostcalls to VMM. We are updating
smccc filter that the SMCCC FID range [RHI_HOSTCONF_VERSION, RHI_HOSTCONF_GET_IPA_CHANGE_ALIGNMENT]
will be handled by the kernel. This is needed because it is the kernel
that is dropping the below check in kvm_init_rmi().

 	/* Only 4k page size on the host is supported */
	if (PAGE_SIZE != SZ_4K)
 		return;

We want to make sure RHI support and dropping of the above check happens
in the same patch and is part of the kernel. 

>
>> +	if (r)
>> +		goto out_destroy;
>>   	return 0;
>>   out_destroy:
>>   	mtree_destroy(&kvm->arch.smccc_filter);
>> @@ -376,6 +388,15 @@ int kvm_smccc_call_handler(struct kvm_vcpu *vcpu)
>>   	case ARM_SMCCC_TRNG_RND32:
>>   	case ARM_SMCCC_TRNG_RND64:
>>   		return kvm_trng_call(vcpu);
>> +	case RHI_HOSTCONF_VERSION:
>> +		val[0] = RHI_HOSTCONF_VER_1_0;
>> +		break;
>> +	case RHI_HOSTCONF_FEATURES:
>> +		val[0] = __RHI_HOSTCONF_GET_IPA_CHANGE_ALIGNMENT;
>> +		break;
>> +	case RHI_HOSTCONF_GET_IPA_CHANGE_ALIGNMENT:
>> +		val[0] = PAGE_SIZE;
>> +		break;
>>   	default:
>>   		return kvm_psci_call(vcpu);
>>   	}
>> diff --git a/arch/arm64/kvm/rmi.c b/arch/arm64/kvm/rmi.c
>> index 9957a71d21b1..bd345e051a24 100644
>> --- a/arch/arm64/kvm/rmi.c
>> +++ b/arch/arm64/kvm/rmi.c
>> @@ -1935,10 +1935,6 @@ EXPORT_SYMBOL_GPL(kvm_has_da_feature);
>>   
>>   void kvm_init_rmi(void)
>>   {
>> -	/* Only 4k page size on the host is supported */
>> -	if (PAGE_SIZE != SZ_4K)
>> -		return;
>
> For the record, these patches doesn't necessarily solve the Host support
> fully. The KVM still needs to support splitting pages for RMM's 4K.
>

We already delegate RMM granules and setup stage 2 in rmm with
RMM_PAGE_SIZE. ie, the shared patchset can be used to setup a 64K host
with 4K Realm running on a RMM using 4K RMM granule size.

>
> That said, this can be ignored as we rebase the KVM to only support
> RMM v2.0, where the Host can set the RMM's Stage2 page size.
>
> Suzuki
>

-aneesh

^ permalink raw reply

* Re: [PATCH v2 3/4] coco: host: arm64: Handle hostconf RHI calls in kernel
From: Suzuki K Poulose @ 2025-12-21 20:10 UTC (permalink / raw)
  To: Aneesh Kumar K.V (Arm), linux-kernel, iommu, linux-coco
  Cc: Catalin Marinas, will, maz, tglx, robin.murphy, akpm, jgg,
	steven.price
In-Reply-To: <20251221160920.297689-4-aneesh.kumar@kernel.org>

On 21/12/2025 16:09, Aneesh Kumar K.V (Arm) wrote:
>   - Mark hostconf RHI SMC IDs as handled in the SMCCC filter.
>   - Return version/features plus PAGE_SIZE alignment for guest queries.
>   - Drop the 4K page-size guard in RMI init now that realm can query IPA
>     change alignment size via the hostconf RHI
> 
> Signed-off-by: Aneesh Kumar K.V (Arm) <aneesh.kumar@kernel.org>
> ---
>   arch/arm64/kvm/hypercalls.c | 23 ++++++++++++++++++++++-
>   arch/arm64/kvm/rmi.c        |  4 ----
>   2 files changed, 22 insertions(+), 5 deletions(-)
> 
> diff --git a/arch/arm64/kvm/hypercalls.c b/arch/arm64/kvm/hypercalls.c
> index 70ac7971416c..2861ca9063dd 100644
> --- a/arch/arm64/kvm/hypercalls.c
> +++ b/arch/arm64/kvm/hypercalls.c
> @@ -8,6 +8,7 @@
>   
>   #include <kvm/arm_hypercalls.h>
>   #include <kvm/arm_psci.h>
> +#include <asm/rhi.h>
>   
>   #define KVM_ARM_SMCCC_STD_FEATURES				\
>   	GENMASK(KVM_REG_ARM_STD_BMAP_BIT_COUNT - 1, 0)
> @@ -77,6 +78,9 @@ static bool kvm_smccc_default_allowed(u32 func_id)
>   	 */
>   	case ARM_SMCCC_VERSION_FUNC_ID:
>   	case ARM_SMCCC_ARCH_FEATURES_FUNC_ID:
> +	case RHI_HOSTCONF_VERSION:
> +	case RHI_HOSTCONF_FEATURES:
> +	case RHI_HOSTCONF_GET_IPA_CHANGE_ALIGNMENT:
>   		return true;
>   	default:
>   		/* PSCI 0.2 and up is in the 0:0x1f range */
> @@ -157,7 +161,15 @@ static int kvm_smccc_filter_insert_reserved(struct kvm *kvm)
>   			       GFP_KERNEL_ACCOUNT);
>   	if (r)
>   		goto out_destroy;
> -
> +	/*
> +	 * Don't forward RHI_HOST_CONF related RHI calls
> +	 */
> +	r = mtree_insert_range(&kvm->arch.smccc_filter,
> +			       RHI_HOSTCONF_VERSION, RHI_HOSTCONF_GET_IPA_CHANGE_ALIGNMENT,
> +			       xa_mk_value(KVM_SMCCC_FILTER_HANDLE),
> +			       GFP_KERNEL_ACCOUNT);

minor nit: this is needed only for the Realms ?

> +	if (r)
> +		goto out_destroy;
>   	return 0;
>   out_destroy:
>   	mtree_destroy(&kvm->arch.smccc_filter);
> @@ -376,6 +388,15 @@ int kvm_smccc_call_handler(struct kvm_vcpu *vcpu)
>   	case ARM_SMCCC_TRNG_RND32:
>   	case ARM_SMCCC_TRNG_RND64:
>   		return kvm_trng_call(vcpu);
> +	case RHI_HOSTCONF_VERSION:
> +		val[0] = RHI_HOSTCONF_VER_1_0;
> +		break;
> +	case RHI_HOSTCONF_FEATURES:
> +		val[0] = __RHI_HOSTCONF_GET_IPA_CHANGE_ALIGNMENT;
> +		break;
> +	case RHI_HOSTCONF_GET_IPA_CHANGE_ALIGNMENT:
> +		val[0] = PAGE_SIZE;
> +		break;
>   	default:
>   		return kvm_psci_call(vcpu);
>   	}
> diff --git a/arch/arm64/kvm/rmi.c b/arch/arm64/kvm/rmi.c
> index 9957a71d21b1..bd345e051a24 100644
> --- a/arch/arm64/kvm/rmi.c
> +++ b/arch/arm64/kvm/rmi.c
> @@ -1935,10 +1935,6 @@ EXPORT_SYMBOL_GPL(kvm_has_da_feature);
>   
>   void kvm_init_rmi(void)
>   {
> -	/* Only 4k page size on the host is supported */
> -	if (PAGE_SIZE != SZ_4K)
> -		return;

For the record, these patches doesn't necessarily solve the Host support
fully. The KVM still needs to support splitting pages for RMM's 4K.

That said, this can be ignored as we rebase the KVM to only support
RMM v2.0, where the Host can set the RMM's Stage2 page size.

Suzuki

> -
>   	/* Continue without realm support if we can't agree on a version */
>   	if (rmi_check_version())
>   		return;


^ permalink raw reply

* [PATCH v2 4/4] dma: direct: set decrypted flag for remapped dma allocations
From: Aneesh Kumar K.V (Arm) @ 2025-12-21 16:09 UTC (permalink / raw)
  To: linux-kernel, iommu, linux-coco
  Cc: Catalin Marinas, will, maz, tglx, robin.murphy, suzuki.poulose,
	akpm, jgg, steven.price, Aneesh Kumar K.V (Arm)
In-Reply-To: <20251221160920.297689-1-aneesh.kumar@kernel.org>

Devices that are DMA non-coherent and need a remap were skipping
dma_set_decrypted(), leaving buffers encrypted even when the device
requires unencrypted access. Move the call after the remap
branch so both paths mark the allocation decrypted (or fail cleanly)
before use.

Fixes: f3c962226dbe ("dma-direct: clean up the remapping checks in dma_direct_alloc")
Signed-off-by: Aneesh Kumar K.V (Arm) <aneesh.kumar@kernel.org>
---
 kernel/dma/direct.c | 8 +++-----
 1 file changed, 3 insertions(+), 5 deletions(-)

diff --git a/kernel/dma/direct.c b/kernel/dma/direct.c
index 3448d877c7c6..a62dc25524cc 100644
--- a/kernel/dma/direct.c
+++ b/kernel/dma/direct.c
@@ -271,9 +271,6 @@ void *dma_direct_alloc(struct device *dev, size_t size,
 	if (remap) {
 		pgprot_t prot = dma_pgprot(dev, PAGE_KERNEL, attrs);
 
-		if (force_dma_unencrypted(dev))
-			prot = pgprot_decrypted(prot);
-
 		/* remove any dirty cache lines on the kernel alias */
 		arch_dma_prep_coherent(page, size);
 
@@ -284,10 +281,11 @@ void *dma_direct_alloc(struct device *dev, size_t size,
 			goto out_free_pages;
 	} else {
 		ret = page_address(page);
-		if (dma_set_decrypted(dev, ret, size))
-			goto out_leak_pages;
 	}
 
+	if (dma_set_decrypted(dev, ret, size))
+		goto out_leak_pages;
+
 	memset(ret, 0, size);
 
 	if (set_uncached) {
-- 
2.43.0


^ permalink raw reply related


This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox