git: 76a2904c352b - main - arm64: Add RSI detection for CCA
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