Linux Confidential Computing Development
 help / color / mirror / Atom feed
* Re: [PATCH v6 00/11] Dynamic PAMT
From: Edgecombe, Rick P @ 2026-07-06 21:01 UTC (permalink / raw)
  To: kvm@vger.kernel.org, linux-coco@lists.linux.dev, Huang, Kai,
	Hansen, Dave, Zhao, Yan Y, kas@kernel.org, seanjc@google.com,
	mingo@redhat.com, linux-kernel@vger.kernel.org,
	pbonzini@redhat.com, nik.borisov@suse.com,
	linux-doc@vger.kernel.org, hpa@zytor.com, tglx@kernel.org,
	Annapurve, Vishal, bp@alien8.de, Gao, Chao, x86@kernel.org
In-Reply-To: <20260526023515.288829-1-rick.p.edgecombe@intel.com>

Sean,

On Mon, 2026-05-25 at 19:35 -0700, Rick Edgecombe wrote:
>   KVM: TDX: Allocate PAMT memory for TD and vCPU control structures
>   KVM: TDX: Get/put PAMT pages when (un)mapping private memory

Would you be willing to take a look at these two patches that need ack's from
the KVM side? I'm hoping to make the next version of this the last one. So it
would be great to get any remaining comments before then.

Thanks.

^ permalink raw reply

* Re: [PATCH v6 09/11] KVM: TDX: Get/put PAMT pages when (un)mapping private memory
From: Sean Christopherson @ 2026-07-06 21:02 UTC (permalink / raw)
  To: Rick P Edgecombe
  Cc: binbin.wu@linux.intel.com, kvm@vger.kernel.org,
	linux-coco@lists.linux.dev, Kai Huang, Dave Hansen, Yan Y Zhao,
	kirill.shutemov@linux.intel.com, kas@kernel.org, mingo@redhat.com,
	linux-kernel@vger.kernel.org, pbonzini@redhat.com,
	nik.borisov@suse.com, linux-doc@vger.kernel.org, hpa@zytor.com,
	tglx@kernel.org, Vishal Annapurve, bp@alien8.de, Chao Gao,
	x86@kernel.org
In-Reply-To: <2bdcc07d98df66954b9508be537b6f6a7c9f88de.camel@intel.com>

On Mon, Jul 06, 2026, Rick P Edgecombe wrote:
> On Fri, 2026-07-03 at 11:15 +0800, Binbin Wu wrote:
> > > @@ -1669,16 +1683,29 @@ static struct page *tdx_spte_to_sept_pt(struct kvm
> > > *kvm, gfn_t gfn,
> > >   static int tdx_sept_map_nonleaf_spte(struct kvm *kvm, gfn_t gfn,
> > >   				     enum pg_level level, u64 new_spte)
> > >   {
> > > +	struct kvm_vcpu *vcpu = kvm_get_running_vcpu();
> > > +	struct vcpu_tdx *tdx = to_tdx(vcpu);
> > 
> > Nit:
> > Is it better to move this after checking vcpu is not NULL?
> > Although tdx is not dereferenced in between, if vcpu is NULL,
> > it means container_of() does arithmetic to a NULL pointer.
> 
> Personally I'm on the fence. I'm going to leave it, because Sean did it that
> way:
> https://lore.kernel.org/kvm/20260129011517.3545883-23-seanjc@google.com/

Heh, because of course I'm omnipotent and never make mistakes.

I agree with the nit in the sense that this isn't a great pattern to encourage,
but IMO the root of the ugly pattern is the use of kvm_get_running_vcpu() (which
is sadly the lesser evil in this case).  I.e. I'm not terribly concerned about
this code leading to more "problems" in the future.  And I don't really want to
grab "tdx" later on because that deviates from the standard patterns in KVM and
incorrectly suggests there _is_ a need to pre-check for a non-NULL vCPU.

All that said, we can get the bost of both words by simply not caching "tdx";
there's only one use anyways.

diff --git arch/x86/kvm/vmx/tdx.c arch/x86/kvm/vmx/tdx.c
index ee073cacafbe..f53bac52449b 100644
--- arch/x86/kvm/vmx/tdx.c
+++ arch/x86/kvm/vmx/tdx.c
@@ -1684,7 +1684,6 @@ static int tdx_sept_map_nonleaf_spte(struct kvm *kvm, gfn_t gfn,
                                     enum pg_level level, u64 new_spte)
 {
        struct kvm_vcpu *vcpu = kvm_get_running_vcpu();
-       struct vcpu_tdx *tdx = to_tdx(vcpu);
        gpa_t gpa = gfn_to_gpa(gfn);
        u64 err, entry, level_state;
        struct page *sept_pt;
@@ -1697,7 +1696,7 @@ static int tdx_sept_map_nonleaf_spte(struct kvm *kvm, gfn_t gfn,
        if (!sept_pt)
                return -EIO;
 
-       ret = tdx_pamt_get(page_to_pfn(sept_pt), &tdx->pamt_cache);
+       ret = tdx_pamt_get(page_to_pfn(sept_pt), &to_tdx(vcpu)->pamt_cache);
        if (ret)
                return ret;
 
@@ -1721,7 +1720,6 @@ static int tdx_sept_map_leaf_spte(struct kvm *kvm, gfn_t gfn, enum pg_level leve
        struct kvm_vcpu *vcpu = kvm_get_running_vcpu();
        struct kvm_tdx *kvm_tdx = to_kvm_tdx(kvm);
        kvm_pfn_t pfn = spte_to_pfn(new_spte);
-       struct vcpu_tdx *tdx = to_tdx(vcpu);
        int ret;
 
        if (KVM_BUG_ON(!vcpu, kvm))
@@ -1733,7 +1731,7 @@ static int tdx_sept_map_leaf_spte(struct kvm *kvm, gfn_t gfn, enum pg_level leve
 
        WARN_ON_ONCE((new_spte & VMX_EPT_RWX_MASK) != VMX_EPT_RWX_MASK);
 
-       ret = tdx_pamt_get(pfn, &tdx->pamt_cache);
+       ret = tdx_pamt_get(pfn, &to_tdx(vcpu)->pamt_cache);
        if (ret)
                return ret;

^ permalink raw reply related

* Re: [PATCH] x86/virt/tdx: Formalize SEAMCALL version encoding support
From: Edgecombe, Rick P @ 2026-07-06 21:44 UTC (permalink / raw)
  To: linux-kernel@vger.kernel.org, yilun.xu@linux.intel.com,
	x86@kernel.org
  Cc: Gao, Chao, Xu, Yilun, Hansen, Dave, dave.hansen@linux.intel.com,
	kas@kernel.org, djbw@kernel.org, Fang, Peter,
	linux-coco@lists.linux.dev
In-Reply-To: <20260702144614.59464-1-yilun.xu@linux.intel.com>

On Thu, 2026-07-02 at 22:46 +0800, Xu Yilun wrote:
> TDX uses the SEAMCALL instruction to invoke various TDX module
> functions. Just like the syscall, a SEAMCALL specifies the operation
> using a function number and parameters. Moreover, TDX also uses SEAMCALL
> versions to extend the functionalities of existing SEAMCALLs while
> keeping backward compatibility. Unlike syscall versions that assign
> brand new numbers, TDX segments the function number into a basic
> function number field and a version field. Together, they encode the new
> function number.

So isn't this pretty much like numbered seamcalls, except there is a special
format for generating seamcall2, seamcall3, etc? In the end you just use a
different number for a different version of the call. So it's just like
syscalls, except there is a pattern in the specific number for calls of the same
family.

> 
> An existing SEAMCALL (TDH.VP.INIT) helper is already using the version
                                    ^ maybe swap the order of these two?
> field. However, having the caller pack the version into the function
          ^Can drop this?
> number open-codes the ABI layout, making the SEAMCALL helper definition
> obscure and error prone.

Do we need the second part of the sentence?

> 
> Add a version field in struct tdx_module_args, so that most existing
> SEAMCALL helpers get a default "version == 0" behavior without code
> churn, while callers requiring extended functionalities can specify the
> version descriptively.
> 
> As an internal implementation detail,

^ Is this needed to make it clear?

>  encode the
> tdx_module_args.version in the function number before calling into
> assembly code.
> 
> Two alternative schemes were considered:
> 
> 1. Define versioned macros like TDH_VP_INIT_V0, TDH_VP_INIT_V1, etc.
>    However, this breaks naming consistency unless all existing stable
>    function macros are changed to TDH_XXX_V0.
> 
> 2. Add an explicit 'version' parameter to the base seamcall() API. This
>    unnecessarily forces all stable SEAMCALL helpers to pass a
>    meaningless '0' argument. Additionally, the magic '0' or '1' values
>    at caller sites are not descriptive.
> 

Dave was recently saying something to the effect of "make every word count". I
think we could lose some filler words.

> Signed-off-by: Xu Yilun <yilun.xu@linux.intel.com>

How about a link to the thread where this was suggested.

> ---
>  arch/x86/include/asm/shared/tdx.h         |  2 ++
>  arch/x86/virt/vmx/tdx/seamcall_internal.h | 19 ++++++++++++++++++-
>  arch/x86/virt/vmx/tdx/tdx.h               |  8 --------
>  arch/x86/virt/vmx/tdx/tdx.c               |  5 +++--
>  4 files changed, 23 insertions(+), 11 deletions(-)
> 
> diff --git a/arch/x86/include/asm/shared/tdx.h b/arch/x86/include/asm/shared/tdx.h
> index f20e91d7ac35..b9aac2de233a 100644
> --- a/arch/x86/include/asm/shared/tdx.h
> +++ b/arch/x86/include/asm/shared/tdx.h
> @@ -143,6 +143,8 @@ struct tdx_module_args {
>  	u64 rbx;
>  	u64 rdi;
>  	u64 rsi;
> +	/* ABI version, encoded in rax */
> +	u8  version;
>  };
>  
>  /* Used to communicate with the TDX module */
> diff --git a/arch/x86/virt/vmx/tdx/seamcall_internal.h b/arch/x86/virt/vmx/tdx/seamcall_internal.h
> index be5f446467df..7002e41cddad 100644
> --- a/arch/x86/virt/vmx/tdx/seamcall_internal.h
> +++ b/arch/x86/virt/vmx/tdx/seamcall_internal.h
> @@ -11,6 +11,7 @@
>  #ifndef _X86_VIRT_SEAMCALL_INTERNAL_H
>  #define _X86_VIRT_SEAMCALL_INTERNAL_H
>  
> +#include <linux/bitfield.h>
>  #include <linux/printk.h>
>  #include <linux/types.h>
>  #include <asm/archrandom.h>
> @@ -23,6 +24,22 @@ u64 __seamcall_saved_ret(u64 fn, struct tdx_module_args *args);
>  
>  typedef u64 (*sc_func_t)(u64 fn, struct tdx_module_args *args);
>  
> +/*
> + * SEAMCALL leaf:
> + *
> + * Bit 15:0	Leaf number
> + * Bit 23:16	Version number
> + */
> +#define SEAMCALL_VERSION_MASK		GENMASK_U64(23, 16)

The annoying thing is that the path touched here is also used for seamldr calls
now, which afaict has no concept of version. Underscoring how much of a mess the
wrapper stack is.

> +
> +static __always_inline u64 __seamcall_encode_fn(sc_func_t func, u64 fn,
> +						struct tdx_module_args *args)
> +{

I have the same question as Xiaoyao. We have so many wrappers already.

> +	FIELD_MODIFY(SEAMCALL_VERSION_MASK, &fn, args->version);
> +
> +	return func(fn, args);
> +}
> +
>  static __always_inline u64 __seamcall_dirty_cache(sc_func_t func, u64 fn,
>  						  struct tdx_module_args *args)
>  {
> @@ -39,7 +56,7 @@ static __always_inline u64 __seamcall_dirty_cache(sc_func_t func, u64 fn,
>  	 */
>  	this_cpu_write(cache_state_incoherent, true);
>  
> -	return func(fn, args);
> +	return __seamcall_encode_fn(func, fn, args);
>  }
>  
>  static __always_inline u64 sc_retry(sc_func_t func, u64 fn,
> diff --git a/arch/x86/virt/vmx/tdx/tdx.h b/arch/x86/virt/vmx/tdx/tdx.h
> index bdfd0e1e337a..63e3acfb5d0c 100644
> --- a/arch/x86/virt/vmx/tdx/tdx.h
> +++ b/arch/x86/virt/vmx/tdx/tdx.h
> @@ -50,14 +50,6 @@
>  #define TDH_SYS_UPDATE			53
>  #define TDH_SYS_DISABLE			69
>  
> -/*
> - * SEAMCALL leaf:
> - *
> - * Bit 15:0	Leaf number
> - * Bit 23:16	Version number
> - */
> -#define TDX_VERSION_SHIFT		16
> -
>  /* TDX page types */
>  #define	PT_NDA		0x0
>  #define	PT_RSVD		0x1
> diff --git a/arch/x86/virt/vmx/tdx/tdx.c b/arch/x86/virt/vmx/tdx/tdx.c
> index 42df8ea464c4..7a89e29b118c 100644
> --- a/arch/x86/virt/vmx/tdx/tdx.c
> +++ b/arch/x86/virt/vmx/tdx/tdx.c
> @@ -1910,10 +1910,11 @@ u64 tdh_vp_init(struct tdx_vp *vp, u64 initial_rcx, u32 x2apicid)
>  		.rcx = vp->tdvpr_pa,
>  		.rdx = initial_rcx,
>  		.r8 = x2apicid,
> +		/* apicid requires version == 1. */
> +		.version = 1,
>  	};
>  
> -	/* apicid requires version == 1. */
> -	return seamcall(TDH_VP_INIT | (1ULL << TDX_VERSION_SHIFT), &args);
> +	return seamcall(TDH_VP_INIT, &args);
>  }
>  EXPORT_SYMBOL_FOR_KVM(tdh_vp_init);
>  


^ permalink raw reply

* Re: [PATCH v6 09/11] KVM: TDX: Get/put PAMT pages when (un)mapping private memory
From: Edgecombe, Rick P @ 2026-07-06 21:52 UTC (permalink / raw)
  To: seanjc@google.com
  Cc: kirill.shutemov@linux.intel.com, linux-coco@lists.linux.dev,
	Huang, Kai, kvm@vger.kernel.org, Hansen, Dave, Zhao, Yan Y,
	kas@kernel.org, binbin.wu@linux.intel.com, mingo@redhat.com,
	pbonzini@redhat.com, nik.borisov@suse.com,
	linux-doc@vger.kernel.org, hpa@zytor.com, tglx@kernel.org,
	Annapurve, Vishal, bp@alien8.de, linux-kernel@vger.kernel.org,
	Gao, Chao, x86@kernel.org
In-Reply-To: <akwX9wUS_C-lc-I8@google.com>

On Mon, 2026-07-06 at 14:02 -0700, Sean Christopherson wrote:
> Heh, because of course I'm omnipotent and never make mistakes.

Just using failable Sean as a tie breaker.

> 
> I agree with the nit in the sense that this isn't a great pattern to encourage,
> but IMO the root of the ugly pattern is the use of kvm_get_running_vcpu() (which
> is sadly the lesser evil in this case).  I.e. I'm not terribly concerned about
> this code leading to more "problems" in the future.  And I don't really want to
> grab "tdx" later on because that deviates from the standard patterns in KVM and
> incorrectly suggests there _is_ a need to pre-check for a non-NULL vCPU.
> 
> All that said, we can get the bost of both words by simply not caching "tdx";
> there's only one use anyways.

Oh yea duh, that's better.

^ permalink raw reply

* Re: [PATCH v8 13/46] KVM: guest_memfd: Add base support for KVM_SET_MEMORY_ATTRIBUTES2
From: Suzuki K Poulose @ 2026-07-06 22:35 UTC (permalink / raw)
  To: Ackerley Tng, aik, andrew.jones, binbin.wu, brauner, chao.p.peng,
	david, jmattson, jthoughton, michael.roth, oupton, pankaj.gupta,
	qperret, rick.p.edgecombe, rientjes, shivankg, steven.price,
	tabba, willy, wyihan, yan.y.zhao, forkloop, pratyush,
	aneesh.kumar, liam, Paolo Bonzini, Sean Christopherson,
	Thomas Gleixner, Ingo Molnar, Borislav Petkov, Dave Hansen, x86,
	H. Peter Anvin, Steven Rostedt, Masami Hiramatsu,
	Mathieu Desnoyers, Jonathan Corbet, Shuah Khan, Shuah Khan,
	Vishal Annapurve, Andrew Morton, Chris Li, Kairui Song,
	Kemeng Shi, Nhat Pham, Barry Song, Axel Rasmussen, Yuanchu Xie,
	Wei Xu, Youngjun Park, Qi Zheng, Shakeel Butt, Kiryl Shutsemau,
	Baoquan He, Jason Gunthorpe, Vlastimil Babka
  Cc: kvm, linux-kernel, linux-trace-kernel, linux-doc, linux-kselftest,
	linux-mm, linux-coco
In-Reply-To: <CAEvNRgFKbKfTMkqh_XF-igm07qYWfRwYJ5SH7wHcLZnqesCzTw@mail.gmail.com>

On 06/07/2026 19:17, Ackerley Tng wrote:
> Suzuki K Poulose <suzuki.poulose@arm.com> writes:
> 
>>
>> [...snip...]
>>
>>> +static int __kvm_gmem_set_attributes(struct inode *inode, pgoff_t start,
>>> +				     size_t nr_pages, uint64_t attrs)
>>> +{
>>> +	struct address_space *mapping = inode->i_mapping;
>>> +	struct gmem_inode *gi = GMEM_I(inode);
>>> +	pgoff_t end = start + nr_pages;
>>> +	struct maple_tree *mt;
>>> +	struct ma_state mas;
>>> +	int r;
>>> +
>>> +	mt = &gi->attributes;
>>> +
>>> +	filemap_invalidate_lock(mapping);
>>> +
>>> +	mas_init(&mas, mt, start);
>>> +	r = kvm_gmem_mas_preallocate(&mas, attrs, start, nr_pages);
>>> +	if (r)
>>> +		goto out;
>>> +
>>> +	/*
>>> +	 * From this point on guest_memfd has performed necessary
>>> +	 * checks and can proceed to do guest-breaking changes.
>>> +	 */
>>> +
>>> +	kvm_gmem_invalidate_start(inode, start, end);
>>
>> I added support for Arm CCA KVM patches with the inplace conversion and
>> I am hitting the following issue.
>>
>> 1. I am supporting INIT_SHARED + MMAP flags.
>> 2. VMM creates the Gmem_fd with both the flags above.
>> 3. Uses the shared gmem-mmap to load the initial payloads (kernel, dtb).
>> 4. At the VM finalization time, Populate the loaded regions one by one
>>      by
>>       a) copying the images to a temparory buffer - Since CCA can't really
>>          load the contents in-place.
> 
> Sounds good :). I see that you blocked this in the kernel by returning
> -EOPNOTSUPP if (!src_page) [0].

We could do the copy in kernel with src_page == dst_page, but that would
affect the batching of Granule delegation (and at which point we might
need a temparory buffer in the kernel as big as the vma_pagesize)

> 
>>       b) Set the "region" to Private in the gmem_fd (via
>> SET_MEMORY_ATTRIBUTES2)
>>       c) Invoke CCA backend to populate the private memory via
>>          ioctl(KVM_ARM_RMI_POPULATE,..) [0]
>>
> 
> This flow sounds right.
> 
>> [0]
>> https://lore.kernel.org/all/20260513131757.116630-27-steven.price@arm.com/
>>
>>
>> 5. Additionally, VMM can mark the entire RAM to be private before the VM
>>      starts running, again via SET_MEMORY_ATTRIBUTES2. On CCA, this
>> action is measured and doesn't require the Host to "commit" memory to
>> the VM.
>> Instead the host can lazily donate memory on a fault.
>>
> 
> For both TDX and SNP, the host can also lazily donate memory,
> guest_memfd supports this.
> 
>> But step (5) triggers the invalidation of both private and shared
>> mappings of the gmem area, from the kvm_gmem_invalidate_start()
>> above.
>>
>> This is because, the entire DRAM now has, some portions PRIVATE (the
>> loaded regions) and the rest are SHARED (from the Gmem_fd creation).
>>    Thus, kvm_gmem_get_invalidate_filter(Dram_start, Dram_end) causes the
>> invalidation of both "PRIVATE" and "SHARED" regions, which results
>> in the destruction of the already loaded data and things go south.
>>
> 
> This destruction will happen for TDX as well. I think we managed to get
> around this because we didn't apply conversion on the already-private
> ranges.
> 
> IIUC on SNP, zapping pages in the stage 2 page tables doesn't destroy
> the data, so that's probably why it has been fine for SNP.

Additionally, the Guest at boot, will try to mark the entire DRAM
as Private (RIPAS_RAM in CCA), which would trigger this anyways.

Suzuki


> 
>> When we know that the kvm_gmem_invalidate_xx is triggered by a
>> conversion, we don't need to invalidate the existing pages that
>> are in the requested state. i.e., the following patch on top of
>> this series does the trick for me :
>>
>>
>> diff --git a/virt/kvm/guest_memfd.c b/virt/kvm/guest_memfd.c
>> index a97fcac34a0e..62e0427a49f4 100644
>> --- a/virt/kvm/guest_memfd.c
>> +++ b/virt/kvm/guest_memfd.c
>> @@ -250,16 +250,23 @@ static void __kvm_gmem_invalidate_start(struct
>> gmem_file *f, pgoff_t start,
>>                   KVM_MMU_UNLOCK(kvm);
>>    }
>>
>> +static void kvm_gmem_invalidate_start_filter(struct inode *inode,
>> pgoff_t start,
>> +                                            pgoff_t end,
>> +                                            enum kvm_gfn_range_filter
>> attr_filter)
>> +{
>> +       struct gmem_file *f;
>> +
>> +       kvm_gmem_for_each_file(f, inode)
>> +               __kvm_gmem_invalidate_start(f, start, end, attr_filter);
>> +}
>> +
>>    static void kvm_gmem_invalidate_start(struct inode *inode, pgoff_t start,
>>                                         pgoff_t end)
>>    {
>>           enum kvm_gfn_range_filter attr_filter;
>> -       struct gmem_file *f;
>> -
>>           attr_filter = kvm_gmem_get_invalidate_filter(inode, start, end);
>>
>> -       kvm_gmem_for_each_file(f, inode)
>> -               __kvm_gmem_invalidate_start(f, start, end, attr_filter);
>> +       kvm_gmem_invalidate_start_filter(inode, start, end, attr_filter);
>>    }
>>
>>    static void __kvm_gmem_invalidate_end(struct gmem_file *f, pgoff_t start,
>> @@ -724,9 +731,14 @@ static int __kvm_gmem_set_attributes(struct inode
>> *inode, pgoff_t start,
>>           /*
>>            * From this point on guest_memfd has performed necessary
>>            * checks and can proceed to do guest-breaking changes.
>> +        * Also, we don't have to invalidate the regions that
>> +        * may already be in the requested state. Hence, we could
>> +        * explicitly filter the invalidations to the opposite
>> +        * state.
>>            */
>>
>> -       kvm_gmem_invalidate_start(inode, start, end);
>> +       kvm_gmem_invalidate_start_filter(inode, start, end,
>> +                                       to_private ? KVM_FILTER_SHARED :
>> KVM_FILTER_PRIVATE);
>>
> 
> I think this makes sense. Thanks for catching this.
> 
>>           if (!to_private)
>>                   kvm_gmem_invalidate(inode, start, end);
>>
>>
>> Thoughts ?
>>
>> Suzuki
>>
>>
>>>
>>> [...snip...]
>>>


^ permalink raw reply

* Re: [PATCH v6 07/11] KVM: TDX: Allocate PAMT memory for TD and vCPU control structures
From: Sean Christopherson @ 2026-07-06 23:47 UTC (permalink / raw)
  To: Rick Edgecombe
  Cc: bp, dave.hansen, hpa, kas, kvm, linux-coco, linux-doc,
	linux-kernel, mingo, nik.borisov, pbonzini, tglx, vannapurve, x86,
	chao.gao, yan.y.zhao, kai.huang, Kirill A. Shutemov
In-Reply-To: <20260526023515.288829-8-rick.p.edgecombe@intel.com>

On Mon, May 25, 2026, Rick Edgecombe wrote:
> From: "Kirill A. Shutemov" <kirill.shutemov@linux.intel.com>
> 
> Use control page helpers for allocating and freeing TD control structures,
> such these operations can work for Dynamic PAMT.
> 
> The TDX module tracks some state for each page of physical memory that it
> might use. It calls this state the PAMT. It includes separate state for
> each page size a physical page could be utilized at within the TDX module
> (1GB, 2MB, 4KB). In Dynamic PAMT, only the 4KB page size state is
> allocated dynamically. So the kernel must install PAMT backing for each 4KB
> page before gifting it to the TDX module, and tear it down after the page
> is reclaimed.
> 
> TD-scoped control pages (TDR, TDCS) and vCPU-scoped control pages (TDVPR,
> TDCX) are all handed to the TDX module at 4KB page size and are therefore
> subject to this requirement. Replace the raw alloc_page()/__free_page()
> calls for these pages with tdx_alloc/free_control_page().
> 
> Switching between special Dynamic PAMT operations or normal page
> alloc/free operations is handled internally in
> tdx_alloc/free_control_page(). So don't check for Dynamic PAMT around these
> calls. Just call them unconditionally. Similarly, drop the NULL checks
> before freeing, as tdx_free_control_page() handles NULL internally.
> 
> No functional change intended when Dynamic PAMT is not in use.
> 
> Assisted-by: GitHub Copilot:claude-opus-4-6 Claude:claude-opus-4-7

Exactly what assistance was given, and when?  I certainly didn't use any of these
tools, and given that Claude Opus 4.6 was released after I posted the v5 RFC, I
doubt Kirill did either.

And in my strong opinion, even if AI tooling was used to rebase the patches, I
don't think that level of "assistance" should be presented this way.  E.g. I would
rather a more informal:

  [ Rick: enhance log, rebase with help from AI tooling]

Because unless I'm missing something, claiming that AI was used to write the patch
is misleading and disingenuous.

> Signed-off-by: Kirill A. Shutemov <kirill.shutemov@linux.intel.com>
> [sean: handle alloc+free+reclaim in one patch]
> Co-developed-by: Sean Christopherson <seanjc@google.com>

Where did this come from?  I don't think me squashing two patches together
warrants a Co-developed-by.

> Signed-off-by: Sean Christopherson <seanjc@google.com>
> [Rick: enhance log]
> Signed-off-by: Rick Edgecombe <rick.p.edgecombe@intel.com>

^ permalink raw reply

* Re: [PATCH v6 07/11] KVM: TDX: Allocate PAMT memory for TD and vCPU control structures
From: Edgecombe, Rick P @ 2026-07-06 23:54 UTC (permalink / raw)
  To: seanjc@google.com
  Cc: kvm@vger.kernel.org, linux-coco@lists.linux.dev, Huang, Kai,
	Hansen, Dave, Zhao, Yan Y, kirill.shutemov@linux.intel.com,
	kas@kernel.org, linux-kernel@vger.kernel.org, mingo@redhat.com,
	pbonzini@redhat.com, nik.borisov@suse.com,
	linux-doc@vger.kernel.org, hpa@zytor.com, tglx@kernel.org,
	Annapurve, Vishal, bp@alien8.de, Gao, Chao, x86@kernel.org
In-Reply-To: <akw-dgBE_dycts0o@google.com>

On Mon, 2026-07-06 at 16:47 -0700, Sean Christopherson wrote:
> On Mon, May 25, 2026, Rick Edgecombe wrote:
> > From: "Kirill A. Shutemov" <kirill.shutemov@linux.intel.com>
> > 
> > Use control page helpers for allocating and freeing TD control structures,
> > such these operations can work for Dynamic PAMT.
> > 
> > The TDX module tracks some state for each page of physical memory that it
> > might use. It calls this state the PAMT. It includes separate state for
> > each page size a physical page could be utilized at within the TDX module
> > (1GB, 2MB, 4KB). In Dynamic PAMT, only the 4KB page size state is
> > allocated dynamically. So the kernel must install PAMT backing for each 4KB
> > page before gifting it to the TDX module, and tear it down after the page
> > is reclaimed.
> > 
> > TD-scoped control pages (TDR, TDCS) and vCPU-scoped control pages (TDVPR,
> > TDCX) are all handed to the TDX module at 4KB page size and are therefore
> > subject to this requirement. Replace the raw alloc_page()/__free_page()
> > calls for these pages with tdx_alloc/free_control_page().
> > 
> > Switching between special Dynamic PAMT operations or normal page
> > alloc/free operations is handled internally in
> > tdx_alloc/free_control_page(). So don't check for Dynamic PAMT around these
> > calls. Just call them unconditionally. Similarly, drop the NULL checks
> > before freeing, as tdx_free_control_page() handles NULL internally.
> > 
> > No functional change intended when Dynamic PAMT is not in use.
> > 
> > Assisted-by: GitHub Copilot:claude-opus-4-6 Claude:claude-opus-4-7
> 
> Exactly what assistance was given, and when?  I certainly didn't use any of these
> tools, and given that Claude Opus 4.6 was released after I posted the v5 RFC, I
> doubt Kirill did either.

On this patch specifically, lots of "review this patch" type experiments IIRC.
Probably mostly around the log.

> 
> And in my strong opinion, even if AI tooling was used to rebase the patches, I
> don't think that level of "assistance" should be presented this way.  E.g. I would
> rather a more informal:
> 
>   [ Rick: enhance log, rebase with help from AI tooling]
> 
> Because unless I'm missing something, claiming that AI was used to write the patch
> is misleading and disingenuous.

Yea, I was just trying to follow the policy. It seems things are swinging the
other way now. This works.

> 
> > Signed-off-by: Kirill A. Shutemov <kirill.shutemov@linux.intel.com>
> > [sean: handle alloc+free+reclaim in one patch]
> > Co-developed-by: Sean Christopherson <seanjc@google.com>
> 
> Where did this come from?  I don't think me squashing two patches together
> warrants a Co-developed-by.

Gosh, I'm sorry. It looks like I added it. Will remove.

> 
> > Signed-off-by: Sean Christopherson <seanjc@google.com>
> > [Rick: enhance log]
> > Signed-off-by: Rick Edgecombe <rick.p.edgecombe@intel.com>


^ permalink raw reply

* Re: [PATCH v6 07/11] KVM: TDX: Allocate PAMT memory for TD and vCPU control structures
From: Sean Christopherson @ 2026-07-07  0:25 UTC (permalink / raw)
  To: Rick P Edgecombe
  Cc: kvm@vger.kernel.org, linux-coco@lists.linux.dev, Kai Huang,
	Dave Hansen, Yan Y Zhao, kirill.shutemov@linux.intel.com,
	kas@kernel.org, linux-kernel@vger.kernel.org, mingo@redhat.com,
	pbonzini@redhat.com, nik.borisov@suse.com,
	linux-doc@vger.kernel.org, hpa@zytor.com, tglx@kernel.org,
	Vishal Annapurve, bp@alien8.de, Chao Gao, x86@kernel.org
In-Reply-To: <b9e2c377a21a53329cd70ac48309981957814686.camel@intel.com>

On Mon, Jul 06, 2026, Rick P Edgecombe wrote:
> On Mon, 2026-07-06 at 16:47 -0700, Sean Christopherson wrote:
> > On Mon, May 25, 2026, Rick Edgecombe wrote:
> > > From: "Kirill A. Shutemov" <kirill.shutemov@linux.intel.com>
> > > 
> > > Use control page helpers for allocating and freeing TD control structures,
> > > such these operations can work for Dynamic PAMT.
> > > 
> > > The TDX module tracks some state for each page of physical memory that it
> > > might use. It calls this state the PAMT. It includes separate state for
> > > each page size a physical page could be utilized at within the TDX module
> > > (1GB, 2MB, 4KB). In Dynamic PAMT, only the 4KB page size state is
> > > allocated dynamically. So the kernel must install PAMT backing for each 4KB
> > > page before gifting it to the TDX module, and tear it down after the page
> > > is reclaimed.
> > > 
> > > TD-scoped control pages (TDR, TDCS) and vCPU-scoped control pages (TDVPR,
> > > TDCX) are all handed to the TDX module at 4KB page size and are therefore
> > > subject to this requirement. Replace the raw alloc_page()/__free_page()
> > > calls for these pages with tdx_alloc/free_control_page().
> > > 
> > > Switching between special Dynamic PAMT operations or normal page
> > > alloc/free operations is handled internally in
> > > tdx_alloc/free_control_page(). So don't check for Dynamic PAMT around these
> > > calls. Just call them unconditionally. Similarly, drop the NULL checks
> > > before freeing, as tdx_free_control_page() handles NULL internally.
> > > 
> > > No functional change intended when Dynamic PAMT is not in use.
> > > 
> > > Assisted-by: GitHub Copilot:claude-opus-4-6 Claude:claude-opus-4-7
> > 
> > Exactly what assistance was given, and when?  I certainly didn't use any of these
> > tools, and given that Claude Opus 4.6 was released after I posted the v5 RFC, I
> > doubt Kirill did either.
> 
> On this patch specifically, lots of "review this patch" type experiments IIRC.
> Probably mostly around the log.
> 
> > 
> > And in my strong opinion, even if AI tooling was used to rebase the patches, I
> > don't think that level of "assistance" should be presented this way.  E.g. I would
> > rather a more informal:
> > 
> >   [ Rick: enhance log, rebase with help from AI tooling]
> > 
> > Because unless I'm missing something, claiming that AI was used to write the patch
> > is misleading and disingenuous.
> 
> Yea, I was just trying to follow the policy. It seems things are swinging the
> other way now. This works.

FWIW, my read of the official policy, even before any change in direction, is that
it only applies to using AI to write code.  It's not like we given any credit in
the patch itself when changes are made in response to code review from human.

^ permalink raw reply

* Re: [PATCH v6 01/11] x86/virt/tdx: Simplify tdmr_get_pamt_sz()
From: Yan Zhao @ 2026-07-07  3:24 UTC (permalink / raw)
  To: Edgecombe, Rick P
  Cc: Gao, Chao, kvm@vger.kernel.org, linux-coco@lists.linux.dev,
	Huang, Kai, Hansen, Dave, kas@kernel.org, seanjc@google.com,
	mingo@redhat.com, linux-kernel@vger.kernel.org,
	pbonzini@redhat.com, nik.borisov@suse.com,
	linux-doc@vger.kernel.org, hpa@zytor.com, tglx@kernel.org,
	Annapurve, Vishal, bp@alien8.de, binbin.wu@linux.intel.com,
	x86@kernel.org
In-Reply-To: <6605c80fc676c069bcbb097c77c07b17eb3eb97c.camel@intel.com>

On Tue, Jul 07, 2026 at 04:18:25AM +0800, Edgecombe, Rick P wrote:
> On Fri, 2026-07-03 at 13:48 +0800, Chao Gao wrote:
> > On Mon, May 25, 2026 at 07:35:05PM -0700, Rick Edgecombe wrote:
> > > Since the loop that iterates over it is gone, further simplify the code by
Nit:
The patch is titled "Simplify tdmr_get_pamt_sz()" but the log mainly talks about
removing the loop in tdmr_set_up_pamt().
So, how about renaming the patch to "Simplify setting up pamt calculation for
TDMRs"?

> > > dropping the array of intermediate size and base storage. Just store the
> > > values to their final locations.
> > 
> > > Accept the small complication of having
> > > to clear tdmr->pamt_4k_base in the error path, so that tdmr_do_pamt_func()
> > > will not try to operate on the TDMR struct when attempting to free it.
> > 
> > The clearing of tdmr->pamt_4k_base was dropped, so this section is a bit
> > stale. Apart from this nit,
> 
> Oh, good point.

With those nits fixed,

Reviewed-by: Yan Zhao <yan.y.zhao@intel.com>


^ permalink raw reply

* Re: [RFC PATCH 09/15] x86/virt/tdx: Add interface to generate a Quote
From: Peter Fang @ 2026-07-07  3:45 UTC (permalink / raw)
  To: Nikolay Borisov
  Cc: Xu Yilun, kas, djbw, rick.p.edgecombe, x86, linux-coco,
	linux-kernel, kvm, sohil.mehta, yilun.xu, baolu.lu,
	zhenzhong.duan, xiaoyao.li
In-Reply-To: <a8441214-1560-498d-ba01-0807502d0e28@suse.com>

On Wed, Jul 01, 2026 at 02:46:16PM +0300, Nikolay Borisov wrote:
> 
> 
> > @@ -1228,6 +1230,86 @@ bool tdx_quote_enabled(void)
> >   }
> >   EXPORT_SYMBOL_FOR_KVM(tdx_quote_enabled);
> > +#define QUOTE_ID_MASK		GENMASK_U64(47, 32)
> > +
> > +static u64 tdx_quote_get(struct tdx_td *td, u64 in_data_pa, u64 in_data_len,
> > +			 u64 hpa_list_pa, u64 total_len, u64 *quote_len)
> > +{
> > +	struct tdx_module_args args = {
> > +		.rcx = tdx_tdr_pa(td),
> > +		/* Don't bother specifying the quote id */
> > +		.rdx = QUOTE_ID_MASK & (u64)-1,
> 
> This is simply equal to QUOTE_ID_MASK, so why not create a special value
> meaning "ANY QUOTE" i.e
> 
> #define QUOTE_ID_MASK ....
> #define ANY_QUOTE QUOTE_ID_MASK
> 
> or some such .

I replaced it with just GENMASK_U64(47, 32) in the v2 series and added a
comment explaining it. QUOTE_ID_MASK isn't really needed since we don't
use any other Quote ID for this SEAMCALL. Hope this is clearer:

        struct tdx_module_args args = {
                .rcx = tdx_tdr_pa(td),
                /* [47:32] QUOTE_ID: All-1s selects the default quote format */
                .rdx = GENMASK_U64(47, 32),
                .r8 = in_data_pa,
                .r9 = in_data_len,
                .r10 = hpa_entries_pa,
                .r11 = total_len,
        };


> 
> > +		.r8 = in_data_pa,
> > +		.r9 = in_data_len,
> > +		.r10 = hpa_list_pa,
> > +		.r11 = total_len,
> > +	};
> > +	u64 r;
> > +
> > +	do {
> > +		r = seamcall_ret(TDH_QUOTE_GET, &args);
> > +	} while (r == TDX_INTERRUPTED_RESUMABLE);
> 
> 
> nit: This pattern seems to repeat a lot, might be worth it to consider
> introducing a wrapper similar to existing sc_retry?

I think Yilun gave some reasoning behind this in a separate reply:

https://lore.kernel.org/linux-coco/akaKmEZnTY4FO2gY@yilunxu-OptiPlex-7050/


> > +void *tdx_quote_generate(struct tdx_td *td, void *in_data, u32 in_data_len,
> > +			 u32 *quote_len)
> > +{
> > +	void *quote_dup = NULL;
> > +	u64 r, out_len;
> > +
> > +	if (!tdx_quote_enabled())
> > +		return NULL;
> > +
> > +	/* TDH.QUOTE.GET expects the input data to fit in a page */
> > +	if (in_data_len > PAGE_SIZE)
> > +		return NULL;
> > +
> > +	mutex_lock(&tdx_quote_lock);
> > +
> > +	/*
> > +	 * Use the first page of the quote buffer for input data. The buffer
> > +	 * must be at least one page in size. @in_data may not be page-aligned,
> > +	 * but TDH.QUOTE.GET expects page-aligned addresses.
> > +	 */
> > +	memcpy(quote_data.buf, in_data, (size_t)in_data_len);
> 
> Perhaps you can use min(PAGE_SIZE, in_data_len) and that way you can
> eliminate the in_data_len check above and copy up-to PAGE_SIZE data, if the
> data is longer - you will copy PAGE_SIZE which will likely result in error
> on generating the quote?

Oh that's an interesting idea. I'm going to change the implementation in
the upcoming v3 series and I'll see if using min() works. Thanks for the
suggestion.

> 

^ permalink raw reply

* Re: [PATCH v6 02/11] x86/virt/tdx: Allocate page bitmap for Dynamic PAMT
From: Yan Zhao @ 2026-07-07  3:59 UTC (permalink / raw)
  To: Rick Edgecombe
  Cc: bp, dave.hansen, hpa, kas, kvm, linux-coco, linux-doc,
	linux-kernel, mingo, nik.borisov, pbonzini, seanjc, tglx,
	vannapurve, x86, chao.gao, kai.huang, Kirill A. Shutemov,
	Binbin Wu
In-Reply-To: <20260526023515.288829-3-rick.p.edgecombe@intel.com>

On Mon, May 25, 2026 at 07:35:06PM -0700, Rick Edgecombe wrote:
> +static inline bool tdx_supports_dynamic_pamt(const struct tdx_sys_info *sysinfo)
> +{
> +	return false; /* To be enabled when kernel is ready */
> +}
> +
Nit:
Would the following style be better, though the comment will soon be removed?

static inline bool tdx_supports_dynamic_pamt(const struct tdx_sys_info *sysinfo)
{
	 /* To be enabled when kernel is ready */
	return false;
}

Reviewed-by: Yan Zhao <yan.y.zhao@intel.com>

^ permalink raw reply

* Re: [PATCH v6 04/11] x86/virt/tdx: Allocate ref counts for Dynamic PAMT memory
From: Yan Zhao @ 2026-07-07  4:53 UTC (permalink / raw)
  To: Rick Edgecombe
  Cc: bp, dave.hansen, hpa, kas, kvm, linux-coco, linux-doc,
	linux-kernel, mingo, nik.borisov, pbonzini, seanjc, tglx,
	vannapurve, x86, chao.gao, kai.huang, Kirill A. Shutemov
In-Reply-To: <20260526023515.288829-5-rick.p.edgecombe@intel.com>

On Mon, May 25, 2026 at 07:35:08PM -0700, Rick Edgecombe wrote:
> From: "Kirill A. Shutemov" <kirill.shutemov@linux.intel.com>
> 
> The PAMT memory holds metadata for all possible TDX protected memory. Each
> physical address range is covered by PAMT entries at three levels (1GB,
> 2MB, 4KB). With Dynamic PAMT, the 4KB range of PAMT is allocated on
                                         ^level ?
> demand. The kernel supplies the TDX module with page pairs to store the
> 4KB entries, which cover 2MB of host physical memory. The kernel must
4KB-level entries ?

> provide this page pair before using pages from the range for TDX. If this
> is not done, SEAMCALLs that give the pages to be protected by the TDX module
Nit: > 75 chars per line.

Reviewed-by: Yan Zhao <yan.y.zhao@intel.com>


 

^ permalink raw reply

* Re: [RFC PATCH 11/15] KVM: TDX: Factor out userspace return path from tdx_get_quote()
From: Peter Fang @ 2026-07-07  5:01 UTC (permalink / raw)
  To: Nikolay Borisov
  Cc: Xu Yilun, kas, djbw, rick.p.edgecombe, x86, linux-coco,
	linux-kernel, kvm, sohil.mehta, yilun.xu, baolu.lu,
	zhenzhong.duan, xiaoyao.li
In-Reply-To: <480873c9-c25b-4666-9abf-2e5b6894eef5@suse.com>

On Thu, Jul 02, 2026 at 01:08:57PM +0300, Nikolay Borisov wrote:
> 
> 
> > diff --git a/arch/x86/kvm/vmx/tdx.c b/arch/x86/kvm/vmx/tdx.c
> > index ed12805bbb44..9f7c39e0d4b5 100644
> > --- a/arch/x86/kvm/vmx/tdx.c
> > +++ b/arch/x86/kvm/vmx/tdx.c
> > @@ -1524,6 +1524,20 @@ static int tdx_complete_simple(struct kvm_vcpu *vcpu)
> >   	return 1;
> >   }
> > +static int tdx_get_quote_user(struct kvm_vcpu *vcpu, u64 gpa, u64 size)
> > +{
> nit: Function name is misleading, imo appropriate name should have
> "fill"/"init" in the name as what it does is to fill the run->tdx structure.
> 
> 
> tdx_fill_quote_user/tdx_init_quote_user
> 

Oh I see that now. Patch 12 adds this pattern to tdx_get_quote():

        if (kvm_tdx->get_quote_in_kernel)
                ret = tdx_get_quote_kernel(vcpu, gpa, size);
        else
                ret = tdx_get_quote_user(vcpu, gpa, size);


The intent was to create some symmetry between the two functions. The
kernel path generates the quote in the kernel without needing to touch
run->tdx, so the two functions are slightly different and perhaps
symmetry doesn't make sense.

How about tdx_prepare_quote_user()? That seems to pair well with
tdx_get_quote_kernel()?

> 
> 
> <snip>
> 

^ permalink raw reply

* Re: [RFC PATCH 12/15] KVM: TDX: Add in-kernel Quote generation
From: Peter Fang @ 2026-07-07  5:04 UTC (permalink / raw)
  To: Nikolay Borisov
  Cc: Xu Yilun, kas, djbw, rick.p.edgecombe, x86, linux-coco,
	linux-kernel, kvm, sohil.mehta, yilun.xu, baolu.lu,
	zhenzhong.duan, xiaoyao.li
In-Reply-To: <b5d0a554-4d2e-4338-918e-1251e697a309@suse.com>

On Thu, Jul 02, 2026 at 06:26:27PM +0300, Nikolay Borisov wrote:
> 
> 
> On 5/22/26 06:41, Xu Yilun wrote:
> > From: Peter Fang <peter.fang@intel.com>
> > 
> > Provide an in-kernel path for TDX Quote generation when handling
> > TDG.VP.VMCALL<GetQuote>, without requiring an exit to userspace.
> > 
> > Use the core TDX API when the TDX Quoting extension is available. For
> > simplicity, each KVM guest checks for availability only once during
> > initialization. KVM does not handle Quoting service disruptions.
> 
> I think calling this in-kernel quote generation vs user-spcae quote
> generation is misleading. Rather the distinction is : quote via the vmm or a
> quote generated by the tdx module/tdx extension. I think this should be the
> level at which the distinction is made.
> 
> 
> i.e tdx_get_quote_vmm vs tdx_get_quote_ext or some along those lines.

Makes sense. I can update the naming. Thanks.

> 
> 
> <snip>

^ permalink raw reply

* Re: [RFC PATCH 15/15] x86/virt/tdx: Enable TDX Quoting extension
From: Peter Fang @ 2026-07-07  5:07 UTC (permalink / raw)
  To: Nikolay Borisov
  Cc: Xu Yilun, kas, djbw, rick.p.edgecombe, x86, linux-coco,
	linux-kernel, kvm, sohil.mehta, yilun.xu, baolu.lu,
	zhenzhong.duan, xiaoyao.li
In-Reply-To: <15b253e2-1a2c-46b2-abe2-bf152d704523@suse.com>

On Fri, Jul 03, 2026 at 10:57:01AM +0300, Nikolay Borisov wrote:
> 
> 
> On 5/22/26 06:41, Xu Yilun wrote:
> > From: Peter Fang <peter.fang@intel.com>
> > 
> > Enable the TDX Quoting feature via TDH.SYS.CONFIG when supported by the
> > TDX module.
> > 
> > The TDX Quoting extension generates TDX attestation Quotes via a
> > SEAMCALL, without using a discrete Quoting engine.
> "Quoting engine" is a new term, introduced here, better say "without
> involvement from the VMM"

Yep, I'll remove that term. Thanks.

> 
> <snip>

^ permalink raw reply

* Re: [PATCH v6 05/11] x86/virt/tdx: Handle concurrent callers in tdx_pamt_get/put()
From: Chao Gao @ 2026-07-07  5:54 UTC (permalink / raw)
  To: Rick Edgecombe
  Cc: bp, dave.hansen, hpa, kas, kvm, linux-coco, linux-doc,
	linux-kernel, mingo, nik.borisov, pbonzini, seanjc, tglx,
	vannapurve, x86, yan.y.zhao, kai.huang, Kirill A. Shutemov
In-Reply-To: <20260526023515.288829-6-rick.p.edgecombe@intel.com>

>@@ -2057,10 +2061,26 @@ static int tdx_pamt_get(kvm_pfn_t pfn)
> 	if (ret)
> 		return ret;
> 
>-	tdx_status = tdh_phymem_pamt_add(pfn, pamt_pages);
>-	if (tdx_status != TDX_SUCCESS) {
>-		ret = -EIO;
>-		goto out_free;
>+	pamt_refcount = tdx_find_pamt_refcount(pfn);
>+
>+	scoped_guard(spinlock, &pamt_lock) {

I am assuming you will convert this to plain lock/unlock as discussed.

With this fixed,

Reviewed-by: Chao Gao <chao.gao@intel.com>

^ permalink raw reply

* Re: [PATCH v6 06/11] x86/virt/tdx: Optimize tdx_pamt_get/put()
From: Chao Gao @ 2026-07-07  6:45 UTC (permalink / raw)
  To: Rick Edgecombe
  Cc: bp, dave.hansen, hpa, kas, kvm, linux-coco, linux-doc,
	linux-kernel, mingo, nik.borisov, pbonzini, seanjc, tglx,
	vannapurve, x86, yan.y.zhao, kai.huang, Kirill A. Shutemov
In-Reply-To: <20260526023515.288829-7-rick.p.edgecombe@intel.com>

On Mon, May 25, 2026 at 07:35:10PM -0700, Rick Edgecombe wrote:
>@@ -2057,32 +2057,50 @@ static int tdx_pamt_get(kvm_pfn_t pfn)

[snip]

>+	/*
>+	 * Unlike tdx_pamt_put() which uses atomic_dec_and_lock() to
>+	 * atomically handle the 1->0 transition, the get side has no
>+	 * equivalent combined primitive for 0->1. Recheck under the
>+	 * lock since another get may have already done the 0->1
>+	 * transition after both saw atomic_inc_not_zero() fail.
>+	 */
>+	if (atomic_read(pamt_refcount)) {
>+		atomic_inc(pamt_refcount);
>+		spin_unlock(&pamt_lock);
>+		goto out_free;

spin_unlock() can be moved to out_free to avoid repeating it before
each 'goto out_free'.

> 	}
> 
>+	tdx_status = tdh_phymem_pamt_add(pfn, pamt_pages);
>+	if (tdx_status == TDX_SUCCESS) {
>+		/*
>+		 * The refcount is zero, and this locked path is the
>+		 * only way to increase it from 0->1.
>+		 */
>+		atomic_set(pamt_refcount, 1);
>+	} else {
>+		WARN_ON_ONCE(1);
>+		ret = -EIO;
>+		spin_unlock(&pamt_lock);
>+		goto out_free;
>+	}

Reduce indentation for the normal path:

	if (tdx_status != TDX_SUCCESS) {
		WARN_ON_ONCE(1);
		ret = -EIO;
		spin_unlock(&pamt_lock);
		goto out_free;
	}

	/*
	 * The refcount is zero, and this locked path is the
	 * only way to increase it from 0->1.
	 */
	atomic_set(pamt_refcount, 1);


The rest looks good to me.

Reviewed-by: Chao Gao <chao.gao@intel.com>

^ permalink raw reply

* Re: [PATCH v6 07/11] KVM: TDX: Allocate PAMT memory for TD and vCPU control structures
From: Chao Gao @ 2026-07-07  6:54 UTC (permalink / raw)
  To: Rick Edgecombe
  Cc: bp, dave.hansen, hpa, kas, kvm, linux-coco, linux-doc,
	linux-kernel, mingo, nik.borisov, pbonzini, seanjc, tglx,
	vannapurve, x86, yan.y.zhao, kai.huang, Kirill A. Shutemov
In-Reply-To: <20260526023515.288829-8-rick.p.edgecombe@intel.com>

On Mon, May 25, 2026 at 07:35:11PM -0700, Rick Edgecombe wrote:
>From: "Kirill A. Shutemov" <kirill.shutemov@linux.intel.com>
>
>Use control page helpers for allocating and freeing TD control structures,
>such these operations can work for Dynamic PAMT.
>
>The TDX module tracks some state for each page of physical memory that it
>might use. It calls this state the PAMT. It includes separate state for
>each page size a physical page could be utilized at within the TDX module
>(1GB, 2MB, 4KB). In Dynamic PAMT, only the 4KB page size state is
>allocated dynamically. So the kernel must install PAMT backing for each 4KB
>page before gifting it to the TDX module, and tear it down after the page
>is reclaimed.
>
>TD-scoped control pages (TDR, TDCS) and vCPU-scoped control pages (TDVPR,
>TDCX) are all handed to the TDX module at 4KB page size and are therefore
>subject to this requirement. Replace the raw alloc_page()/__free_page()
>calls for these pages with tdx_alloc/free_control_page().
>
>Switching between special Dynamic PAMT operations or normal page
>alloc/free operations is handled internally in
>tdx_alloc/free_control_page(). So don't check for Dynamic PAMT around these
>calls. Just call them unconditionally. Similarly, drop the NULL checks
>before freeing, as tdx_free_control_page() handles NULL internally.
>
>No functional change intended when Dynamic PAMT is not in use.
>
>Assisted-by: GitHub Copilot:claude-opus-4-6 Claude:claude-opus-4-7
>Signed-off-by: Kirill A. Shutemov <kirill.shutemov@linux.intel.com>
>[sean: handle alloc+free+reclaim in one patch]
>Co-developed-by: Sean Christopherson <seanjc@google.com>
>Signed-off-by: Sean Christopherson <seanjc@google.com>
>[Rick: enhance log]
>Signed-off-by: Rick Edgecombe <rick.p.edgecombe@intel.com>

Reviewed-by: Chao Gao <chao.gao@intel.com>

^ permalink raw reply

* Re: [PATCH v6 08/11] x86/tdx: Add APIs to support Dynamic PAMT ops from KVM's fault path
From: Chao Gao @ 2026-07-07  7:25 UTC (permalink / raw)
  To: Rick Edgecombe
  Cc: bp, dave.hansen, hpa, kas, kvm, linux-coco, linux-doc,
	linux-kernel, mingo, nik.borisov, pbonzini, seanjc, tglx,
	vannapurve, x86, yan.y.zhao, kai.huang
In-Reply-To: <20260526023515.288829-9-rick.p.edgecombe@intel.com>

On Mon, May 25, 2026 at 07:35:12PM -0700, Rick Edgecombe wrote:
>When handling an EPT violation, KVM holds a spinlock while manipulating
>the EPT. Before entering the spinlock it doesn't know how many EPT page
>tables will need to be installed or whether a huge page will be used. For
>this reason it allocates a worst case number of page tables that it might
>need as part of servicing the EPT violation.
>
>Under Dynamic PAMT these pre-allocated pages will potentially need to have
>Dynamic PAMT backing pages installed for them. KVM already has helpers to
>manage topping up page caches before taking the MMU lock, but they cannot be
>passed from KVM to arch/x86 code.
>
>The problem of how and when to install the DPAMT backing pages for the
>pages given to the TDX module during the fault path has had a lot of
>design attempts.
> - Extracting KVM's MMU caches requires too much inlined code added to
>   headers.
> - A few varieties of installing Dynamic PAMT backing when allocating the
>   S-EPT page tables. [0][1]
> - Using mempool_t to transfer the pages between KVM and arch/x86 doesn't
>   work because it is the component is designed more around maintaining a
>   pool of pages, rather than topping up a continually drained cache.
>
>So don't do these as they all had various problems. Instead just create a
>small simple data structure to use for handing a pre-allocated list of
>pages between KVM and arch/x86 code. Model this on KVM's existing MMU
>memory caches.
>
>Add a tdx_pamt_cache arg to tdx_pamt_get() so it can draw pages from a
>cache when needed. Not all DPAMT page installations will happen under
>spinlock, for example control pages. So have tdx_pamt_get() maintain the
>existing behavior of allocating from the page allocator when NULL is
>passed for the struct tdx_pamt_cache arg. This prevents excess allocations
>for cases where it can be avoided.
>
>Export the new helpers for KVM.
>
>Assisted-by: GitHub Copilot:claude-opus-4-6 Claude:claude-opus-4-7
>Co-developed-by: Sean Christopherson <seanjc@google.com>
>Signed-off-by: Sean Christopherson <seanjc@google.com>
>Signed-off-by: Rick Edgecombe <rick.p.edgecombe@intel.com>

Reviewed-by: Chao Gao <chao.gao@intel.com>

^ permalink raw reply

* Re: [PATCH v7 00/22] dma-mapping: Track shared DMA state through direct, pool and swiotlb paths
From: Aneesh Kumar K.V @ 2026-07-07  8:06 UTC (permalink / raw)
  To: iommu, linux-arm-kernel, linux-kernel, linux-coco
  Cc: Robin Murphy, Marek Szyprowski, Will Deacon, Marc Zyngier,
	Steven Price, Suzuki K Poulose, Catalin Marinas, Jiri Pirko,
	Jason Gunthorpe, Mostafa Saleh, Petr Tesarik,
	Alexey Kardashevskiy, Dan Williams, Xu Yilun, linuxppc-dev,
	linux-s390, Madhavan Srinivasan, Michael Ellerman,
	Nicholas Piggin, Christophe Leroy (CS GROUP), Alexander Gordeev,
	Gerald Schaefer, Heiko Carstens, Vasily Gorbik,
	Christian Borntraeger, Sven Schnelle, x86
In-Reply-To: <20260701054926.825925-1-aneesh.kumar@kernel.org>

"Aneesh Kumar K.V (Arm)" <aneesh.kumar@kernel.org> writes:

> This series tracks confidential-computing shared DMA state through the
> dma-direct, dma-pool, and swiotlb paths so that encrypted and decrypted
> DMA buffers are handled consistently.
>
> Today, the direct DMA path mostly relies on force_dma_unencrypted() for
> shared/decrypted buffer handling. This series consolidates the
> force_dma_unencrypted() checks in the top-level functions and ensures
> that the remaining DMA interfaces use DMA attributes to make the correct
> decisions.
>
> The series separates mapping and allocation state:
> - DMA_ATTR_CC_SHARED describes the DMA address attribute requested for a
>   mapping. It tells the DMA mapping path that the DMA address must target
>   shared/decrypted memory.
> - __DMA_ATTR_ALLOC_CC_SHARED is an internal DMA-mapping attribute used only
>   by allocation paths after the DMA core decides that the backing pages
>   must be allocated as shared/decrypted memory.
>
> The series:
> - moves swiotlb-backed allocations out of __dma_direct_alloc_pages(),
> - uses __DMA_ATTR_ALLOC_CC_SHARED through the dma-direct alloc/free paths
> - teaches the atomic DMA pools to track encrypted versus decrypted
>   state
> - tracks swiotlb pool encryption state and enforces strict pool
>   selection
> - centralizes encrypted/decrypted pgprot handling in dma_pgprot() using
>   DMA attributes
> - passes DMA attributes down to dma_capable() so capability checks can
>   validate whether the selected DMA address encoding matches
>   DMA_ATTR_CC_SHARED
> - makes dma_direct_map_phys() choose the DMA address encoding from
>   DMA_ATTR_CC_SHARED and fall back to swiotlb when a shared DMA request
>   cannot use the direct mapping, which lets arm64 and x86 CCA guests stop
>   relying on SWIOTLB_FORCE for DMA mappings
> - use the selected swiotlb pool state to derive the returned DMA
>   address
> - reports CC_ATTR_GUEST_MEM_ENCRYPT for arm64 Realms, powerpc secure
>   guests, and s390 protected virtualization guests.
>
> Dependency:
> This series depends on the pKVM changes posted at:
> https://lore.kernel.org/all/20260603110522.3331819-1-smostafa@google.com
>
> Please merge this series only after the pKVM changes above are merged.
> Otherwise pKVM will be broken.
>

A rebased tree on top of the dependent pKVM changes can be found at:
https://gitlab.arm.com/linux-arm/linux-cca/-/tree/scratch/pkvm/testing?ref_type=heads

The patches had minor conflicts. I am not sure how we want to get this
merged.

Should we ask the pKVM maintainers for a topic branch, and then I can
repost the updated series on top of that?

-aneesh


^ permalink raw reply

* [PATCH v8 0/6] Switch Arm SMCCC firmware services to an SMCCC bus
From: Aneesh Kumar K.V (Arm) @ 2026-07-07  8:13 UTC (permalink / raw)
  To: linux-coco, linux-arm-kernel, linux-kernel
  Cc: Aneesh Kumar K.V (Arm), Catalin Marinas, Greg KH, Jeremy Linton,
	Jonathan Cameron, Lorenzo Pieralisi, Mark Rutland, Sudeep Holla,
	Will Deacon, Steven Price, Suzuki K Poulose, Andre Przywara

As discussed here:
https://lore.kernel.org/all/20250728135216.48084-12-aneesh.kumar@kernel.org

The earlier CCA guest support used an arm-cca-dev platform device as a pure
software anchor for the TSM class device. That platform device did not
correspond to a DT/ACPI described device, MMIO range, interrupt, or other
platform resource; it existed only to make the CCA guest driver bind and to
place the resulting TSM device in the driver model. The same pattern also
exists for smccc_trng. Creating separate platform devices for such
SMCCC-discovered features is misleading, because those features are not
independent platform devices.

This series adds an Arm SMCCC bus for services discovered through the SMCCC
firmware interface. The bus provides SMCCC device and driver registration
helpers, name-based matching, uevent modalias generation, and a sysfs modalias
attribute. SMCCC service drivers can use MODULE_DEVICE_TABLE(arm_smccc, ...)
to emit arm_smccc:<name> aliases, allowing userspace to autoload service
drivers when the SMCCC core registers matching firmware-service devices.

The series then moves SMCCC TRNG and the Arm CCA guest RSI service off the
platform bus. When the SMCCC core discovers the corresponding firmware
service, it registers an arm-smccc device for that service. The hwrng
arm_smccc_trng driver and the Arm CCA guest TSM provider are converted to
SMCCC drivers that bind to those discovered devices.

The old arm-cca-dev platform device has also been used by userspace as a Realm
guest indicator. Removing it without a replacement would leave userspace
depending on an internal driver-binding device. This series therefore adds
/sys/firmware/cca/realm_guest as a stable, architecture-provided ABI for
detecting whether the kernel is running as an Arm CCA Realm guest, and then
removes the dummy arm-cca-dev platform-device registration.

Changes from v7:
https://lore.kernel.org/all/20260611130429.295516-1-aneesh.kumar@kernel.org
* Rebase to latest kernel
* Add id_table check in arm_smccc_driver_register
* Add smccc device name check in arm_smccc_device_register
* Drop driver_data from struct arm_smccc_device_id  

Changes from v6:
https://lore.kernel.org/all/20260527100233.428018-1-aneesh.kumar@kernel.org
* Move SMCCC bus-related code to bus.c.
* Remove CONFIG_ARM64 #ifdefs and switch device creation to use the generic function-ID support framework.
* Move version-specific checks and other conditionals to the device driver probe routines.
* Move RSI definitions to include/linux/arm-smccc-rsi.h.
* Split the file and variable renames into a separate patch.

Changes from v5:
https://lore.kernel.org/all/20260514094030.42495-1-aneesh.kumar@kernel.org
* Replace the arm-smccc platform-device plus auxiliary-child model with a
  dedicated Arm SMCCC bus.
* Add SMCCC module alias support so SMCCC service drivers can use
  MODULE_DEVICE_TABLE(arm_smccc, ...) and autoload through arm_smccc:<name>
  aliases.
* Convert smccc_trng from a platform driver to an SMCCC driver.
* Convert the Arm CCA guest TSM provider from the arm-cca-dev platform device
  to an SMCCC driver bound to the discovered RSI service.
* Add /sys/firmware/cca/realm_guest before removing the old arm-cca-dev dummy
  platform device.

Changes from v4:
https://lore.kernel.org/all/20260427061615.905018-1-aneesh.kumar@kernel.org
* Add /sys/firmware/cca/realm_guest for detecting realm guest
* Convert smccc_trng to auxiliary device from platform device

Changes from v3:
https://lore.kernel.org/all/20260309100507.2303361-1-aneesh.kumar@kernel.org
* Rebased onto the latest kernel
* Drop pr_fmt() from drivers/firmware/smccc/rmm.c

Cc: Catalin Marinas <catalin.marinas@arm.com>
Cc: Greg KH <gregkh@linuxfoundation.org>
Cc: Jeremy Linton <jeremy.linton@arm.com>
Cc: Jonathan Cameron <jic23@kernel.org>
Cc: Lorenzo Pieralisi <lpieralisi@kernel.org>
Cc: Mark Rutland <mark.rutland@arm.com>
Cc: Sudeep Holla <sudeep.holla@arm.com>
Cc: Will Deacon <will@kernel.org>
Cc: Steven Price <steven.price@arm.com>
Cc: Suzuki K Poulose <Suzuki.Poulose@arm.com>
Cc: Andre Przywara <andre.przywara@arm.com>


Aneesh Kumar K.V (Arm) (6):
  firmware: smccc: Add an Arm SMCCC bus
  firmware: hwrng: arm_smccc_trng: Register as an SMCCC device
  firmware: smccc: Move RSI definitions to include/linux
  virt: coco: arm-cca-guest: Rename TSM report source file
  firmware: smccc: arm-cca-guest: Bind the TSM provider to an SMCCC
    device
  coco: guest: arm64: Replace dummy CCA device with sysfs ABI

 Documentation/ABI/testing/sysfs-firmware-cca  |  10 ++
 arch/arm/include/asm/archrandom.h             |   2 +-
 arch/arm64/include/asm/archrandom.h           |   2 +-
 arch/arm64/include/asm/rsi.h                  |   2 -
 arch/arm64/include/asm/rsi_cmds.h             |  75 +-------
 arch/arm64/kernel/rsi.c                       |  39 ++--
 drivers/char/hw_random/arm_smccc_trng.c       |  32 ++--
 drivers/firmware/smccc/Makefile               |   2 +-
 drivers/firmware/smccc/bus.c                  | 167 ++++++++++++++++++
 drivers/firmware/smccc/smccc.c                |  65 ++++++-
 drivers/virt/coco/arm-cca-guest/Kconfig       |   1 +
 drivers/virt/coco/arm-cca-guest/Makefile      |   2 +
 .../{arm-cca-guest.c => arm-cca.c}            |  62 +++----
 drivers/virt/coco/arm-cca-guest/rsi.h         |  84 +++++++++
 include/linux/arm-smccc-bus.h                 |  49 +++++
 .../linux/arm-smccc-rsi.h                     |   8 +-
 include/linux/device-id/arm_smccc.h           |  16 ++
 include/linux/mod_devicetable.h               |   1 +
 scripts/mod/devicetable-offsets.c             |   3 +
 scripts/mod/file2alias.c                      |   8 +
 20 files changed, 488 insertions(+), 142 deletions(-)
 create mode 100644 Documentation/ABI/testing/sysfs-firmware-cca
 create mode 100644 drivers/firmware/smccc/bus.c
 rename drivers/virt/coco/arm-cca-guest/{arm-cca-guest.c => arm-cca.c} (85%)
 create mode 100644 drivers/virt/coco/arm-cca-guest/rsi.h
 create mode 100644 include/linux/arm-smccc-bus.h
 rename arch/arm64/include/asm/rsi_smc.h => include/linux/arm-smccc-rsi.h (97%)
 create mode 100644 include/linux/device-id/arm_smccc.h


base-commit: 8cdeaa50eae8dad34885515f62559ee83e7e8dda
-- 
2.43.0


^ permalink raw reply

* [PATCH v8 1/6] firmware: smccc: Add an Arm SMCCC bus
From: Aneesh Kumar K.V (Arm) @ 2026-07-07  8:13 UTC (permalink / raw)
  To: linux-coco, linux-arm-kernel, linux-kernel
  Cc: Aneesh Kumar K.V (Arm), Catalin Marinas, Greg KH, Jeremy Linton,
	Jonathan Cameron, Lorenzo Pieralisi, Mark Rutland, Sudeep Holla,
	Will Deacon, Steven Price, Suzuki K Poulose, Andre Przywara
In-Reply-To: <20260707081351.1680209-1-aneesh.kumar@kernel.org>

SMCCC-discovered firmware services are currently represented by separate
platform devices, such as smccc_trng and arm-cca-dev. Those devices do not
represent independent DT/ACPI-described platform resources; they are
features of the SMCCC firmware interface.

Add an Arm SMCCC bus for services discovered through the SMCCC firmware
interface. The bus provides SMCCC device and driver registration helpers,
name-based matching, modalias generation, and a sysfs modalias attribute so
SMCCC service drivers can bind to discovered firmware services and autoload
as modules.

Follow-up changes can then register SMCCC firmware services as arm-smccc
devices instead of creating independent per-feature platform devices.

Based on arm_ffa code

Signed-off-by: Aneesh Kumar K.V (Arm) <aneesh.kumar@kernel.org>
---
 drivers/firmware/smccc/Makefile     |   2 +-
 drivers/firmware/smccc/bus.c        | 167 ++++++++++++++++++++++++++++
 include/linux/arm-smccc-bus.h       |  49 ++++++++
 include/linux/device-id/arm_smccc.h |  16 +++
 include/linux/mod_devicetable.h     |   1 +
 scripts/mod/devicetable-offsets.c   |   3 +
 scripts/mod/file2alias.c            |   8 ++
 7 files changed, 245 insertions(+), 1 deletion(-)
 create mode 100644 drivers/firmware/smccc/bus.c
 create mode 100644 include/linux/arm-smccc-bus.h
 create mode 100644 include/linux/device-id/arm_smccc.h

diff --git a/drivers/firmware/smccc/Makefile b/drivers/firmware/smccc/Makefile
index 40d19144a860..68bbff1407b8 100644
--- a/drivers/firmware/smccc/Makefile
+++ b/drivers/firmware/smccc/Makefile
@@ -1,4 +1,4 @@
 # SPDX-License-Identifier: GPL-2.0
 #
-obj-$(CONFIG_HAVE_ARM_SMCCC_DISCOVERY)	+= smccc.o kvm_guest.o
+obj-$(CONFIG_HAVE_ARM_SMCCC_DISCOVERY)	+= bus.o smccc.o kvm_guest.o
 obj-$(CONFIG_ARM_SMCCC_SOC_ID)	+= soc_id.o
diff --git a/drivers/firmware/smccc/bus.c b/drivers/firmware/smccc/bus.c
new file mode 100644
index 000000000000..61dc2c60757c
--- /dev/null
+++ b/drivers/firmware/smccc/bus.c
@@ -0,0 +1,167 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (C) 2026 Arm Limited
+ */
+
+#include <linux/arm-smccc-bus.h>
+#include <linux/idr.h>
+#include <linux/slab.h>
+
+static DEFINE_IDA(arm_smccc_bus_id);
+
+static int arm_smccc_bus_match(struct device *dev,
+		const struct device_driver *drv)
+{
+	const struct arm_smccc_device_id *id_table;
+	struct arm_smccc_device *smccc_dev = to_arm_smccc_device(dev);
+
+	id_table = to_arm_smccc_driver(drv)->id_table;
+	if (!id_table)
+		return 0;
+
+	while (id_table->name[0]) {
+		if (!strcmp(smccc_dev->name, id_table->name))
+			return 1;
+		id_table++;
+	}
+
+	return 0;
+}
+
+static int arm_smccc_bus_probe(struct device *dev)
+{
+	struct arm_smccc_driver *smccc_drv = to_arm_smccc_driver(dev->driver);
+
+	return smccc_drv->probe(to_arm_smccc_device(dev));
+}
+
+static void arm_smccc_bus_remove(struct device *dev)
+{
+	struct arm_smccc_driver *smcc_drv = to_arm_smccc_driver(dev->driver);
+
+	if (smcc_drv->remove)
+		smcc_drv->remove(to_arm_smccc_device(dev));
+}
+
+static int arm_smccc_bus_uevent(const struct device *dev,
+		struct kobj_uevent_env *env)
+{
+	const struct arm_smccc_device *smccc_dev = to_arm_smccc_device(dev);
+
+	return add_uevent_var(env, "MODALIAS=" ARM_SMCCC_MODULE_PREFIX "%s",
+			      smccc_dev->name);
+}
+
+static ssize_t modalias_show(struct device *dev,
+		struct device_attribute *attr, char *buf)
+{
+	struct arm_smccc_device *smccc_dev = to_arm_smccc_device(dev);
+
+	return sysfs_emit(buf, ARM_SMCCC_MODULE_PREFIX "%s\n", smccc_dev->name);
+}
+static DEVICE_ATTR_RO(modalias);
+
+static struct attribute *arm_smccc_device_attrs[] = {
+	&dev_attr_modalias.attr,
+	NULL,
+};
+ATTRIBUTE_GROUPS(arm_smccc_device);
+
+const struct bus_type arm_smccc_bus_type = {
+	.name = "arm_smccc",
+	.match = arm_smccc_bus_match,
+	.probe = arm_smccc_bus_probe,
+	.remove = arm_smccc_bus_remove,
+	.uevent = arm_smccc_bus_uevent,
+	.dev_groups = arm_smccc_device_groups,
+};
+EXPORT_SYMBOL_GPL(arm_smccc_bus_type);
+
+int arm_smccc_driver_register(struct arm_smccc_driver *driver,
+		struct module *owner, const char *mod_name)
+{
+	if (!driver->probe || !driver->id_table)
+		return -EINVAL;
+
+	driver->driver.bus = &arm_smccc_bus_type;
+	driver->driver.name = driver->name;
+	driver->driver.owner = owner;
+	driver->driver.mod_name = mod_name;
+
+	return driver_register(&driver->driver);
+}
+EXPORT_SYMBOL_GPL(arm_smccc_driver_register);
+
+void arm_smccc_driver_unregister(struct arm_smccc_driver *driver)
+{
+	driver_unregister(&driver->driver);
+}
+EXPORT_SYMBOL_GPL(arm_smccc_driver_unregister);
+
+static void arm_smccc_release_device(struct device *dev)
+{
+	struct arm_smccc_device *smccc_dev = to_arm_smccc_device(dev);
+
+	ida_free(&arm_smccc_bus_id, smccc_dev->id);
+	kfree(smccc_dev);
+}
+
+struct arm_smccc_device *arm_smccc_device_register(const char *name)
+{
+	int id, ret;
+	struct arm_smccc_device *smccc_dev;
+
+	if (!name)
+		return ERR_PTR(-EINVAL);
+
+	id = ida_alloc_min(&arm_smccc_bus_id, 1, GFP_KERNEL);
+	if (id < 0)
+		return ERR_PTR(id);
+
+	smccc_dev = kzalloc_obj(*smccc_dev);
+	if (!smccc_dev) {
+		ida_free(&arm_smccc_bus_id, id);
+		return ERR_PTR(-ENOMEM);
+	}
+
+	smccc_dev->id = id;
+	if (strscpy(smccc_dev->name, name) < 0) {
+		kfree(smccc_dev);
+		ida_free(&arm_smccc_bus_id, id);
+		return ERR_PTR(-EINVAL);
+	}
+	smccc_dev->dev.bus = &arm_smccc_bus_type;
+	smccc_dev->dev.release = arm_smccc_release_device;
+
+	ret = dev_set_name(&smccc_dev->dev, "%s-%d", smccc_dev->name, id);
+	if (ret) {
+		kfree(smccc_dev);
+		ida_free(&arm_smccc_bus_id, id);
+		return ERR_PTR(ret);
+	}
+
+	ret = device_register(&smccc_dev->dev);
+	if (ret) {
+		put_device(&smccc_dev->dev);
+		return ERR_PTR(ret);
+	}
+
+	return smccc_dev;
+}
+EXPORT_SYMBOL_GPL(arm_smccc_device_register);
+
+void arm_smccc_device_unregister(struct arm_smccc_device *smccc_dev)
+{
+	if (!smccc_dev)
+		return;
+
+	device_unregister(&smccc_dev->dev);
+}
+EXPORT_SYMBOL_GPL(arm_smccc_device_unregister);
+
+static int __init arm_smccc_bus_init(void)
+{
+	return bus_register(&arm_smccc_bus_type);
+}
+subsys_initcall(arm_smccc_bus_init);
+
diff --git a/include/linux/arm-smccc-bus.h b/include/linux/arm-smccc-bus.h
new file mode 100644
index 000000000000..2a08868507d1
--- /dev/null
+++ b/include/linux/arm-smccc-bus.h
@@ -0,0 +1,49 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * Copyright (C) 2026 Arm Limited
+ */
+#ifndef __LINUX_ARM_SMCCC_BUS_H
+#define __LINUX_ARM_SMCCC_BUS_H
+
+#include <linux/device.h>
+#include <linux/device-id/arm_smccc.h>
+#include <linux/module.h>
+
+struct arm_smccc_device {
+	int id;
+	char name[ARM_SMCCC_NAME_SIZE];
+	struct device dev;
+};
+
+#define to_arm_smccc_device(d) container_of(d, struct arm_smccc_device, dev)
+
+struct arm_smccc_driver {
+	const char *name;
+	int (*probe)(struct arm_smccc_device *sdev);
+	void (*remove)(struct arm_smccc_device *sdev);
+	const struct arm_smccc_device_id *id_table;
+
+	struct device_driver driver;
+};
+
+#define to_arm_smccc_driver(d) \
+	container_of_const(d, struct arm_smccc_driver, driver)
+
+int arm_smccc_driver_register(struct arm_smccc_driver *driver,
+		struct module *owner, const char *mod_name);
+void arm_smccc_driver_unregister(struct arm_smccc_driver *driver);
+struct arm_smccc_device *arm_smccc_device_register(const char *name);
+void arm_smccc_device_unregister(struct arm_smccc_device *smcc_dev);
+
+#define arm_smccc_register(driver) \
+	arm_smccc_driver_register(driver, THIS_MODULE, KBUILD_MODNAME)
+#define arm_smccc_unregister(driver) \
+	arm_smccc_driver_unregister(driver)
+
+#define module_arm_smccc_driver(__arm_smccc_driver) \
+	module_driver(__arm_smccc_driver, arm_smccc_register, \
+		      arm_smccc_unregister)
+
+extern const struct bus_type arm_smccc_bus_type;
+
+#endif /* __LINUX_ARM_SMCCC_BUS_H */
diff --git a/include/linux/device-id/arm_smccc.h b/include/linux/device-id/arm_smccc.h
new file mode 100644
index 000000000000..c8d38a002bfd
--- /dev/null
+++ b/include/linux/device-id/arm_smccc.h
@@ -0,0 +1,16 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#ifndef __LINUX_DEVICE_ID_ARM_SMCCC_H
+#define __LINUX_DEVICE_ID_ARM_SMCCC_H
+
+#define ARM_SMCCC_NAME_SIZE 40
+#define ARM_SMCCC_MODULE_PREFIX "arm_smccc:"
+
+/**
+ * struct arm_smccc_device_id - Arm SMCCC bus device identifier
+ * @name: SMCCC device name
+ */
+struct arm_smccc_device_id {
+	char name[ARM_SMCCC_NAME_SIZE];
+};
+
+#endif /* __LINUX_DEVICE_ID_ARM_SMCCC_H */
diff --git a/include/linux/mod_devicetable.h b/include/linux/mod_devicetable.h
index a397213bedac..318c4b5c3451 100644
--- a/include/linux/mod_devicetable.h
+++ b/include/linux/mod_devicetable.h
@@ -16,6 +16,7 @@
 #include "device-id/amba.h"
 #include "device-id/ap.h"
 #include "device-id/apr.h"
+#include "device-id/arm_smccc.h"
 #include "device-id/auxiliary.h"
 #include "device-id/bcma.h"
 #include "device-id/ccw.h"
diff --git a/scripts/mod/devicetable-offsets.c b/scripts/mod/devicetable-offsets.c
index b4178c42d08f..a485011ff137 100644
--- a/scripts/mod/devicetable-offsets.c
+++ b/scripts/mod/devicetable-offsets.c
@@ -254,6 +254,9 @@ int main(void)
 	DEVID(auxiliary_device_id);
 	DEVID_FIELD(auxiliary_device_id, name);
 
+	DEVID(arm_smccc_device_id);
+	DEVID_FIELD(arm_smccc_device_id, name);
+
 	DEVID(ssam_device_id);
 	DEVID_FIELD(ssam_device_id, match_flags);
 	DEVID_FIELD(ssam_device_id, domain);
diff --git a/scripts/mod/file2alias.c b/scripts/mod/file2alias.c
index 8d36c74dec2d..7d62e74f475d 100644
--- a/scripts/mod/file2alias.c
+++ b/scripts/mod/file2alias.c
@@ -1349,6 +1349,13 @@ static void do_auxiliary_entry(struct module *mod, void *symval)
 	module_alias_printf(mod, false, AUXILIARY_MODULE_PREFIX "%s", *name);
 }
 
+static void do_arm_smccc_entry(struct module *mod, void *symval)
+{
+	DEF_FIELD_ADDR(symval, arm_smccc_device_id, name);
+
+	module_alias_printf(mod, false, ARM_SMCCC_MODULE_PREFIX "%s", *name);
+}
+
 /*
  * Looks like: ssam:dNcNtNiNfN
  *
@@ -1519,6 +1526,7 @@ static const struct devtable devtable[] = {
 	{"mhi", SIZE_mhi_device_id, do_mhi_entry},
 	{"mhi_ep", SIZE_mhi_device_id, do_mhi_ep_entry},
 	{"auxiliary", SIZE_auxiliary_device_id, do_auxiliary_entry},
+	{"arm_smccc", SIZE_arm_smccc_device_id, do_arm_smccc_entry},
 	{"ssam", SIZE_ssam_device_id, do_ssam_entry},
 	{"dfl", SIZE_dfl_device_id, do_dfl_entry},
 	{"ishtp", SIZE_ishtp_device_id, do_ishtp_entry},
-- 
2.43.0


^ permalink raw reply related

* [PATCH v8 2/6] firmware: hwrng: arm_smccc_trng: Register as an SMCCC device
From: Aneesh Kumar K.V (Arm) @ 2026-07-07  8:13 UTC (permalink / raw)
  To: linux-coco, linux-arm-kernel, linux-kernel
  Cc: Aneesh Kumar K.V (Arm), Catalin Marinas, Greg KH, Jeremy Linton,
	Jonathan Cameron, Lorenzo Pieralisi, Mark Rutland, Sudeep Holla,
	Will Deacon, Steven Price, Suzuki K Poulose, Andre Przywara
In-Reply-To: <20260707081351.1680209-1-aneesh.kumar@kernel.org>

The SMCCC TRNG interface is a firmware-provided SMCCC service rather than a
standalone platform device. Now that the SMCCC core has an SMCCC bus,
create an arm-smccc-trng device for the discovered TRNG service and convert
the hwrng driver to an SMCCC driver.

The SMCCC id table preserves module autoloading for systems where the TRNG
driver is built as a module.

The sysfs device path changes from the old smccc_trng platform-device path
to an arm-smccc device path. No known userspace dependency on the old path
was found; a Debian Code Search lookup for the existing platform-device
name/path did not find any users.

Tested-by: Andre Przywara <andre.przywara@arm.com>
Signed-off-by: Aneesh Kumar K.V (Arm) <aneesh.kumar@kernel.org>
---
 arch/arm/include/asm/archrandom.h       |  2 +-
 arch/arm64/include/asm/archrandom.h     |  2 +-
 drivers/char/hw_random/arm_smccc_trng.c | 32 +++++++++-----
 drivers/firmware/smccc/smccc.c          | 58 +++++++++++++++++++++----
 4 files changed, 72 insertions(+), 22 deletions(-)

diff --git a/arch/arm/include/asm/archrandom.h b/arch/arm/include/asm/archrandom.h
index cc4714eb1a75..ee39a03ddf8a 100644
--- a/arch/arm/include/asm/archrandom.h
+++ b/arch/arm/include/asm/archrandom.h
@@ -2,7 +2,7 @@
 #ifndef _ASM_ARCHRANDOM_H
 #define _ASM_ARCHRANDOM_H
 
-static inline bool __init smccc_probe_trng(void)
+static inline bool smccc_probe_trng(void)
 {
 	return false;
 }
diff --git a/arch/arm64/include/asm/archrandom.h b/arch/arm64/include/asm/archrandom.h
index 8babfbe31f95..7605dd81bd1e 100644
--- a/arch/arm64/include/asm/archrandom.h
+++ b/arch/arm64/include/asm/archrandom.h
@@ -12,7 +12,7 @@
 
 extern bool smccc_trng_available;
 
-static inline bool __init smccc_probe_trng(void)
+static inline bool smccc_probe_trng(void)
 {
 	struct arm_smccc_res res;
 
diff --git a/drivers/char/hw_random/arm_smccc_trng.c b/drivers/char/hw_random/arm_smccc_trng.c
index dcb8e7f37f25..8f7f9d830cf2 100644
--- a/drivers/char/hw_random/arm_smccc_trng.c
+++ b/drivers/char/hw_random/arm_smccc_trng.c
@@ -16,8 +16,10 @@
 #include <linux/device.h>
 #include <linux/hw_random.h>
 #include <linux/module.h>
-#include <linux/platform_device.h>
 #include <linux/arm-smccc.h>
+#include <linux/arm-smccc-bus.h>
+
+#include <asm/archrandom.h>
 
 #ifdef CONFIG_ARM64
 #define ARM_SMCCC_TRNG_RND	ARM_SMCCC_TRNG_RND64
@@ -94,29 +96,37 @@ static int smccc_trng_read(struct hwrng *rng, void *data, size_t max, bool wait)
 	return copied;
 }
 
-static int smccc_trng_probe(struct platform_device *pdev)
+static int smccc_trng_probe(struct arm_smccc_device *sdev)
 {
 	struct hwrng *trng;
 
-	trng = devm_kzalloc(&pdev->dev, sizeof(*trng), GFP_KERNEL);
+	/* validate the minimum version requirement */
+	if (!smccc_probe_trng())
+		return -ENODEV;
+
+	trng = devm_kzalloc(&sdev->dev, sizeof(*trng), GFP_KERNEL);
 	if (!trng)
 		return -ENOMEM;
 
 	trng->name = "smccc_trng";
 	trng->read = smccc_trng_read;
 
-	return devm_hwrng_register(&pdev->dev, trng);
+	return devm_hwrng_register(&sdev->dev, trng);
 }
 
-static struct platform_driver smccc_trng_driver = {
-	.driver = {
-		.name		= "smccc_trng",
-	},
-	.probe		= smccc_trng_probe,
+static const struct arm_smccc_device_id smccc_trng_id_table[] = {
+	{ .name = "arm-smccc-trng" },
+	{}
+};
+MODULE_DEVICE_TABLE(arm_smccc, smccc_trng_id_table);
+
+static struct arm_smccc_driver smccc_trng_driver = {
+	.name	  = KBUILD_MODNAME,
+	.probe	  = smccc_trng_probe,
+	.id_table = smccc_trng_id_table,
 };
-module_platform_driver(smccc_trng_driver);
+module_arm_smccc_driver(smccc_trng_driver);
 
-MODULE_ALIAS("platform:smccc_trng");
 MODULE_AUTHOR("Andre Przywara");
 MODULE_DESCRIPTION("Arm SMCCC TRNG firmware interface support");
 MODULE_LICENSE("GPL");
diff --git a/drivers/firmware/smccc/smccc.c b/drivers/firmware/smccc/smccc.c
index bdee057db2fd..092bdbac26f2 100644
--- a/drivers/firmware/smccc/smccc.c
+++ b/drivers/firmware/smccc/smccc.c
@@ -9,7 +9,8 @@
 #include <linux/init.h>
 #include <linux/arm-smccc.h>
 #include <linux/kernel.h>
-#include <linux/platform_device.h>
+#include <linux/arm-smccc-bus.h>
+
 #include <asm/archrandom.h>
 
 static u32 smccc_version = ARM_SMCCC_VERSION_1_0;
@@ -81,16 +82,55 @@ bool arm_smccc_hypervisor_has_uuid(const uuid_t *hyp_uuid)
 }
 EXPORT_SYMBOL_GPL(arm_smccc_hypervisor_has_uuid);
 
+struct smccc_device_info {
+	u32 func_id;
+	bool requires_smc;
+	const char *device_name;
+};
+
+static const struct smccc_device_info smccc_devices[] __initconst = {
+	{
+		.func_id        = ARM_SMCCC_TRNG_VERSION,
+		.requires_smc   = false,
+		.device_name    = "arm-smccc-trng",
+	},
+};
+
+static bool __init smccc_probe_smccc_device(const struct smccc_device_info *smccc_dev)
+{
+	int ret;
+	struct arm_smccc_res res = {};
+
+	if (smccc_conduit == SMCCC_CONDUIT_NONE)
+		return false;
+
+	if (smccc_dev->requires_smc && smccc_conduit != SMCCC_CONDUIT_SMC)
+		return false;
+
+	arm_smccc_1_1_invoke(smccc_dev->func_id, &res);
+	ret = res.a0;
+
+	if (ret == SMCCC_RET_NOT_SUPPORTED)
+		return false;
+
+	return true;
+}
+
 static int __init smccc_devices_init(void)
 {
-	struct platform_device *pdev;
-
-	if (smccc_trng_available) {
-		pdev = platform_device_register_simple("smccc_trng", -1,
-						       NULL, 0);
-		if (IS_ERR(pdev))
-			pr_err("smccc_trng: could not register device: %ld\n",
-			       PTR_ERR(pdev));
+	struct arm_smccc_device *sdev;
+	const struct smccc_device_info *smccc_dev;
+
+	for (int i = 0; i < ARRAY_SIZE(smccc_devices); i++) {
+		smccc_dev = &smccc_devices[i];
+
+		if (!smccc_probe_smccc_device(smccc_dev))
+			continue;
+
+		sdev = arm_smccc_device_register(smccc_dev->device_name);
+		if (IS_ERR(sdev))
+			pr_err("%s: could not register device: %ld\n",
+			       smccc_dev->device_name, PTR_ERR(sdev));
 	}
 
 	return 0;
-- 
2.43.0


^ permalink raw reply related

* [PATCH v8 3/6] firmware: smccc: Move RSI definitions to include/linux
From: Aneesh Kumar K.V (Arm) @ 2026-07-07  8:13 UTC (permalink / raw)
  To: linux-coco, linux-arm-kernel, linux-kernel
  Cc: Aneesh Kumar K.V (Arm), Catalin Marinas, Greg KH, Jeremy Linton,
	Jonathan Cameron, Lorenzo Pieralisi, Mark Rutland, Sudeep Holla,
	Will Deacon, Steven Price, Suzuki K Poulose, Andre Przywara,
	Suzuki K Poulose
In-Reply-To: <20260707081351.1680209-1-aneesh.kumar@kernel.org>

The RSI SMCCC function IDs describe a firmware ABI and are not arm64
architecture specific definitions. Follow-up changes need to use them from
non-arch code, including drivers/firmware/smccc and the Arm CCA guest
driver.

Move the RSI SMCCC definitions from arch/arm64/include/asm/ to
include/linux/ so they can be shared with the driver code. This also
keeps the firmware interface outside architecture code, as requested [1].

Not all helpers in rsi_cmds.h are used by architecture code. The
attestation token helper wrappers are only used by the Arm CCA guest
driver, so move them to a driver-private header under
drivers/virt/coco/arm-cca-guest/. Keep the remaining RSI command helpers,
which are shared by architecture code and drivers, in the arm64 header.

[1] https://lore.kernel.org/all/agsNO9cc7H-b0H8L@willie-the-truck

Reviewed-by: Suzuki K Poulose <suzuki.poulose@arm.com>
Signed-off-by: Aneesh Kumar K.V (Arm) <aneesh.kumar@kernel.org>
---
 arch/arm64/include/asm/rsi_cmds.h             | 75 +----------------
 .../virt/coco/arm-cca-guest/arm-cca-guest.c   |  2 +
 drivers/virt/coco/arm-cca-guest/rsi.h         | 84 +++++++++++++++++++
 .../linux/arm-smccc-rsi.h                     |  6 +-
 4 files changed, 90 insertions(+), 77 deletions(-)
 create mode 100644 drivers/virt/coco/arm-cca-guest/rsi.h
 rename arch/arm64/include/asm/rsi_smc.h => include/linux/arm-smccc-rsi.h (98%)

diff --git a/arch/arm64/include/asm/rsi_cmds.h b/arch/arm64/include/asm/rsi_cmds.h
index 2c8763876dfb..8537d0fd3da6 100644
--- a/arch/arm64/include/asm/rsi_cmds.h
+++ b/arch/arm64/include/asm/rsi_cmds.h
@@ -6,12 +6,10 @@
 #ifndef __ASM_RSI_CMDS_H
 #define __ASM_RSI_CMDS_H
 
-#include <linux/arm-smccc.h>
+#include <linux/arm-smccc-rsi.h>
 #include <linux/string.h>
 #include <asm/memory.h>
 
-#include <asm/rsi_smc.h>
-
 #define RSI_GRANULE_SHIFT		12
 #define RSI_GRANULE_SIZE		(_AC(1, UL) << RSI_GRANULE_SHIFT)
 
@@ -88,75 +86,4 @@ static inline long rsi_set_addr_range_state(phys_addr_t start,
 	return res.a0;
 }
 
-/**
- * rsi_attestation_token_init - Initialise the operation to retrieve an
- * attestation token.
- *
- * @challenge:	The challenge data to be used in the attestation token
- *		generation.
- * @size:	Size of the challenge data in bytes.
- *
- * Initialises the attestation token generation and returns an upper bound
- * on the attestation token size that can be used to allocate an adequate
- * buffer. The caller is expected to subsequently call
- * rsi_attestation_token_continue() to retrieve the attestation token data on
- * the same CPU.
- *
- * Returns:
- *  On success, returns the upper limit of the attestation report size.
- *  Otherwise, -EINVAL
- */
-static inline long
-rsi_attestation_token_init(const u8 *challenge, unsigned long size)
-{
-	struct arm_smccc_1_2_regs regs = { 0 };
-
-	/* The challenge must be at least 32bytes and at most 64bytes */
-	if (!challenge || size < 32 || size > 64)
-		return -EINVAL;
-
-	regs.a0 = SMC_RSI_ATTESTATION_TOKEN_INIT;
-	memcpy(&regs.a1, challenge, size);
-	arm_smccc_1_2_smc(&regs, &regs);
-
-	if (regs.a0 == RSI_SUCCESS)
-		return regs.a1;
-
-	return -EINVAL;
-}
-
-/**
- * rsi_attestation_token_continue - Continue the operation to retrieve an
- * attestation token.
- *
- * @granule: {I}PA of the Granule to which the token will be written.
- * @offset:  Offset within Granule to start of buffer in bytes.
- * @size:    The size of the buffer.
- * @len:     The number of bytes written to the buffer.
- *
- * Retrieves up to a RSI_GRANULE_SIZE worth of token data per call. The caller
- * is expected to call rsi_attestation_token_init() before calling this
- * function to retrieve the attestation token.
- *
- * Return:
- * * %RSI_SUCCESS     - Attestation token retrieved successfully.
- * * %RSI_INCOMPLETE  - Token generation is not complete.
- * * %RSI_ERROR_INPUT - A parameter was not valid.
- * * %RSI_ERROR_STATE - Attestation not in progress.
- */
-static inline unsigned long rsi_attestation_token_continue(phys_addr_t granule,
-							   unsigned long offset,
-							   unsigned long size,
-							   unsigned long *len)
-{
-	struct arm_smccc_res res;
-
-	arm_smccc_1_1_invoke(SMC_RSI_ATTESTATION_TOKEN_CONTINUE,
-			     granule, offset, size, 0, &res);
-
-	if (len)
-		*len = res.a1;
-	return res.a0;
-}
-
 #endif /* __ASM_RSI_CMDS_H */
diff --git a/drivers/virt/coco/arm-cca-guest/arm-cca-guest.c b/drivers/virt/coco/arm-cca-guest/arm-cca-guest.c
index 32cd038cb79b..d05acddf6c4e 100644
--- a/drivers/virt/coco/arm-cca-guest/arm-cca-guest.c
+++ b/drivers/virt/coco/arm-cca-guest/arm-cca-guest.c
@@ -14,6 +14,8 @@
 
 #include <asm/rsi.h>
 
+#include "rsi.h"
+
 /**
  * struct arm_cca_token_info - a descriptor for the token buffer.
  * @challenge:		Pointer to the challenge data
diff --git a/drivers/virt/coco/arm-cca-guest/rsi.h b/drivers/virt/coco/arm-cca-guest/rsi.h
new file mode 100644
index 000000000000..f7303f4bce17
--- /dev/null
+++ b/drivers/virt/coco/arm-cca-guest/rsi.h
@@ -0,0 +1,84 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * Copyright (C) 2026 ARM Ltd.
+ */
+
+#ifndef _VIRT_COCO_RSI_H_
+#define _VIRT_COCO_RSI_H_
+
+#include <linux/arm-smccc-rsi.h>
+
+/**
+ * rsi_attestation_token_init - Initialise the operation to retrieve an
+ * attestation token.
+ *
+ * @challenge:	The challenge data to be used in the attestation token
+ *		generation.
+ * @size:	Size of the challenge data in bytes.
+ *
+ * Initialises the attestation token generation and returns an upper bound
+ * on the attestation token size that can be used to allocate an adequate
+ * buffer. The caller is expected to subsequently call
+ * rsi_attestation_token_continue() to retrieve the attestation token data on
+ * the same CPU.
+ *
+ * Returns:
+ *  On success, returns the upper limit of the attestation report size.
+ *  Otherwise, -EINVAL
+ */
+static inline long
+rsi_attestation_token_init(const u8 *challenge, unsigned long size)
+{
+	struct arm_smccc_1_2_regs regs = { 0 };
+
+	/* The challenge must be at least 32bytes and at most 64bytes */
+	if (!challenge || size < 32 || size > 64)
+		return -EINVAL;
+
+	regs.a0 = SMC_RSI_ATTESTATION_TOKEN_INIT;
+	memcpy(&regs.a1, challenge, size);
+	arm_smccc_1_2_smc(&regs, &regs);
+
+	if (regs.a0 == RSI_SUCCESS)
+		return regs.a1;
+
+	return -EINVAL;
+}
+
+/**
+ * rsi_attestation_token_continue - Continue the operation to retrieve an
+ * attestation token.
+ *
+ * @granule: {I}PA of the Granule to which the token will be written.
+ * @offset:  Offset within Granule to start of buffer in bytes.
+ * @size:    The size of the buffer.
+ * @len:     The number of bytes written to the buffer.
+ *
+ * Retrieves up to a RSI_GRANULE_SIZE worth of token data per call. The caller
+ * is expected to call rsi_attestation_token_init() before calling this
+ * function to retrieve the attestation token.
+ *
+ * Return:
+ * * %RSI_SUCCESS     - Attestation token retrieved successfully.
+ * * %RSI_INCOMPLETE  - Token generation is not complete.
+ * * %RSI_ERROR_INPUT - A parameter was not valid.
+ * * %RSI_ERROR_STATE - Attestation not in progress.
+ */
+static inline unsigned long rsi_attestation_token_continue(phys_addr_t granule,
+							   unsigned long offset,
+							   unsigned long size,
+							   unsigned long *len)
+{
+	struct arm_smccc_res res;
+
+	arm_smccc_1_1_invoke(SMC_RSI_ATTESTATION_TOKEN_CONTINUE,
+			     granule, offset, size, 0, &res);
+
+	if (len)
+		*len = res.a1;
+	return res.a0;
+}
+
+
+
+#endif
diff --git a/arch/arm64/include/asm/rsi_smc.h b/include/linux/arm-smccc-rsi.h
similarity index 98%
rename from arch/arm64/include/asm/rsi_smc.h
rename to include/linux/arm-smccc-rsi.h
index e19253f96c94..fddb77986f70 100644
--- a/arch/arm64/include/asm/rsi_smc.h
+++ b/include/linux/arm-smccc-rsi.h
@@ -3,8 +3,8 @@
  * Copyright (C) 2023 ARM Ltd.
  */
 
-#ifndef __ASM_RSI_SMC_H_
-#define __ASM_RSI_SMC_H_
+#ifndef __LINUX_ARM_SMCCC_RSI_H_
+#define __LINUX_ARM_SMCCC_RSI_H_
 
 #include <linux/arm-smccc.h>
 
@@ -190,4 +190,4 @@ struct realm_config {
  */
 #define SMC_RSI_HOST_CALL			SMC_RSI_FID(0x199)
 
-#endif /* __ASM_RSI_SMC_H_ */
+#endif /* __LINUX_ARM_SMCCC_RSI_H_ */
-- 
2.43.0


^ permalink raw reply related

* [PATCH v8 4/6] virt: coco: arm-cca-guest: Rename TSM report source file
From: Aneesh Kumar K.V (Arm) @ 2026-07-07  8:13 UTC (permalink / raw)
  To: linux-coco, linux-arm-kernel, linux-kernel
  Cc: Aneesh Kumar K.V (Arm), Catalin Marinas, Greg KH, Jeremy Linton,
	Jonathan Cameron, Lorenzo Pieralisi, Mark Rutland, Sudeep Holla,
	Will Deacon, Steven Price, Suzuki K Poulose, Andre Przywara
In-Reply-To: <20260707081351.1680209-1-aneesh.kumar@kernel.org>

The Arm CCA guest driver currently only implements TSM report support, but
follow-up changes will add more TSM-related functionality to the same
module.

Rename arm-cca-guest.c to arm-cca.c and build it as an object of the
arm-cca-guest module. This leaves room for the module to grow additional
source files.

Signed-off-by: Aneesh Kumar K.V (Arm) <aneesh.kumar@kernel.org>
---
 drivers/virt/coco/arm-cca-guest/Makefile                    | 2 ++
 .../virt/coco/arm-cca-guest/{arm-cca-guest.c => arm-cca.c}  | 6 +++---
 2 files changed, 5 insertions(+), 3 deletions(-)
 rename drivers/virt/coco/arm-cca-guest/{arm-cca-guest.c => arm-cca.c} (97%)

diff --git a/drivers/virt/coco/arm-cca-guest/Makefile b/drivers/virt/coco/arm-cca-guest/Makefile
index 69eeba08e98a..778146148515 100644
--- a/drivers/virt/coco/arm-cca-guest/Makefile
+++ b/drivers/virt/coco/arm-cca-guest/Makefile
@@ -1,2 +1,4 @@
 # SPDX-License-Identifier: GPL-2.0-only
 obj-$(CONFIG_ARM_CCA_GUEST) += arm-cca-guest.o
+
+arm-cca-guest-y += arm-cca.o
diff --git a/drivers/virt/coco/arm-cca-guest/arm-cca-guest.c b/drivers/virt/coco/arm-cca-guest/arm-cca.c
similarity index 97%
rename from drivers/virt/coco/arm-cca-guest/arm-cca-guest.c
rename to drivers/virt/coco/arm-cca-guest/arm-cca.c
index d05acddf6c4e..0c9fb61a28f1 100644
--- a/drivers/virt/coco/arm-cca-guest/arm-cca-guest.c
+++ b/drivers/virt/coco/arm-cca-guest/arm-cca.c
@@ -184,7 +184,7 @@ static int arm_cca_report_new(struct tsm_report *report, void *data)
 	return ret;
 }
 
-static const struct tsm_report_ops arm_cca_tsm_ops = {
+static const struct tsm_report_ops arm_cca_tsm_report_ops = {
 	.name = KBUILD_MODNAME,
 	.report_new = arm_cca_report_new,
 };
@@ -205,7 +205,7 @@ static int __init arm_cca_guest_init(void)
 	if (!is_realm_world())
 		return -ENODEV;
 
-	ret = tsm_report_register(&arm_cca_tsm_ops, NULL);
+	ret = tsm_report_register(&arm_cca_tsm_report_ops, NULL);
 	if (ret < 0)
 		pr_err("Error %d registering with TSM\n", ret);
 
@@ -219,7 +219,7 @@ module_init(arm_cca_guest_init);
  */
 static void __exit arm_cca_guest_exit(void)
 {
-	tsm_report_unregister(&arm_cca_tsm_ops);
+	tsm_report_unregister(&arm_cca_tsm_report_ops);
 }
 module_exit(arm_cca_guest_exit);
 
-- 
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