git: 76a2904c352b - main - arm64: Add RSI detection for CCA

From: Andrew Turner <andrew_at_FreeBSD.org>
Date: Tue, 12 May 2026 16:55:30 UTC
The branch main has been updated by andrew:

URL: https://cgit.FreeBSD.org/src/commit/?id=76a2904c352b497b32fc902523e3e485f7b06ffd

commit 76a2904c352b497b32fc902523e3e485f7b06ffd
Author:     Sarah Walker <sarah.walker2@arm.com>
AuthorDate: 2026-05-12 11:27:13 +0000
Commit:     Andrew Turner <andrew@FreeBSD.org>
CommitDate: 2026-05-12 16:54:40 +0000

    arm64: Add RSI detection for CCA
    
    Detect the presence of the Realm Services Interface (RSI). This detection is
    performed early in bootup; PSCI initialisation has been moved to initarm() to
    faciliate this.
    
    Reviewed by:    andrew
    Sponsored by:   Arm Ltd
    Differential Revision:  https://reviews.freebsd.org/D56598
---
 sys/arm64/arm64/machdep.c |   5 ++
 sys/arm64/arm64/pmap.c    |   2 +
 sys/arm64/arm64/rsi.c     | 185 ++++++++++++++++++++++++++++++++++++++++++++++
 sys/arm64/include/pmap.h  |   3 +
 sys/arm64/include/rsi.h   | 129 ++++++++++++++++++++++++++++++++
 sys/conf/files.arm64      |   1 +
 sys/dev/psci/psci.c       |  11 ++-
 sys/dev/psci/psci.h       |   3 +
 8 files changed, 338 insertions(+), 1 deletion(-)

diff --git a/sys/arm64/arm64/machdep.c b/sys/arm64/arm64/machdep.c
index adfb509d4924..d219c737c215 100644
--- a/sys/arm64/arm64/machdep.c
+++ b/sys/arm64/arm64/machdep.c
@@ -86,6 +86,7 @@
 #include <machine/metadata.h>
 #include <machine/md_var.h>
 #include <machine/pcb.h>
+#include <machine/rsi.h>
 #include <machine/undefined.h>
 #include <machine/vmparam.h>
 
@@ -103,6 +104,7 @@
 #include <dev/ofw/openfirm.h>
 #endif
 
+#include <dev/psci/psci.h>
 #include <dev/smbios/smbios.h>
 
 _Static_assert(sizeof(struct pcb) == 1248, "struct pcb is incorrect size");
@@ -889,6 +891,9 @@ initarm(struct arm64_bootparams *abp)
 
 	valid = bus_probe();
 
+	psci_init(NULL);
+	arm64_rsi_setup_memory();
+
 	cninit();
 	set_ttbr0(abp->kern_ttbr0);
 	pmap_s1_invalidate_all_kernel();
diff --git a/sys/arm64/arm64/pmap.c b/sys/arm64/arm64/pmap.c
index 595fba2da411..2d2982fdfae7 100644
--- a/sys/arm64/arm64/pmap.c
+++ b/sys/arm64/arm64/pmap.c
@@ -205,6 +205,8 @@ __exclusive_cache_line static struct pmap_large_md_page pv_dummy_large;
 #define pv_dummy pv_dummy_large.pv_page
 __read_mostly static struct pmap_large_md_page *pv_table;
 
+__read_mostly uint64_t prot_ns_shared_pa;
+
 static struct pmap_large_md_page *
 _pa_to_pmdp(vm_paddr_t pa)
 {
diff --git a/sys/arm64/arm64/rsi.c b/sys/arm64/arm64/rsi.c
new file mode 100644
index 000000000000..85c7896e13ce
--- /dev/null
+++ b/sys/arm64/arm64/rsi.c
@@ -0,0 +1,185 @@
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2026 Arm Ltd
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include "opt_platform.h"
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/physmem.h>
+#include <sys/rwlock.h>
+
+#include <vm/vm_page.h>
+
+#include <machine/rsi.h>
+#include <machine/vmparam.h>
+
+#include <dev/psci/psci.h>
+#include <dev/psci/smccc.h>
+
+static struct realm_config config;
+static bool rsi_present = false;
+
+#define	PHYSMAP_SIZE (2 * (VM_PHYSSEG_MAX - 1))
+
+static vm_paddr_t physmap[PHYSMAP_SIZE];
+
+static unsigned long
+rsi_request_version(unsigned long req, unsigned long *out_lower,
+    unsigned long *out_higher)
+{
+	struct arm_smccc_res res;
+
+	arm_smccc_invoke_smc(SMC_RSI_ABI_VERSION, req, &res);
+
+	if (out_lower != NULL)
+		*out_lower = res.a1;
+	if (out_higher != NULL)
+		*out_higher = res.a2;
+
+	return (res.a0);
+}
+
+static inline unsigned long
+rsi_get_realm_config(struct realm_config *cfg)
+{
+	struct arm_smccc_res res;
+
+	arm_smccc_invoke_smc(SMC_RSI_REALM_CONFIG, vtophys(cfg), &res);
+	return (res.a0);
+}
+
+static bool
+rsi_version_matches(void)
+{
+	unsigned long ver_lower, ver_higher;
+	unsigned long ret;
+
+	ret = rsi_request_version(RSI_ABI_VERSION, &ver_lower, &ver_higher);
+
+	if (ret == SMCCC_RET_NOT_SUPPORTED)
+		return (false);
+
+	if (ret != RSI_SUCCESS) {
+		printf("RME: RMM doesn't support RSI version %lu.%lu. Supported range: %lu.%lu-%lu.%lu\n",
+		    RSI_ABI_VERSION_MAJOR, RSI_ABI_VERSION_MINOR,
+		    RSI_ABI_VERSION_GET_MAJOR(ver_lower),
+		    RSI_ABI_VERSION_GET_MINOR(ver_lower),
+		    RSI_ABI_VERSION_GET_MAJOR(ver_higher),
+		    RSI_ABI_VERSION_GET_MINOR(ver_higher));
+		return (false);
+	}
+
+	printf("RME: Using RSI version %lu.%lu\n",
+	    RSI_ABI_VERSION_GET_MAJOR(ver_lower),
+	    RSI_ABI_VERSION_GET_MINOR(ver_lower));
+
+	return (true);
+}
+
+
+unsigned long
+rsi_set_addr_range_state(vm_paddr_t start, vm_paddr_t end, enum ripas state,
+    unsigned long flags, vm_paddr_t *top)
+{
+	struct arm_smccc_res res;
+
+	arm_smccc_smc(SMC_RSI_IPA_STATE_SET, start, end, state, flags, 0, 0, 0,
+	    &res);
+
+	if (top)
+		*top = res.a1;
+
+	return (res.a0);
+}
+
+static int
+rsi_set_memory_range(vm_paddr_t start, vm_paddr_t end, enum ripas state,
+    unsigned long flags)
+{
+	unsigned long ret;
+	vm_paddr_t top;
+
+	while (start != end) {
+		ret = rsi_set_addr_range_state(start, end, state, flags, &top);
+		if (ret || top < start || top > end)
+			return (-EINVAL);
+		start = top;
+	}
+
+	return (0);
+}
+
+/*
+ * Convert the specified range to RAM. Do not convert any pages that may have
+ * been DESTROYED, without our permission.
+ */
+static int
+rsi_set_memory_range_protected_safe(vm_paddr_t start, vm_paddr_t end)
+{
+	return (rsi_set_memory_range(start, end, RSI_RIPAS_RAM,
+	    RSI_NO_CHANGE_DESTROYED));
+}
+
+void
+arm64_rsi_setup_memory(void)
+{
+	int physmap_idx;
+	int i;
+
+	if (!psci_conduit_is_smc())
+		return;
+	if (!rsi_version_matches())
+		return;
+	if (rsi_get_realm_config(&config))
+		return;
+
+	prot_ns_shared_pa = 1ul << (config.ipa_bits - 1);
+	if (bootverbose)
+		printf("arm64_rsi_setup_memory: rsi_present, ipa_bits=%lu prot_ns_shared_pa=%lx\n",
+		    config.ipa_bits, prot_ns_shared_pa);
+	rsi_present = true;
+
+	physmap_idx = physmem_all(physmap, nitems(physmap));
+
+	if (bootverbose)
+		printf("physmap:\n");
+
+	for (i = 0; i < physmap_idx; i += 2) {
+		if (bootverbose)
+			printf("  %lx %lx\n", physmap[i], physmap[i + 1]);
+
+		if (rsi_set_memory_range_protected_safe(physmap[i],
+		    physmap[i + 1]))
+			panic("rsi_set_memory_range_protected_safe failed");
+	}
+}
+
+bool
+in_realm(void)
+{
+	return (rsi_present);
+}
diff --git a/sys/arm64/include/pmap.h b/sys/arm64/include/pmap.h
index 2ee70fc754da..00b54a874e12 100644
--- a/sys/arm64/include/pmap.h
+++ b/sys/arm64/include/pmap.h
@@ -43,6 +43,7 @@
 #ifndef LOCORE
 
 #include <sys/queue.h>
+#include <sys/systm.h>
 #include <sys/_lock.h>
 #include <sys/_mutex.h>
 #include <sys/_pv_entry.h>
@@ -132,6 +133,8 @@ extern vm_offset_t virtual_end;
 
 extern pt_entry_t pmap_sh_attr;
 
+extern __read_mostly uint64_t prot_ns_shared_pa;
+
 /*
  * Macros to test if a mapping is mappable with an L1 Section mapping
  * or an L2 Large Page mapping.
diff --git a/sys/arm64/include/rsi.h b/sys/arm64/include/rsi.h
new file mode 100644
index 000000000000..82e54f9c57e3
--- /dev/null
+++ b/sys/arm64/include/rsi.h
@@ -0,0 +1,129 @@
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2026 Arm Ltd
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef _MACHINE_RSI_H_
+#define	_MACHINE_RSI_H_
+
+extern uint64_t prot_ns_shared;
+
+bool in_realm(void);
+
+void arm64_rsi_setup_memory(void);
+
+/*
+ * The major version number of the RSI implementation.  This is increased when
+ * the binary format or semantics of the SMC calls change.
+ */
+#define RSI_ABI_VERSION_MAJOR	UL(1)
+
+/*
+ * The minor version number of the RSI implementation.  This is increased when
+ * a bug is fixed, or a feature is added without breaking binary compatibility.
+ */
+#define RSI_ABI_VERSION_MINOR	UL(0)
+
+#define RSI_ABI_VERSION		((RSI_ABI_VERSION_MAJOR << 16) | \
+				    RSI_ABI_VERSION_MINOR)
+
+#define RSI_ABI_VERSION_GET_MAJOR(_version)	((_version) >> 16)
+#define RSI_ABI_VERSION_GET_MINOR(_version)	((_version) & 0xFFFF)
+
+#define RSI_SUCCESS		UL(0)
+#define RSI_ERROR_INPUT		UL(1)
+#define RSI_ERROR_STATE		UL(2)
+#define RSI_INCOMPLETE		UL(3)
+#define RSI_ERROR_UNKNOWN	UL(4)
+
+#define SMC_RSI_FID(n)		SMCCC_FUNC_ID(SMCCC_FAST_CALL,          \
+				    SMCCC_64BIT_CALL,                   \
+				    SMCCC_STD_SECURE_SERVICE_CALLS,     \
+				    n)
+
+/*
+ * Returns RSI version.
+ *
+ * arg1 == Requested interface revision
+ * ret0 == Status / error
+ * ret1 == Lower implemented interface revision
+ * ret2 == Higher implemented interface revision
+ */
+#define SMC_RSI_ABI_VERSION	SMC_RSI_FID(0x190)
+
+/*
+ * Read configuration for the current Realm.
+ *
+ * arg1 == struct realm_config addr
+ * ret0 == Status / error
+ */
+#define SMC_RSI_REALM_CONFIG	SMC_RSI_FID(0x196)
+
+struct realm_config {
+	union {
+		struct {
+			unsigned long ipa_bits; /* Width of IPA in bits */
+			unsigned long hash_algo; /* Hash algorithm */
+		};
+		uint8_t pad[0x200];
+	};
+	union {
+		uint8_t rpv[64]; /* Realm Personalization Value */
+		uint8_t pad2[0xe00];
+	};
+	/*
+	 * The RMM requires the configuration structure to be aligned to a 4k
+	 * boundary, ensure this happens by aligning this structure.
+	 */
+} __aligned(0x1000);
+
+/*
+ * Request RIPAS of a target IPA range to be changed to a specified value.
+ *
+ * arg1 == Base IPA address of target region
+ * arg2 == Top of the region
+ * arg3 == RIPAS value
+ * arg4 == flags
+ * ret0 == Status / error
+ * ret1 == Top of modified IPA range
+ * ret2 == Whether the Host accepted or rejected the request
+ */
+#define SMC_RSI_IPA_STATE_SET	SMC_RSI_FID(0x197)
+
+#define RSI_NO_CHANGE_DESTROYED	UL(0)
+#define RSI_CHANGE_DESTROYED	UL(1)
+
+#define RSI_ACCEPT		UL(0)
+#define RSI_REJECT		UL(1)
+
+enum ripas {
+	RSI_RIPAS_EMPTY = 0,
+	RSI_RIPAS_RAM
+};
+
+unsigned long rsi_set_addr_range_state(vm_paddr_t start, vm_paddr_t end,
+    enum ripas state, unsigned long flags, vm_paddr_t *top);
+
+#endif	/* !_MACHINE_RSI_H_ */
diff --git a/sys/conf/files.arm64 b/sys/conf/files.arm64
index 44f292d9048f..8f550a644db6 100644
--- a/sys/conf/files.arm64
+++ b/sys/conf/files.arm64
@@ -77,6 +77,7 @@ arm64/arm64/ptrauth.c				standard \
 	compile-with	"${NORMAL_C:N-mbranch-protection*} -mbranch-protection=bti"
 arm64/arm64/pmap.c				standard
 arm64/arm64/ptrace_machdep.c			standard
