* [PATCH 1/2] x86/virt/tdx: Use PFN directly for mapping guest private memory
From: Yan Zhao @ 2026-03-19 0:57 UTC (permalink / raw)
To: seanjc, pbonzini, dave.hansen
Cc: tglx, mingo, bp, kas, x86, linux-kernel, kvm, linux-coco,
kai.huang, rick.p.edgecombe, yan.y.zhao, yilun.xu, vannapurve,
ackerleytng, sagis, binbin.wu, xiaoyao.li, isaku.yamahata
In-Reply-To: <20260319005605.8965-1-yan.y.zhao@intel.com>
From: Sean Christopherson <seanjc@google.com>
Remove the completely unnecessary assumption that memory mapped into a TDX
guest is backed by refcounted struct page memory. From KVM's point of view,
TDH_MEM_PAGE_ADD and TDH_MEM_PAGE_AUG are glorified writes to PTEs, so they
have no business placing requirements on how KVM and guest_memfd manage
memory.
Rip out the misguided struct page assumptions/constraints and instead have
the two SEAMCALL wrapper APIs take PFN directly. This ensures that for
future huge page support in S-EPT, the kernel doesn't pick up even worse
assumptions like "a hugepage must be contained in a single folio".
Use "kvm_pfn_t pfn" for type safety. Using this KVM type is appropriate
since APIs tdh_mem_page_add() and tdh_mem_page_aug() are exported to KVM
only.
[ Yan: Replace "u64 pfn" with "kvm_pfn_t pfn" ]
Signed-off-by: Sean Christopherson <seanjc@google.com>
Signed-off-by: Yan Zhao <yan.y.zhao@intel.com>
---
arch/x86/include/asm/tdx.h | 5 +++--
arch/x86/kvm/vmx/tdx.c | 7 +++----
arch/x86/virt/vmx/tdx/tdx.c | 20 +++++++++++++-------
3 files changed, 19 insertions(+), 13 deletions(-)
diff --git a/arch/x86/include/asm/tdx.h b/arch/x86/include/asm/tdx.h
index a149740b24e8..f3f0b1872176 100644
--- a/arch/x86/include/asm/tdx.h
+++ b/arch/x86/include/asm/tdx.h
@@ -6,6 +6,7 @@
#include <linux/init.h>
#include <linux/bits.h>
#include <linux/mmzone.h>
+#include <linux/kvm_types.h>
#include <asm/errno.h>
#include <asm/ptrace.h>
@@ -195,10 +196,10 @@ static inline int pg_level_to_tdx_sept_level(enum pg_level level)
u64 tdh_vp_enter(struct tdx_vp *vp, struct tdx_module_args *args);
u64 tdh_mng_addcx(struct tdx_td *td, struct page *tdcs_page);
-u64 tdh_mem_page_add(struct tdx_td *td, u64 gpa, struct page *page, struct page *source, u64 *ext_err1, u64 *ext_err2);
+u64 tdh_mem_page_add(struct tdx_td *td, u64 gpa, kvm_pfn_t pfn, struct page *source, u64 *ext_err1, u64 *ext_err2);
u64 tdh_mem_sept_add(struct tdx_td *td, u64 gpa, int level, struct page *page, u64 *ext_err1, u64 *ext_err2);
u64 tdh_vp_addcx(struct tdx_vp *vp, struct page *tdcx_page);
-u64 tdh_mem_page_aug(struct tdx_td *td, u64 gpa, int level, struct page *page, u64 *ext_err1, u64 *ext_err2);
+u64 tdh_mem_page_aug(struct tdx_td *td, u64 gpa, int level, kvm_pfn_t pfn, u64 *ext_err1, u64 *ext_err2);
u64 tdh_mem_range_block(struct tdx_td *td, u64 gpa, int level, u64 *ext_err1, u64 *ext_err2);
u64 tdh_mng_key_config(struct tdx_td *td);
u64 tdh_mng_create(struct tdx_td *td, u16 hkid);
diff --git a/arch/x86/kvm/vmx/tdx.c b/arch/x86/kvm/vmx/tdx.c
index 1e47c194af53..1f1abc5b5655 100644
--- a/arch/x86/kvm/vmx/tdx.c
+++ b/arch/x86/kvm/vmx/tdx.c
@@ -1624,8 +1624,8 @@ static int tdx_mem_page_add(struct kvm *kvm, gfn_t gfn, enum pg_level level,
KVM_BUG_ON(!kvm_tdx->page_add_src, kvm))
return -EIO;
- err = tdh_mem_page_add(&kvm_tdx->td, gpa, pfn_to_page(pfn),
- kvm_tdx->page_add_src, &entry, &level_state);
+ err = tdh_mem_page_add(&kvm_tdx->td, gpa, pfn, kvm_tdx->page_add_src,
+ &entry, &level_state);
if (unlikely(tdx_operand_busy(err)))
return -EBUSY;
@@ -1640,12 +1640,11 @@ static int tdx_mem_page_aug(struct kvm *kvm, gfn_t gfn,
{
int tdx_level = pg_level_to_tdx_sept_level(level);
struct kvm_tdx *kvm_tdx = to_kvm_tdx(kvm);
- struct page *page = pfn_to_page(pfn);
gpa_t gpa = gfn_to_gpa(gfn);
u64 entry, level_state;
u64 err;
- err = tdh_mem_page_aug(&kvm_tdx->td, gpa, tdx_level, page, &entry, &level_state);
+ err = tdh_mem_page_aug(&kvm_tdx->td, gpa, tdx_level, pfn, &entry, &level_state);
if (unlikely(tdx_operand_busy(err)))
return -EBUSY;
diff --git a/arch/x86/virt/vmx/tdx/tdx.c b/arch/x86/virt/vmx/tdx/tdx.c
index cb9b3210ab71..a9dd75190c67 100644
--- a/arch/x86/virt/vmx/tdx/tdx.c
+++ b/arch/x86/virt/vmx/tdx/tdx.c
@@ -30,7 +30,6 @@
#include <linux/suspend.h>
#include <linux/syscore_ops.h>
#include <linux/idr.h>
-#include <linux/kvm_types.h>
#include <asm/page.h>
#include <asm/special_insns.h>
#include <asm/msr-index.h>
@@ -1568,6 +1567,11 @@ static void tdx_clflush_page(struct page *page)
clflush_cache_range(page_to_virt(page), PAGE_SIZE);
}
+static void tdx_clflush_pfn(kvm_pfn_t pfn)
+{
+ clflush_cache_range(__va(PFN_PHYS(pfn)), PAGE_SIZE);
+}
+
noinstr u64 tdh_vp_enter(struct tdx_vp *td, struct tdx_module_args *args)
{
args->rcx = td->tdvpr_pa;
@@ -1588,17 +1592,18 @@ u64 tdh_mng_addcx(struct tdx_td *td, struct page *tdcs_page)
}
EXPORT_SYMBOL_FOR_KVM(tdh_mng_addcx);
-u64 tdh_mem_page_add(struct tdx_td *td, u64 gpa, struct page *page, struct page *source, u64 *ext_err1, u64 *ext_err2)
+u64 tdh_mem_page_add(struct tdx_td *td, u64 gpa, kvm_pfn_t pfn, struct page *source,
+ u64 *ext_err1, u64 *ext_err2)
{
struct tdx_module_args args = {
.rcx = gpa,
.rdx = tdx_tdr_pa(td),
- .r8 = page_to_phys(page),
+ .r8 = PFN_PHYS(pfn),
.r9 = page_to_phys(source),
};
u64 ret;
- tdx_clflush_page(page);
+ tdx_clflush_pfn(pfn);
ret = seamcall_ret(TDH_MEM_PAGE_ADD, &args);
*ext_err1 = args.rcx;
@@ -1639,16 +1644,17 @@ u64 tdh_vp_addcx(struct tdx_vp *vp, struct page *tdcx_page)
}
EXPORT_SYMBOL_FOR_KVM(tdh_vp_addcx);
-u64 tdh_mem_page_aug(struct tdx_td *td, u64 gpa, int level, struct page *page, u64 *ext_err1, u64 *ext_err2)
+u64 tdh_mem_page_aug(struct tdx_td *td, u64 gpa, int level, kvm_pfn_t pfn,
+ u64 *ext_err1, u64 *ext_err2)
{
struct tdx_module_args args = {
.rcx = gpa | level,
.rdx = tdx_tdr_pa(td),
- .r8 = page_to_phys(page),
+ .r8 = PFN_PHYS(pfn),
};
u64 ret;
- tdx_clflush_page(page);
+ tdx_clflush_pfn(pfn);
ret = seamcall_ret(TDH_MEM_PAGE_AUG, &args);
*ext_err1 = args.rcx;
--
2.43.2
^ permalink raw reply related
* [PATCH 0/2] struct page to PFN conversion for TDX guest private memory
From: Yan Zhao @ 2026-03-19 0:56 UTC (permalink / raw)
To: seanjc, pbonzini, dave.hansen
Cc: tglx, mingo, bp, kas, x86, linux-kernel, kvm, linux-coco,
kai.huang, rick.p.edgecombe, yan.y.zhao, yilun.xu, vannapurve,
ackerleytng, sagis, binbin.wu, xiaoyao.li, isaku.yamahata
This series converts TDX SEAMCALL APIs for mapping/unmapping guest private
memory from taking struct page to PFN as input.
Background
----------
TDX SEAMCALL wrappers take struct page as input, which provides:
1. Type safety
2. Make it harder to misuse and make it obvious that physical pages in RAM
are expected from just looking at the API declaration [2][3][4][5].
This is appropriate for SEAMCALL wrappers for TDX control pages (e.g., TDR
page, TDCS pages, TDX SEPT pages), since KVM manages and allocates those
pages explicitly from core MM.
However, unlike TDX control pages, KVM guest memory is not necessarily
backed by refcounted struct page or even struct page (e.g., VM_PFNMAP
memory [6]). Taking struct page as input for SEAMCALL wrappers for
mapping/unmapping guest private memory imposes unnecessary assumptions on
how KVM and guest_memfd manage memory, even though today all TD private
memory is allocated from guest_memfd, which only allocates memory backed by
struct page.
To avoid baking in assumptions throughout KVM about guest memory being
backed by page (or further folio for future TDX private huge pages [7]),
Sean suggested converting from using struct page to PFN for SEAMCALL
wrappers operating on guest private memory [8].
This series therefore converts struct page to PFN for guest private memory
while keeping struct page for TDX control pages, and uses kvm_pfn_t for
type safety.
Sanity check
------------
Reasonable PFN sanity checks in SEAMCALL wrapper APIs (such as checking TDX
convertibility to avoid SEAMCALL failure) are still agreed upon [9][10].
However, as those failures are supposed to only occur when there're kernel
bugs, we decided not to provide any in-kernel sanity checks to keep the
code simple. i.e., when non-TDX-convertible PFNs are passed in, we let
SEAMCALLs fail. Though non-TDX-convertible PFNs may also produce MCEs or
page fault exceptions, this is a separate issue than struct page to PFN
conversion, and such exceptions are obvious enough in themselves.
Changes from Sean's original patch [1]:
---------------------------------------
1. Rebased to latest kvm-x86 next
2. Split to 2 patches for easy review. (Rick)
3. Replaced "u64 pfn" with "kvm_pfn_t pfn" (Rick)
4. Dropped using PFN as input to tdx_reclaim_page(). (Rick)
5. Move mk_keyed_paddr() from tdx.h to tdx.c.
Thanks
Yan
[1] https://lore.kernel.org/kvm/20260129011517.3545883-26-seanjc@google.com
[2] https://lore.kernel.org/all/30d0cef5-82d5-4325-b149-0e99833b8785@intel.com
[3] https://lore.kernel.org/kvm/f4240495-120b-4124-b91a-b365e45bf50a@intel.com
[4] https://lore.kernel.org/kvm/435b8d81-b4de-4933-b0ae-357dea311488@intel.com
[5] https://lore.kernel.org/kvm/1b236a64-d511-49a2-9962-55f4b1eb08e3@intel.com
[6] https://lore.kernel.org/all/20241010182427.1434605-1-seanjc@google.com
[7] https://lore.kernel.org/all/aW3G6yZuvclYABzP@yzhao56-desk.sh.intel.com/
[8] https://lore.kernel.org/all/aWe1tKpFw-As6VKg@google.com
[9] https://lore.kernel.org/all/aWkVLViKBgiVGgaI@google.com
[10] https://lore.kernel.org/all/d119c824-4770-41d2-a926-4ab5268ea3a6@intel.com/
Sean Christopherson (2):
x86/virt/tdx: Use PFN directly for mapping guest private memory
x86/virt/tdx: Use PFN directly for unmapping guest private memory
arch/x86/include/asm/tdx.h | 20 +++++---------------
arch/x86/kvm/vmx/tdx.c | 17 ++++++++---------
arch/x86/virt/vmx/tdx/tdx.c | 36 ++++++++++++++++++++++++------------
3 files changed, 37 insertions(+), 36 deletions(-)
base-commit: 3d6cdcc8883b5726513d245eef0e91cabfc397f7
--
2.43.2
^ permalink raw reply
* Re: [PATCH] KVM: TDX: Fix APIC MSR ranges in tdx_has_emulated_msr()
From: Binbin Wu @ 2026-03-19 1:14 UTC (permalink / raw)
To: Dave Hansen, Dmytro Maluka, kvm, Sean Christopherson,
Paolo Bonzini, Isaku Yamahata
Cc: Thomas Gleixner, Ingo Molnar, Borislav Petkov, Dave Hansen,
maintainer:X86 ARCHITECTURE (32-BIT AND 64-BIT), H. Peter Anvin,
Kiryl Shutsemau, Rick Edgecombe,
open list:X86 ARCHITECTURE (32-BIT AND 64-BIT),
open list:X86 TRUST DOMAIN EXTENSIONS (TDX)
In-Reply-To: <94b06319-2be8-4f01-87d1-8989ae1ca85d@intel.com>
On 3/19/2026 3:42 AM, Dave Hansen wrote:
> On 3/18/26 12:01, Dmytro Maluka wrote:
>> + case X2APIC_MSR(APIC_ISR) ... X2APIC_MSR(APIC_ISR) + APIC_ISR_NR - 1:
>> + case X2APIC_MSR(APIC_TMR) ... X2APIC_MSR(APIC_TMR) + APIC_ISR_NR - 1:
>> + case X2APIC_MSR(APIC_IRR) ... X2APIC_MSR(APIC_IRR) + APIC_ISR_NR - 1:
>
> Thanks for the patch, Dmytro.
>
> <sigh>
>
> So this code never worked (at least for a big chunk of the ranges.
> Isaku, could you please go try to figure out if there are tests for this
> somewhere, and why this never bit us?
The bug doesn't cause problems for TDs because:
- These x2apic MSRs (TASKPRI, PROCPRI, EOI, ISRx, TMRx, IRRx) are virtualized by CPU,
when a TD accesses these MSRs, it doesn't cause #VE, thus no TDVMCALL from the TD to
request the emulation of these MSRs.
- The bug make the "false" range of APIC MSRs smaller, so it doesn't impact the result
for the rest of the APIC MSRs.
The bug could be triggered if a TD issues a TDVMCALL directly to request the
read/write operations for these x2apic MSRs, but a sane TD will not do it.
Currently, we don't have dedicated KVM selftests code to call TDVMCALL directly to request
the emulation for these x2apic MSRs.
>
> It might also be handy to have a:
>
> #define X2APIC_LAST_MSR(r) (X2APIC_MSR(x)+APIC_ISR_NR-1)
>
> so that the resulting code is a bit more readable:
>
> case X2APIC_MSR(APIC_IRR) ... X2APIC_LAST_MSR(APIC_IRR):
>
> Dmytro, if you feel a burning need to respin this, don't let me stop
> you. I can probably just fix this up when it gets applied, or Isaku can
> make those changes and resend it too.
>
^ permalink raw reply
* Re: [PATCH v2 08/19] PCI/TSM: Add "evidence" support
From: Jakub Kicinski @ 2026-03-19 0:00 UTC (permalink / raw)
To: Dan Williams
Cc: linux-coco, linux-pci, gregkh, aik, aneesh.kumar, yilun.xu,
bhelgaas, alistair23, lukas, jgg, Donald Hunter
In-Reply-To: <69b8b234177ea_452b1001a@dwillia2-mobl4.notmuch>
On Mon, 16 Mar 2026 18:45:24 -0700 Dan Williams wrote:
> Jakub Kicinski wrote:
> > On Mon, 2 Mar 2026 16:01:56 -0800 Dan Williams wrote:
> > > The implementation adheres to the guideline from:
> > > Documentation/userspace-api/netlink/genetlink-legacy.rst
> > >
> > > New Netlink families should never respond to a DO operation with
> > > multiple replies, with ``NLM_F_MULTI`` set. Use a filtered dump
> > > instead.
> >
> > My understanding of F_MULTI is that deserializer is supposed to
> > continue deserializing into current object. IOW if we have:
> >
> > struct does_this {
> > int really;
> > int have_to;
> > int be_netlink;
> > };
>
> Heh, sensing a subtle message here...
One learns to optimize for conserving one's own attention wherever
possible :>
> > The main strength of Netlink is "do" commands with multiple optional
> > attrs.
>
> Yes, that is attractive and saves a pile of bug prone ioctl handling.
>
> The gap I need to fill first though is a uAPI that allows for large
> blobs to be fetched after being regenerated / reformatted besed on some
> input attributes.
>
> "Multi message netlink attributes" while inventive, feels less awkward
> and more future proof than a sysfs binary attribute scheme to do the
> same.
Alright, so to make this more Netlink-y you can either:
- delete the F_MULTI and replicate other attrs in each message and
add an offset attr; this will make each message in the dump more
standalone.
- keep the F_MULTI but object_val has to be a multi-attr, and then
we have to teach YNL to correctly append the attrs.
Former is definitely less work. Latter could end up being cleaner
but there are some unknowns so hard to tell for sure; more plumbing.
^ permalink raw reply
* Re: [PATCH v5 09/22] x86/virt/seamldr: Introduce skeleton for TDX module updates
From: Huang, Kai @ 2026-03-18 22:11 UTC (permalink / raw)
To: kvm@vger.kernel.org, linux-coco@lists.linux.dev,
linux-kernel@vger.kernel.org, Gao, Chao
Cc: x86@kernel.org, dave.hansen@linux.intel.com, kas@kernel.org,
seanjc@google.com, Chatre, Reinette, Weiny, Ira,
binbin.wu@linux.intel.com, Verma, Vishal L, nik.borisov@suse.com,
mingo@redhat.com, pbonzini@redhat.com,
tony.lindgren@linux.intel.com, sagis@google.com,
Annapurve, Vishal, hpa@zytor.com, Edgecombe, Rick P,
paulmck@kernel.org, tglx@kernel.org, yilun.xu@linux.intel.com,
Williams, Dan J, bp@alien8.de
In-Reply-To: <20260315135920.354657-10-chao.gao@intel.com>
> +static struct {
> + enum module_update_state state;
> + int thread_ack;
> + /*
> + * Protect update_data. Raw spinlock as it will be acquired from
> + * interrupt-disabled contexts.
> + */
> + raw_spinlock_t lock;
> +} update_data = {
> + .lock = __RAW_SPIN_LOCK_UNLOCKED(update_data.lock)
> +};
> +
> +static void set_target_state(enum module_update_state state)
> +{
> + /* Reset ack counter. */
> + update_data.thread_ack = num_online_cpus();
> + update_data.state = state;
> +}
> +
> +/* Last one to ack a state moves to the next state. */
> +static void ack_state(void)
> +{
> + guard(raw_spinlock)(&update_data.lock);
> + update_data.thread_ack--;
> + if (!update_data.thread_ack)
> + set_target_state(update_data.state + 1);
> +}
> +
> +/*
> + * See multi_cpu_stop() from where this multi-cpu state-machine was
> + * adopted, and the rationale for touch_nmi_watchdog().
> + */
> +static int do_seamldr_install_module(void *seamldr_params)
> +{
> + enum module_update_state newstate, curstate = MODULE_UPDATE_START;
> + int ret = 0;
> +
> + do {
> + /* Chill out and re-read update_data. */
> + cpu_relax();
> + newstate = READ_ONCE(update_data.state);
> +
> + if (newstate != curstate) {
> + curstate = newstate;
> + switch (curstate) {
> + /* TODO: add the update steps. */
> + default:
> + break;
> + }
> +
> + ack_state();
> + } else {
> + touch_nmi_watchdog();
> + rcu_momentary_eqs();
> + }
> + } while (curstate != MODULE_UPDATE_DONE);
> +
> + return ret;
> +}
The read
newstate = READ_ONCE(update_data.state);
.. is done out of the spinlock, but AFAICT it is fine.
The worst case is couple of additional loops on old state. The thread_ack
is protected by the lock thus no ack will get lost.
Reviewed-by: Kai Huang <kai.huang@intel.com>
^ permalink raw reply
* Re: [PATCH v5 07/22] coco/tdx-host: Implement firmware upload sysfs ABI for TDX module updates
From: Huang, Kai @ 2026-03-18 21:45 UTC (permalink / raw)
To: kvm@vger.kernel.org, linux-coco@lists.linux.dev,
linux-kernel@vger.kernel.org, Gao, Chao
Cc: x86@kernel.org, dave.hansen@linux.intel.com, kas@kernel.org,
seanjc@google.com, Chatre, Reinette, Weiny, Ira,
binbin.wu@linux.intel.com, Verma, Vishal L, nik.borisov@suse.com,
mingo@redhat.com, pbonzini@redhat.com,
tony.lindgren@linux.intel.com, sagis@google.com,
Annapurve, Vishal, hpa@zytor.com, Edgecombe, Rick P,
paulmck@kernel.org, tglx@kernel.org, yilun.xu@linux.intel.com,
Williams, Dan J, bp@alien8.de
In-Reply-To: <20260315135920.354657-8-chao.gao@intel.com>
On Sun, 2026-03-15 at 06:58 -0700, Chao Gao wrote:
> Linux kernel supports two primary firmware update mechanisms:
> - request_firmware()
> - firmware upload (or fw_upload)
>
> The former is used by microcode updates, SEV firmware updates, etc. The
> latter is used by CXL and FPGA firmware updates.
>
> One key difference between them is: request_firmware() loads a named
> file from the filesystem where the filename is kernel-controlled, while
> fw_upload accepts firmware data directly from userspace.
>
> Use fw_upload for TDX module updates as loading a named file isn't
> suitable for TDX (see below for more reasons). Specifically, register
> TDX faux device with fw_upload framework to expose sysfs interfaces
> and implement operations to process data blobs supplied by userspace.
>
> Implementation notes:
> 1. P-SEAMLDR processes the entire update at once rather than
> chunk-by-chunk, so .write() is called only once per update; so the
> offset should be always 0.
> 2. An update completes synchronously within .write(), meaning
> .poll_complete() is only called after the update succeeds and so always
> returns success
>
> Why fw_upload instead of request_firmware()?
> ============================================
> The explicit file selection capabilities of fw_upload is preferred over
> the implicit file selection of request_firmware() for the following
> reasons:
>
> a. Intel distributes all versions of the TDX module, allowing admins to
> load any version rather than always defaulting to the latest. This
> flexibility is necessary because future extensions may require reverting to
> a previous version to clear fatal errors.
>
> b. Some module version series are platform-specific. For example, the 1.5.x
> series is for certain platform generations, while the 2.0.x series is
> intended for others.
>
> c. The update policy for TDX module updates is non-linear at times. The
> latest TDX module may not be compatible. For example, TDX module 1.5.x
> may be updated to 1.5.y but not to 1.5.y+1. This policy is documented
> separately in a file released along with each TDX module release.
>
> So, the default policy of "request_firmware()" of "always load latest", is
> not suitable for TDX. Userspace needs to deploy a more sophisticated policy
> check (e.g., latest may not be compatible), and there is potential
> operator choice to consider.
>
> Just have userspace pick rather than add kernel mechanism to change the
> default policy of request_firmware().
>
> Signed-off-by: Chao Gao <chao.gao@intel.com>
> Reviewed-by: Tony Lindgren <tony.lindgren@linux.intel.com>
>
Reviewed-by: Kai Huang <kai.huang@intel.com>
^ permalink raw reply
* Re: [PATCH v5 05/22] x86/virt/seamldr: Retrieve P-SEAMLDR information
From: Huang, Kai @ 2026-03-18 21:40 UTC (permalink / raw)
To: kvm@vger.kernel.org, linux-coco@lists.linux.dev,
linux-kernel@vger.kernel.org, Gao, Chao
Cc: x86@kernel.org, dave.hansen@linux.intel.com, kas@kernel.org,
seanjc@google.com, Chatre, Reinette, Weiny, Ira,
binbin.wu@linux.intel.com, Verma, Vishal L, nik.borisov@suse.com,
mingo@redhat.com, pbonzini@redhat.com,
tony.lindgren@linux.intel.com, sagis@google.com,
Annapurve, Vishal, Chen, Farrah, Edgecombe, Rick P,
paulmck@kernel.org, hpa@zytor.com, tglx@kernel.org,
yilun.xu@linux.intel.com, Williams, Dan J, bp@alien8.de
In-Reply-To: <20260315135920.354657-6-chao.gao@intel.com>
On Sun, 2026-03-15 at 06:58 -0700, Chao Gao wrote:
> P-SEAMLDR returns its information such as version number, in response to
> the SEAMLDR.INFO SEAMCALL.
>
> This information is useful for userspace. For example, the admin can decide
> which TDX module versions are compatible with the P-SEAMLDR according to
> the P-SEAMLDR version.
>
> Retrieve P-SEAMLDR information in preparation for exposing P-SEAMLDR
> version and other necessary information to userspace. Export the new kAPI
> for use by tdx-host.ko.
>
> Note that there are two distinct P-SEAMLDR APIs with similar names:
>
> SEAMLDR.INFO: Returns a SEAMLDR_INFO structure containing SEAMLDR
> information such as version and remaining updates.
>
> SEAMLDR.SEAMINFO: Returns a SEAMLDR_SEAMINFO structure containing SEAM
> and system information such as Convertible Memory
> Regions (CMRs) and number of CPUs and sockets.
>
> The former is used here.
>
> For details, see "Intel® Trust Domain Extensions - SEAM Loader (SEAMLDR)
> Interface Specification" revision 343755-003.
>
> Signed-off-by: Chao Gao <chao.gao@intel.com>
> Tested-by: Farrah Chen <farrah.chen@intel.com>
>
Reviewed-by: Kai Huang <kai.huang@intel.com>
^ permalink raw reply
* Re: [PATCH v5 04/22] x86/virt/seamldr: Introduce a wrapper for P-SEAMLDR SEAMCALLs
From: Huang, Kai @ 2026-03-18 21:38 UTC (permalink / raw)
To: kvm@vger.kernel.org, linux-coco@lists.linux.dev,
linux-kernel@vger.kernel.org, Gao, Chao
Cc: x86@kernel.org, dave.hansen@linux.intel.com, kas@kernel.org,
seanjc@google.com, Chatre, Reinette, Weiny, Ira,
binbin.wu@linux.intel.com, Verma, Vishal L, nik.borisov@suse.com,
mingo@redhat.com, pbonzini@redhat.com,
tony.lindgren@linux.intel.com, sagis@google.com,
Annapurve, Vishal, Chen, Farrah, Edgecombe, Rick P,
paulmck@kernel.org, hpa@zytor.com, tglx@kernel.org,
yilun.xu@linux.intel.com, Williams, Dan J, bp@alien8.de
In-Reply-To: <20260315135920.354657-5-chao.gao@intel.com>
On Sun, 2026-03-15 at 06:58 -0700, Chao Gao wrote:
> The TDX architecture uses the "SEAMCALL" instruction to communicate with
> SEAM mode software. Right now, the only SEAM mode software that the kernel
> communicates with is the TDX module. But, there is actually another
> component that runs in SEAM mode but it is separate from the TDX module:
> the persistent SEAM loader or "P-SEAMLDR". Right now, the only component
> that communicates with it is the BIOS which loads the TDX module itself at
> boot. But, to support updating the TDX module, the kernel now needs to be
> able to talk to it.
>
> P-SEAMLDR SEAMCALLs differ from TDX module SEAMCALLs in areas such as
> concurrency requirements. Add a P-SEAMLDR wrapper to handle these
> differences and prepare for implementing concrete functions.
>
> Note that unlike P-SEAMLDR, there is also a non-persistent SEAM loader
> ("NP-SEAMLDR"). This is an authenticated code module (ACM) that is not
> callable at runtime. Only BIOS launches it to load P-SEAMLDR at boot;
> the kernel does not need to interact with it for runtime update.
>
> For details of P-SEAMLDR SEAMCALLs, see Intel® Trust Domain CPU
> Architectural Extensions, Revision 343754-002, Chapter 2.3 "INSTRUCTION
> SET REFERENCE".
>
> Signed-off-by: Chao Gao <chao.gao@intel.com>
> Reviewed-by: Binbin Wu <binbin.wu@linux.intel.com>
> Tested-by: Farrah Chen <farrah.chen@intel.com>
> Link: https://cdrdv2.intel.com/v1/dl/getContent/733582 # [1]
Reviewed-by: Kai Huang <kai.huang@intel.com>
^ permalink raw reply
* Re: [PATCH v5 03/22] coco/tdx-host: Expose TDX module version
From: Huang, Kai @ 2026-03-18 21:37 UTC (permalink / raw)
To: kvm@vger.kernel.org, linux-coco@lists.linux.dev,
linux-kernel@vger.kernel.org, Gao, Chao, x86@kernel.org
Cc: dave.hansen@linux.intel.com, kas@kernel.org, seanjc@google.com,
Chatre, Reinette, Weiny, Ira, binbin.wu@linux.intel.com,
Verma, Vishal L, nik.borisov@suse.com, pbonzini@redhat.com,
tony.lindgren@linux.intel.com, sagis@google.com,
Annapurve, Vishal, Edgecombe, Rick P, paulmck@kernel.org,
yilun.xu@linux.intel.com, Williams, Dan J
In-Reply-To: <20260315135920.354657-4-chao.gao@intel.com>
On Sun, 2026-03-15 at 06:58 -0700, Chao Gao wrote:
> For TDX module updates, userspace needs to select compatible update
> versions based on the current module version. This design delegates
> module selection complexity to userspace because TDX module update
> policies are complex and version series are platform-specific.
>
> For example, the 1.5.x series is for certain platform generations, while
> the 2.0.x series is intended for others. And TDX module 1.5.x may be
> updated to 1.5.y but not to 1.5.y+1.
>
> Expose the TDX module version to userspace via sysfs to aid module
> selection. Since the TDX faux device will drive module updates, expose
> the version as its attribute.
>
> One bonus of exposing TDX module version via sysfs is: TDX module
> version information remains available even after dmesg logs are cleared.
>
> == Background ==
>
> The "faux device + device attribute" approach compares to other update
> mechanisms as follows:
>
> 1. AMD SEV leverages an existing PCI device for the PSP to expose
> metadata. TDX uses a faux device as it doesn't have PCI device
> in its architecture.
>
> 2. Microcode uses per-CPU virtual devices to report microcode revisions
> because CPUs can have different revisions. But, there is only a
> single TDX module, so exposing the TDX module version through a global
> TDX faux device is appropriate
>
> 3. ARM's CCA implementation isn't in-tree yet, but will likely follow a
> similar faux device approach, though it's unclear whether they need
> to expose firmware version information
>
> Signed-off-by: Chao Gao <chao.gao@intel.com>
> Reviewed-by: Binbin Wu <binbin.wu@linux.intel.com>
> Reviewed-by: Tony Lindgren <tony.lindgren@linux.intel.com>
> Reviewed-by: Xu Yilun <yilun.xu@linux.intel.com>
> Link: https://lore.kernel.org/all/2025073035-bulginess-rematch-b92e@gregkh/ # [1]
>
Reviewed-by: Kai Huang <kai.huang@intel.com>
^ permalink raw reply
* Re: [PATCH v5 08/22] x86/virt/seamldr: Allocate and populate a module update request
From: Huang, Kai @ 2026-03-18 21:36 UTC (permalink / raw)
To: kvm@vger.kernel.org, linux-coco@lists.linux.dev,
linux-kernel@vger.kernel.org, Gao, Chao
Cc: x86@kernel.org, dave.hansen@linux.intel.com, kas@kernel.org,
seanjc@google.com, Chatre, Reinette, Weiny, Ira,
binbin.wu@linux.intel.com, Verma, Vishal L, nik.borisov@suse.com,
mingo@redhat.com, pbonzini@redhat.com,
tony.lindgren@linux.intel.com, sagis@google.com,
Annapurve, Vishal, hpa@zytor.com, Edgecombe, Rick P,
paulmck@kernel.org, tglx@kernel.org, yilun.xu@linux.intel.com,
Williams, Dan J, bp@alien8.de
In-Reply-To: <20260315135920.354657-9-chao.gao@intel.com>
On Sun, 2026-03-15 at 06:58 -0700, Chao Gao wrote:
> P-SEAMLDR uses the SEAMLDR_PARAMS structure to describe TDX module
> update requests. This structure contains physical addresses pointing to
> the module binary and its signature file (or sigstruct), along with an
> update scenario field.
>
> TDX modules are distributed in the tdx_blob format defined in
> blob_structure.txt from the "Intel TDX module Binaries Repository". A
> tdx_blob contains a header, sigstruct, and module binary. This is also the
> format supplied by the userspace to the kernel.
>
> Parse the tdx_blob format and populate a SEAMLDR_PARAMS structure
> accordingly. This structure will be passed to P-SEAMLDR to initiate the
> update.
>
> Note that the sigstruct_pa field in SEAMLDR_PARAMS has been extended to
> a 4-element array. The updated "SEAM Loader (SEAMLDR) Interface
> Specification" will be published separately. P-SEAMLDR compatibility
> validation (such as 4KB vs 16KB sigstruct support) is left to userspace,
> which must verify the P-SEAMLDR version meets the TDX module's minimum
> requirements.
>
> Signed-off-by: Chao Gao <chao.gao@intel.com>
> Reviewed-by: Tony Lindgren <tony.lindgren@linux.intel.com>
> Reviewed-by: Xu Yilun <yilun.xu@linux.intel.com>
>
Reviewed-by: Kai Huang <kai.huang@intel.com>
^ permalink raw reply
* Re: SVSM Development Call March 18, 2026
From: Jörg Rödel @ 2026-03-18 20:59 UTC (permalink / raw)
To: coconut-svsm, linux-coco
In-Reply-To: <jf4dqgnyttqibmmjzi42q77z3frcd2oomrfyjfahiglp5vo5vn@uxhtposjrxox>
Meeting minutes are ready:
https://github.com/coconut-svsm/governance/pull/100
-Joerg
^ permalink raw reply
* Re: [PATCH] KVM: TDX: Fix APIC MSR ranges in tdx_has_emulated_msr()
From: Dmytro Maluka @ 2026-03-18 20:30 UTC (permalink / raw)
To: Dave Hansen
Cc: kvm, Sean Christopherson, Paolo Bonzini, Isaku Yamahata,
Thomas Gleixner, Ingo Molnar, Borislav Petkov, Dave Hansen,
maintainer:X86 ARCHITECTURE (32-BIT AND 64-BIT), H. Peter Anvin,
Kiryl Shutsemau, Rick Edgecombe, Binbin Wu,
open list:X86 ARCHITECTURE (32-BIT AND 64-BIT),
open list:X86 TRUST DOMAIN EXTENSIONS (TDX), Chuanxiao Dong
In-Reply-To: <94b06319-2be8-4f01-87d1-8989ae1ca85d@intel.com>
On Wed, Mar 18, 2026 at 12:42:59PM -0700, Dave Hansen wrote:
> It might also be handy to have a:
>
> #define X2APIC_LAST_MSR(r) (X2APIC_MSR(x)+APIC_ISR_NR-1)
>
> so that the resulting code is a bit more readable:
>
> case X2APIC_MSR(APIC_IRR) ... X2APIC_LAST_MSR(APIC_IRR):
>
> Dmytro, if you feel a burning need to respin this, don't let me stop
> you. I can probably just fix this up when it gets applied, or Isaku can
> make those changes and resend it too.
Sure, please feel free to take over this. I even have no way to test it
anyway. :)
I'm hesitating whether X2APIC_LAST_MSR would be the best name for it,
given that it is for ISR/IRR/TMR only and is using APIC_ISR_NR (so
maybe, don't know, X2APIC_LAST_ISR_MSR?).
^ permalink raw reply
* Re: [PATCH] sample/tsm-mr: Use SHA-2 library APIs
From: Arnd Bergmann @ 2026-03-18 19:57 UTC (permalink / raw)
To: Eric Biggers, linux-crypto
Cc: Arnd Bergmann, Dan Williams, Dionna Amalie Glaze, Cedric Xing,
Andrew Morton, Zi Li, Masami Hiramatsu, Lance Yang, Zhou Yuhang,
Colin Ian King, Ard Biesheuvel, linux-coco, linux-kernel
In-Reply-To: <20260318164233.19800-1-ebiggers@kernel.org>
On Wed, Mar 18, 2026, at 17:42, Eric Biggers wrote:
> Given that tsm_mr_sample has a particular set of algorithms that it
> wants, just use the library APIs for those algorithms rather than
> crypto_shash. This is more straightforward and a bit more efficient.
>
> This fixes an issue where this module failed to build due to the kconfig
> options CRYPTO and CRYPTO_HASH not being selected. Also, even if it
> built, crypto_alloc_shash() could fail at runtime due to the needed
> algorithms not being available.
>
> The library functions simply use direct linking. So if it builds, which
> it will due to the kconfig options being enabled, they are available.
>
> Fixes: f6953f1f9ec4 ("tsm-mr: Add tsm-mr sample code")
> Fixes: 44a3873df811 ("coco/guest: Remove unneeded selection of CRYPTO")
> Signed-off-by: Eric Biggers <ebiggers@kernel.org>
> ---
>
> I'd like to take this via libcrypto-next, as that is where
> "coco/guest: Remove unneeded selection of CRYPTO" is.
Thanks for fixing this! It is indeed nicer than the fix
I sent earlier today.
Acked-by: Arnd Bergmann <arnd@arndb.de>
^ permalink raw reply
* Re: [PATCH] KVM: TDX: Fix APIC MSR ranges in tdx_has_emulated_msr()
From: Dave Hansen @ 2026-03-18 19:42 UTC (permalink / raw)
To: Dmytro Maluka, kvm, Sean Christopherson, Paolo Bonzini,
Isaku Yamahata
Cc: Thomas Gleixner, Ingo Molnar, Borislav Petkov, Dave Hansen,
maintainer:X86 ARCHITECTURE (32-BIT AND 64-BIT), H. Peter Anvin,
Kiryl Shutsemau, Rick Edgecombe, Binbin Wu,
open list:X86 ARCHITECTURE (32-BIT AND 64-BIT),
open list:X86 TRUST DOMAIN EXTENSIONS (TDX)
In-Reply-To: <20260318190111.1041924-1-dmaluka@chromium.org>
On 3/18/26 12:01, Dmytro Maluka wrote:
> + case X2APIC_MSR(APIC_ISR) ... X2APIC_MSR(APIC_ISR) + APIC_ISR_NR - 1:
> + case X2APIC_MSR(APIC_TMR) ... X2APIC_MSR(APIC_TMR) + APIC_ISR_NR - 1:
> + case X2APIC_MSR(APIC_IRR) ... X2APIC_MSR(APIC_IRR) + APIC_ISR_NR - 1:
Thanks for the patch, Dmytro.
<sigh>
So this code never worked (at least for a big chunk of the ranges.
Isaku, could you please go try to figure out if there are tests for this
somewhere, and why this never bit us?
It might also be handy to have a:
#define X2APIC_LAST_MSR(r) (X2APIC_MSR(x)+APIC_ISR_NR-1)
so that the resulting code is a bit more readable:
case X2APIC_MSR(APIC_IRR) ... X2APIC_LAST_MSR(APIC_IRR):
Dmytro, if you feel a burning need to respin this, don't let me stop
you. I can probably just fix this up when it gets applied, or Isaku can
make those changes and resend it too.
^ permalink raw reply
* [PATCH] KVM: TDX: Fix APIC MSR ranges in tdx_has_emulated_msr()
From: Dmytro Maluka @ 2026-03-18 19:01 UTC (permalink / raw)
To: kvm, Sean Christopherson, Paolo Bonzini, Isaku Yamahata
Cc: Dmytro Maluka, Thomas Gleixner, Ingo Molnar, Borislav Petkov,
Dave Hansen, maintainer:X86 ARCHITECTURE (32-BIT AND 64-BIT),
H. Peter Anvin, Kiryl Shutsemau, Rick Edgecombe, Binbin Wu,
open list:X86 ARCHITECTURE (32-BIT AND 64-BIT),
open list:X86 TRUST DOMAIN EXTENSIONS (TDX)
Note: compile-tested only. Bug found by code inspection.
X2APIC_MSR(APIC_xxx + APIC_ISR_NR) is incorrect, since APIC_ISR_NR is
0x8, not 0x80, so shifting it in X2APIC_MSR() results in losing those
lower bits, making it simply equal to X2APIC_MSR(APIC_xxx), i.e. making
the entire range consist of APIC_xxx only. So adding APIC_ISR_NR needs
to be outside X2APIC_MSR().
Additionally, since "..." ranges are inclusive, need to subtract 1.
Fixes: dd50294f3e3c ("KVM: TDX: Implement callbacks for MSR operations")
Signed-off-by: Dmytro Maluka <dmaluka@chromium.org>
---
arch/x86/kvm/vmx/tdx.c | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/arch/x86/kvm/vmx/tdx.c b/arch/x86/kvm/vmx/tdx.c
index c5065f84b78b..466a7de660c2 100644
--- a/arch/x86/kvm/vmx/tdx.c
+++ b/arch/x86/kvm/vmx/tdx.c
@@ -2136,9 +2136,9 @@ bool tdx_has_emulated_msr(u32 index)
case X2APIC_MSR(APIC_TASKPRI):
case X2APIC_MSR(APIC_PROCPRI):
case X2APIC_MSR(APIC_EOI):
- case X2APIC_MSR(APIC_ISR) ... X2APIC_MSR(APIC_ISR + APIC_ISR_NR):
- case X2APIC_MSR(APIC_TMR) ... X2APIC_MSR(APIC_TMR + APIC_ISR_NR):
- case X2APIC_MSR(APIC_IRR) ... X2APIC_MSR(APIC_IRR + APIC_ISR_NR):
+ case X2APIC_MSR(APIC_ISR) ... X2APIC_MSR(APIC_ISR) + APIC_ISR_NR - 1:
+ case X2APIC_MSR(APIC_TMR) ... X2APIC_MSR(APIC_TMR) + APIC_ISR_NR - 1:
+ case X2APIC_MSR(APIC_IRR) ... X2APIC_MSR(APIC_IRR) + APIC_ISR_NR - 1:
return false;
default:
return true;
--
2.53.0.851.ga537e3e6e9-goog
^ permalink raw reply related
* Re: [PATCH v13 04/48] arm64: RMI: Add SMC definitions for calling the RMM
From: Steven Price @ 2026-03-18 17:07 UTC (permalink / raw)
To: Joey Gouly
Cc: kvm, kvmarm, Catalin Marinas, Marc Zyngier, Will Deacon,
James Morse, Oliver Upton, Suzuki K Poulose, Zenghui Yu,
linux-arm-kernel, linux-kernel, Alexandru Elisei,
Christoffer Dall, Fuad Tabba, linux-coco, Ganapatrao Kulkarni,
Gavin Shan, Shanker Donthineni, Alper Gun, Aneesh Kumar K . V,
Emi Kisanuki, Vishal Annapurve
In-Reply-To: <20260318160744.GA3942350@e124191.cambridge.arm.com>
On 18/03/2026 16:07, Joey Gouly wrote:
> On Wed, Mar 18, 2026 at 03:53:28PM +0000, Steven Price wrote:
>> The RMM (Realm Management Monitor) provides functionality that can be
>> accessed by SMC calls from the host.
>>
>> The SMC definitions are based on DEN0137[1] version 2.0-bet0
>>
>> [1] https://developer.arm.com/documentation/den0137/2-0bet0/
>>
>> Signed-off-by: Steven Price <steven.price@arm.com>
>> ---
>> Changes since v12:
>> * Updated to RMM spec v2.0-bet0
>> Changes since v9:
>> * Corrected size of 'ripas_value' in struct rec_exit. The spec states
>> this is an 8-bit type with padding afterwards (rather than a u64).
>> Changes since v8:
>> * Added RMI_PERMITTED_GICV3_HCR_BITS to define which bits the RMM
>> permits to be modified.
>> Changes since v6:
>> * Renamed REC_ENTER_xxx defines to include 'FLAG' to make it obvious
>> these are flag values.
>> Changes since v5:
>> * Sorted the SMC #defines by value.
>> * Renamed SMI_RxI_CALL to SMI_RMI_CALL since the macro is only used for
>> RMI calls.
>> * Renamed REC_GIC_NUM_LRS to REC_MAX_GIC_NUM_LRS since the actual
>> number of available list registers could be lower.
>> * Provided a define for the reserved fields of FeatureRegister0.
>> * Fix inconsistent names for padding fields.
>> Changes since v4:
>> * Update to point to final released RMM spec.
>> * Minor rearrangements.
>> Changes since v3:
>> * Update to match RMM spec v1.0-rel0-rc1.
>> Changes since v2:
>> * Fix specification link.
>> * Rename rec_entry->rec_enter to match spec.
>> * Fix size of pmu_ovf_status to match spec.
>> ---
>> arch/arm64/include/asm/rmi_smc.h | 432 +++++++++++++++++++++++++++++++
>> 1 file changed, 432 insertions(+)
>> create mode 100644 arch/arm64/include/asm/rmi_smc.h
>>
>> diff --git a/arch/arm64/include/asm/rmi_smc.h b/arch/arm64/include/asm/rmi_smc.h
>> new file mode 100644
>> index 000000000000..8a42b83218f8
>> --- /dev/null
>> +++ b/arch/arm64/include/asm/rmi_smc.h
>> @@ -0,0 +1,432 @@
>> +/* SPDX-License-Identifier: GPL-2.0 */
>> +/*
>> + * Copyright (C) 2023-2024 ARM Ltd.
>> + *
>> + * The values and structures in this file are from the Realm Management Monitor
>> + * specification (DEN0137) version 1.0-rel0:
>> + * https://developer.arm.com/documentation/den0137/1-0rel0/
>> + */
>
> Both copyright and version (2.0 now) need updating.
Indeed they do! I didn't think anyone read these comments, but
apparently some people do (I obviously don't otherwise I might have
spotted this!) ;)
Thanks,
Steve
> Thanks,
> Joey
>
>> +
>> +#ifndef __ASM_RMI_SMC_H
>> +#define __ASM_RMI_SMC_H
>> +
>> +#include <linux/arm-smccc.h>
>> +
>> +#define SMC_RMI_CALL(func) \
>> + ARM_SMCCC_CALL_VAL(ARM_SMCCC_FAST_CALL, \
>> + ARM_SMCCC_SMC_64, \
>> + ARM_SMCCC_OWNER_STANDARD, \
>> + (func))
>> +
>> +#define SMC_RMI_VERSION SMC_RMI_CALL(0x0150)
>> +
>> +#define SMC_RMI_RTT_DATA_MAP_INIT SMC_RMI_CALL(0x0153)
>> +
>> +#define SMC_RMI_REALM_ACTIVATE SMC_RMI_CALL(0x0157)
>> +#define SMC_RMI_REALM_CREATE SMC_RMI_CALL(0x0158)
>> +#define SMC_RMI_REALM_DESTROY SMC_RMI_CALL(0x0159)
>> +#define SMC_RMI_REC_CREATE SMC_RMI_CALL(0x015a)
>> +#define SMC_RMI_REC_DESTROY SMC_RMI_CALL(0x015b)
>> +#define SMC_RMI_REC_ENTER SMC_RMI_CALL(0x015c)
>> +#define SMC_RMI_RTT_CREATE SMC_RMI_CALL(0x015d)
>> +#define SMC_RMI_RTT_DESTROY SMC_RMI_CALL(0x015e)
>> +
>> +#define SMC_RMI_RTT_READ_ENTRY SMC_RMI_CALL(0x0161)
>> +
>> +#define SMC_RMI_RTT_DEV_VALIDATE SMC_RMI_CALL(0x0163)
>> +#define SMC_RMI_PSCI_COMPLETE SMC_RMI_CALL(0x0164)
>> +#define SMC_RMI_FEATURES SMC_RMI_CALL(0x0165)
>> +#define SMC_RMI_RTT_FOLD SMC_RMI_CALL(0x0166)
>> +
>> +#define SMC_RMI_RTT_INIT_RIPAS SMC_RMI_CALL(0x0168)
>> +#define SMC_RMI_RTT_SET_RIPAS SMC_RMI_CALL(0x0169)
>> +#define SMC_RMI_VSMMU_CREATE SMC_RMI_CALL(0x016a)
>> +#define SMC_RMI_VSMMU_DESTROY SMC_RMI_CALL(0x016b)
>> +#define SMC_RMI_RMM_CONFIG_SET SMC_RMI_CALL(0x016e)
>> +#define SMC_RMI_PSMMU_IRQ_NOTIFY SMC_RMI_CALL(0x016f)
>> +#define SMC_RMI_ATTEST_PLAT_TOKEN_REFRESH SMC_RMI_CALL(0x0170)
>> +
>> +#define SMC_RMI_PDEV_ABORT SMC_RMI_CALL(0x0174)
>> +#define SMC_RMI_PDEV_COMMUNICATE SMC_RMI_CALL(0x0175)
>> +#define SMC_RMI_PDEV_CREATE SMC_RMI_CALL(0x0176)
>> +#define SMC_RMI_PDEV_DESTROY SMC_RMI_CALL(0x0177)
>> +#define SMC_RMI_PDEV_GET_STATE SMC_RMI_CALL(0x0178)
>> +
>> +#define SMC_RMI_PDEV_STREAM_KEY_REFRESH SMC_RMI_CALL(0x017a)
>> +#define SMC_RMI_PDEV_SET_PUBKEY SMC_RMI_CALL(0x017b)
>> +#define SMC_RMI_PDEV_STOP SMC_RMI_CALL(0x017c)
>> +#define SMC_RMI_RTT_AUX_CREATE SMC_RMI_CALL(0x017d)
>> +#define SMC_RMI_RTT_AUX_DESTROY SMC_RMI_CALL(0x017e)
>> +#define SMC_RMI_RTT_AUX_FOLD SMC_RMI_CALL(0x017f)
>> +
>> +#define SMC_RMI_VDEV_ABORT SMC_RMI_CALL(0x0185)
>> +#define SMC_RMI_VDEV_COMMUNICATE SMC_RMI_CALL(0x0186)
>> +#define SMC_RMI_VDEV_CREATE SMC_RMI_CALL(0x0187)
>> +#define SMC_RMI_VDEV_DESTROY SMC_RMI_CALL(0x0188)
>> +#define SMC_RMI_VDEV_GET_STATE SMC_RMI_CALL(0x0189)
>> +#define SMC_RMI_VDEV_UNLOCK SMC_RMI_CALL(0x018a)
>> +#define SMC_RMI_RTT_SET_S2AP SMC_RMI_CALL(0x018b)
>> +#define SMC_RMI_VDEV_COMPLETE SMC_RMI_CALL(0x018e)
>> +
>> +#define SMC_RMI_VDEV_GET_INTERFACE_REPORT SMC_RMI_CALL(0x01d0)
>> +#define SMC_RMI_VDEV_GET_MEASUREMENTS SMC_RMI_CALL(0x01d1)
>> +#define SMC_RMI_VDEV_LOCK SMC_RMI_CALL(0x01d2)
>> +#define SMC_RMI_VDEV_START SMC_RMI_CALL(0x01d3)
>> +#define SMC_RMI_VDEV_P2P_BIND SMC_RMI_CALL(0x01d4)
>> +#define SMC_RMI_VDEV_P2P_UNBIND SMC_RMI_CALL(0x01d5)
>> +#define SMC_RMI_VSMMU_EVENT_NOTIFY SMC_RMI_CALL(0x01d6)
>> +#define SMC_RMI_PSMMU_ACTIVATE SMC_RMI_CALL(0x01d7)
>> +#define SMC_RMI_PSMMU_DEACTIVATE SMC_RMI_CALL(0x01d8)
>> +
>> +#define SMC_RMI_PSMMU_ST_L2_CREATE SMC_RMI_CALL(0x01db)
>> +#define SMC_RMI_PSMMU_ST_L2_DESTROY SMC_RMI_CALL(0x01dc)
>> +#define SMC_RMI_DPT_L0_CREATE SMC_RMI_CALL(0x01dd)
>> +#define SMC_RMI_DPT_L0_DESTROY SMC_RMI_CALL(0x01de)
>> +#define SMC_RMI_DPT_L1_CREATE SMC_RMI_CALL(0x01df)
>> +#define SMC_RMI_DPT_L1_DESTROY SMC_RMI_CALL(0x01e0)
>> +#define SMC_RMI_GRANULE_TRACKING_GET SMC_RMI_CALL(0x01e1)
>> +
>> +#define SMC_RMI_GRANULE_TRACKING_SET SMC_RMI_CALL(0x01e3)
>> +#define SMC_RMI_CMEM_ADD_PDEV SMC_RMI_CALL(0x01e4)
>> +#define SMC_RMI_CMEM_CREATE SMC_RMI_CALL(0x01e5)
>> +#define SMC_RMI_CMEM_DESTROY SMC_RMI_CALL(0x01e6)
>> +#define SMC_RMI_CMEM_POPULATE SMC_RMI_CALL(0x01e7)
>> +#define SMC_RMI_CMEM_REMOTE_PDEV SMC_RMI_CALL(0x01e8)
>> +#define SMC_RMI_CMEM_START SMC_RMI_CALL(0x01e9)
>> +#define SMC_RMI_CMEM_STOP SMC_RMI_CALL(0x01ea)
>> +#define SMC_RMI_CMEM_UNPOPULATE SMC_RMI_CALL(0x01eb)
>> +#define SMC_RMI_RMM_CONFIG_GET SMC_RMI_CALL(0x01ec)
>> +#define SMC_RMI_PDEV_MEC_UPDATE SMC_RMI_CALL(0x01ed)
>> +#define SMC_RMI_VSMMU_EVENT_COMPLETE SMC_RMI_CALL(0x01ee)
>> +
>> +#define SMC_RMI_PSMMU_EVENT_DISCARD SMC_RMI_CALL(0x01f0)
>> +#define SMC_RMI_GRANULE_RANGE_DELEGATE SMC_RMI_CALL(0x01f1)
>> +#define SMC_RMI_GRANULE_RANGE_UNDELEGATE SMC_RMI_CALL(0x01f2)
>> +#define SMC_RMI_GPT_L1_CREATE SMC_RMI_CALL(0x01f3)
>> +#define SMC_RMI_GPT_L1_DESTROY SMC_RMI_CALL(0x01f4)
>> +#define SMC_RMI_RTT_DATA_MAP SMC_RMI_CALL(0x01f5)
>> +#define SMC_RMI_RTT_DATA_UNMAP SMC_RMI_CALL(0x01f6)
>> +#define SMC_RMI_RTT_DEV_MAP SMC_RMI_CALL(0x01f7)
>> +#define SMC_RMI_RTT_DEV_UNMAP SMC_RMI_CALL(0x01f8)
>> +#define SMC_RMI_RTT_ARCH_DEV_MAP SMC_RMI_CALL(0x01f9)
>> +#define SMC_RMI_RTT_ARCH_DEV_UNMAP SMC_RMI_CALL(0x01fa)
>> +#define SMC_RMI_RTT_UNPROT_MAP SMC_RMI_CALL(0x01fb)
>> +#define SMC_RMI_RTT_UNPROT_UNMAP SMC_RMI_CALL(0x01fc)
>> +#define SMC_RMI_RTT_AUX_PROT_MAP SMC_RMI_CALL(0x01fd)
>> +#define SMC_RMI_RTT_AUX_PROT_UNMAP SMC_RMI_CALL(0x01fe)
>> +#define SMC_RMI_RTT_AUX_UNPROT_MAP SMC_RMI_CALL(0x01ff)
>> +#define SMC_RMI_RTT_AUX_UNMAP_UNMAP SMC_RMI_CALL(0x0200)
>> +#define SMC_RMI_REALM_TERMINATE SMC_RMI_CALL(0x0201)
>> +#define SMC_RMI_RMM_ACTIVATE SMC_RMI_CALL(0x0202)
>> +#define SMC_RMI_OP_CONTINUE SMC_RMI_CALL(0x0203)
>> +#define SMC_RMI_PDEV_STREAM_CONNECT SMC_RMI_CALL(0x0204)
>> +#define SMC_RMI_PDEV_STREAM_DISCONNECT SMC_RMI_CALL(0x0205)
>> +#define SMC_RMI_PDEV_STREAM_COMPLETE SMC_RMI_CALL(0x0206)
>> +#define SMC_RMI_PDEV_STREAM_KEY_PURGE SMC_RMI_CALL(0x0207)
>> +#define SMC_RMI_OP_MEM_DONATE SMC_RMI_CALL(0x0208)
>> +#define SMC_RMI_OP_MEM_RECLAIM SMC_RMI_CALL(0x0209)
>> +#define SMC_RMI_OP_CANCEL SMC_RMI_CALL(0x020a)
>> +#define SMC_RMI_PDEV_SET_PROT SMC_RMI_CALL(0x020b)
>> +
>> +#define RMI_ABI_MAJOR_VERSION 2
>> +#define RMI_ABI_MINOR_VERSION 0
>> +
>> +#define RMI_ABI_VERSION_GET_MAJOR(version) ((version) >> 16)
>> +#define RMI_ABI_VERSION_GET_MINOR(version) ((version) & 0xFFFF)
>> +#define RMI_ABI_VERSION(major, minor) (((major) << 16) | (minor))
>> +
>> +#define RMI_UNASSIGNED 0
>> +#define RMI_ASSIGNED 1
>> +#define RMI_TABLE 2
>> +
>> +#define RMI_RETURN_STATUS(ret) ((ret) & 0xFF)
>> +#define RMI_RETURN_INDEX(ret) (((ret) >> 8) & 0xFF)
>> +#define RMI_RETURN_MEMREQ(ret) (((ret) >> 8) & 0x3)
>> +#define RMI_RETURN_CANCANCEL(ret) (((ret) >> 10) & 0x1)
>> +
>> +#define RMI_SUCCESS 0
>> +#define RMI_ERROR_INPUT 1
>> +#define RMI_ERROR_REALM 2
>> +#define RMI_ERROR_REC 3
>> +#define RMI_ERROR_RTT 4
>> +#define RMI_ERROR_NOT_SUPPORTED 5
>> +#define RMI_ERROR_DEVICE 6
>> +#define RMI_ERROR_RTT_AUX 7
>> +#define RMI_ERROR_PSMMU_ST 8
>> +#define RMI_ERROR_DPT 9
>> +#define RMI_BUSY 10
>> +#define RMI_ERROR_GLOBAL 11
>> +#define RMI_ERROR_TRACKING 12
>> +#define RMI_INCOMPLETE 13
>> +#define RMI_BLOCKED 14
>> +#define RMI_ERROR_GPT 15
>> +#define RMI_ERROR_GRANULE 16
>> +
>> +#define RMI_OP_MEM_REQ_NONE 0
>> +#define RMI_OP_MEM_REQ_DONATE 1
>> +#define RMI_OP_MEM_REQ_RECLAIM 2
>> +
>> +#define RMI_DONATE_SIZE(req) ((req) & 0x3)
>> +#define RMI_DONATE_COUNT_MASK GENMASK(15, 2)
>> +#define RMI_DONATE_COUNT(req) (((req) & RMI_DONATE_COUNT_MASK) >> 2)
>> +#define RMI_DONATE_CONTIG(req) (!!((req) & BIT(16)))
>> +#define RMI_DONATE_STATE(req) (!!((req) & BIT(17)))
>> +
>> +#define RMI_OP_MEM_DELEGATED 0
>> +#define RMI_OP_MEM_UNDELEGATED 1
>> +
>> +#define RMI_ADDR_TYPE_NONE 0
>> +#define RMI_ADDR_TYPE_SINGLE 1
>> +#define RMI_ADDR_TYPE_LIST 2
>> +
>> +#define RMI_ADDR_RANGE_SIZE(ar) (FIELD_GET(GENMASK(1, 0), (ar)))
>> +#define RMI_ADDR_RANGE_COUNT(ar) (FIELD_GET(GENMASK(PAGE_SHIFT - 1, 2), \
>> + (ar)))
>> +#define RMI_ADDR_RANGE_ADDR(ar) ((ar) & PAGE_MASK & GENMASK(51, 0))
>> +#define RMI_ADDR_RANGE_STATE(ar) (FIELD_GET(BIT(63), (ar)))
>> +
>> +enum rmi_ripas {
>> + RMI_EMPTY = 0,
>> + RMI_RAM = 1,
>> + RMI_DESTROYED = 2,
>> +};
>> +
>> +#define RMI_NO_MEASURE_CONTENT 0
>> +#define RMI_MEASURE_CONTENT 1
>> +
>> +#define RMI_FEATURE_REGISTER_0_S2SZ GENMASK(7, 0)
>> +#define RMI_FEATURE_REGISTER_0_LPA2 BIT(8)
>> +#define RMI_FEATURE_REGISTER_0_SVE BIT(9)
>> +#define RMI_FEATURE_REGISTER_0_SVE_VL GENMASK(13, 10)
>> +#define RMI_FEATURE_REGISTER_0_NUM_BPS GENMASK(19, 14)
>> +#define RMI_FEATURE_REGISTER_0_NUM_WPS GENMASK(25, 20)
>> +#define RMI_FEATURE_REGISTER_0_PMU BIT(26)
>> +#define RMI_FEATURE_REGISTER_0_PMU_NUM_CTRS GENMASK(31, 27)
>> +
>> +#define RMI_FEATURE_REGISTER_1_RMI_GRAN_SZ_4KB BIT(0)
>> +#define RMI_FEATURE_REGISTER_1_RMI_GRAN_SZ_16KB BIT(1)
>> +#define RMI_FEATURE_REGISTER_1_RMI_GRAN_SZ_64KB BIT(2)
>> +#define RMI_FEATURE_REGISTER_1_HASH_SHA_256 BIT(3)
>> +#define RMI_FEATURE_REGISTER_1_HASH_SHA_384 BIT(4)
>> +#define RMI_FEATURE_REGISTER_1_HASH_SHA_512 BIT(5)
>> +#define RMI_FEATURE_REGISTER_1_MAX_RECS_ORDER GENMASK(9, 6)
>> +#define RMI_FEATURE_REGISTER_1_L0GPTSZ GENMASK(13, 10)
>> +#define RMI_FEATURE_REGISTER_1_PPS GENMASK(16, 14)
>> +
>> +#define RMI_FEATURE_REGISTER_2_DA BIT(0)
>> +#define RMI_FEATURE_REGISTER_2_DA_COH BIT(1)
>> +#define RMI_FEATURE_REGISTER_2_VSMMU BIT(2)
>> +#define RMI_FEATURE_REGISTER_2_ATS BIT(3)
>> +#define RMI_FEATURE_REGISTER_2_MAX_VDEVS_ORDER GEN_MASK(7, 4)
>> +#define RMI_FEATURE_REGISTER_2_VDEV_KROU BIT(8)
>> +#define RMI_FEATURE_REGISTER_2_NON_TEE_STREAM BIT(9)
>> +
>> +#define RMI_FEATURE_REGISTER_3_MAX_NUM_AUX_PLANES GENMASK(3, 0)
>> +#define RMI_FEATURE_REGISTER_3_RTT_PLAN GENMASK(5, 4)
>> +#define RMI_FEATURE_REGISTER_3_RTT_S2AP_INDIRECT BIT(6)
>> +
>> +#define RMI_FEATURE_REGISTER_4_MEC_COUNT GENMASK(63, 0)
>> +
>> +#define RMI_MEM_CATEGORY_CONVENTIONAL 0
>> +#define RMI_MEM_CATEGORY_DEV_NCOH 1
>> +#define RMI_MEM_CATEGORY_DEV_COH 2
>> +
>> +#define RMI_TRACKING_RESERVED 0
>> +#define RMI_TRACKING_NONE 1
>> +#define RMI_TRACKING_FINE 2
>> +#define RMI_TRACKING_COARSE 3
>> +
>> +#define RMI_GRANULE_SIZE_4KB 0
>> +#define RMI_GRANULE_SIZE_16KB 1
>> +#define RMI_GRANULE_SIZE_64KB 2
>> +
>> +/*
>> + * Note many of these fields are smaller than u64 but all fields have u64
>> + * alignment, so use u64 to ensure correct alignment.
>> + */
>> +struct rmm_config {
>> + union { /* 0x0 */
>> + struct {
>> + u64 tracking_region_size;
>> + u64 rmi_granule_size;
>> + };
>> + u8 sizer[0x1000];
>> + };
>> +};
>> +
>> +#define RMI_REALM_PARAM_FLAG_LPA2 BIT(0)
>> +#define RMI_REALM_PARAM_FLAG_SVE BIT(1)
>> +#define RMI_REALM_PARAM_FLAG_PMU BIT(2)
>> +
>> +struct realm_params {
>> + union { /* 0x0 */
>> + struct {
>> + u64 flags;
>> + u64 s2sz;
>> + u64 sve_vl;
>> + u64 num_bps;
>> + u64 num_wps;
>> + u64 pmu_num_ctrs;
>> + u64 hash_algo;
>> + };
>> + u8 padding0[0x400];
>> + };
>> + union { /* 0x400 */
>> + u8 rpv[64];
>> + u8 padding1[0x400];
>> + };
>> + union { /* 0x800 */
>> + struct {
>> + u64 padding;
>> + u64 rtt_base;
>> + s64 rtt_level_start;
>> + u64 rtt_num_start;
>> + };
>> + u8 padding2[0x800];
>> + };
>> +};
>> +
>> +/*
>> + * The number of GPRs (starting from X0) that are
>> + * configured by the host when a REC is created.
>> + */
>> +#define REC_CREATE_NR_GPRS 8
>> +
>> +#define REC_PARAMS_FLAG_RUNNABLE BIT_ULL(0)
>> +
>> +#define REC_PARAMS_AUX_GRANULES 16
>> +
>> +struct rec_params {
>> + union { /* 0x0 */
>> + u64 flags;
>> + u8 padding0[0x100];
>> + };
>> + union { /* 0x100 */
>> + u64 mpidr;
>> + u8 padding1[0x100];
>> + };
>> + union { /* 0x200 */
>> + u64 pc;
>> + u8 padding2[0x100];
>> + };
>> + union { /* 0x300 */
>> + u64 gprs[REC_CREATE_NR_GPRS];
>> + u8 padding3[0x500];
>> + };
>> + union { /* 0x800 */
>> + struct {
>> + u64 num_rec_aux;
>> + u64 aux[REC_PARAMS_AUX_GRANULES];
>> + };
>> + u8 padding4[0x800];
>> + };
>> +};
>> +
>> +#define REC_ENTER_FLAG_EMULATED_MMIO BIT(0)
>> +#define REC_ENTER_FLAG_INJECT_SEA BIT(1)
>> +#define REC_ENTER_FLAG_TRAP_WFI BIT(2)
>> +#define REC_ENTER_FLAG_TRAP_WFE BIT(3)
>> +#define REC_ENTER_FLAG_RIPAS_RESPONSE BIT(4)
>> +
>> +#define REC_RUN_GPRS 31
>> +#define REC_MAX_GIC_NUM_LRS 16
>> +
>> +#define RMI_PERMITTED_GICV3_HCR_BITS (ICH_HCR_EL2_UIE | \
>> + ICH_HCR_EL2_LRENPIE | \
>> + ICH_HCR_EL2_NPIE | \
>> + ICH_HCR_EL2_VGrp0EIE | \
>> + ICH_HCR_EL2_VGrp0DIE | \
>> + ICH_HCR_EL2_VGrp1EIE | \
>> + ICH_HCR_EL2_VGrp1DIE | \
>> + ICH_HCR_EL2_TDIR)
>> +
>> +struct rec_enter {
>> + union { /* 0x000 */
>> + u64 flags;
>> + u8 padding0[0x200];
>> + };
>> + union { /* 0x200 */
>> + u64 gprs[REC_RUN_GPRS];
>> + u8 padding1[0x100];
>> + };
>> + u8 padding3[0x500];
>> +};
>> +
>> +#define RMI_EXIT_SYNC 0x00
>> +#define RMI_EXIT_IRQ 0x01
>> +#define RMI_EXIT_FIQ 0x02
>> +#define RMI_EXIT_PSCI 0x03
>> +#define RMI_EXIT_RIPAS_CHANGE 0x04
>> +#define RMI_EXIT_HOST_CALL 0x05
>> +#define RMI_EXIT_SERROR 0x06
>> +
>> +struct rec_exit {
>> + union { /* 0x000 */
>> + u8 exit_reason;
>> + u8 padding0[0x100];
>> + };
>> + union { /* 0x100 */
>> + struct {
>> + u64 esr;
>> + u64 far;
>> + u64 hpfar;
>> + u64 rtt_tree;
>> + };
>> + u8 padding1[0x100];
>> + };
>> + union { /* 0x200 */
>> + u64 gprs[REC_RUN_GPRS];
>> + u8 padding2[0x100];
>> + };
>> + union { /* 0x300 */
>> + u8 padding3[0x100];
>> + };
>> + union { /* 0x400 */
>> + struct {
>> + u64 cntp_ctl;
>> + u64 cntp_cval;
>> + u64 cntv_ctl;
>> + u64 cntv_cval;
>> + };
>> + u8 padding4[0x100];
>> + };
>> + union { /* 0x500 */
>> + struct {
>> + u64 ripas_base;
>> + u64 ripas_top;
>> + u8 ripas_value;
>> + u8 padding8[15];
>> + u64 s2ap_base;
>> + u64 s2ap_top;
>> + u64 vdev_id_1;
>> + u64 vdev_id_2;
>> + u64 dev_mem_base;
>> + u64 dev_mem_top;
>> + u64 dev_mem_pa;
>> + };
>> + u8 padding5[0x100];
>> + };
>> + union { /* 0x600 */
>> + struct {
>> + u16 imm;
>> + u16 padding9;
>> + u64 plane;
>> + };
>> + u8 padding6[0x100];
>> + };
>> + union { /* 0x700 */
>> + struct {
>> + u8 pmu_ovf_status;
>> + u8 padding10[15];
>> + u64 vsmmu;
>> + };
>> + u8 padding7[0x100];
>> + };
>> +};
>> +
>> +struct rec_run {
>> + struct rec_enter enter;
>> + struct rec_exit exit;
>> +};
>> +
>> +#endif /* __ASM_RMI_SMC_H */
>> --
>> 2.43.0
>>
>>
^ permalink raw reply
* Re: [PATCH v13 00/48] arm64: Support for Arm CCA in KVM
From: Steven Price @ 2026-03-18 16:53 UTC (permalink / raw)
To: kvm, kvmarm
Cc: Catalin Marinas, Marc Zyngier, Will Deacon, James Morse,
Oliver Upton, Suzuki K Poulose, Zenghui Yu, linux-arm-kernel,
linux-kernel, Joey Gouly, Alexandru Elisei, Christoffer Dall,
Fuad Tabba, linux-coco, Ganapatrao Kulkarni, Gavin Shan,
Shanker Donthineni, Alper Gun, Aneesh Kumar K . V, Emi Kisanuki,
Vishal Annapurve
In-Reply-To: <20260318155413.793430-1-steven.price@arm.com>
And for those who like to use shrinkwrap the following YAML config
should work on top of the 2025.12.0 tag to pull the various repos. Save
the below as e.g. cca-v13.yaml and follow the usual instructions in
cca-3world.yaml but refer to cca-v13.yaml instead.
---8<---
%YAML 1.2
---
concrete: true
layers:
- cca-3world.yaml
build:
linux:
repo:
revision: cca-host/v13
kvmtool:
repo:
kvmtool:
revision: cca/v11
tfa:
params:
RMM_V1_COMPAT: 0
repo:
revision: master
rmm:
repo:
revision: topics/rmm-v2.0-poc
^ permalink raw reply
* [PATCH] sample/tsm-mr: Use SHA-2 library APIs
From: Eric Biggers @ 2026-03-18 16:42 UTC (permalink / raw)
To: linux-crypto
Cc: Arnd Bergmann, Dan Williams, Dionna Amalie Glaze, Cedric Xing,
Eric Biggers, Arnd Bergmann, Andrew Morton, Zi Li,
Masami Hiramatsu, Lance Yang, Zhou Yuhang, Colin Ian King,
Ard Biesheuvel, linux-coco, linux-kernel
Given that tsm_mr_sample has a particular set of algorithms that it
wants, just use the library APIs for those algorithms rather than
crypto_shash. This is more straightforward and a bit more efficient.
This fixes an issue where this module failed to build due to the kconfig
options CRYPTO and CRYPTO_HASH not being selected. Also, even if it
built, crypto_alloc_shash() could fail at runtime due to the needed
algorithms not being available.
The library functions simply use direct linking. So if it builds, which
it will due to the kconfig options being enabled, they are available.
Fixes: f6953f1f9ec4 ("tsm-mr: Add tsm-mr sample code")
Fixes: 44a3873df811 ("coco/guest: Remove unneeded selection of CRYPTO")
Signed-off-by: Eric Biggers <ebiggers@kernel.org>
---
I'd like to take this via libcrypto-next, as that is where
"coco/guest: Remove unneeded selection of CRYPTO" is.
This is an alternative to
https://lore.kernel.org/r/20260318105200.1985712-1-arnd@kernel.org
samples/Kconfig | 2 +
samples/tsm-mr/tsm_mr_sample.c | 68 +++++++++++++++++-----------------
2 files changed, 35 insertions(+), 35 deletions(-)
diff --git a/samples/Kconfig b/samples/Kconfig
index 5bc7c9e5a59e..a75e8e78330d 100644
--- a/samples/Kconfig
+++ b/samples/Kconfig
@@ -184,10 +184,12 @@ config SAMPLE_TIMER
bool "Timer sample"
depends on CC_CAN_LINK && HEADERS_INSTALL
config SAMPLE_TSM_MR
tristate "TSM measurement sample"
+ select CRYPTO_LIB_SHA256
+ select CRYPTO_LIB_SHA512
select TSM_MEASUREMENTS
select VIRT_DRIVERS
help
Build a sample module that emulates MRs (Measurement Registers) and
exposes them to user mode applications through the TSM sysfs
diff --git a/samples/tsm-mr/tsm_mr_sample.c b/samples/tsm-mr/tsm_mr_sample.c
index a2c652148639..c79dbc1e0456 100644
--- a/samples/tsm-mr/tsm_mr_sample.c
+++ b/samples/tsm-mr/tsm_mr_sample.c
@@ -4,11 +4,11 @@
#define pr_fmt(x) KBUILD_MODNAME ": " x
#include <linux/module.h>
#include <linux/tsm-mr.h>
#include <linux/miscdevice.h>
-#include <crypto/hash.h>
+#include <crypto/sha2.h>
static struct {
u8 static_mr[SHA384_DIGEST_SIZE];
u8 config_mr[SHA512_DIGEST_SIZE];
u8 rtmr0[SHA256_DIGEST_SIZE];
@@ -21,51 +21,49 @@ static struct {
.rtmr1 = "rtmr1",
};
static int sample_report_refresh(const struct tsm_measurements *tm)
{
- struct crypto_shash *tfm;
- int rc;
-
- tfm = crypto_alloc_shash(hash_algo_name[HASH_ALGO_SHA512], 0, 0);
- if (IS_ERR(tfm)) {
- pr_err("crypto_alloc_shash failed: %ld\n", PTR_ERR(tfm));
- return PTR_ERR(tfm);
- }
-
- rc = crypto_shash_tfm_digest(tfm, (u8 *)&sample_report,
- offsetof(typeof(sample_report),
- report_digest),
- sample_report.report_digest);
- crypto_free_shash(tfm);
- if (rc)
- pr_err("crypto_shash_tfm_digest failed: %d\n", rc);
- return rc;
+ sha512((const u8 *)&sample_report,
+ offsetof(typeof(sample_report), report_digest),
+ sample_report.report_digest);
+ return 0;
}
static int sample_report_extend_mr(const struct tsm_measurements *tm,
const struct tsm_measurement_register *mr,
const u8 *data)
{
- SHASH_DESC_ON_STACK(desc, 0);
- int rc;
-
- desc->tfm = crypto_alloc_shash(hash_algo_name[mr->mr_hash], 0, 0);
- if (IS_ERR(desc->tfm)) {
- pr_err("crypto_alloc_shash failed: %ld\n", PTR_ERR(desc->tfm));
- return PTR_ERR(desc->tfm);
+ union {
+ struct sha256_ctx sha256;
+ struct sha384_ctx sha384;
+ struct sha512_ctx sha512;
+ } ctx;
+
+ switch (mr->mr_hash) {
+ case HASH_ALGO_SHA256:
+ sha256_init(&ctx.sha256);
+ sha256_update(&ctx.sha256, mr->mr_value, mr->mr_size);
+ sha256_update(&ctx.sha256, data, mr->mr_size);
+ sha256_final(&ctx.sha256, mr->mr_value);
+ return 0;
+ case HASH_ALGO_SHA384:
+ sha384_init(&ctx.sha384);
+ sha384_update(&ctx.sha384, mr->mr_value, mr->mr_size);
+ sha384_update(&ctx.sha384, data, mr->mr_size);
+ sha384_final(&ctx.sha384, mr->mr_value);
+ return 0;
+ case HASH_ALGO_SHA512:
+ sha512_init(&ctx.sha512);
+ sha512_update(&ctx.sha512, mr->mr_value, mr->mr_size);
+ sha512_update(&ctx.sha512, data, mr->mr_size);
+ sha512_final(&ctx.sha512, mr->mr_value);
+ return 0;
+ default:
+ pr_err("Unsupported hash algorithm: %d\n", mr->mr_hash);
+ return -EOPNOTSUPP;
}
-
- rc = crypto_shash_init(desc);
- if (!rc)
- rc = crypto_shash_update(desc, mr->mr_value, mr->mr_size);
- if (!rc)
- rc = crypto_shash_finup(desc, data, mr->mr_size, mr->mr_value);
- crypto_free_shash(desc->tfm);
- if (rc)
- pr_err("SHA calculation failed: %d\n", rc);
- return rc;
}
#define MR_(mr, hash) .mr_value = &sample_report.mr, TSM_MR_(mr, hash)
static const struct tsm_measurement_register sample_mrs[] = {
/* static MR, read-only */
--
2.53.0
^ permalink raw reply related
* Re: [PATCH v13 04/48] arm64: RMI: Add SMC definitions for calling the RMM
From: Joey Gouly @ 2026-03-18 16:07 UTC (permalink / raw)
To: Steven Price
Cc: kvm, kvmarm, Catalin Marinas, Marc Zyngier, Will Deacon,
James Morse, Oliver Upton, Suzuki K Poulose, Zenghui Yu,
linux-arm-kernel, linux-kernel, Alexandru Elisei,
Christoffer Dall, Fuad Tabba, linux-coco, Ganapatrao Kulkarni,
Gavin Shan, Shanker Donthineni, Alper Gun, Aneesh Kumar K . V,
Emi Kisanuki, Vishal Annapurve
In-Reply-To: <20260318155413.793430-5-steven.price@arm.com>
On Wed, Mar 18, 2026 at 03:53:28PM +0000, Steven Price wrote:
> The RMM (Realm Management Monitor) provides functionality that can be
> accessed by SMC calls from the host.
>
> The SMC definitions are based on DEN0137[1] version 2.0-bet0
>
> [1] https://developer.arm.com/documentation/den0137/2-0bet0/
>
> Signed-off-by: Steven Price <steven.price@arm.com>
> ---
> Changes since v12:
> * Updated to RMM spec v2.0-bet0
> Changes since v9:
> * Corrected size of 'ripas_value' in struct rec_exit. The spec states
> this is an 8-bit type with padding afterwards (rather than a u64).
> Changes since v8:
> * Added RMI_PERMITTED_GICV3_HCR_BITS to define which bits the RMM
> permits to be modified.
> Changes since v6:
> * Renamed REC_ENTER_xxx defines to include 'FLAG' to make it obvious
> these are flag values.
> Changes since v5:
> * Sorted the SMC #defines by value.
> * Renamed SMI_RxI_CALL to SMI_RMI_CALL since the macro is only used for
> RMI calls.
> * Renamed REC_GIC_NUM_LRS to REC_MAX_GIC_NUM_LRS since the actual
> number of available list registers could be lower.
> * Provided a define for the reserved fields of FeatureRegister0.
> * Fix inconsistent names for padding fields.
> Changes since v4:
> * Update to point to final released RMM spec.
> * Minor rearrangements.
> Changes since v3:
> * Update to match RMM spec v1.0-rel0-rc1.
> Changes since v2:
> * Fix specification link.
> * Rename rec_entry->rec_enter to match spec.
> * Fix size of pmu_ovf_status to match spec.
> ---
> arch/arm64/include/asm/rmi_smc.h | 432 +++++++++++++++++++++++++++++++
> 1 file changed, 432 insertions(+)
> create mode 100644 arch/arm64/include/asm/rmi_smc.h
>
> diff --git a/arch/arm64/include/asm/rmi_smc.h b/arch/arm64/include/asm/rmi_smc.h
> new file mode 100644
> index 000000000000..8a42b83218f8
> --- /dev/null
> +++ b/arch/arm64/include/asm/rmi_smc.h
> @@ -0,0 +1,432 @@
> +/* SPDX-License-Identifier: GPL-2.0 */
> +/*
> + * Copyright (C) 2023-2024 ARM Ltd.
> + *
> + * The values and structures in this file are from the Realm Management Monitor
> + * specification (DEN0137) version 1.0-rel0:
> + * https://developer.arm.com/documentation/den0137/1-0rel0/
> + */
Both copyright and version (2.0 now) need updating.
Thanks,
Joey
> +
> +#ifndef __ASM_RMI_SMC_H
> +#define __ASM_RMI_SMC_H
> +
> +#include <linux/arm-smccc.h>
> +
> +#define SMC_RMI_CALL(func) \
> + ARM_SMCCC_CALL_VAL(ARM_SMCCC_FAST_CALL, \
> + ARM_SMCCC_SMC_64, \
> + ARM_SMCCC_OWNER_STANDARD, \
> + (func))
> +
> +#define SMC_RMI_VERSION SMC_RMI_CALL(0x0150)
> +
> +#define SMC_RMI_RTT_DATA_MAP_INIT SMC_RMI_CALL(0x0153)
> +
> +#define SMC_RMI_REALM_ACTIVATE SMC_RMI_CALL(0x0157)
> +#define SMC_RMI_REALM_CREATE SMC_RMI_CALL(0x0158)
> +#define SMC_RMI_REALM_DESTROY SMC_RMI_CALL(0x0159)
> +#define SMC_RMI_REC_CREATE SMC_RMI_CALL(0x015a)
> +#define SMC_RMI_REC_DESTROY SMC_RMI_CALL(0x015b)
> +#define SMC_RMI_REC_ENTER SMC_RMI_CALL(0x015c)
> +#define SMC_RMI_RTT_CREATE SMC_RMI_CALL(0x015d)
> +#define SMC_RMI_RTT_DESTROY SMC_RMI_CALL(0x015e)
> +
> +#define SMC_RMI_RTT_READ_ENTRY SMC_RMI_CALL(0x0161)
> +
> +#define SMC_RMI_RTT_DEV_VALIDATE SMC_RMI_CALL(0x0163)
> +#define SMC_RMI_PSCI_COMPLETE SMC_RMI_CALL(0x0164)
> +#define SMC_RMI_FEATURES SMC_RMI_CALL(0x0165)
> +#define SMC_RMI_RTT_FOLD SMC_RMI_CALL(0x0166)
> +
> +#define SMC_RMI_RTT_INIT_RIPAS SMC_RMI_CALL(0x0168)
> +#define SMC_RMI_RTT_SET_RIPAS SMC_RMI_CALL(0x0169)
> +#define SMC_RMI_VSMMU_CREATE SMC_RMI_CALL(0x016a)
> +#define SMC_RMI_VSMMU_DESTROY SMC_RMI_CALL(0x016b)
> +#define SMC_RMI_RMM_CONFIG_SET SMC_RMI_CALL(0x016e)
> +#define SMC_RMI_PSMMU_IRQ_NOTIFY SMC_RMI_CALL(0x016f)
> +#define SMC_RMI_ATTEST_PLAT_TOKEN_REFRESH SMC_RMI_CALL(0x0170)
> +
> +#define SMC_RMI_PDEV_ABORT SMC_RMI_CALL(0x0174)
> +#define SMC_RMI_PDEV_COMMUNICATE SMC_RMI_CALL(0x0175)
> +#define SMC_RMI_PDEV_CREATE SMC_RMI_CALL(0x0176)
> +#define SMC_RMI_PDEV_DESTROY SMC_RMI_CALL(0x0177)
> +#define SMC_RMI_PDEV_GET_STATE SMC_RMI_CALL(0x0178)
> +
> +#define SMC_RMI_PDEV_STREAM_KEY_REFRESH SMC_RMI_CALL(0x017a)
> +#define SMC_RMI_PDEV_SET_PUBKEY SMC_RMI_CALL(0x017b)
> +#define SMC_RMI_PDEV_STOP SMC_RMI_CALL(0x017c)
> +#define SMC_RMI_RTT_AUX_CREATE SMC_RMI_CALL(0x017d)
> +#define SMC_RMI_RTT_AUX_DESTROY SMC_RMI_CALL(0x017e)
> +#define SMC_RMI_RTT_AUX_FOLD SMC_RMI_CALL(0x017f)
> +
> +#define SMC_RMI_VDEV_ABORT SMC_RMI_CALL(0x0185)
> +#define SMC_RMI_VDEV_COMMUNICATE SMC_RMI_CALL(0x0186)
> +#define SMC_RMI_VDEV_CREATE SMC_RMI_CALL(0x0187)
> +#define SMC_RMI_VDEV_DESTROY SMC_RMI_CALL(0x0188)
> +#define SMC_RMI_VDEV_GET_STATE SMC_RMI_CALL(0x0189)
> +#define SMC_RMI_VDEV_UNLOCK SMC_RMI_CALL(0x018a)
> +#define SMC_RMI_RTT_SET_S2AP SMC_RMI_CALL(0x018b)
> +#define SMC_RMI_VDEV_COMPLETE SMC_RMI_CALL(0x018e)
> +
> +#define SMC_RMI_VDEV_GET_INTERFACE_REPORT SMC_RMI_CALL(0x01d0)
> +#define SMC_RMI_VDEV_GET_MEASUREMENTS SMC_RMI_CALL(0x01d1)
> +#define SMC_RMI_VDEV_LOCK SMC_RMI_CALL(0x01d2)
> +#define SMC_RMI_VDEV_START SMC_RMI_CALL(0x01d3)
> +#define SMC_RMI_VDEV_P2P_BIND SMC_RMI_CALL(0x01d4)
> +#define SMC_RMI_VDEV_P2P_UNBIND SMC_RMI_CALL(0x01d5)
> +#define SMC_RMI_VSMMU_EVENT_NOTIFY SMC_RMI_CALL(0x01d6)
> +#define SMC_RMI_PSMMU_ACTIVATE SMC_RMI_CALL(0x01d7)
> +#define SMC_RMI_PSMMU_DEACTIVATE SMC_RMI_CALL(0x01d8)
> +
> +#define SMC_RMI_PSMMU_ST_L2_CREATE SMC_RMI_CALL(0x01db)
> +#define SMC_RMI_PSMMU_ST_L2_DESTROY SMC_RMI_CALL(0x01dc)
> +#define SMC_RMI_DPT_L0_CREATE SMC_RMI_CALL(0x01dd)
> +#define SMC_RMI_DPT_L0_DESTROY SMC_RMI_CALL(0x01de)
> +#define SMC_RMI_DPT_L1_CREATE SMC_RMI_CALL(0x01df)
> +#define SMC_RMI_DPT_L1_DESTROY SMC_RMI_CALL(0x01e0)
> +#define SMC_RMI_GRANULE_TRACKING_GET SMC_RMI_CALL(0x01e1)
> +
> +#define SMC_RMI_GRANULE_TRACKING_SET SMC_RMI_CALL(0x01e3)
> +#define SMC_RMI_CMEM_ADD_PDEV SMC_RMI_CALL(0x01e4)
> +#define SMC_RMI_CMEM_CREATE SMC_RMI_CALL(0x01e5)
> +#define SMC_RMI_CMEM_DESTROY SMC_RMI_CALL(0x01e6)
> +#define SMC_RMI_CMEM_POPULATE SMC_RMI_CALL(0x01e7)
> +#define SMC_RMI_CMEM_REMOTE_PDEV SMC_RMI_CALL(0x01e8)
> +#define SMC_RMI_CMEM_START SMC_RMI_CALL(0x01e9)
> +#define SMC_RMI_CMEM_STOP SMC_RMI_CALL(0x01ea)
> +#define SMC_RMI_CMEM_UNPOPULATE SMC_RMI_CALL(0x01eb)
> +#define SMC_RMI_RMM_CONFIG_GET SMC_RMI_CALL(0x01ec)
> +#define SMC_RMI_PDEV_MEC_UPDATE SMC_RMI_CALL(0x01ed)
> +#define SMC_RMI_VSMMU_EVENT_COMPLETE SMC_RMI_CALL(0x01ee)
> +
> +#define SMC_RMI_PSMMU_EVENT_DISCARD SMC_RMI_CALL(0x01f0)
> +#define SMC_RMI_GRANULE_RANGE_DELEGATE SMC_RMI_CALL(0x01f1)
> +#define SMC_RMI_GRANULE_RANGE_UNDELEGATE SMC_RMI_CALL(0x01f2)
> +#define SMC_RMI_GPT_L1_CREATE SMC_RMI_CALL(0x01f3)
> +#define SMC_RMI_GPT_L1_DESTROY SMC_RMI_CALL(0x01f4)
> +#define SMC_RMI_RTT_DATA_MAP SMC_RMI_CALL(0x01f5)
> +#define SMC_RMI_RTT_DATA_UNMAP SMC_RMI_CALL(0x01f6)
> +#define SMC_RMI_RTT_DEV_MAP SMC_RMI_CALL(0x01f7)
> +#define SMC_RMI_RTT_DEV_UNMAP SMC_RMI_CALL(0x01f8)
> +#define SMC_RMI_RTT_ARCH_DEV_MAP SMC_RMI_CALL(0x01f9)
> +#define SMC_RMI_RTT_ARCH_DEV_UNMAP SMC_RMI_CALL(0x01fa)
> +#define SMC_RMI_RTT_UNPROT_MAP SMC_RMI_CALL(0x01fb)
> +#define SMC_RMI_RTT_UNPROT_UNMAP SMC_RMI_CALL(0x01fc)
> +#define SMC_RMI_RTT_AUX_PROT_MAP SMC_RMI_CALL(0x01fd)
> +#define SMC_RMI_RTT_AUX_PROT_UNMAP SMC_RMI_CALL(0x01fe)
> +#define SMC_RMI_RTT_AUX_UNPROT_MAP SMC_RMI_CALL(0x01ff)
> +#define SMC_RMI_RTT_AUX_UNMAP_UNMAP SMC_RMI_CALL(0x0200)
> +#define SMC_RMI_REALM_TERMINATE SMC_RMI_CALL(0x0201)
> +#define SMC_RMI_RMM_ACTIVATE SMC_RMI_CALL(0x0202)
> +#define SMC_RMI_OP_CONTINUE SMC_RMI_CALL(0x0203)
> +#define SMC_RMI_PDEV_STREAM_CONNECT SMC_RMI_CALL(0x0204)
> +#define SMC_RMI_PDEV_STREAM_DISCONNECT SMC_RMI_CALL(0x0205)
> +#define SMC_RMI_PDEV_STREAM_COMPLETE SMC_RMI_CALL(0x0206)
> +#define SMC_RMI_PDEV_STREAM_KEY_PURGE SMC_RMI_CALL(0x0207)
> +#define SMC_RMI_OP_MEM_DONATE SMC_RMI_CALL(0x0208)
> +#define SMC_RMI_OP_MEM_RECLAIM SMC_RMI_CALL(0x0209)
> +#define SMC_RMI_OP_CANCEL SMC_RMI_CALL(0x020a)
> +#define SMC_RMI_PDEV_SET_PROT SMC_RMI_CALL(0x020b)
> +
> +#define RMI_ABI_MAJOR_VERSION 2
> +#define RMI_ABI_MINOR_VERSION 0
> +
> +#define RMI_ABI_VERSION_GET_MAJOR(version) ((version) >> 16)
> +#define RMI_ABI_VERSION_GET_MINOR(version) ((version) & 0xFFFF)
> +#define RMI_ABI_VERSION(major, minor) (((major) << 16) | (minor))
> +
> +#define RMI_UNASSIGNED 0
> +#define RMI_ASSIGNED 1
> +#define RMI_TABLE 2
> +
> +#define RMI_RETURN_STATUS(ret) ((ret) & 0xFF)
> +#define RMI_RETURN_INDEX(ret) (((ret) >> 8) & 0xFF)
> +#define RMI_RETURN_MEMREQ(ret) (((ret) >> 8) & 0x3)
> +#define RMI_RETURN_CANCANCEL(ret) (((ret) >> 10) & 0x1)
> +
> +#define RMI_SUCCESS 0
> +#define RMI_ERROR_INPUT 1
> +#define RMI_ERROR_REALM 2
> +#define RMI_ERROR_REC 3
> +#define RMI_ERROR_RTT 4
> +#define RMI_ERROR_NOT_SUPPORTED 5
> +#define RMI_ERROR_DEVICE 6
> +#define RMI_ERROR_RTT_AUX 7
> +#define RMI_ERROR_PSMMU_ST 8
> +#define RMI_ERROR_DPT 9
> +#define RMI_BUSY 10
> +#define RMI_ERROR_GLOBAL 11
> +#define RMI_ERROR_TRACKING 12
> +#define RMI_INCOMPLETE 13
> +#define RMI_BLOCKED 14
> +#define RMI_ERROR_GPT 15
> +#define RMI_ERROR_GRANULE 16
> +
> +#define RMI_OP_MEM_REQ_NONE 0
> +#define RMI_OP_MEM_REQ_DONATE 1
> +#define RMI_OP_MEM_REQ_RECLAIM 2
> +
> +#define RMI_DONATE_SIZE(req) ((req) & 0x3)
> +#define RMI_DONATE_COUNT_MASK GENMASK(15, 2)
> +#define RMI_DONATE_COUNT(req) (((req) & RMI_DONATE_COUNT_MASK) >> 2)
> +#define RMI_DONATE_CONTIG(req) (!!((req) & BIT(16)))
> +#define RMI_DONATE_STATE(req) (!!((req) & BIT(17)))
> +
> +#define RMI_OP_MEM_DELEGATED 0
> +#define RMI_OP_MEM_UNDELEGATED 1
> +
> +#define RMI_ADDR_TYPE_NONE 0
> +#define RMI_ADDR_TYPE_SINGLE 1
> +#define RMI_ADDR_TYPE_LIST 2
> +
> +#define RMI_ADDR_RANGE_SIZE(ar) (FIELD_GET(GENMASK(1, 0), (ar)))
> +#define RMI_ADDR_RANGE_COUNT(ar) (FIELD_GET(GENMASK(PAGE_SHIFT - 1, 2), \
> + (ar)))
> +#define RMI_ADDR_RANGE_ADDR(ar) ((ar) & PAGE_MASK & GENMASK(51, 0))
> +#define RMI_ADDR_RANGE_STATE(ar) (FIELD_GET(BIT(63), (ar)))
> +
> +enum rmi_ripas {
> + RMI_EMPTY = 0,
> + RMI_RAM = 1,
> + RMI_DESTROYED = 2,
> +};
> +
> +#define RMI_NO_MEASURE_CONTENT 0
> +#define RMI_MEASURE_CONTENT 1
> +
> +#define RMI_FEATURE_REGISTER_0_S2SZ GENMASK(7, 0)
> +#define RMI_FEATURE_REGISTER_0_LPA2 BIT(8)
> +#define RMI_FEATURE_REGISTER_0_SVE BIT(9)
> +#define RMI_FEATURE_REGISTER_0_SVE_VL GENMASK(13, 10)
> +#define RMI_FEATURE_REGISTER_0_NUM_BPS GENMASK(19, 14)
> +#define RMI_FEATURE_REGISTER_0_NUM_WPS GENMASK(25, 20)
> +#define RMI_FEATURE_REGISTER_0_PMU BIT(26)
> +#define RMI_FEATURE_REGISTER_0_PMU_NUM_CTRS GENMASK(31, 27)
> +
> +#define RMI_FEATURE_REGISTER_1_RMI_GRAN_SZ_4KB BIT(0)
> +#define RMI_FEATURE_REGISTER_1_RMI_GRAN_SZ_16KB BIT(1)
> +#define RMI_FEATURE_REGISTER_1_RMI_GRAN_SZ_64KB BIT(2)
> +#define RMI_FEATURE_REGISTER_1_HASH_SHA_256 BIT(3)
> +#define RMI_FEATURE_REGISTER_1_HASH_SHA_384 BIT(4)
> +#define RMI_FEATURE_REGISTER_1_HASH_SHA_512 BIT(5)
> +#define RMI_FEATURE_REGISTER_1_MAX_RECS_ORDER GENMASK(9, 6)
> +#define RMI_FEATURE_REGISTER_1_L0GPTSZ GENMASK(13, 10)
> +#define RMI_FEATURE_REGISTER_1_PPS GENMASK(16, 14)
> +
> +#define RMI_FEATURE_REGISTER_2_DA BIT(0)
> +#define RMI_FEATURE_REGISTER_2_DA_COH BIT(1)
> +#define RMI_FEATURE_REGISTER_2_VSMMU BIT(2)
> +#define RMI_FEATURE_REGISTER_2_ATS BIT(3)
> +#define RMI_FEATURE_REGISTER_2_MAX_VDEVS_ORDER GEN_MASK(7, 4)
> +#define RMI_FEATURE_REGISTER_2_VDEV_KROU BIT(8)
> +#define RMI_FEATURE_REGISTER_2_NON_TEE_STREAM BIT(9)
> +
> +#define RMI_FEATURE_REGISTER_3_MAX_NUM_AUX_PLANES GENMASK(3, 0)
> +#define RMI_FEATURE_REGISTER_3_RTT_PLAN GENMASK(5, 4)
> +#define RMI_FEATURE_REGISTER_3_RTT_S2AP_INDIRECT BIT(6)
> +
> +#define RMI_FEATURE_REGISTER_4_MEC_COUNT GENMASK(63, 0)
> +
> +#define RMI_MEM_CATEGORY_CONVENTIONAL 0
> +#define RMI_MEM_CATEGORY_DEV_NCOH 1
> +#define RMI_MEM_CATEGORY_DEV_COH 2
> +
> +#define RMI_TRACKING_RESERVED 0
> +#define RMI_TRACKING_NONE 1
> +#define RMI_TRACKING_FINE 2
> +#define RMI_TRACKING_COARSE 3
> +
> +#define RMI_GRANULE_SIZE_4KB 0
> +#define RMI_GRANULE_SIZE_16KB 1
> +#define RMI_GRANULE_SIZE_64KB 2
> +
> +/*
> + * Note many of these fields are smaller than u64 but all fields have u64
> + * alignment, so use u64 to ensure correct alignment.
> + */
> +struct rmm_config {
> + union { /* 0x0 */
> + struct {
> + u64 tracking_region_size;
> + u64 rmi_granule_size;
> + };
> + u8 sizer[0x1000];
> + };
> +};
> +
> +#define RMI_REALM_PARAM_FLAG_LPA2 BIT(0)
> +#define RMI_REALM_PARAM_FLAG_SVE BIT(1)
> +#define RMI_REALM_PARAM_FLAG_PMU BIT(2)
> +
> +struct realm_params {
> + union { /* 0x0 */
> + struct {
> + u64 flags;
> + u64 s2sz;
> + u64 sve_vl;
> + u64 num_bps;
> + u64 num_wps;
> + u64 pmu_num_ctrs;
> + u64 hash_algo;
> + };
> + u8 padding0[0x400];
> + };
> + union { /* 0x400 */
> + u8 rpv[64];
> + u8 padding1[0x400];
> + };
> + union { /* 0x800 */
> + struct {
> + u64 padding;
> + u64 rtt_base;
> + s64 rtt_level_start;
> + u64 rtt_num_start;
> + };
> + u8 padding2[0x800];
> + };
> +};
> +
> +/*
> + * The number of GPRs (starting from X0) that are
> + * configured by the host when a REC is created.
> + */
> +#define REC_CREATE_NR_GPRS 8
> +
> +#define REC_PARAMS_FLAG_RUNNABLE BIT_ULL(0)
> +
> +#define REC_PARAMS_AUX_GRANULES 16
> +
> +struct rec_params {
> + union { /* 0x0 */
> + u64 flags;
> + u8 padding0[0x100];
> + };
> + union { /* 0x100 */
> + u64 mpidr;
> + u8 padding1[0x100];
> + };
> + union { /* 0x200 */
> + u64 pc;
> + u8 padding2[0x100];
> + };
> + union { /* 0x300 */
> + u64 gprs[REC_CREATE_NR_GPRS];
> + u8 padding3[0x500];
> + };
> + union { /* 0x800 */
> + struct {
> + u64 num_rec_aux;
> + u64 aux[REC_PARAMS_AUX_GRANULES];
> + };
> + u8 padding4[0x800];
> + };
> +};
> +
> +#define REC_ENTER_FLAG_EMULATED_MMIO BIT(0)
> +#define REC_ENTER_FLAG_INJECT_SEA BIT(1)
> +#define REC_ENTER_FLAG_TRAP_WFI BIT(2)
> +#define REC_ENTER_FLAG_TRAP_WFE BIT(3)
> +#define REC_ENTER_FLAG_RIPAS_RESPONSE BIT(4)
> +
> +#define REC_RUN_GPRS 31
> +#define REC_MAX_GIC_NUM_LRS 16
> +
> +#define RMI_PERMITTED_GICV3_HCR_BITS (ICH_HCR_EL2_UIE | \
> + ICH_HCR_EL2_LRENPIE | \
> + ICH_HCR_EL2_NPIE | \
> + ICH_HCR_EL2_VGrp0EIE | \
> + ICH_HCR_EL2_VGrp0DIE | \
> + ICH_HCR_EL2_VGrp1EIE | \
> + ICH_HCR_EL2_VGrp1DIE | \
> + ICH_HCR_EL2_TDIR)
> +
> +struct rec_enter {
> + union { /* 0x000 */
> + u64 flags;
> + u8 padding0[0x200];
> + };
> + union { /* 0x200 */
> + u64 gprs[REC_RUN_GPRS];
> + u8 padding1[0x100];
> + };
> + u8 padding3[0x500];
> +};
> +
> +#define RMI_EXIT_SYNC 0x00
> +#define RMI_EXIT_IRQ 0x01
> +#define RMI_EXIT_FIQ 0x02
> +#define RMI_EXIT_PSCI 0x03
> +#define RMI_EXIT_RIPAS_CHANGE 0x04
> +#define RMI_EXIT_HOST_CALL 0x05
> +#define RMI_EXIT_SERROR 0x06
> +
> +struct rec_exit {
> + union { /* 0x000 */
> + u8 exit_reason;
> + u8 padding0[0x100];
> + };
> + union { /* 0x100 */
> + struct {
> + u64 esr;
> + u64 far;
> + u64 hpfar;
> + u64 rtt_tree;
> + };
> + u8 padding1[0x100];
> + };
> + union { /* 0x200 */
> + u64 gprs[REC_RUN_GPRS];
> + u8 padding2[0x100];
> + };
> + union { /* 0x300 */
> + u8 padding3[0x100];
> + };
> + union { /* 0x400 */
> + struct {
> + u64 cntp_ctl;
> + u64 cntp_cval;
> + u64 cntv_ctl;
> + u64 cntv_cval;
> + };
> + u8 padding4[0x100];
> + };
> + union { /* 0x500 */
> + struct {
> + u64 ripas_base;
> + u64 ripas_top;
> + u8 ripas_value;
> + u8 padding8[15];
> + u64 s2ap_base;
> + u64 s2ap_top;
> + u64 vdev_id_1;
> + u64 vdev_id_2;
> + u64 dev_mem_base;
> + u64 dev_mem_top;
> + u64 dev_mem_pa;
> + };
> + u8 padding5[0x100];
> + };
> + union { /* 0x600 */
> + struct {
> + u16 imm;
> + u16 padding9;
> + u64 plane;
> + };
> + u8 padding6[0x100];
> + };
> + union { /* 0x700 */
> + struct {
> + u8 pmu_ovf_status;
> + u8 padding10[15];
> + u64 vsmmu;
> + };
> + u8 padding7[0x100];
> + };
> +};
> +
> +struct rec_run {
> + struct rec_enter enter;
> + struct rec_exit exit;
> +};
> +
> +#endif /* __ASM_RMI_SMC_H */
> --
> 2.43.0
>
>
^ permalink raw reply
* [PATCH v13 48/48] [WIP] arm64: RMI: Add support for SRO
From: Steven Price @ 2026-03-18 15:54 UTC (permalink / raw)
To: kvm, kvmarm
Cc: Steven Price, Catalin Marinas, Marc Zyngier, Will Deacon,
James Morse, Oliver Upton, Suzuki K Poulose, Zenghui Yu,
linux-arm-kernel, linux-kernel, Joey Gouly, Alexandru Elisei,
Christoffer Dall, Fuad Tabba, linux-coco, Ganapatrao Kulkarni,
Gavin Shan, Shanker Donthineni, Alper Gun, Aneesh Kumar K . V,
Emi Kisanuki, Vishal Annapurve
In-Reply-To: <20260318155413.793430-1-steven.price@arm.com>
RMM v2.0 introduces the concept of "Stateful RMI Operations" (SRO).
This means that an SMC can return with an operation still in progress.
The host is expected to continue the operation until it reaches a
conclusion (either success or failure). During this process the RMM can
request addition memory ('donate') or hand memory back to the host
('reclaim'). The host can request an operation is cancelled, but must
still continue the operation until it has completed (otherwise the
incomplete operation may cause future RMM operations to fail).
SROs may request memory and these operations sometimes have to be
performed in places where memory allocation may not be possible. To deal
with this a SRO may be started, but then cancelled when the memory
allocation cannot be completed. The reclaimed memory will then be stored
in a struct rmi_sro_state object with the intention that once Linux has
returned to a state where memory allocation is possible, the failed
allocation can be reattempted (with GFP flags enabling sleeping and/or
direct reclaim) and the SRO operation reattempted (after acquiring the
necessary locks). In the worst case this may require several attempts
(if the RMM makes several memory requests) but should always make
forward progress.
This patch is currently a work-in-progress showing the general structure
of how this should work and implementing SROs for two operations
(RMI_REC_CREATE and RMI_REC_DESTROY). I'm aware there is missing
error-checking and there are some details in the specification that need
clarifying. These operations are also 'easy' in that we don't have
restrictions on memory allocation in these contexts.
Signed-off-by: Steven Price <steven.price@arm.com>
---
arch/arm64/include/asm/kvm_rmi.h | 8 -
arch/arm64/include/asm/rmi_cmds.h | 71 +++---
arch/arm64/include/asm/rmi_smc.h | 27 +--
arch/arm64/kvm/rmi.c | 385 +++++++++++++++++++++++-------
4 files changed, 347 insertions(+), 144 deletions(-)
diff --git a/arch/arm64/include/asm/kvm_rmi.h b/arch/arm64/include/asm/kvm_rmi.h
index b914b9a84bd8..e1f5523c2dfa 100644
--- a/arch/arm64/include/asm/kvm_rmi.h
+++ b/arch/arm64/include/asm/kvm_rmi.h
@@ -51,7 +51,6 @@ enum realm_state {
* @state: The lifetime state machine for the realm
* @rd: Kernel mapping of the Realm Descriptor (RD)
* @params: Parameters for the RMI_REALM_CREATE command
- * @num_aux: The number of auxiliary pages required by the RMM
* @ia_bits: Number of valid Input Address bits in the IPA
*/
struct realm {
@@ -60,7 +59,6 @@ struct realm {
void *rd;
struct realm_params *params;
- unsigned long num_aux;
unsigned int ia_bits;
};
@@ -75,12 +73,6 @@ struct realm {
struct realm_rec {
unsigned long mpidr;
void *rec_page;
- /*
- * REC_PARAMS_AUX_GRANULES is the maximum number of 4K granules that
- * the RMM can require. The array is sized to be large enough for the
- * maximum number of host sized pages that could be required.
- */
- struct page *aux_pages[(REC_PARAMS_AUX_GRANULES * SZ_4K) >> PAGE_SHIFT];
struct rec_run *run;
};
diff --git a/arch/arm64/include/asm/rmi_cmds.h b/arch/arm64/include/asm/rmi_cmds.h
index 9c4f83644a61..b761d74e1273 100644
--- a/arch/arm64/include/asm/rmi_cmds.h
+++ b/arch/arm64/include/asm/rmi_cmds.h
@@ -17,6 +17,27 @@ struct rtt_entry {
int ripas;
};
+#define RMI_MAX_ADDR_LIST 256
+
+struct rmi_sro_state {
+ struct arm_smccc_1_2_regs regs;
+
+ unsigned long addr_count;
+ unsigned long addr_list[RMI_MAX_ADDR_LIST];
+};
+
+#define rmi_init_sro(...) ({ \
+ struct rmi_sro_state *sro = kmalloc_obj(*sro); \
+ if (sro) \
+ *sro = (struct rmi_sro_state){.regs = {__VA_ARGS__}}; \
+ sro; \
+})
+
+#define rmi_smccc(...) do { \
+ arm_smccc_1_1_invoke(__VA_ARGS__); \
+} while (RMI_RETURN_STATUS(res.a0) == RMI_BUSY || \
+ RMI_RETURN_STATUS(res.a0) == RMI_BLOCKED)
+
/**
* rmi_rmm_config_get() - Get the system configuration
* @cfg_ptr: PA of a struct rmm_config
@@ -410,29 +431,7 @@ static inline int rmi_realm_destroy(unsigned long rd)
}
/**
- * rmi_rec_aux_count() - Get number of auxiliary granules required
- * @rd: PA of the RD
- * @aux_count: Number of granules written to this pointer
- *
- * A REC may require extra auxiliary granules to be delegated for the RMM to
- * store metadata (not visible to the normal world) in. This function provides
- * the number of granules that are required.
- *
- * Return: RMI return code
- */
-static inline int rmi_rec_aux_count(unsigned long rd, unsigned long *aux_count)
-{
- struct arm_smccc_res res;
-
- arm_smccc_1_1_invoke(SMC_RMI_REC_AUX_COUNT, rd, &res);
-
- if (aux_count)
- *aux_count = res.a1;
- return res.a0;
-}
-
-/**
- * rmi_rec_create() - Create a REC
+ * rmi_rec_create_sro_init() - Init an SRO to create a REC
* @rd: PA of the RD
* @rec: PA of the target REC
* @params: PA of REC parameters
@@ -440,33 +439,27 @@ static inline int rmi_rec_aux_count(unsigned long rd, unsigned long *aux_count)
* Create a REC using the parameters specified in the struct rec_params pointed
* to by @params.
*
- * Return: RMI return code
+ * Returns: Allocated SRO object
*/
-static inline int rmi_rec_create(unsigned long rd, unsigned long rec,
- unsigned long params)
+static inline struct rmi_sro_state *
+rmi_rec_create_sro_init(unsigned long rd,
+ unsigned long rec,
+ unsigned long params)
{
- struct arm_smccc_res res;
-
- arm_smccc_1_1_invoke(SMC_RMI_REC_CREATE, rd, rec, params, &res);
-
- return res.a0;
+ return rmi_init_sro(SMC_RMI_REC_CREATE, rd, rec, params);
}
/**
- * rmi_rec_destroy() - Destroy a REC
+ * rmi_rec_destroy_sro_init() - Init an SRO to destroy a REC
* @rec: PA of the target REC
*
* Destroys a REC. The REC must not be running.
*
- * Return: RMI return code
+ * Return: Allocated SRO object
*/
-static inline int rmi_rec_destroy(unsigned long rec)
+static inline struct rmi_sro_state *rmi_rec_destroy_sro_init(unsigned long rec)
{
- struct arm_smccc_res res;
-
- arm_smccc_1_1_invoke(SMC_RMI_REC_DESTROY, rec, &res);
-
- return res.a0;
+ return rmi_init_sro(SMC_RMI_REC_DESTROY, rec);
}
/**
diff --git a/arch/arm64/include/asm/rmi_smc.h b/arch/arm64/include/asm/rmi_smc.h
index 049d71470486..fa23818e1b4c 100644
--- a/arch/arm64/include/asm/rmi_smc.h
+++ b/arch/arm64/include/asm/rmi_smc.h
@@ -38,7 +38,6 @@
#define SMC_RMI_PSCI_COMPLETE SMC_RMI_CALL(0x0164)
#define SMC_RMI_FEATURES SMC_RMI_CALL(0x0165)
#define SMC_RMI_RTT_FOLD SMC_RMI_CALL(0x0166)
-#define SMC_RMI_REC_AUX_COUNT SMC_RMI_CALL(0x0167) //
#define SMC_RMI_RTT_INIT_RIPAS SMC_RMI_CALL(0x0168)
#define SMC_RMI_RTT_SET_RIPAS SMC_RMI_CALL(0x0169)
#define SMC_RMI_VSMMU_CREATE SMC_RMI_CALL(0x016a)
@@ -180,11 +179,18 @@
#define RMI_ADDR_TYPE_SINGLE 1
#define RMI_ADDR_TYPE_LIST 2
-#define RMI_ADDR_RANGE_SIZE(ar) (FIELD_GET(GENMASK(1, 0), (ar)))
-#define RMI_ADDR_RANGE_COUNT(ar) (FIELD_GET(GENMASK(PAGE_SHIFT - 1, 2), \
+#define RMI_ADDR_RANGE_SIZE_MASK GENMASK(1, 0)
+#define RMI_ADDR_RANGE_COUNT_MASK GENMASK(PAGE_SHIFT - 1, 2)
+#define RMI_ADDR_RANGE_ADDR_MASK (PAGE_MASK & GENMASK(51, 0))
+#define RMI_ADDR_RANGE_STATE_MASK BIT(63)
+
+#define RMI_ADDR_RANGE_SIZE(ar) (FIELD_GET(RMI_ADDR_RANGE_SIZE_MASK, \
+ (ar)))
+#define RMI_ADDR_RANGE_COUNT(ar) (FIELD_GET(RMI_ADDR_RANGE_COUNT_MASK, \
+ (ar)))
+#define RMI_ADDR_RANGE_ADDR(ar) ((ar) & RMI_ADDR_RANGE_ADDR_MASK)
+#define RMI_ADDR_RANGE_STATE(ar) (FIELD_GET(RMI_ADDR_RANGE_STATE_MASK, \
(ar)))
-#define RMI_ADDR_RANGE_ADDR(ar) ((ar) & PAGE_MASK & GENMASK(51, 0))
-#define RMI_ADDR_RANGE_STATE(ar) (FIELD_GET(BIT(63), (ar)))
enum rmi_ripas {
RMI_EMPTY = 0,
@@ -295,8 +301,6 @@ struct realm_params {
#define REC_PARAMS_FLAG_RUNNABLE BIT_ULL(0)
-#define REC_PARAMS_AUX_GRANULES 16
-
struct rec_params {
union { /* 0x0 */
u64 flags;
@@ -312,14 +316,7 @@ struct rec_params {
};
union { /* 0x300 */
u64 gprs[REC_CREATE_NR_GPRS];
- u8 padding3[0x500];
- };
- union { /* 0x800 */
- struct {
- u64 num_rec_aux;
- u64 aux[REC_PARAMS_AUX_GRANULES];
- };
- u8 padding4[0x800];
+ u8 padding3[0xd00];
};
};
diff --git a/arch/arm64/kvm/rmi.c b/arch/arm64/kvm/rmi.c
index e76e58762f55..10ff1c3bddaf 100644
--- a/arch/arm64/kvm/rmi.c
+++ b/arch/arm64/kvm/rmi.c
@@ -20,6 +20,295 @@ static unsigned long rmm_feat_reg1;
#define RMM_L2_BLOCK_SIZE PMD_SIZE
+static int delegate_range(phys_addr_t phys, unsigned long size);
+static int undelegate_range(phys_addr_t phys, unsigned long size);
+
+static unsigned long donate_req_to_size(unsigned long donatereq)
+{
+ unsigned long unit_size = RMI_DONATE_SIZE(donatereq);
+
+ switch (unit_size) {
+ case 0:
+ return PAGE_SIZE;
+ case 1:
+ return PMD_SIZE;
+ case 2:
+ return PUD_SIZE;
+ case 3:
+ return P4D_SIZE;
+ }
+ unreachable();
+}
+
+static void rmi_smccc_invoke(struct arm_smccc_1_2_regs *regs_in,
+ struct arm_smccc_1_2_regs *regs_out)
+{
+ struct arm_smccc_1_2_regs regs = *regs_in;
+ unsigned long status;
+
+ do {
+ arm_smccc_1_2_invoke(®s, regs_out);
+ status = RMI_RETURN_STATUS(regs_out->a0);
+ } while (status == RMI_BUSY || status == RMI_BLOCKED);
+}
+
+static int rmi_sro_donate_contig(struct rmi_sro_state *sro,
+ unsigned long sro_handle,
+ unsigned long donatereq,
+ struct arm_smccc_1_2_regs *out_regs,
+ gfp_t gfp)
+{
+ unsigned long unit_size = RMI_DONATE_SIZE(donatereq);
+ unsigned long count = RMI_DONATE_COUNT(donatereq);
+ unsigned long state = RMI_DONATE_STATE(donatereq);
+ unsigned long size;
+ unsigned long addr_range;
+ struct page *pages;
+ phys_addr_t phys;
+ struct arm_smccc_1_2_regs regs = {
+ SMC_RMI_OP_MEM_DONATE,
+ sro_handle
+ };
+
+ for (int i = 0; i < sro->addr_count; i++) {
+ unsigned long entry = sro->addr_list[i];
+
+ if (RMI_ADDR_RANGE_SIZE(entry) == unit_size &&
+ RMI_ADDR_RANGE_COUNT(entry) == count &&
+ RMI_ADDR_RANGE_STATE(entry) == state) {
+ sro->addr_count--;
+ swap(sro->addr_list[sro->addr_count],
+ sro->addr_list[i]);
+
+ goto out;
+ }
+ }
+
+ size = donate_req_to_size(donatereq) * count;
+
+ pages = alloc_pages(gfp, get_order(size));
+ if (!pages)
+ return -ENOMEM;
+ phys = page_to_phys(pages);
+
+ if (state == RMI_OP_MEM_DELEGATED) {
+ if (delegate_range(phys, size)) {
+ __free_pages(pages, get_order(size));
+ return -ENXIO;
+ }
+ }
+
+ addr_range = phys & RMI_ADDR_RANGE_ADDR_MASK;
+ FIELD_MODIFY(RMI_ADDR_RANGE_SIZE_MASK, &addr_range, unit_size);
+ FIELD_MODIFY(RMI_ADDR_RANGE_COUNT_MASK, &addr_range, count);
+ FIELD_MODIFY(RMI_ADDR_RANGE_STATE_MASK, &addr_range, state);
+
+ sro->addr_list[sro->addr_count] = addr_range;
+
+out:
+ regs.a2 = virt_to_phys(&sro->addr_list[sro->addr_count]);
+ regs.a3 = 1;
+ rmi_smccc_invoke(®s, out_regs);
+
+ unsigned long donated_granules = out_regs->a1;
+
+ WARN_ON(donated_granules > 1);
+ if (WARN_ON(donated_granules == 0)) {
+ sro->addr_count++;
+ return 0;
+ }
+
+ return 0;
+}
+
+static int rmi_sro_donate_noncontig(struct rmi_sro_state *sro,
+ unsigned long sro_handle,
+ unsigned long donatereq,
+ struct arm_smccc_1_2_regs *out_regs,
+ gfp_t gfp)
+{
+ unsigned long unit_size = RMI_DONATE_SIZE(donatereq);
+ unsigned long count = RMI_DONATE_COUNT(donatereq);
+ unsigned long state = RMI_DONATE_STATE(donatereq);
+ unsigned long found = 0;
+ unsigned long addr_list_start = sro->addr_count;
+ struct arm_smccc_1_2_regs regs = {
+ SMC_RMI_OP_MEM_DONATE,
+ sro_handle
+ };
+
+ for (int i = 0; i < addr_list_start && found < count; i++) {
+ unsigned long entry = sro->addr_list[i];
+
+ if (RMI_ADDR_RANGE_SIZE(entry) == unit_size &&
+ RMI_ADDR_RANGE_COUNT(entry) == 1 &&
+ RMI_ADDR_RANGE_STATE(entry) == state) {
+ addr_list_start--;
+ swap(sro->addr_list[addr_list_start],
+ sro->addr_list[i]);
+ found++;
+ i--;
+ }
+ }
+
+ while (found < count) {
+ unsigned long addr_range;
+ unsigned long size = donate_req_to_size(donatereq);
+
+ struct page *pages = alloc_pages(gfp, get_order(size));
+ phys_addr_t phys;
+
+ if (!pages)
+ return -ENOMEM;
+
+ phys = page_to_phys(pages);
+
+ if (state == RMI_OP_MEM_DELEGATED) {
+ if (delegate_range(phys, size)) {
+ __free_pages(pages, get_order(size));
+ return -ENXIO;
+ }
+ }
+
+ addr_range = phys & RMI_ADDR_RANGE_ADDR_MASK;
+ FIELD_MODIFY(RMI_ADDR_RANGE_SIZE_MASK, &addr_range, unit_size);
+ FIELD_MODIFY(RMI_ADDR_RANGE_COUNT_MASK, &addr_range, 1);
+ FIELD_MODIFY(RMI_ADDR_RANGE_STATE_MASK, &addr_range, state);
+
+ sro->addr_list[sro->addr_count++] = addr_range;
+ found++;
+ }
+
+ regs.a2 = virt_to_phys(&sro->addr_list[addr_list_start]);
+ regs.a3 = found;
+ rmi_smccc_invoke(®s, out_regs);
+
+ unsigned long donated_granules = out_regs->a1;
+
+ while (donated_granules < found) {
+ swap(sro->addr_list[addr_list_start++],
+ sro->addr_list[--sro->addr_count]);
+ found--;
+ }
+ sro->addr_count -= donated_granules;
+
+ return 0;
+}
+
+static int rmi_sro_donate(struct rmi_sro_state *sro,
+ unsigned long sro_handle,
+ unsigned long donatereq,
+ struct arm_smccc_1_2_regs *regs,
+ gfp_t gfp)
+{
+ unsigned long count = RMI_DONATE_COUNT(donatereq);
+
+ if (WARN_ON(!count))
+ return 0;
+
+ if (RMI_DONATE_CONTIG(donatereq)) {
+ return rmi_sro_donate_contig(sro, sro_handle, donatereq,
+ regs, gfp);
+ } else {
+ return rmi_sro_donate_noncontig(sro, sro_handle, donatereq,
+ regs, gfp);
+ }
+}
+
+static int rmi_sro_reclaim(struct rmi_sro_state *sro,
+ unsigned long sro_handle,
+ struct arm_smccc_1_2_regs *out_regs)
+{
+ struct arm_smccc_1_2_regs regs = {
+ SMC_RMI_OP_MEM_RECLAIM,
+ sro_handle,
+ virt_to_phys(&sro->addr_list[sro->addr_count]),
+ RMI_MAX_ADDR_LIST - sro->addr_count
+ };
+ rmi_smccc_invoke(®s, out_regs);
+ sro->addr_count += out_regs->a1;
+
+ return 0;
+}
+
+static void rmi_sro_free(struct rmi_sro_state *sro)
+{
+ for (int i = 0; i < sro->addr_count; i++) {
+ unsigned long entry = sro->addr_list[i];
+ unsigned long addr = RMI_ADDR_RANGE_ADDR(entry);
+ unsigned long unit_size = RMI_ADDR_RANGE_SIZE(entry);
+ unsigned long count = RMI_ADDR_RANGE_COUNT(entry);
+ unsigned long state = RMI_ADDR_RANGE_STATE(entry);
+ unsigned long size = donate_req_to_size(unit_size) * count;
+
+ if (state == RMI_OP_MEM_DELEGATED) {
+ if (WARN_ON(undelegate_range(addr, size))) {
+ /* Leak the pages */
+ continue;
+ }
+ }
+ __free_pages(phys_to_page(addr), get_order(size));
+ }
+
+ sro->addr_count = 0;
+}
+
+DEFINE_FREE(sro, struct rmi_sro_state *, if (_T) rmi_sro_free(_T))
+
+static unsigned long rmi_sro_execute(struct rmi_sro_state *sro)
+{
+ unsigned long sro_handle;
+ struct arm_smccc_1_2_regs regs;
+ struct arm_smccc_1_2_regs *regs_in = &sro->regs;
+
+ rmi_smccc_invoke(regs_in, ®s);
+
+ sro_handle = regs.a1;
+
+ while (RMI_RETURN_STATUS(regs.a0) == RMI_INCOMPLETE) {
+ bool can_cancel = RMI_RETURN_CANCANCEL(regs.a0);
+ int ret;
+
+ switch (RMI_RETURN_MEMREQ(regs.a0)) {
+ case RMI_OP_MEM_REQ_NONE:
+ regs = (struct arm_smccc_1_2_regs){
+ SMC_RMI_OP_CONTINUE, sro_handle, 0
+ };
+ rmi_smccc_invoke(®s, ®s);
+ break;
+ case RMI_OP_MEM_REQ_DONATE:
+ ret = rmi_sro_donate(sro, sro_handle, regs.a2, ®s,
+ GFP_KERNEL);
+ break;
+ case RMI_OP_MEM_REQ_RECLAIM:
+ ret = rmi_sro_reclaim(sro, sro_handle, ®s);
+ break;
+ default:
+ ret = WARN_ON(1);
+ break;
+ }
+
+ if (ret) {
+ if (can_cancel) {
+ /*
+ * FIXME: Handle cancelling properly!
+ *
+ * If the operation has failed due to memory
+ * allocation failure then the information on
+ * the memory allocation should be saved, so
+ * that the allocation can be repeated outside
+ * of any context which prevented the
+ * allocation.
+ */
+ }
+ if (WARN_ON(ret))
+ return ret;
+ }
+ }
+
+ return regs.a0;
+}
+
static inline unsigned long rmi_rtt_level_mapsize(int level)
{
if (WARN_ON(level > RMM_RTT_MAX_LEVEL))
@@ -795,12 +1084,6 @@ static int realm_create_rd(struct kvm *kvm)
goto out_undelegate_tables;
}
- if (WARN_ON(rmi_rec_aux_count(rd_phys, &realm->num_aux))) {
- WARN_ON(rmi_realm_destroy(rd_phys));
- r = -ENXIO;
- goto out_undelegate_tables;
- }
-
realm->rd = rd;
WRITE_ONCE(realm->state, REALM_STATE_NEW);
/* The realm is up, free the parameters. */
@@ -1432,65 +1715,9 @@ int noinstr kvm_rec_enter(struct kvm_vcpu *vcpu)
return ret;
}
-static void free_rec_aux(struct page **aux_pages,
- unsigned int num_aux)
-{
- unsigned int i;
- unsigned int page_count = 0;
-
- for (i = 0; i < num_aux; i++) {
- struct page *aux_page = aux_pages[page_count++];
- phys_addr_t aux_page_phys = page_to_phys(aux_page);
-
- if (!WARN_ON(undelegate_page(aux_page_phys)))
- __free_page(aux_page);
- aux_page_phys += PAGE_SIZE;
- }
-}
-
-static int alloc_rec_aux(struct page **aux_pages,
- u64 *aux_phys_pages,
- unsigned int num_aux)
-{
- struct page *aux_page;
- unsigned int i;
- int ret;
-
- for (i = 0; i < num_aux; i++) {
- phys_addr_t aux_page_phys;
-
- aux_page = alloc_page(GFP_KERNEL);
- if (!aux_page) {
- ret = -ENOMEM;
- goto out_err;
- }
-
- aux_page_phys = page_to_phys(aux_page);
- if (delegate_page(aux_page_phys)) {
- ret = -ENXIO;
- goto err_undelegate;
- }
- aux_phys_pages[i] = aux_page_phys;
- aux_pages[i] = aux_page;
- }
-
- return 0;
-err_undelegate:
- while (i > 0) {
- i--;
- if (WARN_ON(undelegate_page(aux_phys_pages[i]))) {
- /* Leak the page if the undelegate fails */
- goto out_err;
- }
- }
- __free_page(aux_page);
-out_err:
- free_rec_aux(aux_pages, i);
- return ret;
-}
-
static int kvm_create_rec(struct kvm_vcpu *vcpu)
{
+ struct rmi_sro_state *sro __free(sro) = NULL;
struct user_pt_regs *vcpu_regs = vcpu_gp_regs(vcpu);
unsigned long mpidr = kvm_vcpu_get_mpidr_aff(vcpu);
struct realm *realm = &vcpu->kvm->arch.realm;
@@ -1538,18 +1765,17 @@ static int kvm_create_rec(struct kvm_vcpu *vcpu)
goto out_free_pages;
}
- r = alloc_rec_aux(rec->aux_pages, params->aux, realm->num_aux);
- if (r)
- goto out_undelegate_rmm_rec;
-
- params->num_rec_aux = realm->num_aux;
params->mpidr = mpidr;
- if (rmi_rec_create(virt_to_phys(realm->rd),
- rec_page_phys,
- virt_to_phys(params))) {
+ sro = rmi_rec_create_sro_init(virt_to_phys(realm->rd),
+ rec_page_phys, virt_to_phys(params));
+ if (!sro) {
+ r = -ENOMEM;
+ goto out_undelegate_rmm_rec;
+ }
+ if (rmi_sro_execute(sro)) {
r = -ENXIO;
- goto out_free_rec_aux;
+ goto out_undelegate_rmm_rec;
}
rec->mpidr = mpidr;
@@ -1557,8 +1783,6 @@ static int kvm_create_rec(struct kvm_vcpu *vcpu)
free_page((unsigned long)params);
return 0;
-out_free_rec_aux:
- free_rec_aux(rec->aux_pages, realm->num_aux);
out_undelegate_rmm_rec:
if (WARN_ON(undelegate_page(rec_page_phys)))
rec->rec_page = NULL;
@@ -1572,7 +1796,7 @@ static int kvm_create_rec(struct kvm_vcpu *vcpu)
void kvm_destroy_rec(struct kvm_vcpu *vcpu)
{
- struct realm *realm = &vcpu->kvm->arch.realm;
+ struct rmi_sro_state *sro __free(sro) = NULL;
struct realm_rec *rec = &vcpu->arch.rec;
unsigned long rec_page_phys;
@@ -1588,15 +1812,12 @@ void kvm_destroy_rec(struct kvm_vcpu *vcpu)
rec_page_phys = virt_to_phys(rec->rec_page);
- /*
- * The REC and any AUX pages cannot be reclaimed until the REC is
- * destroyed. So if the REC destroy fails then the REC page and any AUX
- * pages will be leaked.
- */
- if (WARN_ON(rmi_rec_destroy(rec_page_phys)))
+ sro = rmi_rec_destroy_sro_init(rec_page_phys);
+ if (WARN_ON(!sro))
return;
- free_rec_aux(rec->aux_pages, realm->num_aux);
+ if (WARN_ON(rmi_sro_execute(sro)))
+ return;
free_delegated_page(rec_page_phys);
}
--
2.43.0
^ permalink raw reply related
* [PATCH v13 47/48] arm64: RMI: Enable realms to be created
From: Steven Price @ 2026-03-18 15:54 UTC (permalink / raw)
To: kvm, kvmarm
Cc: Steven Price, Catalin Marinas, Marc Zyngier, Will Deacon,
James Morse, Oliver Upton, Suzuki K Poulose, Zenghui Yu,
linux-arm-kernel, linux-kernel, Joey Gouly, Alexandru Elisei,
Christoffer Dall, Fuad Tabba, linux-coco, Ganapatrao Kulkarni,
Gavin Shan, Shanker Donthineni, Alper Gun, Aneesh Kumar K . V,
Emi Kisanuki, Vishal Annapurve
In-Reply-To: <20260318155413.793430-1-steven.price@arm.com>
All the pieces are now in place, so enable kvm_rmi_is_available when the
RMM is detected.
Signed-off-by: Steven Price <steven.price@arm.com>
---
arch/arm64/kvm/rmi.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/arch/arm64/kvm/rmi.c b/arch/arm64/kvm/rmi.c
index f69151d4235a..e76e58762f55 100644
--- a/arch/arm64/kvm/rmi.c
+++ b/arch/arm64/kvm/rmi.c
@@ -1723,5 +1723,5 @@ void kvm_init_rmi(void)
if (rmi_init_metadata())
return;
- /* Future patch will enable static branch kvm_rmi_is_available */
+ static_branch_enable(&kvm_rmi_is_available);
}
--
2.43.0
^ permalink raw reply related
* [PATCH v13 46/48] KVM: arm64: Expose KVM_ARM_VCPU_REC to user space
From: Steven Price @ 2026-03-18 15:54 UTC (permalink / raw)
To: kvm, kvmarm
Cc: Steven Price, Catalin Marinas, Marc Zyngier, Will Deacon,
James Morse, Oliver Upton, Suzuki K Poulose, Zenghui Yu,
linux-arm-kernel, linux-kernel, Joey Gouly, Alexandru Elisei,
Christoffer Dall, Fuad Tabba, linux-coco, Ganapatrao Kulkarni,
Gavin Shan, Shanker Donthineni, Alper Gun, Aneesh Kumar K . V,
Emi Kisanuki, Vishal Annapurve
In-Reply-To: <20260318155413.793430-1-steven.price@arm.com>
Increment KVM_VCPU_MAX_FEATURES to expose the new capability to user
space.
Signed-off-by: Steven Price <steven.price@arm.com>
Reviewed-by: Gavin Shan <gshan@redhat.com>
---
Changes since v8:
* Since NV is now merged and enabled, this no longer conflicts with it.
---
arch/arm64/include/asm/kvm_host.h | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/arch/arm64/include/asm/kvm_host.h b/arch/arm64/include/asm/kvm_host.h
index 1d5fb001408c..b02f97de4436 100644
--- a/arch/arm64/include/asm/kvm_host.h
+++ b/arch/arm64/include/asm/kvm_host.h
@@ -40,7 +40,7 @@
#define KVM_MAX_VCPUS VGIC_V3_MAX_CPUS
-#define KVM_VCPU_MAX_FEATURES 9
+#define KVM_VCPU_MAX_FEATURES 10
#define KVM_VCPU_VALID_FEATURES (BIT(KVM_VCPU_MAX_FEATURES) - 1)
#define KVM_REQ_SLEEP \
--
2.43.0
^ permalink raw reply related
* [PATCH v13 45/48] arm64: RMI: Provide accurate register list
From: Steven Price @ 2026-03-18 15:54 UTC (permalink / raw)
To: kvm, kvmarm
Cc: Jean-Philippe Brucker, Catalin Marinas, Marc Zyngier, Will Deacon,
James Morse, Oliver Upton, Suzuki K Poulose, Zenghui Yu,
linux-arm-kernel, linux-kernel, Joey Gouly, Alexandru Elisei,
Christoffer Dall, Fuad Tabba, linux-coco, Ganapatrao Kulkarni,
Gavin Shan, Shanker Donthineni, Alper Gun, Aneesh Kumar K . V,
Emi Kisanuki, Vishal Annapurve, Steven Price
In-Reply-To: <20260318155413.793430-1-steven.price@arm.com>
From: Jean-Philippe Brucker <jean-philippe@linaro.org>
Userspace can set a few registers with KVM_SET_ONE_REG (9 GP registers
at runtime, and 3 system registers during initialization). Update the
register list returned by KVM_GET_REG_LIST.
Signed-off-by: Jean-Philippe Brucker <jean-philippe@linaro.org>
Signed-off-by: Steven Price <steven.price@arm.com>
---
Changes since v11:
* Reworked due to upstream changes.
Changes since v8:
* Minor type changes following review.
Changes since v7:
* Reworked on upstream changes.
---
arch/arm64/kvm/guest.c | 6 ++++++
arch/arm64/kvm/hypercalls.c | 4 ++--
arch/arm64/kvm/sys_regs.c | 29 +++++++++++++++++++++++------
3 files changed, 31 insertions(+), 8 deletions(-)
diff --git a/arch/arm64/kvm/guest.c b/arch/arm64/kvm/guest.c
index 2c4db2d1a6ca..23fdb2ee8a61 100644
--- a/arch/arm64/kvm/guest.c
+++ b/arch/arm64/kvm/guest.c
@@ -620,6 +620,9 @@ static unsigned long num_sve_regs(const struct kvm_vcpu *vcpu)
if (!kvm_arm_vcpu_sve_finalized(vcpu))
return 1; /* KVM_REG_ARM64_SVE_VLS */
+ if (kvm_is_realm(vcpu->kvm))
+ return 1; /* KVM_REG_ARM64_SVE_VLS */
+
return slices * (SVE_NUM_PREGS + SVE_NUM_ZREGS + 1 /* FFR */)
+ 1; /* KVM_REG_ARM64_SVE_VLS */
}
@@ -647,6 +650,9 @@ static int copy_sve_reg_indices(const struct kvm_vcpu *vcpu,
if (!kvm_arm_vcpu_sve_finalized(vcpu))
return num_regs;
+ if (kvm_is_realm(vcpu->kvm))
+ return num_regs;
+
for (i = 0; i < slices; i++) {
for (n = 0; n < SVE_NUM_ZREGS; n++) {
reg = KVM_REG_ARM64_SVE_ZREG(n, i);
diff --git a/arch/arm64/kvm/hypercalls.c b/arch/arm64/kvm/hypercalls.c
index 58c5fe7d7572..70ac7971416c 100644
--- a/arch/arm64/kvm/hypercalls.c
+++ b/arch/arm64/kvm/hypercalls.c
@@ -414,14 +414,14 @@ void kvm_arm_teardown_hypercalls(struct kvm *kvm)
int kvm_arm_get_fw_num_regs(struct kvm_vcpu *vcpu)
{
- return ARRAY_SIZE(kvm_arm_fw_reg_ids);
+ return kvm_is_realm(vcpu->kvm) ? 0 : ARRAY_SIZE(kvm_arm_fw_reg_ids);
}
int kvm_arm_copy_fw_reg_indices(struct kvm_vcpu *vcpu, u64 __user *uindices)
{
int i;
- for (i = 0; i < ARRAY_SIZE(kvm_arm_fw_reg_ids); i++) {
+ for (i = 0; i < kvm_arm_get_fw_num_regs(vcpu); i++) {
if (put_user(kvm_arm_fw_reg_ids[i], uindices++))
return -EFAULT;
}
diff --git a/arch/arm64/kvm/sys_regs.c b/arch/arm64/kvm/sys_regs.c
index ebb428b861f5..088d900b9c3a 100644
--- a/arch/arm64/kvm/sys_regs.c
+++ b/arch/arm64/kvm/sys_regs.c
@@ -5436,18 +5436,18 @@ int kvm_arm_sys_reg_set_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg
sys_reg_descs, ARRAY_SIZE(sys_reg_descs));
}
-static unsigned int num_demux_regs(void)
+static inline unsigned int num_demux_regs(struct kvm_vcpu *vcpu)
{
- return CSSELR_MAX;
+ return kvm_is_realm(vcpu->kvm) ? 0 : CSSELR_MAX;
}
-static int write_demux_regids(u64 __user *uindices)
+static int write_demux_regids(struct kvm_vcpu *vcpu, u64 __user *uindices)
{
u64 val = KVM_REG_ARM64 | KVM_REG_SIZE_U32 | KVM_REG_ARM_DEMUX;
unsigned int i;
val |= KVM_REG_ARM_DEMUX_ID_CCSIDR;
- for (i = 0; i < CSSELR_MAX; i++) {
+ for (i = 0; i < num_demux_regs(vcpu); i++) {
if (put_user(val | i, uindices))
return -EFAULT;
uindices++;
@@ -5491,11 +5491,28 @@ static bool copy_reg_to_user(const struct sys_reg_desc *reg, u64 __user **uind)
return true;
}
+static inline bool kvm_realm_sys_reg_hidden_user(const struct kvm_vcpu *vcpu,
+ u64 reg)
+{
+ if (!kvm_is_realm(vcpu->kvm))
+ return false;
+
+ switch (reg) {
+ case SYS_ID_AA64DFR0_EL1:
+ case SYS_PMCR_EL0:
+ return false;
+ }
+ return true;
+}
+
static int walk_one_sys_reg(const struct kvm_vcpu *vcpu,
const struct sys_reg_desc *rd,
u64 __user **uind,
unsigned int *total)
{
+ if (kvm_realm_sys_reg_hidden_user(vcpu, reg_to_encoding(rd)))
+ return 0;
+
/*
* Ignore registers we trap but don't save,
* and for which no custom user accessor is provided.
@@ -5533,7 +5550,7 @@ static int walk_sys_regs(struct kvm_vcpu *vcpu, u64 __user *uind)
unsigned long kvm_arm_num_sys_reg_descs(struct kvm_vcpu *vcpu)
{
- return num_demux_regs()
+ return num_demux_regs(vcpu)
+ walk_sys_regs(vcpu, (u64 __user *)NULL);
}
@@ -5546,7 +5563,7 @@ int kvm_arm_copy_sys_reg_indices(struct kvm_vcpu *vcpu, u64 __user *uindices)
return err;
uindices += err;
- return write_demux_regids(uindices);
+ return write_demux_regids(vcpu, uindices);
}
#define KVM_ARM_FEATURE_ID_RANGE_INDEX(r) \
--
2.43.0
^ permalink raw reply related
* [PATCH v13 44/48] arm64: RMI: Provide register list for unfinalized RMI RECs
From: Steven Price @ 2026-03-18 15:54 UTC (permalink / raw)
To: kvm, kvmarm
Cc: Jean-Philippe Brucker, Catalin Marinas, Marc Zyngier, Will Deacon,
James Morse, Oliver Upton, Suzuki K Poulose, Zenghui Yu,
linux-arm-kernel, linux-kernel, Joey Gouly, Alexandru Elisei,
Christoffer Dall, Fuad Tabba, linux-coco, Ganapatrao Kulkarni,
Gavin Shan, Shanker Donthineni, Alper Gun, Aneesh Kumar K . V,
Emi Kisanuki, Vishal Annapurve, Steven Price
In-Reply-To: <20260318155413.793430-1-steven.price@arm.com>
From: Jean-Philippe Brucker <jean-philippe@linaro.org>
KVM_GET_REG_LIST should not be called before SVE is finalized. The ioctl
handler currently returns -EPERM in this case. But because it uses
kvm_arm_vcpu_is_finalized(), it now also rejects the call for
unfinalized REC even though finalizing the REC can only be done late,
after Realm descriptor creation.
Move the check to copy_sve_reg_indices(). One adverse side effect of
this change is that a KVM_GET_REG_LIST call that only probes for the
array size will now succeed even if SVE is not finalized, but that seems
harmless since the following KVM_GET_REG_LIST with the full array will
fail.
Signed-off-by: Jean-Philippe Brucker <jean-philippe@linaro.org>
Signed-off-by: Steven Price <steven.price@arm.com>
Reviewed-by: Gavin Shan <gshan@redhat.com>
---
arch/arm64/kvm/arm.c | 4 ----
arch/arm64/kvm/guest.c | 10 +++++-----
2 files changed, 5 insertions(+), 9 deletions(-)
diff --git a/arch/arm64/kvm/arm.c b/arch/arm64/kvm/arm.c
index cd2cb5e54f21..11a816fe981c 100644
--- a/arch/arm64/kvm/arm.c
+++ b/arch/arm64/kvm/arm.c
@@ -1923,10 +1923,6 @@ long kvm_arch_vcpu_ioctl(struct file *filp,
if (unlikely(!kvm_vcpu_initialized(vcpu)))
break;
- r = -EPERM;
- if (!kvm_arm_vcpu_is_finalized(vcpu))
- break;
-
r = -EFAULT;
if (copy_from_user(®_list, user_list, sizeof(reg_list)))
break;
diff --git a/arch/arm64/kvm/guest.c b/arch/arm64/kvm/guest.c
index 999edf0b5219..2c4db2d1a6ca 100644
--- a/arch/arm64/kvm/guest.c
+++ b/arch/arm64/kvm/guest.c
@@ -617,8 +617,8 @@ static unsigned long num_sve_regs(const struct kvm_vcpu *vcpu)
if (!vcpu_has_sve(vcpu))
return 0;
- /* Policed by KVM_GET_REG_LIST: */
- WARN_ON(!kvm_arm_vcpu_sve_finalized(vcpu));
+ if (!kvm_arm_vcpu_sve_finalized(vcpu))
+ return 1; /* KVM_REG_ARM64_SVE_VLS */
return slices * (SVE_NUM_PREGS + SVE_NUM_ZREGS + 1 /* FFR */)
+ 1; /* KVM_REG_ARM64_SVE_VLS */
@@ -635,9 +635,6 @@ static int copy_sve_reg_indices(const struct kvm_vcpu *vcpu,
if (!vcpu_has_sve(vcpu))
return 0;
- /* Policed by KVM_GET_REG_LIST: */
- WARN_ON(!kvm_arm_vcpu_sve_finalized(vcpu));
-
/*
* Enumerate this first, so that userspace can save/restore in
* the order reported by KVM_GET_REG_LIST:
@@ -647,6 +644,9 @@ static int copy_sve_reg_indices(const struct kvm_vcpu *vcpu,
return -EFAULT;
++num_regs;
+ if (!kvm_arm_vcpu_sve_finalized(vcpu))
+ return num_regs;
+
for (i = 0; i < slices; i++) {
for (n = 0; n < SVE_NUM_ZREGS; n++) {
reg = KVM_REG_ARM64_SVE_ZREG(n, i);
--
2.43.0
^ permalink raw reply related
* [PATCH v13 43/48] arm64: RMI: Configure max SVE vector length for a Realm
From: Steven Price @ 2026-03-18 15:54 UTC (permalink / raw)
To: kvm, kvmarm
Cc: Jean-Philippe Brucker, Catalin Marinas, Marc Zyngier, Will Deacon,
James Morse, Oliver Upton, Suzuki K Poulose, Zenghui Yu,
linux-arm-kernel, linux-kernel, Joey Gouly, Alexandru Elisei,
Christoffer Dall, Fuad Tabba, linux-coco, Ganapatrao Kulkarni,
Gavin Shan, Shanker Donthineni, Alper Gun, Aneesh Kumar K . V,
Emi Kisanuki, Vishal Annapurve, Steven Price
In-Reply-To: <20260318155413.793430-1-steven.price@arm.com>
From: Jean-Philippe Brucker <jean-philippe@linaro.org>
Obtain the max vector length configured by userspace on the vCPUs, and
write it into the Realm parameters. By default the vCPU is configured
with the max vector length reported by RMM, and userspace can reduce it
with a write to KVM_REG_ARM64_SVE_VLS.
Signed-off-by: Jean-Philippe Brucker <jean-philippe@linaro.org>
Signed-off-by: Steven Price <steven.price@arm.com>
---
Changes since v6:
* Rename max_vl/realm_max_vl to vl/last_vl - there is nothing "maximum"
about them, we're just checking that all realms have the same vector
length
---
arch/arm64/kvm/guest.c | 3 ++-
arch/arm64/kvm/rmi.c | 37 +++++++++++++++++++++++++++++++++++++
2 files changed, 39 insertions(+), 1 deletion(-)
diff --git a/arch/arm64/kvm/guest.c b/arch/arm64/kvm/guest.c
index 705c2ccc335d..999edf0b5219 100644
--- a/arch/arm64/kvm/guest.c
+++ b/arch/arm64/kvm/guest.c
@@ -361,7 +361,7 @@ static int set_sve_vls(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
if (!vcpu_has_sve(vcpu))
return -ENOENT;
- if (kvm_arm_vcpu_sve_finalized(vcpu))
+ if (kvm_arm_vcpu_sve_finalized(vcpu) || kvm_realm_is_created(vcpu->kvm))
return -EPERM; /* too late! */
if (WARN_ON(vcpu->arch.sve_state))
@@ -756,6 +756,7 @@ static bool validate_realm_set_reg(struct kvm_vcpu *vcpu,
switch (reg->id) {
case KVM_REG_ARM_PMCR_EL0:
case KVM_REG_ARM_ID_AA64DFR0_EL1:
+ case KVM_REG_ARM64_SVE_VLS:
return true;
}
}
diff --git a/arch/arm64/kvm/rmi.c b/arch/arm64/kvm/rmi.c
index f2aeda7f5e6e..f69151d4235a 100644
--- a/arch/arm64/kvm/rmi.c
+++ b/arch/arm64/kvm/rmi.c
@@ -706,6 +706,39 @@ static void realm_unmap_shared_range(struct kvm *kvm,
start, end);
}
+static int realm_init_sve_param(struct kvm *kvm, struct realm_params *params)
+{
+ unsigned long i;
+ struct kvm_vcpu *vcpu;
+ int vl, last_vl = -1;
+
+ if (!kvm_has_sve(kvm))
+ return 0;
+
+ /*
+ * Get the preferred SVE configuration, set by userspace with the
+ * KVM_ARM_VCPU_SVE feature and KVM_REG_ARM64_SVE_VLS pseudo-register.
+ */
+ kvm_for_each_vcpu(i, vcpu, kvm) {
+ if (!kvm_arm_vcpu_sve_finalized(vcpu))
+ return -EINVAL;
+
+ vl = vcpu->arch.sve_max_vl;
+
+ /* We need all vCPUs to have the same SVE config */
+ if (last_vl >= 0 && last_vl != vl)
+ return -EINVAL;
+
+ last_vl = vl;
+ }
+
+ if (last_vl > 0) {
+ params->sve_vl = sve_vq_from_vl(last_vl) - 1;
+ params->flags |= RMI_REALM_PARAM_FLAG_SVE;
+ }
+ return 0;
+}
+
static int realm_create_rd(struct kvm *kvm)
{
struct realm *realm = &kvm->arch.realm;
@@ -751,6 +784,10 @@ static int realm_create_rd(struct kvm *kvm)
if (kvm_lpa2_is_enabled())
params->flags |= RMI_REALM_PARAM_FLAG_LPA2;
+ r = realm_init_sve_param(kvm, params);
+ if (r)
+ goto out_undelegate_tables;
+
params_phys = virt_to_phys(params);
if (rmi_realm_create(rd_phys, params_phys)) {
--
2.43.0
^ permalink raw reply related
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox