From 54be8f7de502270e345af1f0d436ddfc5f5b8934 Mon Sep 17 00:00:00 2001 From: Ian May Date: Thu, 4 Dec 2025 23:06:35 -0800 Subject: [PATCH] "target/arm: Handle KVM_CAP_ARM_RME ABI change between kernel versions The KVM_CAP_ARM_RME capability number changed between Linux kernel versions 6.16 and 6.17 (from 243 to 244). This change adds runtime detection of the host kernel version to ensure QEMU remains compatible with both kernel versions during the transition period. The implementation: - Defaults to KVM_CAP_ARM_RME (244) from the updated headers - Detects kernel 6.16 at runtime and uses the previous value (243) - Applies the correct capability number to all RME-related ioctls This allows the same QEMU binary to work correctly on hosts running either kernel version. Signed-off-by: Shanker Donthineni Signed-off-by: Ian May --- linux-headers/linux/kvm.h | 2 +- target/arm/kvm-rme.c | 33 +++++++++++++++++++++++++-------- 2 files changed, 26 insertions(+), 9 deletions(-) diff --git a/linux-headers/linux/kvm.h b/linux-headers/linux/kvm.h index 81ff244d5f..c1d148cb2d 100644 --- a/linux-headers/linux/kvm.h +++ b/linux-headers/linux/kvm.h @@ -963,7 +963,7 @@ struct kvm_enable_cap { #define KVM_CAP_ARM_EL2 240 #define KVM_CAP_ARM_EL2_E2H0 241 #define KVM_CAP_RISCV_MP_STATE_RESET 242 -#define KVM_CAP_ARM_RME 243 +#define KVM_CAP_ARM_RME 244 struct kvm_irq_routing_irqchip { __u32 irqchip; diff --git a/target/arm/kvm-rme.c b/target/arm/kvm-rme.c index 120ff5c324..cf4f1ed1d7 100644 --- a/target/arm/kvm-rme.c +++ b/target/arm/kvm-rme.c @@ -21,6 +21,7 @@ #include "system/confidential-guest-support.h" #include "system/kvm.h" #include "system/runstate.h" +#include #define TYPE_RME_GUEST "rme-guest" OBJECT_DECLARE_SIMPLE_TYPE(RmeGuest, RME_GUEST) @@ -86,6 +87,7 @@ struct RmeGuest { RmeRamRegion init_ram; uint8_t ipa_bits; size_t num_cpus; + unsigned int rme_capable; /* Runtime-detected KVM_CAP_ARM_RME value */ RealmDmaRegion *dma_region; QLIST_HEAD(, RealmRamDiscardListener) ram_discard_list; @@ -428,7 +430,7 @@ static int rme_configure_mec(RmeGuest *guest, Error **errp) } /* First query if MEC is supported by the kernel */ - ret = kvm_vm_enable_cap(kvm_state, KVM_CAP_ARM_RME, 0, + ret = kvm_vm_enable_cap(kvm_state, rme_guest->rme_capable, 0, KVM_CAP_ARM_RME_CONFIG_REALM, (intptr_t)&mec_query); if (ret) { if (private_mec_requested) { @@ -453,7 +455,7 @@ static int rme_configure_mec(RmeGuest *guest, Error **errp) return 0; } - ret = kvm_vm_enable_cap(kvm_state, KVM_CAP_ARM_RME, 0, + ret = kvm_vm_enable_cap(kvm_state, rme_guest->rme_capable, 0, KVM_CAP_ARM_RME_CONFIG_REALM, (intptr_t)&mec_cfg); if (ret) { error_setg_errno(errp, -ret, "MEC configuration failed"); @@ -493,7 +495,7 @@ static int rme_configure_one(RmeGuest *guest, uint32_t cfg, Error **errp) g_assert_not_reached(); } - ret = kvm_vm_enable_cap(kvm_state, KVM_CAP_ARM_RME, 0, + ret = kvm_vm_enable_cap(kvm_state, rme_guest->rme_capable, 0, KVM_CAP_ARM_RME_CONFIG_REALM, (intptr_t)&args); if (ret) { error_setg_errno(errp, -ret, "failed to configure %s", cfg_str); @@ -535,7 +537,7 @@ static int rme_init_ram(RmeRamRegion *ram, Error **errp) .size = end - start, }; - ret = kvm_vm_enable_cap(kvm_state, KVM_CAP_ARM_RME, 0, + ret = kvm_vm_enable_cap(kvm_state, rme_guest->rme_capable, 0, KVM_CAP_ARM_RME_INIT_RIPAS_REALM, (intptr_t)&init_args); if (ret) { @@ -560,7 +562,7 @@ static int rme_populate_range(hwaddr base, size_t size, bool measure, .flags = measure ? KVM_ARM_RME_POPULATE_FLAGS_MEASURE : 0, }; - ret = kvm_vm_enable_cap(kvm_state, KVM_CAP_ARM_RME, 0, + ret = kvm_vm_enable_cap(kvm_state, rme_guest->rme_capable, 0, KVM_CAP_ARM_RME_POPULATE_REALM, (intptr_t)&populate_args); if (ret) { @@ -629,7 +631,7 @@ static int rme_create_realm(Error **errp) return -1; } - ret = kvm_vm_enable_cap(kvm_state, KVM_CAP_ARM_RME, 0, + ret = kvm_vm_enable_cap(kvm_state, rme_guest->rme_capable, 0, KVM_CAP_ARM_RME_CREATE_REALM); if (ret) { error_setg_errno(errp, -ret, "failed to create Realm Descriptor"); @@ -658,7 +660,7 @@ static int rme_create_realm(Error **errp) return -1; } - ret = kvm_vm_enable_cap(kvm_state, KVM_CAP_ARM_RME, 0, + ret = kvm_vm_enable_cap(kvm_state, rme_guest->rme_capable, 0, KVM_CAP_ARM_RME_ACTIVATE_REALM); if (ret) { error_setg_errno(errp, -ret, "failed to activate realm"); @@ -786,13 +788,28 @@ static void rme_guest_class_init(ObjectClass *oc, const void *data) static void rme_guest_init(Object *obj) { + struct utsname buf; + int major, minor; + if (rme_guest) { error_report("a single instance of RmeGuest is supported"); exit(1); } + rme_guest = RME_GUEST(obj); rme_guest->measurement_algo = RME_GUEST_MEASUREMENT_ALGORITHM_SHA512; rme_guest->mec_specified = false; + + rme_guest->rme_capable = KVM_CAP_ARM_RME; + + if (uname(&buf) == 0) { + if (sscanf(buf.release, "%d.%d", &major, &minor) == 2) { + /* For Linux kernel v6.16, KVM_CAP_ARM_RME == 243 */ + if ((major == 6) && (minor == 16)) { + rme_guest->rme_capable = 243; + } + } + } } static void rme_guest_finalize(Object *obj) @@ -865,7 +882,7 @@ int kvm_arm_rme_init(MachineState *ms) return -EINVAL; } - if (!kvm_check_extension(kvm_state, KVM_CAP_ARM_RME)) { + if (!kvm_check_extension(kvm_state, rme_guest->rme_capable)) { return -ENODEV; }