Loading arch/x86/kvm/cpuid.c +26 −16 Original line number Diff line number Diff line Loading @@ -189,15 +189,15 @@ static int kvm_cpuid_check_equal(struct kvm_vcpu *vcpu, struct kvm_cpuid_entry2 return 0; } static struct kvm_hypervisor_cpuid kvm_get_hypervisor_cpuid(struct kvm_vcpu *vcpu, const char *sig) static struct kvm_hypervisor_cpuid __kvm_get_hypervisor_cpuid(struct kvm_cpuid_entry2 *entries, int nent, const char *sig) { struct kvm_hypervisor_cpuid cpuid = {}; struct kvm_cpuid_entry2 *entry; u32 base; for_each_possible_hypervisor_cpuid_base(base) { entry = kvm_find_cpuid_entry(vcpu, base); entry = cpuid_entry2_find(entries, nent, base, KVM_CPUID_INDEX_NOT_SIGNIFICANT); if (entry) { u32 signature[3]; Loading @@ -217,22 +217,29 @@ static struct kvm_hypervisor_cpuid kvm_get_hypervisor_cpuid(struct kvm_vcpu *vcp return cpuid; } static struct kvm_cpuid_entry2 *__kvm_find_kvm_cpuid_features(struct kvm_vcpu *vcpu, struct kvm_cpuid_entry2 *entries, int nent) static struct kvm_hypervisor_cpuid kvm_get_hypervisor_cpuid(struct kvm_vcpu *vcpu, const char *sig) { u32 base = vcpu->arch.kvm_cpuid.base; if (!base) return NULL; return __kvm_get_hypervisor_cpuid(vcpu->arch.cpuid_entries, vcpu->arch.cpuid_nent, sig); } return cpuid_entry2_find(entries, nent, base | KVM_CPUID_FEATURES, static struct kvm_cpuid_entry2 *__kvm_find_kvm_cpuid_features(struct kvm_cpuid_entry2 *entries, int nent, u32 kvm_cpuid_base) { return cpuid_entry2_find(entries, nent, kvm_cpuid_base | KVM_CPUID_FEATURES, KVM_CPUID_INDEX_NOT_SIGNIFICANT); } static struct kvm_cpuid_entry2 *kvm_find_kvm_cpuid_features(struct kvm_vcpu *vcpu) { return __kvm_find_kvm_cpuid_features(vcpu, vcpu->arch.cpuid_entries, vcpu->arch.cpuid_nent); u32 base = vcpu->arch.kvm_cpuid.base; if (!base) return NULL; return __kvm_find_kvm_cpuid_features(vcpu->arch.cpuid_entries, vcpu->arch.cpuid_nent, base); } void kvm_update_pv_runtime(struct kvm_vcpu *vcpu) Loading Loading @@ -266,6 +273,7 @@ static void __kvm_update_cpuid_runtime(struct kvm_vcpu *vcpu, struct kvm_cpuid_e int nent) { struct kvm_cpuid_entry2 *best; struct kvm_hypervisor_cpuid kvm_cpuid; best = cpuid_entry2_find(entries, nent, 1, KVM_CPUID_INDEX_NOT_SIGNIFICANT); if (best) { Loading @@ -292,10 +300,12 @@ static void __kvm_update_cpuid_runtime(struct kvm_vcpu *vcpu, struct kvm_cpuid_e cpuid_entry_has(best, X86_FEATURE_XSAVEC))) best->ebx = xstate_required_size(vcpu->arch.xcr0, true); best = __kvm_find_kvm_cpuid_features(vcpu, entries, nent); if (kvm_hlt_in_guest(vcpu->kvm) && best && (best->eax & (1 << KVM_FEATURE_PV_UNHALT))) kvm_cpuid = __kvm_get_hypervisor_cpuid(entries, nent, KVM_SIGNATURE); if (kvm_cpuid.base) { best = __kvm_find_kvm_cpuid_features(entries, nent, kvm_cpuid.base); if (kvm_hlt_in_guest(vcpu->kvm) && best) best->eax &= ~(1 << KVM_FEATURE_PV_UNHALT); } if (!kvm_check_has_quirk(vcpu->kvm, KVM_X86_QUIRK_MISC_ENABLE_NO_MWAIT)) { best = cpuid_entry2_find(entries, nent, 0x1, KVM_CPUID_INDEX_NOT_SIGNIFICANT); Loading tools/testing/selftests/kvm/include/x86_64/processor.h +11 −0 Original line number Diff line number Diff line Loading @@ -1037,8 +1037,19 @@ static inline void vcpu_set_cpuid(struct kvm_vcpu *vcpu) void vcpu_set_cpuid_property(struct kvm_vcpu *vcpu, struct kvm_x86_cpu_property property, uint32_t value); void vcpu_set_cpuid_maxphyaddr(struct kvm_vcpu *vcpu, uint8_t maxphyaddr); void vcpu_clear_cpuid_entry(struct kvm_vcpu *vcpu, uint32_t function); 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_or_clear_cpuid_feature(struct kvm_vcpu *vcpu, struct kvm_x86_cpu_feature feature, bool set); Loading tools/testing/selftests/kvm/x86_64/kvm_pv_test.c +39 −0 Original line number Diff line number Diff line Loading @@ -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; Loading @@ -151,4 +188,6 @@ int main(void) enter_guest(vcpu); kvm_vm_free(vm); test_pv_unhalt(); } Loading
arch/x86/kvm/cpuid.c +26 −16 Original line number Diff line number Diff line Loading @@ -189,15 +189,15 @@ static int kvm_cpuid_check_equal(struct kvm_vcpu *vcpu, struct kvm_cpuid_entry2 return 0; } static struct kvm_hypervisor_cpuid kvm_get_hypervisor_cpuid(struct kvm_vcpu *vcpu, const char *sig) static struct kvm_hypervisor_cpuid __kvm_get_hypervisor_cpuid(struct kvm_cpuid_entry2 *entries, int nent, const char *sig) { struct kvm_hypervisor_cpuid cpuid = {}; struct kvm_cpuid_entry2 *entry; u32 base; for_each_possible_hypervisor_cpuid_base(base) { entry = kvm_find_cpuid_entry(vcpu, base); entry = cpuid_entry2_find(entries, nent, base, KVM_CPUID_INDEX_NOT_SIGNIFICANT); if (entry) { u32 signature[3]; Loading @@ -217,22 +217,29 @@ static struct kvm_hypervisor_cpuid kvm_get_hypervisor_cpuid(struct kvm_vcpu *vcp return cpuid; } static struct kvm_cpuid_entry2 *__kvm_find_kvm_cpuid_features(struct kvm_vcpu *vcpu, struct kvm_cpuid_entry2 *entries, int nent) static struct kvm_hypervisor_cpuid kvm_get_hypervisor_cpuid(struct kvm_vcpu *vcpu, const char *sig) { u32 base = vcpu->arch.kvm_cpuid.base; if (!base) return NULL; return __kvm_get_hypervisor_cpuid(vcpu->arch.cpuid_entries, vcpu->arch.cpuid_nent, sig); } return cpuid_entry2_find(entries, nent, base | KVM_CPUID_FEATURES, static struct kvm_cpuid_entry2 *__kvm_find_kvm_cpuid_features(struct kvm_cpuid_entry2 *entries, int nent, u32 kvm_cpuid_base) { return cpuid_entry2_find(entries, nent, kvm_cpuid_base | KVM_CPUID_FEATURES, KVM_CPUID_INDEX_NOT_SIGNIFICANT); } static struct kvm_cpuid_entry2 *kvm_find_kvm_cpuid_features(struct kvm_vcpu *vcpu) { return __kvm_find_kvm_cpuid_features(vcpu, vcpu->arch.cpuid_entries, vcpu->arch.cpuid_nent); u32 base = vcpu->arch.kvm_cpuid.base; if (!base) return NULL; return __kvm_find_kvm_cpuid_features(vcpu->arch.cpuid_entries, vcpu->arch.cpuid_nent, base); } void kvm_update_pv_runtime(struct kvm_vcpu *vcpu) Loading Loading @@ -266,6 +273,7 @@ static void __kvm_update_cpuid_runtime(struct kvm_vcpu *vcpu, struct kvm_cpuid_e int nent) { struct kvm_cpuid_entry2 *best; struct kvm_hypervisor_cpuid kvm_cpuid; best = cpuid_entry2_find(entries, nent, 1, KVM_CPUID_INDEX_NOT_SIGNIFICANT); if (best) { Loading @@ -292,10 +300,12 @@ static void __kvm_update_cpuid_runtime(struct kvm_vcpu *vcpu, struct kvm_cpuid_e cpuid_entry_has(best, X86_FEATURE_XSAVEC))) best->ebx = xstate_required_size(vcpu->arch.xcr0, true); best = __kvm_find_kvm_cpuid_features(vcpu, entries, nent); if (kvm_hlt_in_guest(vcpu->kvm) && best && (best->eax & (1 << KVM_FEATURE_PV_UNHALT))) kvm_cpuid = __kvm_get_hypervisor_cpuid(entries, nent, KVM_SIGNATURE); if (kvm_cpuid.base) { best = __kvm_find_kvm_cpuid_features(entries, nent, kvm_cpuid.base); if (kvm_hlt_in_guest(vcpu->kvm) && best) best->eax &= ~(1 << KVM_FEATURE_PV_UNHALT); } if (!kvm_check_has_quirk(vcpu->kvm, KVM_X86_QUIRK_MISC_ENABLE_NO_MWAIT)) { best = cpuid_entry2_find(entries, nent, 0x1, KVM_CPUID_INDEX_NOT_SIGNIFICANT); Loading
tools/testing/selftests/kvm/include/x86_64/processor.h +11 −0 Original line number Diff line number Diff line Loading @@ -1037,8 +1037,19 @@ static inline void vcpu_set_cpuid(struct kvm_vcpu *vcpu) void vcpu_set_cpuid_property(struct kvm_vcpu *vcpu, struct kvm_x86_cpu_property property, uint32_t value); void vcpu_set_cpuid_maxphyaddr(struct kvm_vcpu *vcpu, uint8_t maxphyaddr); void vcpu_clear_cpuid_entry(struct kvm_vcpu *vcpu, uint32_t function); 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_or_clear_cpuid_feature(struct kvm_vcpu *vcpu, struct kvm_x86_cpu_feature feature, bool set); Loading
tools/testing/selftests/kvm/x86_64/kvm_pv_test.c +39 −0 Original line number Diff line number Diff line Loading @@ -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; Loading @@ -151,4 +188,6 @@ int main(void) enter_guest(vcpu); kvm_vm_free(vm); test_pv_unhalt(); }