diff --git a/target/arm/aarch64-qmp-cmds.c b/target/arm/aarch64-qmp-cmds.c index 241a6662f1..f2b331aa52 100644 --- a/target/arm/aarch64-qmp-cmds.c +++ b/target/arm/aarch64-qmp-cmds.c @@ -37,8 +37,9 @@ CcaCapability *qmp_query_cca_capabilities(Error **errp) } /* - * Use the runtime-detected KVM_CAP_ARM_RME value to handle - * the ABI change between kernel versions (243 on 6.16, 244 on later). + * Use kvm_arm_rme_get_cap() to get the KVM CCA capability value + * from the kernel's sysfs module parameter, handling ABI changes + * between kernel versions gracefully. */ if (!kvm_check_extension(kvm_state, kvm_arm_rme_get_cap())) { error_setg(errp, "RME is not enabled in KVM"); diff --git a/target/arm/kvm-rme.c b/target/arm/kvm-rme.c index 5b6de24539..0b98b169b3 100644 --- a/target/arm/kvm-rme.c +++ b/target/arm/kvm-rme.c @@ -24,10 +24,30 @@ #include /* - * Returns the correct KVM_CAP_ARM_RME capability value for the running kernel. - * This handles the ABI change between kernel versions: - * - Linux 6.16: KVM_CAP_ARM_RME == 243 - * - Linux 6.17+: KVM_CAP_ARM_RME == 244 + * Sysfs paths for KVM CCA capability detection. + * v11+ host patches (6.18+) use RMI naming, v10 (6.17) uses RME naming. + */ +#define KVM_CAP_ARM_RMI_SYSFS_PATH "/sys/module/kvm/parameters/kvm_cap_arm_rmi" +#define KVM_CAP_ARM_RME_SYSFS_PATH "/sys/module/kvm/parameters/kvm_cap_arm_rme" + +/* + * Returns the correct KVM CCA capability value for the running kernel. + * + * The ARM CCA host patches underwent a naming change from RME to RMI in v11: + * - v10 (Linux 6.17): KVM_CAP_ARM_RME, sysfs param kvm_cap_arm_rme + * - v11 (Linux 6.18+): KVM_CAP_ARM_RMI, sysfs param kvm_cap_arm_rmi + * + * Detection order: + * 1. Try reading from the v11 sysfs module parameter (RMI naming): + * /sys/module/kvm/parameters/kvm_cap_arm_rmi + * + * 2. Try reading from the v10 sysfs module parameter (RME naming): + * /sys/module/kvm/parameters/kvm_cap_arm_rme + * + * 3. Fall back to uname-based detection for Linux 6.16 dev kernel + * (which does not have the sysfs parameter): capability == 243 + * + * 4. Otherwise use the compile-time KVM_CAP_ARM_RME value. */ unsigned int kvm_arm_rme_get_cap(void) { @@ -35,16 +55,33 @@ unsigned int kvm_arm_rme_get_cap(void) static bool detected = false; if (!detected) { - struct utsname buf; - int major, minor; + FILE *f = NULL; + int cap; rme_cap = 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_cap = 243; + /* First try v11 sysfs path (RMI naming, 6.18+ kernels) */ + f = fopen(KVM_CAP_ARM_RMI_SYSFS_PATH, "r"); + if (!f) { + /* Then try v10 sysfs path (RME naming, 6.17 kernels) */ + f = fopen(KVM_CAP_ARM_RME_SYSFS_PATH, "r"); + } + + if (f) { + if (fscanf(f, "%d", &cap) == 1 && cap > 0) { + rme_cap = cap; + } + fclose(f); + } else { + /* Fallback for 6.16 dev kernel (no sysfs parameter) */ + struct utsname buf; + int major, minor; + + if (uname(&buf) == 0) { + if (sscanf(buf.release, "%d.%d", &major, &minor) == 2) { + if (major == 6 && minor == 16) { + rme_cap = 243; + } } } } diff --git a/target/arm/kvm_arm.h b/target/arm/kvm_arm.h index 1eab906d0a..07d1b0cecb 100644 --- a/target/arm/kvm_arm.h +++ b/target/arm/kvm_arm.h @@ -277,9 +277,16 @@ void arm_cpu_kvm_set_irq(void *arm_cpu, int irq, int level); /** * kvm_arm_rme_get_cap: * - * Returns the correct KVM_CAP_ARM_RME capability value for the running - * kernel. This handles the ABI change between kernel versions where the - * capability number differs (e.g., 243 on kernel 6.16, 244 on later kernels). + * Returns the correct KVM CCA capability value for the running kernel. + * Supports both v10 (RME naming, 6.17) and v11+ (RMI naming, 6.18+) host patches. + * + * First tries to read from the sysfs module parameters: + * /sys/module/kvm/parameters/kvm_cap_arm_rmi (v11+, 6.18+) + * /sys/module/kvm/parameters/kvm_cap_arm_rme (v10, 6.17) + * + * Falls back to uname-based kernel version detection (6.16=243, 6.17=244, + * 6.18=246) if sysfs is not available, or uses the compile-time + * KVM_CAP_ARM_RME value as a last resort. */ unsigned int kvm_arm_rme_get_cap(void);