diff options
-rw-r--r-- | arch/x86/include/asm/kvm_host.h | 6 | ||||
-rw-r--r-- | arch/x86/kvm/cpuid.c | 2 | ||||
-rw-r--r-- | arch/x86/kvm/cpuid.h | 8 | ||||
-rw-r--r-- | arch/x86/kvm/svm.c | 59 | ||||
-rw-r--r-- | arch/x86/kvm/x86.c | 20 |
5 files changed, 94 insertions, 1 deletions
diff --git a/arch/x86/include/asm/kvm_host.h b/arch/x86/include/asm/kvm_host.h index 52d6640a5ca1..bd69c93da8fa 100644 --- a/arch/x86/include/asm/kvm_host.h +++ b/arch/x86/include/asm/kvm_host.h | |||
@@ -478,6 +478,12 @@ struct kvm_vcpu_arch { | |||
478 | u32 id; | 478 | u32 id; |
479 | bool send_user_only; | 479 | bool send_user_only; |
480 | } apf; | 480 | } apf; |
481 | |||
482 | /* OSVW MSRs (AMD only) */ | ||
483 | struct { | ||
484 | u64 length; | ||
485 | u64 status; | ||
486 | } osvw; | ||
481 | }; | 487 | }; |
482 | 488 | ||
483 | struct kvm_arch { | 489 | struct kvm_arch { |
diff --git a/arch/x86/kvm/cpuid.c b/arch/x86/kvm/cpuid.c index 89b02bfaaca5..9fed5bedaad6 100644 --- a/arch/x86/kvm/cpuid.c +++ b/arch/x86/kvm/cpuid.c | |||
@@ -236,7 +236,7 @@ static int do_cpuid_ent(struct kvm_cpuid_entry2 *entry, u32 function, | |||
236 | const u32 kvm_supported_word6_x86_features = | 236 | const u32 kvm_supported_word6_x86_features = |
237 | F(LAHF_LM) | F(CMP_LEGACY) | 0 /*SVM*/ | 0 /* ExtApicSpace */ | | 237 | F(LAHF_LM) | F(CMP_LEGACY) | 0 /*SVM*/ | 0 /* ExtApicSpace */ | |
238 | F(CR8_LEGACY) | F(ABM) | F(SSE4A) | F(MISALIGNSSE) | | 238 | F(CR8_LEGACY) | F(ABM) | F(SSE4A) | F(MISALIGNSSE) | |
239 | F(3DNOWPREFETCH) | 0 /* OSVW */ | 0 /* IBS */ | F(XOP) | | 239 | F(3DNOWPREFETCH) | F(OSVW) | 0 /* IBS */ | F(XOP) | |
240 | 0 /* SKINIT, WDT, LWP */ | F(FMA4) | F(TBM); | 240 | 0 /* SKINIT, WDT, LWP */ | F(FMA4) | F(TBM); |
241 | 241 | ||
242 | /* cpuid 0xC0000001.edx */ | 242 | /* cpuid 0xC0000001.edx */ |
diff --git a/arch/x86/kvm/cpuid.h b/arch/x86/kvm/cpuid.h index 5b97e1797a6d..26d1fb437eb5 100644 --- a/arch/x86/kvm/cpuid.h +++ b/arch/x86/kvm/cpuid.h | |||
@@ -43,4 +43,12 @@ static inline bool guest_cpuid_has_fsgsbase(struct kvm_vcpu *vcpu) | |||
43 | return best && (best->ebx & bit(X86_FEATURE_FSGSBASE)); | 43 | return best && (best->ebx & bit(X86_FEATURE_FSGSBASE)); |
44 | } | 44 | } |
45 | 45 | ||
46 | static inline bool guest_cpuid_has_osvw(struct kvm_vcpu *vcpu) | ||
47 | { | ||
48 | struct kvm_cpuid_entry2 *best; | ||
49 | |||
50 | best = kvm_find_cpuid_entry(vcpu, 0x80000001, 0); | ||
51 | return best && (best->ecx & bit(X86_FEATURE_OSVW)); | ||
52 | } | ||
53 | |||
46 | #endif | 54 | #endif |
diff --git a/arch/x86/kvm/svm.c b/arch/x86/kvm/svm.c index 5fa553babe56..fce3ba0f2079 100644 --- a/arch/x86/kvm/svm.c +++ b/arch/x86/kvm/svm.c | |||
@@ -110,6 +110,12 @@ struct nested_state { | |||
110 | #define MSRPM_OFFSETS 16 | 110 | #define MSRPM_OFFSETS 16 |
111 | static u32 msrpm_offsets[MSRPM_OFFSETS] __read_mostly; | 111 | static u32 msrpm_offsets[MSRPM_OFFSETS] __read_mostly; |
112 | 112 | ||
113 | /* | ||
114 | * Set osvw_len to higher value when updated Revision Guides | ||
115 | * are published and we know what the new status bits are | ||
116 | */ | ||
117 | static uint64_t osvw_len = 4, osvw_status; | ||
118 | |||
113 | struct vcpu_svm { | 119 | struct vcpu_svm { |
114 | struct kvm_vcpu vcpu; | 120 | struct kvm_vcpu vcpu; |
115 | struct vmcb *vmcb; | 121 | struct vmcb *vmcb; |
@@ -556,6 +562,27 @@ static void svm_init_erratum_383(void) | |||
556 | erratum_383_found = true; | 562 | erratum_383_found = true; |
557 | } | 563 | } |
558 | 564 | ||
565 | static void svm_init_osvw(struct kvm_vcpu *vcpu) | ||
566 | { | ||
567 | /* | ||
568 | * Guests should see errata 400 and 415 as fixed (assuming that | ||
569 | * HLT and IO instructions are intercepted). | ||
570 | */ | ||
571 | vcpu->arch.osvw.length = (osvw_len >= 3) ? (osvw_len) : 3; | ||
572 | vcpu->arch.osvw.status = osvw_status & ~(6ULL); | ||
573 | |||
574 | /* | ||
575 | * By increasing VCPU's osvw.length to 3 we are telling the guest that | ||
576 | * all osvw.status bits inside that length, including bit 0 (which is | ||
577 | * reserved for erratum 298), are valid. However, if host processor's | ||
578 | * osvw_len is 0 then osvw_status[0] carries no information. We need to | ||
579 | * be conservative here and therefore we tell the guest that erratum 298 | ||
580 | * is present (because we really don't know). | ||
581 | */ | ||
582 | if (osvw_len == 0 && boot_cpu_data.x86 == 0x10) | ||
583 | vcpu->arch.osvw.status |= 1; | ||
584 | } | ||
585 | |||
559 | static int has_svm(void) | 586 | static int has_svm(void) |
560 | { | 587 | { |
561 | const char *msg; | 588 | const char *msg; |
@@ -620,6 +647,36 @@ static int svm_hardware_enable(void *garbage) | |||
620 | __get_cpu_var(current_tsc_ratio) = TSC_RATIO_DEFAULT; | 647 | __get_cpu_var(current_tsc_ratio) = TSC_RATIO_DEFAULT; |
621 | } | 648 | } |
622 | 649 | ||
650 | |||
651 | /* | ||
652 | * Get OSVW bits. | ||
653 | * | ||
654 | * Note that it is possible to have a system with mixed processor | ||
655 | * revisions and therefore different OSVW bits. If bits are not the same | ||
656 | * on different processors then choose the worst case (i.e. if erratum | ||
657 | * is present on one processor and not on another then assume that the | ||
658 | * erratum is present everywhere). | ||
659 | */ | ||
660 | if (cpu_has(&boot_cpu_data, X86_FEATURE_OSVW)) { | ||
661 | uint64_t len, status = 0; | ||
662 | int err; | ||
663 | |||
664 | len = native_read_msr_safe(MSR_AMD64_OSVW_ID_LENGTH, &err); | ||
665 | if (!err) | ||
666 | status = native_read_msr_safe(MSR_AMD64_OSVW_STATUS, | ||
667 | &err); | ||
668 | |||
669 | if (err) | ||
670 | osvw_status = osvw_len = 0; | ||
671 | else { | ||
672 | if (len < osvw_len) | ||
673 | osvw_len = len; | ||
674 | osvw_status |= status; | ||
675 | osvw_status &= (1ULL << osvw_len) - 1; | ||
676 | } | ||
677 | } else | ||
678 | osvw_status = osvw_len = 0; | ||
679 | |||
623 | svm_init_erratum_383(); | 680 | svm_init_erratum_383(); |
624 | 681 | ||
625 | return 0; | 682 | return 0; |
@@ -1186,6 +1243,8 @@ static struct kvm_vcpu *svm_create_vcpu(struct kvm *kvm, unsigned int id) | |||
1186 | if (kvm_vcpu_is_bsp(&svm->vcpu)) | 1243 | if (kvm_vcpu_is_bsp(&svm->vcpu)) |
1187 | svm->vcpu.arch.apic_base |= MSR_IA32_APICBASE_BSP; | 1244 | svm->vcpu.arch.apic_base |= MSR_IA32_APICBASE_BSP; |
1188 | 1245 | ||
1246 | svm_init_osvw(&svm->vcpu); | ||
1247 | |||
1189 | return &svm->vcpu; | 1248 | return &svm->vcpu; |
1190 | 1249 | ||
1191 | free_page4: | 1250 | free_page4: |
diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c index a3ce196d21fe..2bd77a3a41ed 100644 --- a/arch/x86/kvm/x86.c +++ b/arch/x86/kvm/x86.c | |||
@@ -1675,6 +1675,16 @@ int kvm_set_msr_common(struct kvm_vcpu *vcpu, u32 msr, u64 data) | |||
1675 | */ | 1675 | */ |
1676 | pr_unimpl(vcpu, "ignored wrmsr: 0x%x data %llx\n", msr, data); | 1676 | pr_unimpl(vcpu, "ignored wrmsr: 0x%x data %llx\n", msr, data); |
1677 | break; | 1677 | break; |
1678 | case MSR_AMD64_OSVW_ID_LENGTH: | ||
1679 | if (!guest_cpuid_has_osvw(vcpu)) | ||
1680 | return 1; | ||
1681 | vcpu->arch.osvw.length = data; | ||
1682 | break; | ||
1683 | case MSR_AMD64_OSVW_STATUS: | ||
1684 | if (!guest_cpuid_has_osvw(vcpu)) | ||
1685 | return 1; | ||
1686 | vcpu->arch.osvw.status = data; | ||
1687 | break; | ||
1678 | default: | 1688 | default: |
1679 | if (msr && (msr == vcpu->kvm->arch.xen_hvm_config.msr)) | 1689 | if (msr && (msr == vcpu->kvm->arch.xen_hvm_config.msr)) |
1680 | return xen_hvm_config(vcpu, data); | 1690 | return xen_hvm_config(vcpu, data); |
@@ -1959,6 +1969,16 @@ int kvm_get_msr_common(struct kvm_vcpu *vcpu, u32 msr, u64 *pdata) | |||
1959 | */ | 1969 | */ |
1960 | data = 0xbe702111; | 1970 | data = 0xbe702111; |
1961 | break; | 1971 | break; |
1972 | case MSR_AMD64_OSVW_ID_LENGTH: | ||
1973 | if (!guest_cpuid_has_osvw(vcpu)) | ||
1974 | return 1; | ||
1975 | data = vcpu->arch.osvw.length; | ||
1976 | break; | ||
1977 | case MSR_AMD64_OSVW_STATUS: | ||
1978 | if (!guest_cpuid_has_osvw(vcpu)) | ||
1979 | return 1; | ||
1980 | data = vcpu->arch.osvw.status; | ||
1981 | break; | ||
1962 | default: | 1982 | default: |
1963 | if (kvm_pmu_msr(vcpu, msr)) | 1983 | if (kvm_pmu_msr(vcpu, msr)) |
1964 | return kvm_pmu_get_msr(vcpu, msr, pdata); | 1984 | return kvm_pmu_get_msr(vcpu, msr, pdata); |