* [PATCH v6 0/6] arm64: hyperv: Add Realm support for Hyper-V
@ 2026-10-31 0:14 Kameron Carr
2026-10-31 0:14 ` [PATCH v6 1/6] arm64: rsi: Add RSI host call structure and helper function Kameron Carr
` (5 more replies)
0 siblings, 6 replies; 9+ messages in thread
From: Kameron Carr @ 2026-10-31 0:14 UTC (permalink / raw)
To: decui, haiyangz, mhklinux, wei.liu
Cc: arnd, catalin.marinas, linux-arch, linux-arm-kernel, linux-hyperv,
linux-kernel, lpieralisi, mark.rutland, sudeep.holla, thuth, will
Realms (CoCo VMs on ARM) require host calls to be routed through the RMM
(Realm Management Monitor) via the RSI (Realm Service Interface). This
series implements most of the necessary changes to support Realms on
Hyper-V.
One required change is not included in this series. The two buffers
allocated via vzalloc() in netvsc_init_buf() cannot be decrypted in
vmbus_establish_gpadl(). Currently only linearly mapped memory can be
decrypted.
This patch series was tested by booting a Realm on Cobalt 200 running
Windows. I tested 4KB and 64KB page size. I replaced vzalloc() in
netvsc_init_buf() with alloc_pages_node() -> set_memory_decrypted() ->
vmap() in my testing as a workaround for the issue mentioned above [1].
Changes since v1 [2]:
Patch 1: Add explicit padding to the RSI host call structure
Patch 3: Change from a per-cpu pointer lazily allocated to an array
of host call structs indexed by cpu id
Patch 4: Align input_page + output_page allocation to PAGE_SIZE since
that is the smallest unit of memory that can be decrypted
~Remove KASAN tags before passing address to
set_memory_decrypted() since __is_lm_address() does pointer
arithmetic.~ (reverted in v3)
Patch 5: Add a helper function to reduce repetition
Check for NULL before indexing into host call array
Changes since v2 [3]:
Patch 3: Remove hv_hostcall_free() and inline the logic for simplicity
Reorder edits to keep #include line at the end of the file
Patch 4: Remove kasan_reset_tag()
Changes since v3 [4]:
Rebased onto arm64 for-next/smccc-bus which includes moving RSI header
files out of arch/arm64 [5]
Changes since v4 [6]:
Patch 1, 2, 4: Fix commit message to reflect the new header file names
Patch 5: Remove extra blank line
Changes since v5 [7]:
Patch 2: Move Realm hypervisor detection out of the generic
arm_smccc_hypervisor_has_uuid() into hyperv_detect_via_smccc()
so other SMCCC users are unaffected
Patch 3: Drop the <linux/arm-rsi-cmds.h> include, now added in patch 2
[1] https://lore.kernel.org/all/20260721195633.1438361-1-kameroncarr@linux.microsoft.com/
[2] https://lore.kernel.org/all/20260609181030.2378391-1-kameroncarr@linux.microsoft.com/
[3] https://lore.kernel.org/all/20260625173500.1995481-1-kameroncarr@linux.microsoft.com/
[4] https://lore.kernel.org/all/20260721201148.1441143-1-kameroncarr@linux.microsoft.com/
[5] https://lore.kernel.org/all/20260923140405.1111554-4-aneesh.kumar@kernel.org/
[6] https://lore.kernel.org/all/20261001220552.1793471-1-kameroncarr@linux.microsoft.com/
[7] https://lore.kernel.org/all/20261002215725.2015959-1-kameroncarr@linux.microsoft.com/
Kameron Carr (6):
arm64: rsi: Add RSI host call structure and helper function
arm64: hyperv: Detect Hyper-V via RSI host call in CCA Realms
arm64: hyperv: Add per-CPU RSI host call infrastructure for CCA Realms
Drivers: hv: Mark shared memory as decrypted for CCA Realms
arm64: hyperv: Route hypercalls through RSI host call in CCA Realms
arm64: hyperv: Implement hv_is_isolation_supported() for CCA Realms
arch/arm64/hyperv/hv_core.c | 155 +++++++++++++++++++++++-------
arch/arm64/hyperv/mshyperv.c | 62 +++++++++++-
arch/arm64/include/asm/mshyperv.h | 4 +
drivers/hv/hv_common.c | 17 +++-
include/asm-generic/mshyperv.h | 1 +
include/linux/arm-rsi-cmds.h | 22 +++++
include/linux/arm-smccc-rsi.h | 7 ++
7 files changed, 228 insertions(+), 40 deletions(-)
base-commit: bce57945f5e7207960b2bd567a6e880f90258ffb
--
2.45.4
^ permalink raw reply [flat|nested] 9+ messages in thread
* [PATCH v6 1/6] arm64: rsi: Add RSI host call structure and helper function
2026-10-31 0:14 [PATCH v6 0/6] arm64: hyperv: Add Realm support for Hyper-V Kameron Carr
@ 2026-10-31 0:14 ` Kameron Carr
2026-10-31 4:51 ` Dexuan Cui
2026-10-31 0:14 ` [PATCH v6 2/6] arm64: hyperv: Detect Hyper-V via RSI host call in CCA Realms Kameron Carr
` (4 subsequent siblings)
5 siblings, 1 reply; 9+ messages in thread
From: Kameron Carr @ 2026-10-31 0:14 UTC (permalink / raw)
To: decui, haiyangz, mhklinux, wei.liu
Cc: arnd, catalin.marinas, linux-arch, linux-arm-kernel, linux-hyperv,
linux-kernel, lpieralisi, mark.rutland, sudeep.holla, thuth, will
Add struct rsi_host_call to arm-smccc-rsi.h, which represents the host
call data structure used by the Realm Management Monitor (RMM) for the
RSI_HOST_CALL interface. The structure contains a 16-bit immediate field
and 31 general-purpose register values, aligned to 256 bytes as required
by the CCA RMM specification.
Add rsi_host_call() static inline wrapper in arm-rsi-cmds.h that invokes
SMC_RSI_HOST_CALL with the physical address of the host call structure.
This will be used by Hyper-V guest code to route hypercalls through the
RSI interface when running inside an Arm CCA Realm.
Reviewed-by: Michael Kelley <mhklinux@outlook.com>
Signed-off-by: Kameron Carr <kameroncarr@linux.microsoft.com>
---
include/linux/arm-rsi-cmds.h | 22 ++++++++++++++++++++++
include/linux/arm-smccc-rsi.h | 7 +++++++
2 files changed, 29 insertions(+)
diff --git a/include/linux/arm-rsi-cmds.h b/include/linux/arm-rsi-cmds.h
index 3f7a6a8..01d292e 100644
--- a/include/linux/arm-rsi-cmds.h
+++ b/include/linux/arm-rsi-cmds.h
@@ -236,4 +236,26 @@ static inline unsigned long rsi_attestation_token_continue(phys_addr_t granule,
return res.a0;
}
+/**
+ * rsi_host_call - Make a Host call.
+ * @host_call_struct: IPA of host call structure
+ *
+ * This call will fail if the IPA of the host call structure:
+ * * is not aligned to 256 bytes,
+ * * is not protected / encrypted,
+ * * is RIPAS_EMPTY
+ *
+ * Returns:
+ * On success, returns RSI_SUCCESS.
+ * Otherwise, returns an error code.
+ */
+static inline unsigned long rsi_host_call(phys_addr_t host_call_struct)
+{
+ struct arm_smccc_res res;
+
+ arm_smccc_smc(SMC_RSI_HOST_CALL, host_call_struct, 0, 0, 0, 0, 0, 0,
+ &res);
+ return res.a0;
+}
+
#endif /* __LINUX_ARM_RSI_CMDS_H_ */
diff --git a/include/linux/arm-smccc-rsi.h b/include/linux/arm-smccc-rsi.h
index fddb779..4c8530b 100644
--- a/include/linux/arm-smccc-rsi.h
+++ b/include/linux/arm-smccc-rsi.h
@@ -142,6 +142,13 @@ struct realm_config {
*/
} __aligned(0x1000);
+struct rsi_host_call {
+ u16 immediate;
+ u8 _padding[6];
+ u64 gprs[31];
+} __aligned(256);
+static_assert(sizeof(struct rsi_host_call) == 256);
+
#endif /* __ASSEMBLER__ */
/*
--
2.45.4
^ permalink raw reply related [flat|nested] 9+ messages in thread
* [PATCH v6 2/6] arm64: hyperv: Detect Hyper-V via RSI host call in CCA Realms
2026-10-31 0:14 [PATCH v6 0/6] arm64: hyperv: Add Realm support for Hyper-V Kameron Carr
2026-10-31 0:14 ` [PATCH v6 1/6] arm64: rsi: Add RSI host call structure and helper function Kameron Carr
@ 2026-10-31 0:14 ` Kameron Carr
2026-10-31 0:14 ` [PATCH v6 3/6] arm64: hyperv: Add per-CPU RSI host call infrastructure for " Kameron Carr
` (3 subsequent siblings)
5 siblings, 0 replies; 9+ messages in thread
From: Kameron Carr @ 2026-10-31 0:14 UTC (permalink / raw)
To: decui, haiyangz, mhklinux, wei.liu
Cc: arnd, catalin.marinas, linux-arch, linux-arm-kernel, linux-hyperv,
linux-kernel, lpieralisi, mark.rutland, sudeep.holla, thuth, will
When booting without ACPI, hyperv_detect_via_smccc() detects Hyper-V by
querying the SMCCC vendor hypervisor UID. In an Arm CCA Realm the SMCCC
call is handled by the RMM rather than by the hypervisor, so the
query never reaches Hyper-V and detection fails.
When running in a Realm, forward ARM_SMCCC_VENDOR_HYP_CALL_UID_FUNC_ID
to the host with RSI_HOST_CALL instead, which is how Hyper-V hypercalls
are issued from a Realm.
This is done in the Hyper-V code rather than in the generic
arm_smccc_hypervisor_has_uuid() because the other users expect different
behavior.
hyperv_init() is an early_initcall and runs before the secondary CPUs
are brought up, so a single __initdata host call structure is used
without locking.
ACPI-based detection and non-Realm guests are unaffected.
Signed-off-by: Kameron Carr <kameroncarr@linux.microsoft.com>
---
arch/arm64/hyperv/mshyperv.c | 25 +++++++++++++++++++++++++
1 file changed, 25 insertions(+)
diff --git a/arch/arm64/hyperv/mshyperv.c b/arch/arm64/hyperv/mshyperv.c
index 4fdc26a..82572c5 100644
--- a/arch/arm64/hyperv/mshyperv.c
+++ b/arch/arm64/hyperv/mshyperv.c
@@ -11,6 +11,7 @@
#include <linux/types.h>
#include <linux/acpi.h>
+#include <linux/arm-rsi-cmds.h>
#include <linux/export.h>
#include <linux/errno.h>
#include <linux/version.h>
@@ -60,6 +61,27 @@ static bool __init hyperv_detect_via_acpi(void)
#endif
+/*
+ * In a Realm, the SMCCC call is handled by the RMM rather than by
+ * Hyper-V, so the vendor hypervisor UID query must be forwarded to the
+ * host with RSI_HOST_CALL, in the same way as hypercalls.
+ */
+static bool __init hyperv_realm_has_uuid(const uuid_t *hyperv_uuid)
+{
+ static struct rsi_host_call hc __initdata;
+ uuid_t uuid;
+
+ hc.gprs[0] = ARM_SMCCC_VENDOR_HYP_CALL_UID_FUNC_ID;
+
+ if (rsi_host_call(__pa_symbol(&hc)) != RSI_SUCCESS ||
+ hc.gprs[0] == SMCCC_RET_NOT_SUPPORTED)
+ return false;
+
+ uuid = smccc_res_to_uuid(hc.gprs[0], hc.gprs[1], hc.gprs[2],
+ hc.gprs[3]);
+ return uuid_equal(&uuid, hyperv_uuid);
+}
+
static bool __init hyperv_detect_via_smccc(void)
{
uuid_t hyperv_uuid = UUID_INIT(
@@ -67,6 +89,9 @@ static bool __init hyperv_detect_via_smccc(void)
0x75, 0x6c, 0xef, 0x8e,
0x24, 0x70, 0x59, 0x16);
+ if (is_realm_world())
+ return hyperv_realm_has_uuid(&hyperv_uuid);
+
return arm_smccc_hypervisor_has_uuid(&hyperv_uuid);
}
--
2.45.4
^ permalink raw reply related [flat|nested] 9+ messages in thread
* [PATCH v6 3/6] arm64: hyperv: Add per-CPU RSI host call infrastructure for CCA Realms
2026-10-31 0:14 [PATCH v6 0/6] arm64: hyperv: Add Realm support for Hyper-V Kameron Carr
2026-10-31 0:14 ` [PATCH v6 1/6] arm64: rsi: Add RSI host call structure and helper function Kameron Carr
2026-10-31 0:14 ` [PATCH v6 2/6] arm64: hyperv: Detect Hyper-V via RSI host call in CCA Realms Kameron Carr
@ 2026-10-31 0:14 ` Kameron Carr
2026-10-31 0:14 ` [PATCH v6 4/6] Drivers: hv: Mark shared memory as decrypted " Kameron Carr
` (2 subsequent siblings)
5 siblings, 0 replies; 9+ messages in thread
From: Kameron Carr @ 2026-10-31 0:14 UTC (permalink / raw)
To: decui, haiyangz, mhklinux, wei.liu
Cc: arnd, catalin.marinas, linux-arch, linux-arm-kernel, linux-hyperv,
linux-kernel, lpieralisi, mark.rutland, sudeep.holla, thuth, will
Arm CCA Realms cannot issue Hyper-V hypercalls via HVC; the guest must
route them through the RSI_HOST_CALL interface, which takes the IPA of a
per-CPU rsi_host_call structure as its argument.
Add hv_hostcall_array as a per-CPU struct array and allocate it during
hyperv_init(). The allocation is gated on is_realm_world() so non-Realm
arm64 Hyper-V guests pay no memory cost.
Reviewed-by: Michael Kelley <mhklinux@outlook.com>
Signed-off-by: Kameron Carr <kameroncarr@linux.microsoft.com>
---
arch/arm64/hyperv/mshyperv.c | 27 +++++++++++++++++++++++++--
arch/arm64/include/asm/mshyperv.h | 4 ++++
2 files changed, 29 insertions(+), 2 deletions(-)
diff --git a/arch/arm64/hyperv/mshyperv.c b/arch/arm64/hyperv/mshyperv.c
index 82572c5..46ab2da 100644
--- a/arch/arm64/hyperv/mshyperv.c
+++ b/arch/arm64/hyperv/mshyperv.c
@@ -14,12 +14,16 @@
#include <linux/arm-rsi-cmds.h>
#include <linux/export.h>
#include <linux/errno.h>
+#include <linux/slab.h>
#include <linux/version.h>
#include <linux/cpuhotplug.h>
#include <asm/mshyperv.h>
static bool hyperv_initialized;
+struct rsi_host_call *hv_hostcall_array;
+EXPORT_SYMBOL_GPL(hv_hostcall_array);
+
int hv_get_hypervisor_version(union hv_hypervisor_version_info *info)
{
hv_get_vpreg_128(HV_REGISTER_HYPERVISOR_VERSION,
@@ -110,6 +114,20 @@ static int __init hyperv_init(void)
if (!hyperv_detect_via_acpi() && !hyperv_detect_via_smccc())
return 0;
+ /*
+ * The RSI host-call buffers are only ever used when
+ * is_realm_world() is true. Skip the allocation on non-Realm
+ * guests. A single contiguous array of nr_cpu_ids entries is
+ * allocated; each CPU indexes into it by its processor ID.
+ */
+ if (is_realm_world()) {
+ hv_hostcall_array = kcalloc(nr_cpu_ids,
+ sizeof(struct rsi_host_call),
+ GFP_KERNEL);
+ if (!hv_hostcall_array)
+ return -ENOMEM;
+ }
+
/* Setup the guest ID */
guest_id = hv_generate_guest_id(LINUX_VERSION_CODE);
hv_set_vpreg(HV_REGISTER_GUEST_OS_ID, guest_id);
@@ -131,13 +149,13 @@ static int __init hyperv_init(void)
ret = hv_common_init();
if (ret)
- return ret;
+ goto free_hostcall_mem;
ret = cpuhp_setup_state(CPUHP_AP_HYPERV_ONLINE, "arm64/hyperv_init:online",
hv_common_cpu_init, hv_common_cpu_die);
if (ret < 0) {
hv_common_free();
- return ret;
+ goto free_hostcall_mem;
}
if (ms_hyperv.priv_high & HV_ACCESS_PARTITION_ID)
@@ -150,6 +168,11 @@ static int __init hyperv_init(void)
hyperv_initialized = true;
return 0;
+
+free_hostcall_mem:
+ kfree(hv_hostcall_array);
+ hv_hostcall_array = NULL;
+ return ret;
}
early_initcall(hyperv_init);
diff --git a/arch/arm64/include/asm/mshyperv.h b/arch/arm64/include/asm/mshyperv.h
index b721d31..aed0aa5 100644
--- a/arch/arm64/include/asm/mshyperv.h
+++ b/arch/arm64/include/asm/mshyperv.h
@@ -61,6 +61,10 @@ static inline u64 hv_get_non_nested_msr(unsigned int reg)
ARM_SMCCC_OWNER_VENDOR_HYP, \
HV_SMCCC_FUNC_NUMBER)
+/* Per-CPU-indexed RSI host call structures for CCA Realms */
+struct rsi_host_call;
+extern struct rsi_host_call *hv_hostcall_array;
+
#include <asm-generic/mshyperv.h>
#endif
--
2.45.4
^ permalink raw reply related [flat|nested] 9+ messages in thread
* [PATCH v6 4/6] Drivers: hv: Mark shared memory as decrypted for CCA Realms
2026-10-31 0:14 [PATCH v6 0/6] arm64: hyperv: Add Realm support for Hyper-V Kameron Carr
` (2 preceding siblings ...)
2026-10-31 0:14 ` [PATCH v6 3/6] arm64: hyperv: Add per-CPU RSI host call infrastructure for " Kameron Carr
@ 2026-10-31 0:14 ` Kameron Carr
2026-10-31 0:27 ` sashiko-bot
2026-10-31 0:14 ` [PATCH v6 5/6] arm64: hyperv: Route hypercalls through RSI host call in " Kameron Carr
2026-10-31 0:14 ` [PATCH v6 6/6] arm64: hyperv: Implement hv_is_isolation_supported() for " Kameron Carr
5 siblings, 1 reply; 9+ messages in thread
From: Kameron Carr @ 2026-10-31 0:14 UTC (permalink / raw)
To: decui, haiyangz, mhklinux, wei.liu
Cc: arnd, catalin.marinas, linux-arch, linux-arm-kernel, linux-hyperv,
linux-kernel, lpieralisi, mark.rutland, sudeep.holla, thuth, will
In hv_common_cpu_init(), the per-CPU hypercall input/output pages need
to be marked as decrypted (shared) for confidential VM isolation types.
This is already done for SNP and TDX isolation; extend the same handling
to Arm CCA Realm guests so that the host hypervisor can access the
shared hypercall buffers.
is_realm_world() is declared in include/linux/arm-rsi-cmds.h which only
builds on arm64 (it includes <asm/memory.h>), so using it directly in
the arch-neutral drivers/hv/hv_common.c would break the x86 build.
Introduce a Hyper-V-specific helper following the established
hv_isolation_type_snp() / hv_isolation_type_tdx() pattern.
On architectures other than arm64 the weak default keeps the existing
behaviour.
Reviewed-by: Michael Kelley <mhklinux@outlook.com>
Signed-off-by: Kameron Carr <kameroncarr@linux.microsoft.com>
---
arch/arm64/hyperv/mshyperv.c | 5 +++++
drivers/hv/hv_common.c | 17 +++++++++++++----
include/asm-generic/mshyperv.h | 1 +
3 files changed, 19 insertions(+), 4 deletions(-)
diff --git a/arch/arm64/hyperv/mshyperv.c b/arch/arm64/hyperv/mshyperv.c
index 46ab2da..da6c3aa0 100644
--- a/arch/arm64/hyperv/mshyperv.c
+++ b/arch/arm64/hyperv/mshyperv.c
@@ -182,3 +182,8 @@ bool hv_is_hyperv_initialized(void)
return hyperv_initialized;
}
EXPORT_SYMBOL_GPL(hv_is_hyperv_initialized);
+
+bool hv_isolation_type_cca(void)
+{
+ return is_realm_world();
+}
diff --git a/drivers/hv/hv_common.c b/drivers/hv/hv_common.c
index 31256cb..a60c92c 100644
--- a/drivers/hv/hv_common.c
+++ b/drivers/hv/hv_common.c
@@ -476,6 +476,7 @@ int hv_common_cpu_init(unsigned int cpu)
u64 msr_vp_index;
gfp_t flags;
const int pgcount = hv_output_page_exists() ? 2 : 1;
+ const size_t alloc_size = ALIGN((size_t)pgcount * HV_HYP_PAGE_SIZE, PAGE_SIZE);
void *mem;
int ret = 0;
@@ -489,7 +490,7 @@ int hv_common_cpu_init(unsigned int cpu)
* online and then taken offline
*/
if (!*inputarg) {
- mem = kmalloc_array(pgcount, HV_HYP_PAGE_SIZE, flags);
+ mem = kmalloc(alloc_size, flags);
if (!mem)
return -ENOMEM;
@@ -499,14 +500,16 @@ int hv_common_cpu_init(unsigned int cpu)
}
if (!ms_hyperv.paravisor_present &&
- (hv_isolation_type_snp() || hv_isolation_type_tdx())) {
- ret = set_memory_decrypted((unsigned long)mem, pgcount);
+ (hv_isolation_type_snp() || hv_isolation_type_tdx() ||
+ hv_isolation_type_cca())) {
+ ret = set_memory_decrypted((unsigned long)mem,
+ alloc_size >> PAGE_SHIFT);
if (ret) {
/* It may be unsafe to free 'mem' */
return ret;
}
- memset(mem, 0x00, pgcount * HV_HYP_PAGE_SIZE);
+ memset(mem, 0x00, alloc_size);
}
/*
@@ -666,6 +669,12 @@ bool __weak hv_isolation_type_tdx(void)
}
EXPORT_SYMBOL_GPL(hv_isolation_type_tdx);
+bool __weak hv_isolation_type_cca(void)
+{
+ return false;
+}
+EXPORT_SYMBOL_GPL(hv_isolation_type_cca);
+
void __weak hv_setup_vmbus_handler(void (*handler)(void))
{
}
diff --git a/include/asm-generic/mshyperv.h b/include/asm-generic/mshyperv.h
index bf601d6..1fa79ab 100644
--- a/include/asm-generic/mshyperv.h
+++ b/include/asm-generic/mshyperv.h
@@ -79,6 +79,7 @@ u64 hv_do_fast_hypercall16(u16 control, u64 input1, u64 input2);
bool hv_isolation_type_snp(void);
bool hv_isolation_type_tdx(void);
+bool hv_isolation_type_cca(void);
/*
* On architectures where Hyper-V doesn't support AEOI (e.g., ARM64),
--
2.45.4
^ permalink raw reply related [flat|nested] 9+ messages in thread
* [PATCH v6 5/6] arm64: hyperv: Route hypercalls through RSI host call in CCA Realms
2026-10-31 0:14 [PATCH v6 0/6] arm64: hyperv: Add Realm support for Hyper-V Kameron Carr
` (3 preceding siblings ...)
2026-10-31 0:14 ` [PATCH v6 4/6] Drivers: hv: Mark shared memory as decrypted " Kameron Carr
@ 2026-10-31 0:14 ` Kameron Carr
2026-10-31 0:14 ` [PATCH v6 6/6] arm64: hyperv: Implement hv_is_isolation_supported() for " Kameron Carr
5 siblings, 0 replies; 9+ messages in thread
From: Kameron Carr @ 2026-10-31 0:14 UTC (permalink / raw)
To: decui, haiyangz, mhklinux, wei.liu
Cc: arnd, catalin.marinas, linux-arch, linux-arm-kernel, linux-hyperv,
linux-kernel, lpieralisi, mark.rutland, sudeep.holla, thuth, will
Modify the five hypercall wrapper functions to check is_realm_world()
and use the per-CPU rsi_host_call structure when inside a Realm.
Reviewed-by: Michael Kelley <mhklinux@outlook.com>
Signed-off-by: Kameron Carr <kameroncarr@linux.microsoft.com>
---
arch/arm64/hyperv/hv_core.c | 155 ++++++++++++++++++++++++++++--------
1 file changed, 121 insertions(+), 34 deletions(-)
diff --git a/arch/arm64/hyperv/hv_core.c b/arch/arm64/hyperv/hv_core.c
index e33a9e3..2f6fc14 100644
--- a/arch/arm64/hyperv/hv_core.c
+++ b/arch/arm64/hyperv/hv_core.c
@@ -12,11 +12,43 @@
#include <linux/export.h>
#include <linux/mm.h>
#include <linux/arm-smccc.h>
+#include <linux/arm-rsi-cmds.h>
#include <linux/module.h>
+#include <linux/smp.h>
#include <asm-generic/bug.h>
#include <hyperv/hvhdk.h>
#include <asm/mshyperv.h>
+/*
+ * hv_do_rsi_hypercall - Helper function to invoke a hypercall from a
+ * Realm world using the RSI interface.
+ */
+static u64 hv_do_rsi_hypercall(u64 control, u64 input1, u64 input2)
+{
+ struct rsi_host_call *hostcall;
+ unsigned long flags;
+ u64 ret;
+
+ if (!hv_hostcall_array)
+ return HV_STATUS_INVALID_HYPERCALL_INPUT;
+
+ local_irq_save(flags);
+ hostcall = &hv_hostcall_array[smp_processor_id()];
+ memset(hostcall, 0, sizeof(*hostcall));
+ hostcall->gprs[0] = HV_FUNC_ID;
+ hostcall->gprs[1] = control;
+ hostcall->gprs[2] = input1;
+ hostcall->gprs[3] = input2;
+
+ if (rsi_host_call(virt_to_phys(hostcall)) == RSI_SUCCESS)
+ ret = hostcall->gprs[0];
+ else
+ ret = HV_STATUS_INVALID_HYPERCALL_INPUT;
+
+ local_irq_restore(flags);
+ return ret;
+}
+
/*
* hv_do_hypercall- Invoke the specified hypercall
*/
@@ -29,8 +61,11 @@ u64 hv_do_hypercall(u64 control, void *input, void *output)
input_address = input ? virt_to_phys(input) : 0;
output_address = output ? virt_to_phys(output) : 0;
- arm_smccc_1_1_hvc(HV_FUNC_ID, control,
- input_address, output_address, &res);
+ if (is_realm_world())
+ return hv_do_rsi_hypercall(control, input_address, output_address);
+
+ arm_smccc_1_1_hvc(HV_FUNC_ID, control, input_address,
+ output_address, &res);
return res.a0;
}
EXPORT_SYMBOL_GPL(hv_do_hypercall);
@@ -48,6 +83,9 @@ u64 hv_do_fast_hypercall8(u16 code, u64 input)
control = (u64)code | HV_HYPERCALL_FAST_BIT;
+ if (is_realm_world())
+ return hv_do_rsi_hypercall(control, input, 0);
+
arm_smccc_1_1_hvc(HV_FUNC_ID, control, input, &res);
return res.a0;
}
@@ -65,6 +103,9 @@ u64 hv_do_fast_hypercall16(u16 code, u64 input1, u64 input2)
control = (u64)code | HV_HYPERCALL_FAST_BIT;
+ if (is_realm_world())
+ return hv_do_rsi_hypercall(control, input1, input2);
+
arm_smccc_1_1_hvc(HV_FUNC_ID, control, input1, input2, &res);
return res.a0;
}
@@ -76,24 +117,44 @@ EXPORT_SYMBOL_GPL(hv_do_fast_hypercall16);
void hv_set_vpreg(u32 msr, u64 value)
{
struct arm_smccc_res res;
+ struct rsi_host_call *hostcall;
+ unsigned long flags;
+ u64 status;
- arm_smccc_1_1_hvc(HV_FUNC_ID,
- HVCALL_SET_VP_REGISTERS | HV_HYPERCALL_FAST_BIT |
- HV_HYPERCALL_REP_COMP_1,
- HV_PARTITION_ID_SELF,
- HV_VP_INDEX_SELF,
- msr,
- 0,
- value,
- 0,
- &res);
+ if (is_realm_world()) {
+ local_irq_save(flags);
+ hostcall = &hv_hostcall_array[smp_processor_id()];
+ memset(hostcall, 0, sizeof(*hostcall));
+ hostcall->gprs[0] = HV_FUNC_ID;
+ hostcall->gprs[1] = HVCALL_SET_VP_REGISTERS |
+ HV_HYPERCALL_FAST_BIT |
+ HV_HYPERCALL_REP_COMP_1;
+ hostcall->gprs[2] = HV_PARTITION_ID_SELF;
+ hostcall->gprs[3] = HV_VP_INDEX_SELF;
+ hostcall->gprs[4] = msr;
+ hostcall->gprs[6] = value;
+
+ if (rsi_host_call(virt_to_phys(hostcall)) == RSI_SUCCESS)
+ status = hostcall->gprs[0];
+ else
+ status = HV_STATUS_INVALID_HYPERCALL_INPUT;
+ local_irq_restore(flags);
+ } else {
+ arm_smccc_1_1_hvc(HV_FUNC_ID,
+ HVCALL_SET_VP_REGISTERS |
+ HV_HYPERCALL_FAST_BIT |
+ HV_HYPERCALL_REP_COMP_1,
+ HV_PARTITION_ID_SELF, HV_VP_INDEX_SELF, msr,
+ 0, value, 0, &res);
+ status = res.a0;
+ }
/*
- * Something is fundamentally broken in the hypervisor if
- * setting a VP register fails. There's really no way to
- * continue as a guest VM, so panic.
+ * Something is fundamentally broken in the hypervisor (or, in a
+ * Realm, the RMM denied the host call) if setting a VP register
+ * fails. There's really no way to continue as a guest VM, so panic.
*/
- BUG_ON(!hv_result_success(res.a0));
+ BUG_ON(!hv_result_success(status));
}
EXPORT_SYMBOL_GPL(hv_set_vpreg);
@@ -108,29 +169,55 @@ void hv_get_vpreg_128(u32 msr, struct hv_get_vp_registers_output *result)
{
struct arm_smccc_1_2_regs args;
struct arm_smccc_1_2_regs res;
+ struct rsi_host_call *hostcall;
+ unsigned long flags;
+ u64 status;
- args.a0 = HV_FUNC_ID;
- args.a1 = HVCALL_GET_VP_REGISTERS | HV_HYPERCALL_FAST_BIT |
- HV_HYPERCALL_REP_COMP_1;
- args.a2 = HV_PARTITION_ID_SELF;
- args.a3 = HV_VP_INDEX_SELF;
- args.a4 = msr;
+ if (is_realm_world()) {
+ local_irq_save(flags);
+ hostcall = &hv_hostcall_array[smp_processor_id()];
+ memset(hostcall, 0, sizeof(*hostcall));
- /*
- * Use the SMCCC 1.2 interface because the results are in registers
- * beyond X0-X3.
- */
- arm_smccc_1_2_hvc(&args, &res);
+ hostcall->gprs[0] = HV_FUNC_ID;
+ hostcall->gprs[1] = HVCALL_GET_VP_REGISTERS |
+ HV_HYPERCALL_FAST_BIT |
+ HV_HYPERCALL_REP_COMP_1;
+ hostcall->gprs[2] = HV_PARTITION_ID_SELF;
+ hostcall->gprs[3] = HV_VP_INDEX_SELF;
+ hostcall->gprs[4] = msr;
+
+ if (rsi_host_call(virt_to_phys(hostcall)) == RSI_SUCCESS) {
+ status = hostcall->gprs[0];
+ result->as64.low = hostcall->gprs[6];
+ result->as64.high = hostcall->gprs[7];
+ } else {
+ status = HV_STATUS_INVALID_HYPERCALL_INPUT;
+ }
+ local_irq_restore(flags);
+ } else {
+ args.a0 = HV_FUNC_ID;
+ args.a1 = HVCALL_GET_VP_REGISTERS | HV_HYPERCALL_FAST_BIT |
+ HV_HYPERCALL_REP_COMP_1;
+ args.a2 = HV_PARTITION_ID_SELF;
+ args.a3 = HV_VP_INDEX_SELF;
+ args.a4 = msr;
+
+ /*
+ * Use the SMCCC 1.2 interface because the results are in
+ * registers beyond X0-X3.
+ */
+ arm_smccc_1_2_hvc(&args, &res);
+ status = res.a0;
+ result->as64.low = res.a6;
+ result->as64.high = res.a7;
+ }
/*
- * Something is fundamentally broken in the hypervisor if
- * getting a VP register fails. There's really no way to
- * continue as a guest VM, so panic.
+ * Something is fundamentally broken in the hypervisor (or, in a
+ * Realm, the RMM denied the host call) if getting a VP register
+ * fails. There's really no way to continue as a guest VM, so panic.
*/
- BUG_ON(!hv_result_success(res.a0));
-
- result->as64.low = res.a6;
- result->as64.high = res.a7;
+ BUG_ON(!hv_result_success(status));
}
EXPORT_SYMBOL_GPL(hv_get_vpreg_128);
--
2.45.4
^ permalink raw reply related [flat|nested] 9+ messages in thread
* [PATCH v6 6/6] arm64: hyperv: Implement hv_is_isolation_supported() for CCA Realms
2026-10-31 0:14 [PATCH v6 0/6] arm64: hyperv: Add Realm support for Hyper-V Kameron Carr
` (4 preceding siblings ...)
2026-10-31 0:14 ` [PATCH v6 5/6] arm64: hyperv: Route hypercalls through RSI host call in " Kameron Carr
@ 2026-10-31 0:14 ` Kameron Carr
5 siblings, 0 replies; 9+ messages in thread
From: Kameron Carr @ 2026-10-31 0:14 UTC (permalink / raw)
To: decui, haiyangz, mhklinux, wei.liu
Cc: arnd, catalin.marinas, linux-arch, linux-arm-kernel, linux-hyperv,
linux-kernel, lpieralisi, mark.rutland, sudeep.holla, thuth, will
Provide an arm64 implementation of hv_is_isolation_supported() that
overrides the __weak default in drivers/hv/hv_common.c.
The implementation deliberately does not depend on
hv_is_hyperv_initialized() because hv_common_init() consults
hv_is_isolation_supported() before hyperv_initialized is set.
Reviewed-by: Michael Kelley <mhklinux@outlook.com>
Signed-off-by: Kameron Carr <kameroncarr@linux.microsoft.com>
---
arch/arm64/hyperv/mshyperv.c | 5 +++++
1 file changed, 5 insertions(+)
diff --git a/arch/arm64/hyperv/mshyperv.c b/arch/arm64/hyperv/mshyperv.c
index da6c3aa0..8a2c446 100644
--- a/arch/arm64/hyperv/mshyperv.c
+++ b/arch/arm64/hyperv/mshyperv.c
@@ -187,3 +187,8 @@ bool hv_isolation_type_cca(void)
{
return is_realm_world();
}
+
+bool hv_is_isolation_supported(void)
+{
+ return is_realm_world();
+}
--
2.45.4
^ permalink raw reply related [flat|nested] 9+ messages in thread
* Re: [PATCH v6 4/6] Drivers: hv: Mark shared memory as decrypted for CCA Realms
2026-10-31 0:14 ` [PATCH v6 4/6] Drivers: hv: Mark shared memory as decrypted " Kameron Carr
@ 2026-10-31 0:27 ` sashiko-bot
0 siblings, 0 replies; 9+ messages in thread
From: sashiko-bot @ 2026-10-31 0:27 UTC (permalink / raw)
To: Kameron Carr; +Cc: linux-hyperv
Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
- [High] hv: arm64: set_memory_decrypted() in hv_common_cpu_init() hits BBML3 -EBUSY
--
commit 8d15e623ca43bf983a70fccbb187c60423dd18ef
Author: Kameron Carr <kameroncarr@linux.microsoft.com>
Drivers: hv: Mark shared memory as decrypted for CCA Realms
This commit introduces hv_isolation_type_cca() and extends
hv_common_cpu_init() to mark the per-CPU hypercall input and output pages as
decrypted on Arm CCA Realm guests. It also aligns the hypercall buffer
allocation size to PAGE_SIZE when calling set_memory_decrypted().
> diff --git a/drivers/hv/hv_common.c b/drivers/hv/hv_common.c
> index 31256cb22b39e..a60c92cd83eac 100644
> --- a/drivers/hv/hv_common.c
> +++ b/drivers/hv/hv_common.c
> @@ -476,6 +476,7 @@ int hv_common_cpu_init(unsigned int cpu)
> u64 msr_vp_index;
> gfp_t flags;
> const int pgcount = hv_output_page_exists() ? 2 : 1;
> + const size_t alloc_size = ALIGN((size_t)pgcount * HV_HYP_PAGE_SIZE, PAGE_SIZE);
> void *mem;
> int ret = 0;
>
> @@ -489,7 +490,7 @@ int hv_common_cpu_init(unsigned int cpu)
> * online and then taken offline
> */
> if (!*inputarg) {
> - mem = kmalloc_array(pgcount, HV_HYP_PAGE_SIZE, flags);
> + mem = kmalloc(alloc_size, flags);
> if (!mem)
> return -ENOMEM;
>
> @@ -499,14 +500,16 @@ int hv_common_cpu_init(unsigned int cpu)
> }
>
> if (!ms_hyperv.paravisor_present &&
> - (hv_isolation_type_snp() || hv_isolation_type_tdx())) {
> - ret = set_memory_decrypted((unsigned long)mem, pgcount);
> + (hv_isolation_type_snp() || hv_isolation_type_tdx() ||
> + hv_isolation_type_cca())) {
> + ret = set_memory_decrypted((unsigned long)mem,
> + alloc_size >> PAGE_SHIFT);
> if (ret) {
> /* It may be unsafe to free 'mem' */\
> return ret;
> }
[Severity: High]
Can calling set_memory_decrypted() from hv_common_cpu_init() fail with -EBUSY
and prevent secondary CPUs from coming online on BBML3-capable arm64 systems?
On arm64, when the boot CPU supports BBML3 and debug_pagealloc is disabled,
paging_init() -> map_mem() sets linear_map_requires_bbml3 = true and maps the
linear region with block/contiguous descriptors because is_realm_world()
makes can_set_direct_map() return true.
In arch/arm64/hyperv/mshyperv.c, hyperv_init() runs as an early_initcall()
during do_pre_smp_initcalls() and registers hv_common_cpu_init() for
CPUHP_AP_HYPERV_ONLINE:
ret = cpuhp_setup_state(CPUHP_AP_HYPERV_ONLINE, "arm64/hyperv_init:online",
hv_common_cpu_init, hv_common_cpu_die);
Next, smp_init() calls bringup_nonboot_cpus() before smp_cpus_done() ->
setup_system_features() -> setup_system_capabilities() finalizes the
ARM64_HAS_BBML3 capability. During bringup_nonboot_cpus(), each secondary CPU
is marked online in secondary_start_kernel() (making num_online_cpus() > 1)
and then executes CPUHP_AP_HYPERV_ONLINE -> hv_common_cpu_init() while
system_supports_bbml3() and system_capabilities_finalized() are still false.
That leads to the following call chain on the secondary CPU:
hv_common_cpu_init()
set_memory_decrypted()
realm_set_memory_decrypted()
__set_memory_enc_dec()
__change_memory_common()
update_range_prot()
split_kernel_leaf_mapping()
In arch/arm64/mm/mmu.c:split_kernel_leaf_mapping(), splitting the linear map
in this window triggers a warning and returns -EBUSY:
if (!linear_map_requires_bbml3 || is_kfence_address((void *)start))
return 0;
if (!system_supports_bbml3()) {
if (system_capabilities_finalized())
return 0;
if (WARN_ON(!page_alloc_available))
return -EBUSY;
/*
* Boot-time: Started secondary cpus but don't know if they
* support BBML3 yet. Can't allow splitting in this window
* in case they don't.
*/
if (WARN_ON(num_online_cpus() > 1))
return -EBUSY;
}
When split_kernel_leaf_mapping() returns -EBUSY, hv_common_cpu_init() leaks
the mem buffer and returns -EBUSY from the CPUHP_AP_HYPERV_ONLINE callback,
aborting secondary CPU bringup.
Should the per-CPU hypercall buffers for possible CPUs be allocated and
decrypted earlier on the boot CPU (for example in hv_common_init() while
num_online_cpus() == 1), or after system capabilities have been finalized?
--
Sashiko AI review · https://sashiko.dev/#/patchset/20261031001412.4150488-1-kameroncarr@linux.microsoft.com?part=4
^ permalink raw reply [flat|nested] 9+ messages in thread
* RE: [PATCH v6 1/6] arm64: rsi: Add RSI host call structure and helper function
2026-10-31 0:14 ` [PATCH v6 1/6] arm64: rsi: Add RSI host call structure and helper function Kameron Carr
@ 2026-10-31 4:51 ` Dexuan Cui
0 siblings, 0 replies; 9+ messages in thread
From: Dexuan Cui @ 2026-10-31 4:51 UTC (permalink / raw)
To: Kameron Carr, Haiyang Zhang, mhklinux@outlook.com,
wei.liu@kernel.org
Cc: arnd@arndb.de, catalin.marinas@arm.com,
linux-arch@vger.kernel.org, linux-arm-kernel@lists.infradead.org,
linux-hyperv@vger.kernel.org, linux-kernel@vger.kernel.org,
lpieralisi@kernel.org, Mark.Rutland, sudeep.holla@kernel.org,
thuth@redhat.com, will@kernel.org
> From: Kameron Carr <kameroncarr@linux.microsoft.com>
> Sent: Friday, October 30, 2026 5:14 PM
> To: Dexuan Cui <DECUI@microsoft.com>; Haiyang Zhang
> <haiyangz@microsoft.com>; mhklinux@outlook.com; wei.liu@kernel.org
> Cc: arnd@arndb.de; catalin.marinas@arm.com; linux-arch@vger.kernel.org;
> linux-arm-kernel@lists.infradead.org; linux-hyperv@vger.kernel.org; linux-
> kernel@vger.kernel.org; lpieralisi@kernel.org; Mark.Rutland
> <Mark.Rutland@arm.com>; sudeep.holla@kernel.org; thuth@redhat.com;
> will@kernel.org
> Subject: [PATCH v6 1/6] arm64: rsi: Add RSI host call structure and helper
> function
>
> Add struct rsi_host_call to arm-smccc-rsi.h, which represents the host
> call data structure used by the Realm Management Monitor (RMM) for the
> RSI_HOST_CALL interface. The structure contains a 16-bit immediate field
> and 31 general-purpose register values, aligned to 256 bytes as required
> by the CCA RMM specification.
>
> Add rsi_host_call() static inline wrapper in arm-rsi-cmds.h that invokes
> SMC_RSI_HOST_CALL with the physical address of the host call structure.
> This will be used by Hyper-V guest code to route hypercalls through the
> RSI interface when running inside an Arm CCA Realm.
>
> Reviewed-by: Michael Kelley <mhklinux@outlook.com>
> Signed-off-by: Kameron Carr <kameroncarr@linux.microsoft.com>
> ---
Catalin provided Reviewed-by to v5's patch #1, which is the same
as v6's patch #1:
https://lore.kernel.org/all/auPOxoaRbdOEHnv_@arm.com/
^ permalink raw reply [flat|nested] 9+ messages in thread
end of thread, other threads:[~2026-10-31 4:51 UTC | newest]
Thread overview: 9+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-10-31 0:14 [PATCH v6 0/6] arm64: hyperv: Add Realm support for Hyper-V Kameron Carr
2026-10-31 0:14 ` [PATCH v6 1/6] arm64: rsi: Add RSI host call structure and helper function Kameron Carr
2026-10-31 4:51 ` Dexuan Cui
2026-10-31 0:14 ` [PATCH v6 2/6] arm64: hyperv: Detect Hyper-V via RSI host call in CCA Realms Kameron Carr
2026-10-31 0:14 ` [PATCH v6 3/6] arm64: hyperv: Add per-CPU RSI host call infrastructure for " Kameron Carr
2026-10-31 0:14 ` [PATCH v6 4/6] Drivers: hv: Mark shared memory as decrypted " Kameron Carr
2026-10-31 0:27 ` sashiko-bot
2026-10-31 0:14 ` [PATCH v6 5/6] arm64: hyperv: Route hypercalls through RSI host call in " Kameron Carr
2026-10-31 0:14 ` [PATCH v6 6/6] arm64: hyperv: Implement hv_is_isolation_supported() for " Kameron Carr
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.