diff options
-rw-r--r-- | arch/x86/include/asm/msr-index.h | 1 | ||||
-rw-r--r-- | arch/x86/kvm/svm.c | 54 |
2 files changed, 54 insertions, 1 deletions
diff --git a/arch/x86/include/asm/msr-index.h b/arch/x86/include/asm/msr-index.h index 3cce71413d0b..485b4f1f079b 100644 --- a/arch/x86/include/asm/msr-index.h +++ b/arch/x86/include/asm/msr-index.h | |||
@@ -118,6 +118,7 @@ | |||
118 | complete list. */ | 118 | complete list. */ |
119 | 119 | ||
120 | #define MSR_AMD64_PATCH_LEVEL 0x0000008b | 120 | #define MSR_AMD64_PATCH_LEVEL 0x0000008b |
121 | #define MSR_AMD64_TSC_RATIO 0xc0000104 | ||
121 | #define MSR_AMD64_NB_CFG 0xc001001f | 122 | #define MSR_AMD64_NB_CFG 0xc001001f |
122 | #define MSR_AMD64_PATCH_LOADER 0xc0010020 | 123 | #define MSR_AMD64_PATCH_LOADER 0xc0010020 |
123 | #define MSR_AMD64_OSVW_ID_LENGTH 0xc0010140 | 124 | #define MSR_AMD64_OSVW_ID_LENGTH 0xc0010140 |
diff --git a/arch/x86/kvm/svm.c b/arch/x86/kvm/svm.c index 779b09194f03..830150099958 100644 --- a/arch/x86/kvm/svm.c +++ b/arch/x86/kvm/svm.c | |||
@@ -63,6 +63,8 @@ MODULE_LICENSE("GPL"); | |||
63 | 63 | ||
64 | #define DEBUGCTL_RESERVED_BITS (~(0x3fULL)) | 64 | #define DEBUGCTL_RESERVED_BITS (~(0x3fULL)) |
65 | 65 | ||
66 | #define TSC_RATIO_RSVD 0xffffff0000000000ULL | ||
67 | |||
66 | static bool erratum_383_found __read_mostly; | 68 | static bool erratum_383_found __read_mostly; |
67 | 69 | ||
68 | static const u32 host_save_user_msrs[] = { | 70 | static const u32 host_save_user_msrs[] = { |
@@ -136,8 +138,13 @@ struct vcpu_svm { | |||
136 | unsigned int3_injected; | 138 | unsigned int3_injected; |
137 | unsigned long int3_rip; | 139 | unsigned long int3_rip; |
138 | u32 apf_reason; | 140 | u32 apf_reason; |
141 | |||
142 | u64 tsc_ratio; | ||
139 | }; | 143 | }; |
140 | 144 | ||
145 | static DEFINE_PER_CPU(u64, current_tsc_ratio); | ||
146 | #define TSC_RATIO_DEFAULT 0x0100000000ULL | ||
147 | |||
141 | #define MSR_INVALID 0xffffffffU | 148 | #define MSR_INVALID 0xffffffffU |
142 | 149 | ||
143 | static struct svm_direct_access_msrs { | 150 | static struct svm_direct_access_msrs { |
@@ -560,6 +567,10 @@ static int has_svm(void) | |||
560 | 567 | ||
561 | static void svm_hardware_disable(void *garbage) | 568 | static void svm_hardware_disable(void *garbage) |
562 | { | 569 | { |
570 | /* Make sure we clean up behind us */ | ||
571 | if (static_cpu_has(X86_FEATURE_TSCRATEMSR)) | ||
572 | wrmsrl(MSR_AMD64_TSC_RATIO, TSC_RATIO_DEFAULT); | ||
573 | |||
563 | cpu_svm_disable(); | 574 | cpu_svm_disable(); |
564 | } | 575 | } |
565 | 576 | ||
@@ -601,6 +612,11 @@ static int svm_hardware_enable(void *garbage) | |||
601 | 612 | ||
602 | wrmsrl(MSR_VM_HSAVE_PA, page_to_pfn(sd->save_area) << PAGE_SHIFT); | 613 | wrmsrl(MSR_VM_HSAVE_PA, page_to_pfn(sd->save_area) << PAGE_SHIFT); |
603 | 614 | ||
615 | if (static_cpu_has(X86_FEATURE_TSCRATEMSR)) { | ||
616 | wrmsrl(MSR_AMD64_TSC_RATIO, TSC_RATIO_DEFAULT); | ||
617 | __get_cpu_var(current_tsc_ratio) = TSC_RATIO_DEFAULT; | ||
618 | } | ||
619 | |||
604 | svm_init_erratum_383(); | 620 | svm_init_erratum_383(); |
605 | 621 | ||
606 | return 0; | 622 | return 0; |
@@ -843,6 +859,32 @@ static void init_sys_seg(struct vmcb_seg *seg, uint32_t type) | |||
843 | seg->base = 0; | 859 | seg->base = 0; |
844 | } | 860 | } |
845 | 861 | ||
862 | static u64 __scale_tsc(u64 ratio, u64 tsc) | ||
863 | { | ||
864 | u64 mult, frac, _tsc; | ||
865 | |||
866 | mult = ratio >> 32; | ||
867 | frac = ratio & ((1ULL << 32) - 1); | ||
868 | |||
869 | _tsc = tsc; | ||
870 | _tsc *= mult; | ||
871 | _tsc += (tsc >> 32) * frac; | ||
872 | _tsc += ((tsc & ((1ULL << 32) - 1)) * frac) >> 32; | ||
873 | |||
874 | return _tsc; | ||
875 | } | ||
876 | |||
877 | static u64 svm_scale_tsc(struct kvm_vcpu *vcpu, u64 tsc) | ||
878 | { | ||
879 | struct vcpu_svm *svm = to_svm(vcpu); | ||
880 | u64 _tsc = tsc; | ||
881 | |||
882 | if (svm->tsc_ratio != TSC_RATIO_DEFAULT) | ||
883 | _tsc = __scale_tsc(svm->tsc_ratio, tsc); | ||
884 | |||
885 | return _tsc; | ||
886 | } | ||
887 | |||
846 | static void svm_write_tsc_offset(struct kvm_vcpu *vcpu, u64 offset) | 888 | static void svm_write_tsc_offset(struct kvm_vcpu *vcpu, u64 offset) |
847 | { | 889 | { |
848 | struct vcpu_svm *svm = to_svm(vcpu); | 890 | struct vcpu_svm *svm = to_svm(vcpu); |
@@ -1037,6 +1079,8 @@ static struct kvm_vcpu *svm_create_vcpu(struct kvm *kvm, unsigned int id) | |||
1037 | goto out; | 1079 | goto out; |
1038 | } | 1080 | } |
1039 | 1081 | ||
1082 | svm->tsc_ratio = TSC_RATIO_DEFAULT; | ||
1083 | |||
1040 | err = kvm_vcpu_init(&svm->vcpu, kvm, id); | 1084 | err = kvm_vcpu_init(&svm->vcpu, kvm, id); |
1041 | if (err) | 1085 | if (err) |
1042 | goto free_svm; | 1086 | goto free_svm; |
@@ -1130,6 +1174,12 @@ static void svm_vcpu_load(struct kvm_vcpu *vcpu, int cpu) | |||
1130 | 1174 | ||
1131 | for (i = 0; i < NR_HOST_SAVE_USER_MSRS; i++) | 1175 | for (i = 0; i < NR_HOST_SAVE_USER_MSRS; i++) |
1132 | rdmsrl(host_save_user_msrs[i], svm->host_user_msrs[i]); | 1176 | rdmsrl(host_save_user_msrs[i], svm->host_user_msrs[i]); |
1177 | |||
1178 | if (static_cpu_has(X86_FEATURE_TSCRATEMSR) && | ||
1179 | svm->tsc_ratio != __get_cpu_var(current_tsc_ratio)) { | ||
1180 | __get_cpu_var(current_tsc_ratio) = svm->tsc_ratio; | ||
1181 | wrmsrl(MSR_AMD64_TSC_RATIO, svm->tsc_ratio); | ||
1182 | } | ||
1133 | } | 1183 | } |
1134 | 1184 | ||
1135 | static void svm_vcpu_put(struct kvm_vcpu *vcpu) | 1185 | static void svm_vcpu_put(struct kvm_vcpu *vcpu) |
@@ -2784,7 +2834,9 @@ static int svm_get_msr(struct kvm_vcpu *vcpu, unsigned ecx, u64 *data) | |||
2784 | case MSR_IA32_TSC: { | 2834 | case MSR_IA32_TSC: { |
2785 | struct vmcb *vmcb = get_host_vmcb(svm); | 2835 | struct vmcb *vmcb = get_host_vmcb(svm); |
2786 | 2836 | ||
2787 | *data = vmcb->control.tsc_offset + native_read_tsc(); | 2837 | *data = vmcb->control.tsc_offset + |
2838 | svm_scale_tsc(vcpu, native_read_tsc()); | ||
2839 | |||
2788 | break; | 2840 | break; |
2789 | } | 2841 | } |
2790 | case MSR_STAR: | 2842 | case MSR_STAR: |