Arm CCA guests can run with a PAGE_SIZE that is smaller than the granule size used by the host to track Realm IPA state. In that configuration, changing a guest PAGE_SIZE range between protected and shared state can cover only part of the host-owned state-change unit.
The Realm Host Interface specification (Arm DEN0148) [1] defines the Host Configuration interface for querying host capabilities, including the IPA state change alignment.
Add the RHI HostConf definitions and a get_ipa_state_change_alignment() helper. The helper uses RSI_HOST_CALL to query the supported HostConf version and features, and reads the IPA state change alignment when available. It falls back to PAGE_SIZE if the interface is unavailable or returns an invalid value.
[1] https://support.arm.com/documentation/den0148/latest/
Signed-off-by: Aneesh Kumar K.V (Arm) aneesh.kumar@kernel.org --- MAINTAINERS | 1 + drivers/firmware/arm_rmm/rsi.c | 47 ++++++++++++++++++++++++++++++++++ include/linux/arm-rsi-cmds.h | 10 ++++++++ include/linux/arm-smccc-rhi.h | 25 ++++++++++++++++++ include/linux/arm-smccc-rsi.h | 7 +++++ 5 files changed, 90 insertions(+) create mode 100644 include/linux/arm-smccc-rhi.h
diff --git a/MAINTAINERS b/MAINTAINERS index 1e543163a8cc..87ec876868eb 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -3956,6 +3956,7 @@ F: drivers/firmware/arm_rmm/ F: drivers/virt/coco/arm-cca-guest/ F: drivers/virt/coco/pkvm-guest/ F: include/linux/arm-rsi-cmds.h +F: include/linux/arm-smccc-rhi.h F: include/linux/arm-smccc-rsi.h F: tools/testing/selftests/arm64/ X: arch/arm64/boot/dts/ diff --git a/drivers/firmware/arm_rmm/rsi.c b/drivers/firmware/arm_rmm/rsi.c index 0fcc4e33bd92..883f6091ff95 100644 --- a/drivers/firmware/arm_rmm/rsi.c +++ b/drivers/firmware/arm_rmm/rsi.c @@ -8,7 +8,9 @@ #include <linux/psci.h> #include <linux/swiotlb.h> #include <linux/arm-rsi-cmds.h> +#include <linux/arm-smccc-rhi.h> #include <linux/kobject.h> +#include <linux/string.h> #include <linux/sysfs.h>
#include <asm/io.h> @@ -162,6 +164,51 @@ static int realm_register_memory_enc_ops(void) return arm64_mem_crypt_ops_register(&realm_crypt_ops); }
+/* we need an aligned struct for rsi_host_call. slab is not yet ready */ +static struct rsi_host_call hostconf_call __initdata; +static unsigned long __maybe_unused __init get_ipa_state_change_alignment(void) +{ + long ret; + unsigned long shared_granule_size; + + memset(&hostconf_call, 0, sizeof(hostconf_call)); + hostconf_call.gprs[0] = RHI_HOSTCONF_VERSION; + ret = rsi_host_call(lm_alias(&hostconf_call)); + if (ret != RSI_SUCCESS) + goto err_out; + + if (hostconf_call.gprs[0] != RHI_HOSTCONF_VER_1_0) + goto err_out; + + memset(&hostconf_call, 0, sizeof(hostconf_call)); + hostconf_call.gprs[0] = RHI_HOSTCONF_FEATURES; + ret = rsi_host_call(lm_alias(&hostconf_call)); + if (ret != RSI_SUCCESS) + goto err_out; + + if (!(hostconf_call.gprs[0] & RHI_HOSTCONF_FEATURE_GET_IPA_CHANGE_ALIGNMENT)) + goto err_out; + + memset(&hostconf_call, 0, sizeof(hostconf_call)); + hostconf_call.gprs[0] = RHI_HOSTCONF_GET_IPA_CHANGE_ALIGNMENT; + ret = rsi_host_call(lm_alias(&hostconf_call)); + if (ret != RSI_SUCCESS) + goto err_out; + + shared_granule_size = hostconf_call.gprs[0]; + if (shared_granule_size & (SZ_4K - 1) || + !is_power_of_2(shared_granule_size)) + goto err_out; + + return max(PAGE_SIZE, shared_granule_size); +err_out: + /* + * For failure condition assume host is built with 4K page size + * and hence IPA state change alignment can be guest PAGE_SIZE. + */ + return PAGE_SIZE; +} + void __init arm64_rsi_init(void) { if (arm_smccc_1_1_get_conduit() != SMCCC_CONDUIT_SMC) diff --git a/include/linux/arm-rsi-cmds.h b/include/linux/arm-rsi-cmds.h index 3f7a6a833993..996f1621b996 100644 --- a/include/linux/arm-rsi-cmds.h +++ b/include/linux/arm-rsi-cmds.h @@ -236,4 +236,14 @@ static inline unsigned long rsi_attestation_token_continue(phys_addr_t granule, return res.a0; }
+static inline unsigned long rsi_host_call(struct rsi_host_call *rhi_call) +{ + phys_addr_t addr = virt_to_phys(rhi_call); + struct arm_smccc_res res; + + arm_smccc_1_1_invoke(SMC_RSI_HOST_CALL, addr, &res); + + return res.a0; +} + #endif /* __LINUX_ARM_RSI_CMDS_H_ */ diff --git a/include/linux/arm-smccc-rhi.h b/include/linux/arm-smccc-rhi.h new file mode 100644 index 000000000000..be89185cddae --- /dev/null +++ b/include/linux/arm-smccc-rhi.h @@ -0,0 +1,25 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (C) 2026 ARM Ltd. + */ + +#ifndef __LINUX_ARM_SMCCC_RHI_H_ +#define __LINUX_ARM_SMCCC_RHI_H_ + +#include <linux/arm-smccc.h> + +#define SMC_RHI_CALL(func) \ + ARM_SMCCC_CALL_VAL(ARM_SMCCC_FAST_CALL, \ + ARM_SMCCC_SMC_64, \ + ARM_SMCCC_OWNER_STANDARD_HYP,\ + (func)) + +#define RHI_HOSTCONF_VER_1_0 0x10000 +#define RHI_HOSTCONF_VERSION SMC_RHI_CALL(0x004E) + +#define RHI_HOSTCONF_FEATURE_GET_IPA_CHANGE_ALIGNMENT BIT(0) +#define RHI_HOSTCONF_FEATURES SMC_RHI_CALL(0x004F) + +#define RHI_HOSTCONF_GET_IPA_CHANGE_ALIGNMENT SMC_RHI_CALL(0x0050) + +#endif /* __LINUX_ARM_SMCCC_RHI_H_ */ diff --git a/include/linux/arm-smccc-rsi.h b/include/linux/arm-smccc-rsi.h index fddb77986f70..3532a3f08f4e 100644 --- a/include/linux/arm-smccc-rsi.h +++ b/include/linux/arm-smccc-rsi.h @@ -182,6 +182,13 @@ struct realm_config { */ #define SMC_RSI_IPA_STATE_GET SMC_RSI_FID(0x198)
+struct rsi_host_call { + union { + u16 imm; + u64 padding0; + }; + u64 gprs[31]; +} __aligned(0x100); /* * Make a Host call. *