Skip to content

Commit 63d8c70

Browse files
committed
KVM: x86: Clear PV_UNHALT for !HLT-exiting only when userspace sets CPUID
Now that KVM disallows disabling HLT-exiting after vCPUs have been created, i.e. now that it's impossible for kvm_hlt_in_guest() to change while vCPUs are running, apply KVM's PV_UNHALT quirk only when userspace is setting guest CPUID. Opportunistically rename the helper to make it clear that KVM's behavior is a quirk that should never have been added. KVM's documentation explicitly states that userspace should not advertise PV_UNHALT if HLT-exiting is disabled, but for unknown reasons, commit caa057a ("KVM: X86: Provide a capability to disable HLT intercepts") didn't stop at documenting the requirement and also massaged the incoming guest CPUID. Unfortunately, it's quite likely that userspace has come to rely on KVM's behavior, i.e. the code can't simply be deleted. The only reason KVM doesn't have an "official" quirk is that there is no known use case where disabling the quirk would make sense, i.e. letting userspace disable the quirk would further increase KVM's burden without any benefit. Reviewed-by: Maxim Levitsky <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Sean Christopherson <[email protected]>
1 parent 8c01290 commit 63d8c70

File tree

1 file changed

+11
-17
lines changed

1 file changed

+11
-17
lines changed

arch/x86/kvm/cpuid.c

Lines changed: 11 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -178,6 +178,8 @@ static int kvm_check_cpuid(struct kvm_vcpu *vcpu)
178178
return fpu_enable_guest_xfd_features(&vcpu->arch.guest_fpu, xfeatures);
179179
}
180180

181+
static u32 kvm_apply_cpuid_pv_features_quirk(struct kvm_vcpu *vcpu);
182+
181183
/* Check whether the supplied CPUID data is equal to what is already set for the vCPU. */
182184
static int kvm_cpuid_check_equal(struct kvm_vcpu *vcpu, struct kvm_cpuid_entry2 *e2,
183185
int nent)
@@ -197,6 +199,7 @@ static int kvm_cpuid_check_equal(struct kvm_vcpu *vcpu, struct kvm_cpuid_entry2
197199
* Note! @e2 and @nent track the _old_ CPUID entries!
198200
*/
199201
kvm_update_cpuid_runtime(vcpu);
202+
kvm_apply_cpuid_pv_features_quirk(vcpu);
200203

201204
if (nent != vcpu->arch.cpuid_nent)
202205
return -EINVAL;
@@ -267,18 +270,17 @@ static struct kvm_cpuid_entry2 *kvm_find_kvm_cpuid_features(struct kvm_vcpu *vcp
267270
vcpu->arch.cpuid_nent, base);
268271
}
269272

270-
static void kvm_update_pv_runtime(struct kvm_vcpu *vcpu)
273+
static u32 kvm_apply_cpuid_pv_features_quirk(struct kvm_vcpu *vcpu)
271274
{
272275
struct kvm_cpuid_entry2 *best = kvm_find_kvm_cpuid_features(vcpu);
273276

274-
vcpu->arch.pv_cpuid.features = 0;
277+
if (!best)
278+
return 0;
275279

276-
/*
277-
* save the feature bitmap to avoid cpuid lookup for every PV
278-
* operation
279-
*/
280-
if (best)
281-
vcpu->arch.pv_cpuid.features = best->eax;
280+
if (kvm_hlt_in_guest(vcpu->kvm))
281+
best->eax &= ~(1 << KVM_FEATURE_PV_UNHALT);
282+
283+
return best->eax;
282284
}
283285

284286
/*
@@ -300,7 +302,6 @@ static void __kvm_update_cpuid_runtime(struct kvm_vcpu *vcpu, struct kvm_cpuid_e
300302
int nent)
301303
{
302304
struct kvm_cpuid_entry2 *best;
303-
struct kvm_hypervisor_cpuid kvm_cpuid;
304305

305306
best = cpuid_entry2_find(entries, nent, 1, KVM_CPUID_INDEX_NOT_SIGNIFICANT);
306307
if (best) {
@@ -327,13 +328,6 @@ static void __kvm_update_cpuid_runtime(struct kvm_vcpu *vcpu, struct kvm_cpuid_e
327328
cpuid_entry_has(best, X86_FEATURE_XSAVEC)))
328329
best->ebx = xstate_required_size(vcpu->arch.xcr0, true);
329330

330-
kvm_cpuid = __kvm_get_hypervisor_cpuid(entries, nent, KVM_SIGNATURE);
331-
if (kvm_cpuid.base) {
332-
best = __kvm_find_kvm_cpuid_features(entries, nent, kvm_cpuid.base);
333-
if (kvm_hlt_in_guest(vcpu->kvm) && best)
334-
best->eax &= ~(1 << KVM_FEATURE_PV_UNHALT);
335-
}
336-
337331
if (!kvm_check_has_quirk(vcpu->kvm, KVM_X86_QUIRK_MISC_ENABLE_NO_MWAIT)) {
338332
best = cpuid_entry2_find(entries, nent, 0x1, KVM_CPUID_INDEX_NOT_SIGNIFICANT);
339333
if (best)
@@ -417,7 +411,7 @@ void kvm_vcpu_after_set_cpuid(struct kvm_vcpu *vcpu)
417411
vcpu->arch.guest_supported_xcr0 =
418412
cpuid_get_supported_xcr0(vcpu->arch.cpuid_entries, vcpu->arch.cpuid_nent);
419413

420-
kvm_update_pv_runtime(vcpu);
414+
vcpu->arch.pv_cpuid.features = kvm_apply_cpuid_pv_features_quirk(vcpu);
421415

422416
vcpu->arch.is_amd_compatible = guest_cpuid_is_amd_or_hygon(vcpu);
423417
vcpu->arch.maxphyaddr = cpuid_query_maxphyaddr(vcpu);

0 commit comments

Comments
 (0)