diff options
author | Sheng Yang <sheng@linux.intel.com> | 2009-12-18 03:48:47 -0500 |
---|---|---|
committer | Marcelo Tosatti <mtosatti@redhat.com> | 2010-03-01 10:35:40 -0500 |
commit | 4e47c7a6d714cf352b719db92a924b6ec487acc5 (patch) | |
tree | b968765b85124e0b59f415bf8e4d499ef953236e /arch/x86 | |
parent | 0e85188049afacdfce9c026144142264981bbabb (diff) |
KVM: VMX: Add instruction rdtscp support for guest
Before enabling, execution of "rdtscp" in guest would result in #UD.
Signed-off-by: Sheng Yang <sheng@linux.intel.com>
Signed-off-by: Avi Kivity <avi@redhat.com>
Diffstat (limited to 'arch/x86')
-rw-r--r-- | arch/x86/include/asm/kvm_host.h | 1 | ||||
-rw-r--r-- | arch/x86/include/asm/vmx.h | 1 | ||||
-rw-r--r-- | arch/x86/kvm/svm.c | 7 | ||||
-rw-r--r-- | arch/x86/kvm/vmx.c | 60 | ||||
-rw-r--r-- | arch/x86/kvm/x86.c | 3 |
5 files changed, 68 insertions, 4 deletions
diff --git a/arch/x86/include/asm/kvm_host.h b/arch/x86/include/asm/kvm_host.h index 7ff0ea371e3c..fe4df464fb39 100644 --- a/arch/x86/include/asm/kvm_host.h +++ b/arch/x86/include/asm/kvm_host.h | |||
@@ -521,6 +521,7 @@ struct kvm_x86_ops { | |||
521 | int (*get_tdp_level)(void); | 521 | int (*get_tdp_level)(void); |
522 | u64 (*get_mt_mask)(struct kvm_vcpu *vcpu, gfn_t gfn, bool is_mmio); | 522 | u64 (*get_mt_mask)(struct kvm_vcpu *vcpu, gfn_t gfn, bool is_mmio); |
523 | bool (*gb_page_enable)(void); | 523 | bool (*gb_page_enable)(void); |
524 | bool (*rdtscp_supported)(void); | ||
524 | 525 | ||
525 | const struct trace_print_flags *exit_reasons_str; | 526 | const struct trace_print_flags *exit_reasons_str; |
526 | }; | 527 | }; |
diff --git a/arch/x86/include/asm/vmx.h b/arch/x86/include/asm/vmx.h index 8f6b0111446a..713ed9a5b1d3 100644 --- a/arch/x86/include/asm/vmx.h +++ b/arch/x86/include/asm/vmx.h | |||
@@ -53,6 +53,7 @@ | |||
53 | */ | 53 | */ |
54 | #define SECONDARY_EXEC_VIRTUALIZE_APIC_ACCESSES 0x00000001 | 54 | #define SECONDARY_EXEC_VIRTUALIZE_APIC_ACCESSES 0x00000001 |
55 | #define SECONDARY_EXEC_ENABLE_EPT 0x00000002 | 55 | #define SECONDARY_EXEC_ENABLE_EPT 0x00000002 |
56 | #define SECONDARY_EXEC_RDTSCP 0x00000008 | ||
56 | #define SECONDARY_EXEC_ENABLE_VPID 0x00000020 | 57 | #define SECONDARY_EXEC_ENABLE_VPID 0x00000020 |
57 | #define SECONDARY_EXEC_WBINVD_EXITING 0x00000040 | 58 | #define SECONDARY_EXEC_WBINVD_EXITING 0x00000040 |
58 | #define SECONDARY_EXEC_UNRESTRICTED_GUEST 0x00000080 | 59 | #define SECONDARY_EXEC_UNRESTRICTED_GUEST 0x00000080 |
diff --git a/arch/x86/kvm/svm.c b/arch/x86/kvm/svm.c index 41777e6d9761..7f4e225feebf 100644 --- a/arch/x86/kvm/svm.c +++ b/arch/x86/kvm/svm.c | |||
@@ -2914,6 +2914,11 @@ static bool svm_gb_page_enable(void) | |||
2914 | return true; | 2914 | return true; |
2915 | } | 2915 | } |
2916 | 2916 | ||
2917 | static bool svm_rdtscp_supported(void) | ||
2918 | { | ||
2919 | return false; | ||
2920 | } | ||
2921 | |||
2917 | static struct kvm_x86_ops svm_x86_ops = { | 2922 | static struct kvm_x86_ops svm_x86_ops = { |
2918 | .cpu_has_kvm_support = has_svm, | 2923 | .cpu_has_kvm_support = has_svm, |
2919 | .disabled_by_bios = is_disabled, | 2924 | .disabled_by_bios = is_disabled, |
@@ -2982,6 +2987,8 @@ static struct kvm_x86_ops svm_x86_ops = { | |||
2982 | .gb_page_enable = svm_gb_page_enable, | 2987 | .gb_page_enable = svm_gb_page_enable, |
2983 | 2988 | ||
2984 | .cpuid_update = svm_cpuid_update, | 2989 | .cpuid_update = svm_cpuid_update, |
2990 | |||
2991 | .rdtscp_supported = svm_rdtscp_supported, | ||
2985 | }; | 2992 | }; |
2986 | 2993 | ||
2987 | static int __init svm_init(void) | 2994 | static int __init svm_init(void) |
diff --git a/arch/x86/kvm/vmx.c b/arch/x86/kvm/vmx.c index 75e8931e96c7..74a66f0c00b4 100644 --- a/arch/x86/kvm/vmx.c +++ b/arch/x86/kvm/vmx.c | |||
@@ -151,6 +151,8 @@ struct vcpu_vmx { | |||
151 | ktime_t entry_time; | 151 | ktime_t entry_time; |
152 | s64 vnmi_blocked_time; | 152 | s64 vnmi_blocked_time; |
153 | u32 exit_reason; | 153 | u32 exit_reason; |
154 | |||
155 | bool rdtscp_enabled; | ||
154 | }; | 156 | }; |
155 | 157 | ||
156 | static inline struct vcpu_vmx *to_vmx(struct kvm_vcpu *vcpu) | 158 | static inline struct vcpu_vmx *to_vmx(struct kvm_vcpu *vcpu) |
@@ -225,7 +227,7 @@ static const u32 vmx_msr_index[] = { | |||
225 | #ifdef CONFIG_X86_64 | 227 | #ifdef CONFIG_X86_64 |
226 | MSR_SYSCALL_MASK, MSR_LSTAR, MSR_CSTAR, | 228 | MSR_SYSCALL_MASK, MSR_LSTAR, MSR_CSTAR, |
227 | #endif | 229 | #endif |
228 | MSR_EFER, MSR_K6_STAR, | 230 | MSR_EFER, MSR_TSC_AUX, MSR_K6_STAR, |
229 | }; | 231 | }; |
230 | #define NR_VMX_MSR ARRAY_SIZE(vmx_msr_index) | 232 | #define NR_VMX_MSR ARRAY_SIZE(vmx_msr_index) |
231 | 233 | ||
@@ -362,6 +364,12 @@ static inline int cpu_has_vmx_vpid(void) | |||
362 | SECONDARY_EXEC_ENABLE_VPID; | 364 | SECONDARY_EXEC_ENABLE_VPID; |
363 | } | 365 | } |
364 | 366 | ||
367 | static inline int cpu_has_vmx_rdtscp(void) | ||
368 | { | ||
369 | return vmcs_config.cpu_based_2nd_exec_ctrl & | ||
370 | SECONDARY_EXEC_RDTSCP; | ||
371 | } | ||
372 | |||
365 | static inline int cpu_has_virtual_nmis(void) | 373 | static inline int cpu_has_virtual_nmis(void) |
366 | { | 374 | { |
367 | return vmcs_config.pin_based_exec_ctrl & PIN_BASED_VIRTUAL_NMIS; | 375 | return vmcs_config.pin_based_exec_ctrl & PIN_BASED_VIRTUAL_NMIS; |
@@ -893,6 +901,11 @@ static void vmx_queue_exception(struct kvm_vcpu *vcpu, unsigned nr, | |||
893 | vmcs_write32(VM_ENTRY_INTR_INFO_FIELD, intr_info); | 901 | vmcs_write32(VM_ENTRY_INTR_INFO_FIELD, intr_info); |
894 | } | 902 | } |
895 | 903 | ||
904 | static bool vmx_rdtscp_supported(void) | ||
905 | { | ||
906 | return cpu_has_vmx_rdtscp(); | ||
907 | } | ||
908 | |||
896 | /* | 909 | /* |
897 | * Swap MSR entry in host/guest MSR entry array. | 910 | * Swap MSR entry in host/guest MSR entry array. |
898 | */ | 911 | */ |
@@ -928,6 +941,9 @@ static void setup_msrs(struct vcpu_vmx *vmx) | |||
928 | index = __find_msr_index(vmx, MSR_CSTAR); | 941 | index = __find_msr_index(vmx, MSR_CSTAR); |
929 | if (index >= 0) | 942 | if (index >= 0) |
930 | move_msr_up(vmx, index, save_nmsrs++); | 943 | move_msr_up(vmx, index, save_nmsrs++); |
944 | index = __find_msr_index(vmx, MSR_TSC_AUX); | ||
945 | if (index >= 0 && vmx->rdtscp_enabled) | ||
946 | move_msr_up(vmx, index, save_nmsrs++); | ||
931 | /* | 947 | /* |
932 | * MSR_K6_STAR is only needed on long mode guests, and only | 948 | * MSR_K6_STAR is only needed on long mode guests, and only |
933 | * if efer.sce is enabled. | 949 | * if efer.sce is enabled. |
@@ -1017,6 +1033,10 @@ static int vmx_get_msr(struct kvm_vcpu *vcpu, u32 msr_index, u64 *pdata) | |||
1017 | case MSR_IA32_SYSENTER_ESP: | 1033 | case MSR_IA32_SYSENTER_ESP: |
1018 | data = vmcs_readl(GUEST_SYSENTER_ESP); | 1034 | data = vmcs_readl(GUEST_SYSENTER_ESP); |
1019 | break; | 1035 | break; |
1036 | case MSR_TSC_AUX: | ||
1037 | if (!to_vmx(vcpu)->rdtscp_enabled) | ||
1038 | return 1; | ||
1039 | /* Otherwise falls through */ | ||
1020 | default: | 1040 | default: |
1021 | vmx_load_host_state(to_vmx(vcpu)); | 1041 | vmx_load_host_state(to_vmx(vcpu)); |
1022 | msr = find_msr_entry(to_vmx(vcpu), msr_index); | 1042 | msr = find_msr_entry(to_vmx(vcpu), msr_index); |
@@ -1080,7 +1100,15 @@ static int vmx_set_msr(struct kvm_vcpu *vcpu, u32 msr_index, u64 data) | |||
1080 | vcpu->arch.pat = data; | 1100 | vcpu->arch.pat = data; |
1081 | break; | 1101 | break; |
1082 | } | 1102 | } |
1083 | /* Otherwise falls through to kvm_set_msr_common */ | 1103 | ret = kvm_set_msr_common(vcpu, msr_index, data); |
1104 | break; | ||
1105 | case MSR_TSC_AUX: | ||
1106 | if (!vmx->rdtscp_enabled) | ||
1107 | return 1; | ||
1108 | /* Check reserved bit, higher 32 bits should be zero */ | ||
1109 | if ((data >> 32) != 0) | ||
1110 | return 1; | ||
1111 | /* Otherwise falls through */ | ||
1084 | default: | 1112 | default: |
1085 | msr = find_msr_entry(vmx, msr_index); | 1113 | msr = find_msr_entry(vmx, msr_index); |
1086 | if (msr) { | 1114 | if (msr) { |
@@ -1260,7 +1288,8 @@ static __init int setup_vmcs_config(struct vmcs_config *vmcs_conf) | |||
1260 | SECONDARY_EXEC_ENABLE_VPID | | 1288 | SECONDARY_EXEC_ENABLE_VPID | |
1261 | SECONDARY_EXEC_ENABLE_EPT | | 1289 | SECONDARY_EXEC_ENABLE_EPT | |
1262 | SECONDARY_EXEC_UNRESTRICTED_GUEST | | 1290 | SECONDARY_EXEC_UNRESTRICTED_GUEST | |
1263 | SECONDARY_EXEC_PAUSE_LOOP_EXITING; | 1291 | SECONDARY_EXEC_PAUSE_LOOP_EXITING | |
1292 | SECONDARY_EXEC_RDTSCP; | ||
1264 | if (adjust_vmx_controls(min2, opt2, | 1293 | if (adjust_vmx_controls(min2, opt2, |
1265 | MSR_IA32_VMX_PROCBASED_CTLS2, | 1294 | MSR_IA32_VMX_PROCBASED_CTLS2, |
1266 | &_cpu_based_2nd_exec_control) < 0) | 1295 | &_cpu_based_2nd_exec_control) < 0) |
@@ -3988,8 +4017,31 @@ static bool vmx_gb_page_enable(void) | |||
3988 | return false; | 4017 | return false; |
3989 | } | 4018 | } |
3990 | 4019 | ||
4020 | static inline u32 bit(int bitno) | ||
4021 | { | ||
4022 | return 1 << (bitno & 31); | ||
4023 | } | ||
4024 | |||
3991 | static void vmx_cpuid_update(struct kvm_vcpu *vcpu) | 4025 | static void vmx_cpuid_update(struct kvm_vcpu *vcpu) |
3992 | { | 4026 | { |
4027 | struct kvm_cpuid_entry2 *best; | ||
4028 | struct vcpu_vmx *vmx = to_vmx(vcpu); | ||
4029 | u32 exec_control; | ||
4030 | |||
4031 | vmx->rdtscp_enabled = false; | ||
4032 | if (vmx_rdtscp_supported()) { | ||
4033 | exec_control = vmcs_read32(SECONDARY_VM_EXEC_CONTROL); | ||
4034 | if (exec_control & SECONDARY_EXEC_RDTSCP) { | ||
4035 | best = kvm_find_cpuid_entry(vcpu, 0x80000001, 0); | ||
4036 | if (best && (best->edx & bit(X86_FEATURE_RDTSCP))) | ||
4037 | vmx->rdtscp_enabled = true; | ||
4038 | else { | ||
4039 | exec_control &= ~SECONDARY_EXEC_RDTSCP; | ||
4040 | vmcs_write32(SECONDARY_VM_EXEC_CONTROL, | ||
4041 | exec_control); | ||
4042 | } | ||
4043 | } | ||
4044 | } | ||
3993 | } | 4045 | } |
3994 | 4046 | ||
3995 | static struct kvm_x86_ops vmx_x86_ops = { | 4047 | static struct kvm_x86_ops vmx_x86_ops = { |
@@ -4058,6 +4110,8 @@ static struct kvm_x86_ops vmx_x86_ops = { | |||
4058 | .gb_page_enable = vmx_gb_page_enable, | 4110 | .gb_page_enable = vmx_gb_page_enable, |
4059 | 4111 | ||
4060 | .cpuid_update = vmx_cpuid_update, | 4112 | .cpuid_update = vmx_cpuid_update, |
4113 | |||
4114 | .rdtscp_supported = vmx_rdtscp_supported, | ||
4061 | }; | 4115 | }; |
4062 | 4116 | ||
4063 | static int __init vmx_init(void) | 4117 | static int __init vmx_init(void) |
diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c index e5ac21f992f0..8798504ace11 100644 --- a/arch/x86/kvm/x86.c +++ b/arch/x86/kvm/x86.c | |||
@@ -1646,6 +1646,7 @@ static void do_cpuid_ent(struct kvm_cpuid_entry2 *entry, u32 function, | |||
1646 | #else | 1646 | #else |
1647 | unsigned f_lm = 0; | 1647 | unsigned f_lm = 0; |
1648 | #endif | 1648 | #endif |
1649 | unsigned f_rdtscp = kvm_x86_ops->rdtscp_supported() ? F(RDTSCP) : 0; | ||
1649 | 1650 | ||
1650 | /* cpuid 1.edx */ | 1651 | /* cpuid 1.edx */ |
1651 | const u32 kvm_supported_word0_x86_features = | 1652 | const u32 kvm_supported_word0_x86_features = |
@@ -1665,7 +1666,7 @@ static void do_cpuid_ent(struct kvm_cpuid_entry2 *entry, u32 function, | |||
1665 | F(MTRR) | F(PGE) | F(MCA) | F(CMOV) | | 1666 | F(MTRR) | F(PGE) | F(MCA) | F(CMOV) | |
1666 | F(PAT) | F(PSE36) | 0 /* Reserved */ | | 1667 | F(PAT) | F(PSE36) | 0 /* Reserved */ | |
1667 | f_nx | 0 /* Reserved */ | F(MMXEXT) | F(MMX) | | 1668 | f_nx | 0 /* Reserved */ | F(MMXEXT) | F(MMX) | |
1668 | F(FXSR) | F(FXSR_OPT) | f_gbpages | 0 /* RDTSCP */ | | 1669 | F(FXSR) | F(FXSR_OPT) | f_gbpages | f_rdtscp | |
1669 | 0 /* Reserved */ | f_lm | F(3DNOWEXT) | F(3DNOW); | 1670 | 0 /* Reserved */ | f_lm | F(3DNOWEXT) | F(3DNOW); |
1670 | /* cpuid 1.ecx */ | 1671 | /* cpuid 1.ecx */ |
1671 | const u32 kvm_supported_word4_x86_features = | 1672 | const u32 kvm_supported_word4_x86_features = |