KVM: selftests: Check that PV_UNHALT is cleared when HLT exiting is disabled
authorVitaly Kuznetsov <vkuznets@redhat.com>
Wed, 28 Feb 2024 10:18:37 +0000 (11:18 +0100)
committerSean Christopherson <seanjc@google.com>
Wed, 6 Mar 2024 17:59:20 +0000 (09:59 -0800)
KVM_FEATURE_PV_UNHALT is expected to get cleared from KVM PV feature CPUID
data when KVM_X86_DISABLE_EXITS_HLT is enabled. Add the corresponding test
to kvm_pv_test.

Note, the newly added code doesn't actually test KVM_FEATURE_PV_UNHALT and
KVM_X86_DISABLE_EXITS_HLT features.

Signed-off-by: Vitaly Kuznetsov <vkuznets@redhat.com>
Link: https://lore.kernel.org/r/20240228101837.93642-4-vkuznets@redhat.com
[sean: add and use vcpu_cpuid_has()]
Signed-off-by: Sean Christopherson <seanjc@google.com>
tools/testing/selftests/kvm/include/x86_64/processor.h
tools/testing/selftests/kvm/x86_64/kvm_pv_test.c

index a84863503fcb46cda532840f3be4512cf35061c3..8b5c804562f99dfc2ebacbbd6ae130804b291f89 100644 (file)
@@ -995,6 +995,15 @@ static inline void vcpu_set_cpuid(struct kvm_vcpu *vcpu)
        vcpu_ioctl(vcpu, KVM_GET_CPUID2, vcpu->cpuid);
 }
 
+static inline bool vcpu_cpuid_has(struct kvm_vcpu *vcpu,
+                                 struct kvm_x86_cpu_feature feature)
+{
+       struct kvm_cpuid_entry2 *entry;
+
+       entry = __vcpu_get_cpuid_entry(vcpu, feature.function, feature.index);
+       return *((&entry->eax) + feature.reg) & BIT(feature.bit);
+}
+
 void vcpu_set_cpuid_maxphyaddr(struct kvm_vcpu *vcpu, uint8_t maxphyaddr);
 
 void vcpu_clear_cpuid_entry(struct kvm_vcpu *vcpu, uint32_t function);
index 9e2879af7c201fb749120cee94a61e03dfaf162b..40cc59f4e6501316695485a10532479787899d81 100644 (file)
@@ -133,6 +133,43 @@ static void enter_guest(struct kvm_vcpu *vcpu)
        }
 }
 
+static void test_pv_unhalt(void)
+{
+       struct kvm_vcpu *vcpu;
+       struct kvm_vm *vm;
+       struct kvm_cpuid_entry2 *ent;
+       u32 kvm_sig_old;
+
+       pr_info("testing KVM_FEATURE_PV_UNHALT\n");
+
+       TEST_REQUIRE(KVM_CAP_X86_DISABLE_EXITS);
+
+       /* KVM_PV_UNHALT test */
+       vm = vm_create_with_one_vcpu(&vcpu, guest_main);
+       vcpu_set_cpuid_feature(vcpu, X86_FEATURE_KVM_PV_UNHALT);
+
+       TEST_ASSERT(vcpu_cpuid_has(vcpu, X86_FEATURE_KVM_PV_UNHALT),
+                   "Enabling X86_FEATURE_KVM_PV_UNHALT had no effect");
+
+       /* Make sure KVM clears vcpu->arch.kvm_cpuid */
+       ent = vcpu_get_cpuid_entry(vcpu, KVM_CPUID_SIGNATURE);
+       kvm_sig_old = ent->ebx;
+       ent->ebx = 0xdeadbeef;
+       vcpu_set_cpuid(vcpu);
+
+       vm_enable_cap(vm, KVM_CAP_X86_DISABLE_EXITS, KVM_X86_DISABLE_EXITS_HLT);
+       ent = vcpu_get_cpuid_entry(vcpu, KVM_CPUID_SIGNATURE);
+       ent->ebx = kvm_sig_old;
+       vcpu_set_cpuid(vcpu);
+
+       TEST_ASSERT(!vcpu_cpuid_has(vcpu, X86_FEATURE_KVM_PV_UNHALT),
+                   "KVM_FEATURE_PV_UNHALT is set with KVM_CAP_X86_DISABLE_EXITS");
+
+       /* FIXME: actually test KVM_FEATURE_PV_UNHALT feature */
+
+       kvm_vm_free(vm);
+}
+
 int main(void)
 {
        struct kvm_vcpu *vcpu;
@@ -151,4 +188,6 @@ int main(void)
 
        enter_guest(vcpu);
        kvm_vm_free(vm);
+
+       test_pv_unhalt();
 }