+arm64/arm64/rsi.c				standard
 arm64/arm64/sdt_machdep.c			optional kdtrace_hooks
 arm64/arm64/sigtramp.S				standard
 arm64/arm64/spec_workaround.c			standard
diff --git a/sys/dev/psci/psci.c b/sys/dev/psci/psci.c
index 2b250401ae83..872fae056a4b 100644
--- a/sys/dev/psci/psci.c
+++ b/sys/dev/psci/psci.c
@@ -133,7 +133,7 @@ static int psci_def_callfn(register_t, register_t, register_t, register_t,
 
 psci_callfn_t psci_callfn = psci_def_callfn;
 
-static void
+void
 psci_init(void *dummy)
 {
 	psci_callfn_t new_callfn;
@@ -146,8 +146,11 @@ psci_init(void *dummy)
 	psci_callfn = new_callfn;
 	psci_present = true;
 }
+
+#ifdef __arm__
 /* This needs to be before cpu_mp at SI_SUB_CPU, SI_ORDER_THIRD */
 SYSINIT(psci_start, SI_SUB_CPU, SI_ORDER_FIRST, psci_init, NULL);
+#endif
 
 static int
 psci_def_callfn(register_t a __unused, register_t b __unused,
@@ -631,3 +634,9 @@ psci_v0_2_init(device_t dev, int default_version)
 	device_printf(dev, "PSCI version number mismatched with DT\n");
 	return (1);
 }
+
+bool
+psci_conduit_is_smc(void)
+{
+	return (psci_callfn == arm_smccc_smc);
+}
diff --git a/sys/dev/psci/psci.h b/sys/dev/psci/psci.h
index 6704eaf26c71..c250bf45d344 100644
--- a/sys/dev/psci/psci.h
+++ b/sys/dev/psci/psci.h
@@ -44,6 +44,9 @@ void	psci_reset(void);
 int32_t	psci_features(uint32_t);
 int	psci_get_version(void);
 
+void	psci_init(void *dummy);
+bool	psci_conduit_is_smc(void);
+
 /* Handler to let us call into the PSCI/SMCCC firmware */
 extern psci_callfn_t psci_callfn;
 static inline int