diff options
| author | Kyle Huey <me@kylehuey.com> | 2017-03-20 04:16:28 -0400 |
|---|---|---|
| committer | Paolo Bonzini <pbonzini@redhat.com> | 2017-04-21 06:50:06 -0400 |
| commit | db2336a80489e7c3c7728cefd9be58fac5ecfb39 (patch) | |
| tree | 2a462ecee35d68dea1b931ba5ee226933e663cd0 | |
| parent | bd17117bb2af60d4bc44e0f9c859e800a3d99722 (diff) | |
KVM: x86: virtualize cpuid faulting
Hardware support for faulting on the cpuid instruction is not required to
emulate it, because cpuid triggers a VM exit anyways. KVM handles the relevant
MSRs (MSR_PLATFORM_INFO and MSR_MISC_FEATURES_ENABLE) and upon a
cpuid-induced VM exit checks the cpuid faulting state and the CPL.
kvm_require_cpl is even kind enough to inject the GP fault for us.
Signed-off-by: Kyle Huey <khuey@kylehuey.com>
Reviewed-by: David Matlack <dmatlack@google.com>
[Return "1" from kvm_emulate_cpuid, it's not void. - Paolo]
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
| -rw-r--r-- | arch/x86/include/asm/kvm_host.h | 2 | ||||
| -rw-r--r-- | arch/x86/kvm/cpuid.c | 3 | ||||
| -rw-r--r-- | arch/x86/kvm/cpuid.h | 11 | ||||
| -rw-r--r-- | arch/x86/kvm/emulate.c | 7 | ||||
| -rw-r--r-- | arch/x86/kvm/x86.c | 26 |
5 files changed, 49 insertions, 0 deletions
diff --git a/arch/x86/include/asm/kvm_host.h b/arch/x86/include/asm/kvm_host.h index 2cc5ec7cc6f5..f5c942edbc86 100644 --- a/arch/x86/include/asm/kvm_host.h +++ b/arch/x86/include/asm/kvm_host.h | |||
| @@ -611,6 +611,8 @@ struct kvm_vcpu_arch { | |||
| 611 | unsigned long dr7; | 611 | unsigned long dr7; |
| 612 | unsigned long eff_db[KVM_NR_DB_REGS]; | 612 | unsigned long eff_db[KVM_NR_DB_REGS]; |
| 613 | unsigned long guest_debug_dr7; | 613 | unsigned long guest_debug_dr7; |
| 614 | u64 msr_platform_info; | ||
| 615 | u64 msr_misc_features_enables; | ||
| 614 | 616 | ||
| 615 | u64 mcg_cap; | 617 | u64 mcg_cap; |
| 616 | u64 mcg_status; | 618 | u64 mcg_status; |
diff --git a/arch/x86/kvm/cpuid.c b/arch/x86/kvm/cpuid.c index efde6cc50875..a181ae76c71c 100644 --- a/arch/x86/kvm/cpuid.c +++ b/arch/x86/kvm/cpuid.c | |||
| @@ -876,6 +876,9 @@ int kvm_emulate_cpuid(struct kvm_vcpu *vcpu) | |||
| 876 | { | 876 | { |
| 877 | u32 eax, ebx, ecx, edx; | 877 | u32 eax, ebx, ecx, edx; |
| 878 | 878 | ||
| 879 | if (cpuid_fault_enabled(vcpu) && !kvm_require_cpl(vcpu, 0)) | ||
| 880 | return 1; | ||
| 881 | |||
| 879 | eax = kvm_register_read(vcpu, VCPU_REGS_RAX); | 882 | eax = kvm_register_read(vcpu, VCPU_REGS_RAX); |
| 880 | ecx = kvm_register_read(vcpu, VCPU_REGS_RCX); | 883 | ecx = kvm_register_read(vcpu, VCPU_REGS_RCX); |
| 881 | kvm_cpuid(vcpu, &eax, &ebx, &ecx, &edx); | 884 | kvm_cpuid(vcpu, &eax, &ebx, &ecx, &edx); |
diff --git a/arch/x86/kvm/cpuid.h b/arch/x86/kvm/cpuid.h index 35058c2c0eea..a6fd40aade7c 100644 --- a/arch/x86/kvm/cpuid.h +++ b/arch/x86/kvm/cpuid.h | |||
| @@ -205,4 +205,15 @@ static inline int guest_cpuid_stepping(struct kvm_vcpu *vcpu) | |||
| 205 | return x86_stepping(best->eax); | 205 | return x86_stepping(best->eax); |
| 206 | } | 206 | } |
| 207 | 207 | ||
| 208 | static inline bool supports_cpuid_fault(struct kvm_vcpu *vcpu) | ||
| 209 | { | ||
| 210 | return vcpu->arch.msr_platform_info & MSR_PLATFORM_INFO_CPUID_FAULT; | ||
| 211 | } | ||
| 212 | |||
| 213 | static inline bool cpuid_fault_enabled(struct kvm_vcpu *vcpu) | ||
| 214 | { | ||
| 215 | return vcpu->arch.msr_misc_features_enables & | ||
| 216 | MSR_MISC_FEATURES_ENABLES_CPUID_FAULT; | ||
| 217 | } | ||
| 218 | |||
| 208 | #endif | 219 | #endif |
diff --git a/arch/x86/kvm/emulate.c b/arch/x86/kvm/emulate.c index 45c7306c8780..6a2ea945d01f 100644 --- a/arch/x86/kvm/emulate.c +++ b/arch/x86/kvm/emulate.c | |||
| @@ -3854,6 +3854,13 @@ static int em_sti(struct x86_emulate_ctxt *ctxt) | |||
| 3854 | static int em_cpuid(struct x86_emulate_ctxt *ctxt) | 3854 | static int em_cpuid(struct x86_emulate_ctxt *ctxt) |
| 3855 | { | 3855 | { |
| 3856 | u32 eax, ebx, ecx, edx; | 3856 | u32 eax, ebx, ecx, edx; |
| 3857 | u64 msr = 0; | ||
| 3858 | |||
| 3859 | ctxt->ops->get_msr(ctxt, MSR_MISC_FEATURES_ENABLES, &msr); | ||
| 3860 | if (msr & MSR_MISC_FEATURES_ENABLES_CPUID_FAULT && | ||
| 3861 | ctxt->ops->cpl(ctxt)) { | ||
| 3862 | return emulate_gp(ctxt, 0); | ||
| 3863 | } | ||
| 3857 | 3864 | ||
| 3858 | eax = reg_read(ctxt, VCPU_REGS_RAX); | 3865 | eax = reg_read(ctxt, VCPU_REGS_RAX); |
| 3859 | ecx = reg_read(ctxt, VCPU_REGS_RCX); | 3866 | ecx = reg_read(ctxt, VCPU_REGS_RCX); |
diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c index 34bf64fb4dea..49a69c0a0d50 100644 --- a/arch/x86/kvm/x86.c +++ b/arch/x86/kvm/x86.c | |||
| @@ -1007,6 +1007,8 @@ static u32 emulated_msrs[] = { | |||
| 1007 | MSR_IA32_MCG_CTL, | 1007 | MSR_IA32_MCG_CTL, |
| 1008 | MSR_IA32_MCG_EXT_CTL, | 1008 | MSR_IA32_MCG_EXT_CTL, |
| 1009 | MSR_IA32_SMBASE, | 1009 | MSR_IA32_SMBASE, |
| 1010 | MSR_PLATFORM_INFO, | ||
| 1011 | MSR_MISC_FEATURES_ENABLES, | ||
| 1010 | }; | 1012 | }; |
| 1011 | 1013 | ||
| 1012 | static unsigned num_emulated_msrs; | 1014 | static unsigned num_emulated_msrs; |
| @@ -2314,6 +2316,21 @@ int kvm_set_msr_common(struct kvm_vcpu *vcpu, struct msr_data *msr_info) | |||
| 2314 | return 1; | 2316 | return 1; |
| 2315 | vcpu->arch.osvw.status = data; | 2317 | vcpu->arch.osvw.status = data; |
| 2316 | break; | 2318 | break; |
| 2319 | case MSR_PLATFORM_INFO: | ||
| 2320 | if (!msr_info->host_initiated || | ||
| 2321 | data & ~MSR_PLATFORM_INFO_CPUID_FAULT || | ||
| 2322 | (!(data & MSR_PLATFORM_INFO_CPUID_FAULT) && | ||
| 2323 | cpuid_fault_enabled(vcpu))) | ||
| 2324 | return 1; | ||
| 2325 | vcpu->arch.msr_platform_info = data; | ||
| 2326 | break; | ||
| 2327 | case MSR_MISC_FEATURES_ENABLES: | ||
| 2328 | if (data & ~MSR_MISC_FEATURES_ENABLES_CPUID_FAULT || | ||
| 2329 | (data & MSR_MISC_FEATURES_ENABLES_CPUID_FAULT && | ||
| 2330 | !supports_cpuid_fault(vcpu))) | ||
| 2331 | return 1; | ||
| 2332 | vcpu->arch.msr_misc_features_enables = data; | ||
| 2333 | break; | ||
| 2317 | default: | 2334 | default: |
| 2318 | if (msr && (msr == vcpu->kvm->arch.xen_hvm_config.msr)) | 2335 | if (msr && (msr == vcpu->kvm->arch.xen_hvm_config.msr)) |
| 2319 | return xen_hvm_config(vcpu, data); | 2336 | return xen_hvm_config(vcpu, data); |
| @@ -2529,6 +2546,12 @@ int kvm_get_msr_common(struct kvm_vcpu *vcpu, struct msr_data *msr_info) | |||
| 2529 | return 1; | 2546 | return 1; |
| 2530 | msr_info->data = vcpu->arch.osvw.status; | 2547 | msr_info->data = vcpu->arch.osvw.status; |
| 2531 | break; | 2548 | break; |
| 2549 | case MSR_PLATFORM_INFO: | ||
| 2550 | msr_info->data = vcpu->arch.msr_platform_info; | ||
| 2551 | break; | ||
| 2552 | case MSR_MISC_FEATURES_ENABLES: | ||
| 2553 | msr_info->data = vcpu->arch.msr_misc_features_enables; | ||
| 2554 | break; | ||
| 2532 | default: | 2555 | default: |
| 2533 | if (kvm_pmu_is_valid_msr(vcpu, msr_info->index)) | 2556 | if (kvm_pmu_is_valid_msr(vcpu, msr_info->index)) |
| 2534 | return kvm_pmu_get_msr(vcpu, msr_info->index, &msr_info->data); | 2557 | return kvm_pmu_get_msr(vcpu, msr_info->index, &msr_info->data); |
| @@ -7710,6 +7733,9 @@ void kvm_vcpu_reset(struct kvm_vcpu *vcpu, bool init_event) | |||
| 7710 | if (!init_event) { | 7733 | if (!init_event) { |
| 7711 | kvm_pmu_reset(vcpu); | 7734 | kvm_pmu_reset(vcpu); |
| 7712 | vcpu->arch.smbase = 0x30000; | 7735 | vcpu->arch.smbase = 0x30000; |
| 7736 | |||
| 7737 | vcpu->arch.msr_platform_info = MSR_PLATFORM_INFO_CPUID_FAULT; | ||
| 7738 | vcpu->arch.msr_misc_features_enables = 0; | ||
| 7713 | } | 7739 | } |
| 7714 | 7740 | ||
| 7715 | memset(vcpu->arch.regs, 0, sizeof(vcpu->arch.regs)); | 7741 | memset(vcpu->arch.regs, 0, sizeof(vcpu->arch.regs)); |
