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.
Unified · Split
| @@ -611,6 +611,8 @@ struct kvm_vcpu_arch { · 610 unmodified lines | ||
| 611 | 611 | unsigned long dr7; |
| 612 | 612 | unsigned long eff_db[KVM_NR_DB_REGS]; |
| 613 | 613 | unsigned long guest_debug_dr7; |
| 614 | + u64 msr_platform_info; | |
| 615 | + u64 msr_misc_features_enables; | |
| 614 | 616 | |
| 615 | 617 | u64 mcg_cap; |
| 616 | 618 | u64 mcg_status; |
| @@ -876,6 +876,9 @@ int kvm_emulate_cpuid(struct kvm_vcpu *vcpu) · 875 unmodified lines | ||
| 876 | 876 | { |
| 877 | 877 | u32 eax, ebx, ecx, edx; |
| 878 | 878 | |
| 879 | + if (cpuid_fault_enabled(vcpu) && !kvm_require_cpl(vcpu, 0)) | |
| 880 | + return 1; | |
| 881 | + | |
| 879 | 882 | eax = kvm_register_read(vcpu, VCPU_REGS_RAX); |
| 880 | 883 | ecx = kvm_register_read(vcpu, VCPU_REGS_RCX); |
| 881 | 884 | kvm_cpuid(vcpu, &eax, &ebx, &ecx, &edx); |
| @@ -205,4 +205,15 @@ static inline int guest_cpuid_stepping(struct kvm_vcpu *vcpu) · 204 unmodified lines | ||
| 205 | 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 | 219 | #endif |
| @@ -3854,6 +3854,13 @@ static int em_sti(struct x86_emulate_ctxt *ctxt) · 3853 unmodified lines | ||
| 3854 | 3854 | static int em_cpuid(struct x86_emulate_ctxt *ctxt) |
| 3855 | 3855 | { |
| 3856 | 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 | 3865 | eax = reg_read(ctxt, VCPU_REGS_RAX); |
| 3859 | 3866 | ecx = reg_read(ctxt, VCPU_REGS_RCX); |
| @@ -1007,6 +1007,8 @@ static u32 emulated_msrs[] = { · 1006 unmodified lines | ||
| 1007 | 1007 | MSR_IA32_MCG_CTL, |
| 1008 | 1008 | MSR_IA32_MCG_EXT_CTL, |
| 1009 | 1009 | MSR_IA32_SMBASE, |
| 1010 | + MSR_PLATFORM_INFO, | |
| 1011 | + MSR_MISC_FEATURES_ENABLES, | |
| 1010 | 1012 | }; |
| 1011 | 1013 | |
| 1012 | 1014 | static unsigned num_emulated_msrs; |
| @@ -2314,6 +2316,21 @@ int kvm_set_msr_common(struct kvm_vcpu *vcpu, struct msr_data *msr_info) · 1301 unmodified lines | ||
| 2314 | 2316 | return 1; |
| 2315 | 2317 | vcpu->arch.osvw.status = data; |
| 2316 | 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 | 2334 | default: |
| 2318 | 2335 | if (msr && (msr == vcpu->kvm->arch.xen_hvm_config.msr)) |
| 2319 | 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) · 209 unmodified lines | ||
| 2529 | 2546 | return 1; |
| 2530 | 2547 | msr_info->data = vcpu->arch.osvw.status; |
| 2531 | 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 | 2555 | default: |
| 2533 | 2556 | if (kvm_pmu_is_valid_msr(vcpu, msr_info->index)) |
| 2534 | 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) · 5175 unmodified lines | ||
| 7710 | 7733 | if (!init_event) { |
| 7711 | 7734 | kvm_pmu_reset(vcpu); |
| 7712 | 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 | 7741 | memset(vcpu->arch.regs, 0, sizeof(vcpu->arch.regs)); |