target/arm: Init sve_vq in kvm_arm_set_cpu_features_from_host
Probe for SVE vector sizes with the same scratch vm that we use for probing other features. Remove a separate initialization path in arm_cpu_sve_finalize. Unexport kvm_arm_sve_get_vls. Signed-off-by: Richard Henderson <richard.henderson@linaro.org> Reviewed-by: Peter Maydell <peter.maydell@linaro.org> Message-id: 20260216034432.23912-5-richard.henderson@linaro.org Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
Richard Henderson committed
Feb 26, 2026 at 11:27 UTC
5b3feb36aecd15e4248b6a5f9eeb9c28189c7faf
4 files changed
+27
-79
target/arm/cpu64.c
+1
-19
@@ -79,28 +79,10 @@ void arm_cpu_sve_finalize(ARMCPU *cpu, Error **errp)
79
*/
80
uint32_t vq_map = cpu->sve_vq.map;
81
uint32_t vq_init = cpu->sve_vq.init;
82
- uint32_t vq_supported;
82
+ uint32_t vq_supported = cpu->sve_vq.supported;
83
uint32_t vq_mask = 0;
84
uint32_t tmp, vq, max_vq = 0;
85
86
- /*
87
- * CPU models specify a set of supported vector lengths which are
88
- * enabled by default. Attempting to enable any vector length not set
89
- * in the supported bitmap results in an error. When KVM is enabled we
90
- * fetch the supported bitmap from the host.
91
- */
92
- if (kvm_enabled()) {
93
- if (kvm_arm_sve_supported()) {
94
- cpu->sve_vq.supported = kvm_arm_sve_get_vls(cpu);
95
- vq_supported = cpu->sve_vq.supported;
96
- } else {
97
- assert(!cpu_isar_feature(aa64_sve, cpu));
98
- vq_supported = 0;
99
- }
100
- } else {
101
- vq_supported = cpu->sve_vq.supported;
102
- }
103
-
86
/*
87
* Process explicit sve<N> properties.
88
* From the properties, sve_vq_map<N> implies sve_vq_init<N>.
target/arm/kvm-stub.c
-5
@@ -95,11 +95,6 @@ void kvm_arm_steal_time_finalize(ARMCPU *cpu, Error **errp)
95
g_assert_not_reached();
96
}
97
98
-uint32_t kvm_arm_sve_get_vls(ARMCPU *cpu)
99
-{
100
- g_assert_not_reached();
101
-}
102
-
98
void kvm_arm_enable_mte(Object *cpuobj, Error **errp)
99
{
100
g_assert_not_reached();
target/arm/kvm.c
+26
-45
@@ -60,6 +60,7 @@ typedef struct ARMHostCPUFeatures {
60
ARMISARegisters isar;
61
uint64_t features;
62
uint32_t target;
63
+ uint32_t sve_vq_supported;
64
const char *dtb_compatible;
65
} ARMHostCPUFeatures;
66
@@ -243,58 +244,34 @@ static int get_host_cpu_reg(int fd, ARMHostCPUFeatures *ahcf,
244
return ret;
245
}
246
246
-uint32_t kvm_arm_sve_get_vls(ARMCPU *cpu)
247
+static uint32_t kvm_arm_sve_get_vls(int fd)
248
{
249
/* Only call this function if kvm_arm_sve_supported() returns true. */
249
- static uint64_t vls[KVM_ARM64_SVE_VLS_WORDS];
250
- static bool probed;
250
+ uint64_t vls[KVM_ARM64_SVE_VLS_WORDS];
251
+ struct kvm_one_reg reg = {
252
+ .id = KVM_REG_ARM64_SVE_VLS,
253
+ .addr = (uint64_t)&vls[0],
254
+ };
255
uint32_t vq = 0;
252
- int i;
253
-
254
- /*
255
- * KVM ensures all host CPUs support the same set of vector lengths.
256
- * So we only need to create the scratch VCPUs once and then cache
257
- * the results.
258
- */
259
- if (!probed) {
260
- struct kvm_vcpu_init init = {
261
- .target = -1,
262
- .features[0] = (1 << KVM_ARM_VCPU_SVE),
263
- };
264
- struct kvm_one_reg reg = {
265
- .id = KVM_REG_ARM64_SVE_VLS,
266
- .addr = (uint64_t)&vls[0],
267
- };
268
- int fdarray[3], ret;
269
-
270
- probed = true;
256
+ int ret;
257
272
- if (!kvm_arm_create_scratch_host_vcpu(fdarray, &init)) {
273
- error_report("failed to create scratch VCPU with SVE enabled");
274
- abort();
275
- }
276
- ret = ioctl(fdarray[2], KVM_GET_ONE_REG, ®);
277
- kvm_arm_destroy_scratch_host_vcpu(fdarray);
278
- if (ret) {
279
- error_report("failed to get KVM_REG_ARM64_SVE_VLS: %s",
280
- strerror(errno));
281
- abort();
282
- }
258
+ ret = ioctl(fd, KVM_GET_ONE_REG, ®);
259
+ if (ret) {
260
+ error_report("failed to get KVM_REG_ARM64_SVE_VLS: %s",
261
+ strerror(errno));
262
+ abort();
263
+ }
264
284
- for (i = KVM_ARM64_SVE_VLS_WORDS - 1; i >= 0; --i) {
285
- if (vls[i]) {
286
- vq = 64 - clz64(vls[i]) + i * 64;
287
- break;
288
- }
289
- }
290
- if (vq > ARM_MAX_VQ) {
291
- warn_report("KVM supports vector lengths larger than "
292
- "QEMU can enable");
293
- vls[0] &= MAKE_64BIT_MASK(0, ARM_MAX_VQ);
265
+ for (int i = KVM_ARM64_SVE_VLS_WORDS - 1; i >= 0; --i) {
266
+ if (vls[i]) {
267
+ vq = 64 - clz64(vls[i]) + i * 64;
268
+ break;
269
}
270
}
296
-
297
- return vls[0];
271
+ if (vq > ARM_MAX_VQ) {
272
+ warn_report("KVM supports vector lengths larger than QEMU can enable");
273
+ }
274
+ return vls[0] & MAKE_64BIT_MASK(0, ARM_MAX_VQ);
275
}
276
277
static bool kvm_arm_get_host_cpu_features(ARMHostCPUFeatures *ahcf)
@@ -469,6 +446,9 @@ static bool kvm_arm_get_host_cpu_features(ARMHostCPUFeatures *ahcf)
446
* So only read the register if we set KVM_ARM_VCPU_SVE above.
447
*/
448
err |= get_host_cpu_reg(fd, ahcf, ID_AA64ZFR0_EL1_IDX);
449
+
450
+ /* Read the set of supported vector lengths. */
451
+ arm_host_cpu_features.sve_vq_supported = kvm_arm_sve_get_vls(fd);
452
}
453
}
454
@@ -516,6 +496,7 @@ void kvm_arm_set_cpu_features_from_host(ARMCPU *cpu)
496
cpu->kvm_target = arm_host_cpu_features.target;
497
cpu->dtb_compatible = arm_host_cpu_features.dtb_compatible;
498
cpu->isar = arm_host_cpu_features.isar;
499
+ cpu->sve_vq.supported = arm_host_cpu_features.sve_vq_supported;
500
env->features = arm_host_cpu_features.features;
501
}
502
target/arm/kvm_arm.h
-10
@@ -124,16 +124,6 @@ bool kvm_arm_create_scratch_host_vcpu(int *fdarray,
124
*/
125
void kvm_arm_destroy_scratch_host_vcpu(int *fdarray);
126
127
-/**
128
- * kvm_arm_sve_get_vls:
129
- * @cpu: ARMCPU
130
- *
131
- * Get all the SVE vector lengths supported by the KVM host, setting
132
- * the bits corresponding to their length in quadwords minus one
133
- * (vq - 1) up to ARM_MAX_VQ. Return the resulting map.
134
- */
135
-uint32_t kvm_arm_sve_get_vls(ARMCPU *cpu);
136
-
127
/**
128
* kvm_arm_set_cpu_features_from_host:
129
* @cpu: ARMCPU to set the features for