Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 3 additions & 2 deletions target/arm/aarch64-qmp-cmds.c
Original file line number Diff line number Diff line change
Expand Up @@ -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");
Expand Down
59 changes: 48 additions & 11 deletions target/arm/kvm-rme.c
Original file line number Diff line number Diff line change
Expand Up @@ -24,27 +24,64 @@
#include <sys/utsname.h>

/*
* 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)
{
static unsigned int rme_cap = 0;
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;
}
}
}
}
Expand Down
13 changes: 10 additions & 3 deletions target/arm/kvm_arm.h
Original file line number Diff line number Diff line change
Expand Up @@ -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);

Expand Down