diff options
author | Yang, Sheng <sheng.yang@intel.com> | 2007-07-31 07:23:01 -0400 |
---|---|---|
committer | Avi Kivity <avi@qumranet.com> | 2007-10-13 04:18:22 -0400 |
commit | 002c7f7c32a6123f0894d7d579ffae8e98911830 (patch) | |
tree | 91d46dd1d6f04f25e4f658eb8620fe69c1557c17 /drivers | |
parent | 39214915f50f6ac2350355f2db63910d968fa790 (diff) |
KVM: VMX: Add cpu consistency check
All the physical CPUs on the board should support the same VMX feature
set. Add check_processor_compatibility to kvm_arch_ops for the consistency
check.
Signed-off-by: Sheng Yang <sheng.yang@intel.com>
Signed-off-by: Avi Kivity <avi@qumranet.com>
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/kvm/kvm.h | 1 | ||||
-rw-r--r-- | drivers/kvm/kvm_main.c | 10 | ||||
-rw-r--r-- | drivers/kvm/svm.c | 6 | ||||
-rw-r--r-- | drivers/kvm/vmx.c | 51 |
4 files changed, 50 insertions, 18 deletions
diff --git a/drivers/kvm/kvm.h b/drivers/kvm/kvm.h index 7a34706f42be..cfda3abff89a 100644 --- a/drivers/kvm/kvm.h +++ b/drivers/kvm/kvm.h | |||
@@ -420,6 +420,7 @@ struct kvm_arch_ops { | |||
420 | int (*disabled_by_bios)(void); /* __init */ | 420 | int (*disabled_by_bios)(void); /* __init */ |
421 | void (*hardware_enable)(void *dummy); /* __init */ | 421 | void (*hardware_enable)(void *dummy); /* __init */ |
422 | void (*hardware_disable)(void *dummy); | 422 | void (*hardware_disable)(void *dummy); |
423 | void (*check_processor_compatibility)(void *rtn); | ||
423 | int (*hardware_setup)(void); /* __init */ | 424 | int (*hardware_setup)(void); /* __init */ |
424 | void (*hardware_unsetup)(void); /* __exit */ | 425 | void (*hardware_unsetup)(void); /* __exit */ |
425 | 426 | ||
diff --git a/drivers/kvm/kvm_main.c b/drivers/kvm/kvm_main.c index 5dee3024579d..2be6b1ca1a06 100644 --- a/drivers/kvm/kvm_main.c +++ b/drivers/kvm/kvm_main.c | |||
@@ -3102,6 +3102,7 @@ int kvm_init_arch(struct kvm_arch_ops *ops, unsigned int vcpu_size, | |||
3102 | struct module *module) | 3102 | struct module *module) |
3103 | { | 3103 | { |
3104 | int r; | 3104 | int r; |
3105 | int cpu; | ||
3105 | 3106 | ||
3106 | if (kvm_arch_ops) { | 3107 | if (kvm_arch_ops) { |
3107 | printk(KERN_ERR "kvm: already loaded the other module\n"); | 3108 | printk(KERN_ERR "kvm: already loaded the other module\n"); |
@@ -3123,6 +3124,14 @@ int kvm_init_arch(struct kvm_arch_ops *ops, unsigned int vcpu_size, | |||
3123 | if (r < 0) | 3124 | if (r < 0) |
3124 | goto out; | 3125 | goto out; |
3125 | 3126 | ||
3127 | for_each_online_cpu(cpu) { | ||
3128 | smp_call_function_single(cpu, | ||
3129 | kvm_arch_ops->check_processor_compatibility, | ||
3130 | &r, 0, 1); | ||
3131 | if (r < 0) | ||
3132 | goto out_free_0; | ||
3133 | } | ||
3134 | |||
3126 | on_each_cpu(hardware_enable, NULL, 0, 1); | 3135 | on_each_cpu(hardware_enable, NULL, 0, 1); |
3127 | r = register_cpu_notifier(&kvm_cpu_notifier); | 3136 | r = register_cpu_notifier(&kvm_cpu_notifier); |
3128 | if (r) | 3137 | if (r) |
@@ -3169,6 +3178,7 @@ out_free_2: | |||
3169 | unregister_cpu_notifier(&kvm_cpu_notifier); | 3178 | unregister_cpu_notifier(&kvm_cpu_notifier); |
3170 | out_free_1: | 3179 | out_free_1: |
3171 | on_each_cpu(hardware_disable, NULL, 0, 1); | 3180 | on_each_cpu(hardware_disable, NULL, 0, 1); |
3181 | out_free_0: | ||
3172 | kvm_arch_ops->hardware_unsetup(); | 3182 | kvm_arch_ops->hardware_unsetup(); |
3173 | out: | 3183 | out: |
3174 | kvm_arch_ops = NULL; | 3184 | kvm_arch_ops = NULL; |
diff --git a/drivers/kvm/svm.c b/drivers/kvm/svm.c index 5277084f3a35..827bc2774e73 100644 --- a/drivers/kvm/svm.c +++ b/drivers/kvm/svm.c | |||
@@ -1798,11 +1798,17 @@ svm_patch_hypercall(struct kvm_vcpu *vcpu, unsigned char *hypercall) | |||
1798 | hypercall[3] = 0xc3; | 1798 | hypercall[3] = 0xc3; |
1799 | } | 1799 | } |
1800 | 1800 | ||
1801 | static void svm_check_processor_compat(void *rtn) | ||
1802 | { | ||
1803 | *(int *)rtn = 0; | ||
1804 | } | ||
1805 | |||
1801 | static struct kvm_arch_ops svm_arch_ops = { | 1806 | static struct kvm_arch_ops svm_arch_ops = { |
1802 | .cpu_has_kvm_support = has_svm, | 1807 | .cpu_has_kvm_support = has_svm, |
1803 | .disabled_by_bios = is_disabled, | 1808 | .disabled_by_bios = is_disabled, |
1804 | .hardware_setup = svm_hardware_setup, | 1809 | .hardware_setup = svm_hardware_setup, |
1805 | .hardware_unsetup = svm_hardware_unsetup, | 1810 | .hardware_unsetup = svm_hardware_unsetup, |
1811 | .check_processor_compatibility = svm_check_processor_compat, | ||
1806 | .hardware_enable = svm_hardware_enable, | 1812 | .hardware_enable = svm_hardware_enable, |
1807 | .hardware_disable = svm_hardware_disable, | 1813 | .hardware_disable = svm_hardware_disable, |
1808 | 1814 | ||
diff --git a/drivers/kvm/vmx.c b/drivers/kvm/vmx.c index 2b30274656f4..c4b8bfea4410 100644 --- a/drivers/kvm/vmx.c +++ b/drivers/kvm/vmx.c | |||
@@ -840,13 +840,13 @@ static __init int adjust_vmx_controls(u32 ctl_min, u32 ctl_opt, | |||
840 | 840 | ||
841 | /* Ensure minimum (required) set of control bits are supported. */ | 841 | /* Ensure minimum (required) set of control bits are supported. */ |
842 | if (ctl_min & ~ctl) | 842 | if (ctl_min & ~ctl) |
843 | return -1; | 843 | return -EIO; |
844 | 844 | ||
845 | *result = ctl; | 845 | *result = ctl; |
846 | return 0; | 846 | return 0; |
847 | } | 847 | } |
848 | 848 | ||
849 | static __init int setup_vmcs_config(void) | 849 | static __init int setup_vmcs_config(struct vmcs_config *vmcs_conf) |
850 | { | 850 | { |
851 | u32 vmx_msr_low, vmx_msr_high; | 851 | u32 vmx_msr_low, vmx_msr_high; |
852 | u32 min, opt; | 852 | u32 min, opt; |
@@ -859,7 +859,7 @@ static __init int setup_vmcs_config(void) | |||
859 | opt = 0; | 859 | opt = 0; |
860 | if (adjust_vmx_controls(min, opt, MSR_IA32_VMX_PINBASED_CTLS, | 860 | if (adjust_vmx_controls(min, opt, MSR_IA32_VMX_PINBASED_CTLS, |
861 | &_pin_based_exec_control) < 0) | 861 | &_pin_based_exec_control) < 0) |
862 | return -1; | 862 | return -EIO; |
863 | 863 | ||
864 | min = CPU_BASED_HLT_EXITING | | 864 | min = CPU_BASED_HLT_EXITING | |
865 | #ifdef CONFIG_X86_64 | 865 | #ifdef CONFIG_X86_64 |
@@ -872,7 +872,7 @@ static __init int setup_vmcs_config(void) | |||
872 | opt = 0; | 872 | opt = 0; |
873 | if (adjust_vmx_controls(min, opt, MSR_IA32_VMX_PROCBASED_CTLS, | 873 | if (adjust_vmx_controls(min, opt, MSR_IA32_VMX_PROCBASED_CTLS, |
874 | &_cpu_based_exec_control) < 0) | 874 | &_cpu_based_exec_control) < 0) |
875 | return -1; | 875 | return -EIO; |
876 | 876 | ||
877 | min = 0; | 877 | min = 0; |
878 | #ifdef CONFIG_X86_64 | 878 | #ifdef CONFIG_X86_64 |
@@ -881,37 +881,37 @@ static __init int setup_vmcs_config(void) | |||
881 | opt = 0; | 881 | opt = 0; |
882 | if (adjust_vmx_controls(min, opt, MSR_IA32_VMX_EXIT_CTLS, | 882 | if (adjust_vmx_controls(min, opt, MSR_IA32_VMX_EXIT_CTLS, |
883 | &_vmexit_control) < 0) | 883 | &_vmexit_control) < 0) |
884 | return -1; | 884 | return -EIO; |
885 | 885 | ||
886 | min = opt = 0; | 886 | min = opt = 0; |
887 | if (adjust_vmx_controls(min, opt, MSR_IA32_VMX_ENTRY_CTLS, | 887 | if (adjust_vmx_controls(min, opt, MSR_IA32_VMX_ENTRY_CTLS, |
888 | &_vmentry_control) < 0) | 888 | &_vmentry_control) < 0) |
889 | return -1; | 889 | return -EIO; |
890 | 890 | ||
891 | rdmsr(MSR_IA32_VMX_BASIC, vmx_msr_low, vmx_msr_high); | 891 | rdmsr(MSR_IA32_VMX_BASIC, vmx_msr_low, vmx_msr_high); |
892 | 892 | ||
893 | /* IA-32 SDM Vol 3B: VMCS size is never greater than 4kB. */ | 893 | /* IA-32 SDM Vol 3B: VMCS size is never greater than 4kB. */ |
894 | if ((vmx_msr_high & 0x1fff) > PAGE_SIZE) | 894 | if ((vmx_msr_high & 0x1fff) > PAGE_SIZE) |
895 | return -1; | 895 | return -EIO; |
896 | 896 | ||
897 | #ifdef CONFIG_X86_64 | 897 | #ifdef CONFIG_X86_64 |
898 | /* IA-32 SDM Vol 3B: 64-bit CPUs always have VMX_BASIC_MSR[48]==0. */ | 898 | /* IA-32 SDM Vol 3B: 64-bit CPUs always have VMX_BASIC_MSR[48]==0. */ |
899 | if (vmx_msr_high & (1u<<16)) | 899 | if (vmx_msr_high & (1u<<16)) |
900 | return -1; | 900 | return -EIO; |
901 | #endif | 901 | #endif |
902 | 902 | ||
903 | /* Require Write-Back (WB) memory type for VMCS accesses. */ | 903 | /* Require Write-Back (WB) memory type for VMCS accesses. */ |
904 | if (((vmx_msr_high >> 18) & 15) != 6) | 904 | if (((vmx_msr_high >> 18) & 15) != 6) |
905 | return -1; | 905 | return -EIO; |
906 | 906 | ||
907 | vmcs_config.size = vmx_msr_high & 0x1fff; | 907 | vmcs_conf->size = vmx_msr_high & 0x1fff; |
908 | vmcs_config.order = get_order(vmcs_config.size); | 908 | vmcs_conf->order = get_order(vmcs_config.size); |
909 | vmcs_config.revision_id = vmx_msr_low; | 909 | vmcs_conf->revision_id = vmx_msr_low; |
910 | 910 | ||
911 | vmcs_config.pin_based_exec_ctrl = _pin_based_exec_control; | 911 | vmcs_conf->pin_based_exec_ctrl = _pin_based_exec_control; |
912 | vmcs_config.cpu_based_exec_ctrl = _cpu_based_exec_control; | 912 | vmcs_conf->cpu_based_exec_ctrl = _cpu_based_exec_control; |
913 | vmcs_config.vmexit_ctrl = _vmexit_control; | 913 | vmcs_conf->vmexit_ctrl = _vmexit_control; |
914 | vmcs_config.vmentry_ctrl = _vmentry_control; | 914 | vmcs_conf->vmentry_ctrl = _vmentry_control; |
915 | 915 | ||
916 | return 0; | 916 | return 0; |
917 | } | 917 | } |
@@ -971,8 +971,8 @@ static __init int alloc_kvm_area(void) | |||
971 | 971 | ||
972 | static __init int hardware_setup(void) | 972 | static __init int hardware_setup(void) |
973 | { | 973 | { |
974 | if (setup_vmcs_config() < 0) | 974 | if (setup_vmcs_config(&vmcs_config) < 0) |
975 | return -1; | 975 | return -EIO; |
976 | return alloc_kvm_area(); | 976 | return alloc_kvm_area(); |
977 | } | 977 | } |
978 | 978 | ||
@@ -2414,11 +2414,26 @@ free_vcpu: | |||
2414 | return ERR_PTR(err); | 2414 | return ERR_PTR(err); |
2415 | } | 2415 | } |
2416 | 2416 | ||
2417 | static void __init vmx_check_processor_compat(void *rtn) | ||
2418 | { | ||
2419 | struct vmcs_config vmcs_conf; | ||
2420 | |||
2421 | *(int *)rtn = 0; | ||
2422 | if (setup_vmcs_config(&vmcs_conf) < 0) | ||
2423 | *(int *)rtn = -EIO; | ||
2424 | if (memcmp(&vmcs_config, &vmcs_conf, sizeof(struct vmcs_config)) != 0) { | ||
2425 | printk(KERN_ERR "kvm: CPU %d feature inconsistency!\n", | ||
2426 | smp_processor_id()); | ||
2427 | *(int *)rtn = -EIO; | ||
2428 | } | ||
2429 | } | ||
2430 | |||
2417 | static struct kvm_arch_ops vmx_arch_ops = { | 2431 | static struct kvm_arch_ops vmx_arch_ops = { |
2418 | .cpu_has_kvm_support = cpu_has_kvm_support, | 2432 | .cpu_has_kvm_support = cpu_has_kvm_support, |
2419 | .disabled_by_bios = vmx_disabled_by_bios, | 2433 | .disabled_by_bios = vmx_disabled_by_bios, |
2420 | .hardware_setup = hardware_setup, | 2434 | .hardware_setup = hardware_setup, |
2421 | .hardware_unsetup = hardware_unsetup, | 2435 | .hardware_unsetup = hardware_unsetup, |
2436 | .check_processor_compatibility = vmx_check_processor_compat, | ||
2422 | .hardware_enable = hardware_enable, | 2437 | .hardware_enable = hardware_enable, |
2423 | .hardware_disable = hardware_disable, | 2438 | .hardware_disable = hardware_disable, |
2424 | 2439 | ||