Commit ce34865bb2 for qemu.org
commit ce34865bb2a3e4e413f521e5f08be5979259d90b
Author: Eric Auger <eric.auger@redhat.com>
Date: Fri Oct 30 14:13:18 2026 +0100
target/arm/kvm: Improve error handling on scratch vcpu probe
Pass an error handle to both kvm_arm_create_scratch_host_vcpu()
and kvm_arm_get_host_cpu_features(). This allows to improve the
error reporting on kvm_arm_set_cpu_features_from_host().
If any, the error is stored in the new cpu->host_cpu_probe_err
field and further propagated on realize().
In arm_gic_cap_kvm_probe() call path we just pass a NULL error handle
to kvm_arm_create_scratch_host_vcpu because we don't care about the
failure nature and just want to revert to emulated versions if it
fails.
Signed-off-by: Eric Auger <eric.auger@redhat.com>
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
Message-id: 20261030131406.461599-11-eric.auger@redhat.com
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
diff --git a/target/arm/kvm.c b/target/arm/kvm.c
index f9c7577460..b66eb4f6c2 100644
--- a/target/arm/kvm.c
+++ b/target/arm/kvm.c
@@ -62,6 +62,7 @@ typedef struct ARMHostCPUFeatures {
uint32_t target;
uint32_t sve_vq_supported;
const char *dtb_compatible;
+ Error *probe_err;
} ARMHostCPUFeatures;
static ARMHostCPUFeatures arm_host_cpu_features;
@@ -104,13 +105,14 @@ static int kvm_arm_vcpu_finalize(ARMCPU *cpu, int feature)
}
bool kvm_arm_create_scratch_host_vcpu(int *fdarray,
- struct kvm_vcpu_init *init)
+ struct kvm_vcpu_init *init, Error **errp)
{
int ret = 0, kvmfd = -1, vmfd = -1, cpufd = -1;
int max_vm_pa_size;
kvmfd = qemu_open_old("/dev/kvm", O_RDWR);
if (kvmfd < 0) {
+ error_setg_errno(errp, errno, "Failed to open /dev/kvm");
goto err;
}
max_vm_pa_size = ioctl(kvmfd, KVM_CHECK_EXTENSION, KVM_CAP_ARM_VM_IPA_SIZE);
@@ -121,6 +123,7 @@ bool kvm_arm_create_scratch_host_vcpu(int *fdarray,
vmfd = ioctl(kvmfd, KVM_CREATE_VM, max_vm_pa_size);
} while (vmfd == -1 && errno == EINTR);
if (vmfd < 0) {
+ error_setg_errno(errp, errno, "Failed to create the scratch VM");
goto err;
}
@@ -140,6 +143,7 @@ bool kvm_arm_create_scratch_host_vcpu(int *fdarray,
cpufd = ioctl(vmfd, KVM_CREATE_VCPU, 0);
if (cpufd < 0) {
+ error_setg_errno(errp, errno, "Failed to create the scratch VCPU");
goto err;
}
@@ -153,12 +157,16 @@ bool kvm_arm_create_scratch_host_vcpu(int *fdarray,
ret = ioctl(vmfd, KVM_ARM_PREFERRED_TARGET, &preferred);
if (ret < 0) {
+ error_setg_errno(errp, errno,
+ "Failed to get the preferred KVM target");
goto err;
}
init->target = preferred.target;
}
ret = ioctl(cpufd, KVM_ARM_VCPU_INIT, init);
if (ret < 0) {
+ error_setg_errno(errp, errno,
+ "Failed to initialize the scratch VCPU");
goto err;
}
@@ -312,13 +320,19 @@ static uint32_t kvm_arm_sve_get_vls(int fd)
return vls[0] & MAKE_64BIT_MASK(0, ARM_MAX_VQ);
}
-static void kvm_arm_get_host_cpu_features(ARMHostCPUFeatures *ahcf)
+/**
+ * kvm_arm_get_host_cpu_features:
+ * @ahcf: host CPU feature struct to populate
+ * @errp: error handle
+ *
+ * Identify the feature bits corresponding to the host CPU by creating a
+ * scratch VM/vCPU and querying its ID registers.
+ *
+ * On failure, @ahcf->target is QEMU_KVM_ARM_TARGET_NONE and *errp is set
+ * On success, @ahcf->target is set to a valid KVM target.
+ */
+static void kvm_arm_get_host_cpu_features(ARMHostCPUFeatures *ahcf, Error **errp)
{
- /* Identify the feature bits corresponding to the host CPU, and
- * fill out the ARMHostCPUClass fields accordingly. To do this
- * we have to create a scratch VM, create a single CPU inside it,
- * and then query that CPU for the relevant ID registers.
- */
int fdarray[3];
bool sve_supported;
bool el2_supported;
@@ -330,6 +344,7 @@ static void kvm_arm_get_host_cpu_features(ARMHostCPUFeatures *ahcf)
ahcf->dtb_compatible = "arm,armv8";
if (!kvm_enabled()) {
+ error_setg(errp, "KVM is not enabled");
return;
}
@@ -371,7 +386,7 @@ static void kvm_arm_get_host_cpu_features(ARMHostCPUFeatures *ahcf)
features |= 1ULL << ARM_FEATURE_PMU;
}
- if (!kvm_arm_create_scratch_host_vcpu(fdarray, &init)) {
+ if (!kvm_arm_create_scratch_host_vcpu(fdarray, &init, errp)) {
return;
}
@@ -502,6 +517,7 @@ static void kvm_arm_get_host_cpu_features(ARMHostCPUFeatures *ahcf)
kvm_arm_destroy_scratch_host_vcpu(fdarray);
if (err < 0) {
+ error_setg(errp, "Failed to read some host CPU ID registers");
return;
}
@@ -528,7 +544,8 @@ void kvm_arm_set_cpu_features_from_host(ARMCPU *cpu)
CPUARMState *env = &cpu->env;
if (!arm_host_cpu_features.dtb_compatible) {
- kvm_arm_get_host_cpu_features(&arm_host_cpu_features);
+ kvm_arm_get_host_cpu_features(&arm_host_cpu_features,
+ &arm_host_cpu_features.probe_err);
}
cpu->kvm_target = arm_host_cpu_features.target;
@@ -538,8 +555,7 @@ void kvm_arm_set_cpu_features_from_host(ARMCPU *cpu)
* We can't report this error yet, so flag that we need to
* in arm_cpu_realizefn().
*/
- error_setg(&cpu->host_cpu_probe_err,
- "failed to retrieve host CPU features");
+ cpu->host_cpu_probe_err = error_copy(arm_host_cpu_features.probe_err);
return;
}
@@ -2674,7 +2690,7 @@ void arm_gic_cap_kvm_probe(GICCapability *v2, GICCapability *v3)
{
int fdarray[3];
- if (!kvm_arm_create_scratch_host_vcpu(fdarray, NULL)) {
+ if (!kvm_arm_create_scratch_host_vcpu(fdarray, NULL, NULL)) {
return;
}
diff --git a/target/arm/kvm_arm.h b/target/arm/kvm_arm.h
index e7c40fb003..9c7e7f654a 100644
--- a/target/arm/kvm_arm.h
+++ b/target/arm/kvm_arm.h
@@ -105,6 +105,7 @@ struct kvm_vcpu_init;
* @init: filled in with the necessary values for creating a host
* vcpu. If NULL is provided, will not init the vCPU (though the cpufd
* will still be set up).
+ * @errp: Error handle
*
* Create a scratch vcpu in its own VM of the type preferred by the host
* kernel (as would be used for '-cpu host'), for purposes of probing it
@@ -114,7 +115,7 @@ struct kvm_vcpu_init;
* false on failure (and fdarray and init are not valid).
*/
bool kvm_arm_create_scratch_host_vcpu(int *fdarray,
- struct kvm_vcpu_init *init);
+ struct kvm_vcpu_init *init, Error **errp);
/**
* kvm_arm_destroy_scratch_host_vcpu: