Commit 002c7f7c authored by Yang, Sheng's avatar Yang, Sheng Committed by Avi Kivity

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: default avatarSheng Yang <sheng.yang@intel.com>
Signed-off-by: default avatarAvi Kivity <avi@qumranet.com>
parent 39214915
...@@ -420,6 +420,7 @@ struct kvm_arch_ops { ...@@ -420,6 +420,7 @@ struct kvm_arch_ops {
int (*disabled_by_bios)(void); /* __init */ int (*disabled_by_bios)(void); /* __init */
void (*hardware_enable)(void *dummy); /* __init */ void (*hardware_enable)(void *dummy); /* __init */
void (*hardware_disable)(void *dummy); void (*hardware_disable)(void *dummy);
void (*check_processor_compatibility)(void *rtn);
int (*hardware_setup)(void); /* __init */ int (*hardware_setup)(void); /* __init */
void (*hardware_unsetup)(void); /* __exit */ void (*hardware_unsetup)(void); /* __exit */
......
...@@ -3102,6 +3102,7 @@ int kvm_init_arch(struct kvm_arch_ops *ops, unsigned int vcpu_size, ...@@ -3102,6 +3102,7 @@ int kvm_init_arch(struct kvm_arch_ops *ops, unsigned int vcpu_size,
struct module *module) struct module *module)
{ {
int r; int r;
int cpu;
if (kvm_arch_ops) { if (kvm_arch_ops) {
printk(KERN_ERR "kvm: already loaded the other module\n"); 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,6 +3124,14 @@ int kvm_init_arch(struct kvm_arch_ops *ops, unsigned int vcpu_size,
if (r < 0) if (r < 0)
goto out; goto out;
for_each_online_cpu(cpu) {
smp_call_function_single(cpu,
kvm_arch_ops->check_processor_compatibility,
&r, 0, 1);
if (r < 0)
goto out_free_0;
}
on_each_cpu(hardware_enable, NULL, 0, 1); on_each_cpu(hardware_enable, NULL, 0, 1);
r = register_cpu_notifier(&kvm_cpu_notifier); r = register_cpu_notifier(&kvm_cpu_notifier);
if (r) if (r)
...@@ -3169,6 +3178,7 @@ int kvm_init_arch(struct kvm_arch_ops *ops, unsigned int vcpu_size, ...@@ -3169,6 +3178,7 @@ int kvm_init_arch(struct kvm_arch_ops *ops, unsigned int vcpu_size,
unregister_cpu_notifier(&kvm_cpu_notifier); unregister_cpu_notifier(&kvm_cpu_notifier);
out_free_1: out_free_1:
on_each_cpu(hardware_disable, NULL, 0, 1); on_each_cpu(hardware_disable, NULL, 0, 1);
out_free_0:
kvm_arch_ops->hardware_unsetup(); kvm_arch_ops->hardware_unsetup();
out: out:
kvm_arch_ops = NULL; kvm_arch_ops = NULL;
......
...@@ -1798,11 +1798,17 @@ svm_patch_hypercall(struct kvm_vcpu *vcpu, unsigned char *hypercall) ...@@ -1798,11 +1798,17 @@ svm_patch_hypercall(struct kvm_vcpu *vcpu, unsigned char *hypercall)
hypercall[3] = 0xc3; hypercall[3] = 0xc3;
} }
static void svm_check_processor_compat(void *rtn)
{
*(int *)rtn = 0;
}
static struct kvm_arch_ops svm_arch_ops = { static struct kvm_arch_ops svm_arch_ops = {
.cpu_has_kvm_support = has_svm, .cpu_has_kvm_support = has_svm,
.disabled_by_bios = is_disabled, .disabled_by_bios = is_disabled,
.hardware_setup = svm_hardware_setup, .hardware_setup = svm_hardware_setup,
.hardware_unsetup = svm_hardware_unsetup, .hardware_unsetup = svm_hardware_unsetup,
.check_processor_compatibility = svm_check_processor_compat,
.hardware_enable = svm_hardware_enable, .hardware_enable = svm_hardware_enable,
.hardware_disable = svm_hardware_disable, .hardware_disable = svm_hardware_disable,
......
...@@ -840,13 +840,13 @@ static __init int adjust_vmx_controls(u32 ctl_min, u32 ctl_opt, ...@@ -840,13 +840,13 @@ static __init int adjust_vmx_controls(u32 ctl_min, u32 ctl_opt,
/* Ensure minimum (required) set of control bits are supported. */ /* Ensure minimum (required) set of control bits are supported. */
if (ctl_min & ~ctl) if (ctl_min & ~ctl)
return -1; return -EIO;
*result = ctl; *result = ctl;
return 0; return 0;
} }
static __init int setup_vmcs_config(void) static __init int setup_vmcs_config(struct vmcs_config *vmcs_conf)
{ {
u32 vmx_msr_low, vmx_msr_high; u32 vmx_msr_low, vmx_msr_high;
u32 min, opt; u32 min, opt;
...@@ -859,7 +859,7 @@ static __init int setup_vmcs_config(void) ...@@ -859,7 +859,7 @@ static __init int setup_vmcs_config(void)
opt = 0; opt = 0;
if (adjust_vmx_controls(min, opt, MSR_IA32_VMX_PINBASED_CTLS, if (adjust_vmx_controls(min, opt, MSR_IA32_VMX_PINBASED_CTLS,
&_pin_based_exec_control) < 0) &_pin_based_exec_control) < 0)
return -1; return -EIO;
min = CPU_BASED_HLT_EXITING | min = CPU_BASED_HLT_EXITING |
#ifdef CONFIG_X86_64 #ifdef CONFIG_X86_64
...@@ -872,7 +872,7 @@ static __init int setup_vmcs_config(void) ...@@ -872,7 +872,7 @@ static __init int setup_vmcs_config(void)
opt = 0; opt = 0;
if (adjust_vmx_controls(min, opt, MSR_IA32_VMX_PROCBASED_CTLS, if (adjust_vmx_controls(min, opt, MSR_IA32_VMX_PROCBASED_CTLS,
&_cpu_based_exec_control) < 0) &_cpu_based_exec_control) < 0)
return -1; return -EIO;
min = 0; min = 0;
#ifdef CONFIG_X86_64 #ifdef CONFIG_X86_64
...@@ -881,37 +881,37 @@ static __init int setup_vmcs_config(void) ...@@ -881,37 +881,37 @@ static __init int setup_vmcs_config(void)
opt = 0; opt = 0;
if (adjust_vmx_controls(min, opt, MSR_IA32_VMX_EXIT_CTLS, if (adjust_vmx_controls(min, opt, MSR_IA32_VMX_EXIT_CTLS,
&_vmexit_control) < 0) &_vmexit_control) < 0)
return -1; return -EIO;
min = opt = 0; min = opt = 0;
if (adjust_vmx_controls(min, opt, MSR_IA32_VMX_ENTRY_CTLS, if (adjust_vmx_controls(min, opt, MSR_IA32_VMX_ENTRY_CTLS,
&_vmentry_control) < 0) &_vmentry_control) < 0)
return -1; return -EIO;
rdmsr(MSR_IA32_VMX_BASIC, vmx_msr_low, vmx_msr_high); rdmsr(MSR_IA32_VMX_BASIC, vmx_msr_low, vmx_msr_high);
/* IA-32 SDM Vol 3B: VMCS size is never greater than 4kB. */ /* IA-32 SDM Vol 3B: VMCS size is never greater than 4kB. */
if ((vmx_msr_high & 0x1fff) > PAGE_SIZE) if ((vmx_msr_high & 0x1fff) > PAGE_SIZE)
return -1; return -EIO;
#ifdef CONFIG_X86_64 #ifdef CONFIG_X86_64
/* IA-32 SDM Vol 3B: 64-bit CPUs always have VMX_BASIC_MSR[48]==0. */ /* IA-32 SDM Vol 3B: 64-bit CPUs always have VMX_BASIC_MSR[48]==0. */
if (vmx_msr_high & (1u<<16)) if (vmx_msr_high & (1u<<16))
return -1; return -EIO;
#endif #endif
/* Require Write-Back (WB) memory type for VMCS accesses. */ /* Require Write-Back (WB) memory type for VMCS accesses. */
if (((vmx_msr_high >> 18) & 15) != 6) if (((vmx_msr_high >> 18) & 15) != 6)
return -1; return -EIO;
vmcs_config.size = vmx_msr_high & 0x1fff; vmcs_conf->size = vmx_msr_high & 0x1fff;
vmcs_config.order = get_order(vmcs_config.size); vmcs_conf->order = get_order(vmcs_config.size);
vmcs_config.revision_id = vmx_msr_low; vmcs_conf->revision_id = vmx_msr_low;
vmcs_config.pin_based_exec_ctrl = _pin_based_exec_control; vmcs_conf->pin_based_exec_ctrl = _pin_based_exec_control;
vmcs_config.cpu_based_exec_ctrl = _cpu_based_exec_control; vmcs_conf->cpu_based_exec_ctrl = _cpu_based_exec_control;
vmcs_config.vmexit_ctrl = _vmexit_control; vmcs_conf->vmexit_ctrl = _vmexit_control;
vmcs_config.vmentry_ctrl = _vmentry_control; vmcs_conf->vmentry_ctrl = _vmentry_control;
return 0; return 0;
} }
...@@ -971,8 +971,8 @@ static __init int alloc_kvm_area(void) ...@@ -971,8 +971,8 @@ static __init int alloc_kvm_area(void)
static __init int hardware_setup(void) static __init int hardware_setup(void)
{ {
if (setup_vmcs_config() < 0) if (setup_vmcs_config(&vmcs_config) < 0)
return -1; return -EIO;
return alloc_kvm_area(); return alloc_kvm_area();
} }
...@@ -2414,11 +2414,26 @@ static struct kvm_vcpu *vmx_create_vcpu(struct kvm *kvm, unsigned int id) ...@@ -2414,11 +2414,26 @@ static struct kvm_vcpu *vmx_create_vcpu(struct kvm *kvm, unsigned int id)
return ERR_PTR(err); return ERR_PTR(err);
} }
static void __init vmx_check_processor_compat(void *rtn)
{
struct vmcs_config vmcs_conf;
*(int *)rtn = 0;
if (setup_vmcs_config(&vmcs_conf) < 0)
*(int *)rtn = -EIO;
if (memcmp(&vmcs_config, &vmcs_conf, sizeof(struct vmcs_config)) != 0) {
printk(KERN_ERR "kvm: CPU %d feature inconsistency!\n",
smp_processor_id());
*(int *)rtn = -EIO;
}
}
static struct kvm_arch_ops vmx_arch_ops = { static struct kvm_arch_ops vmx_arch_ops = {
.cpu_has_kvm_support = cpu_has_kvm_support, .cpu_has_kvm_support = cpu_has_kvm_support,
.disabled_by_bios = vmx_disabled_by_bios, .disabled_by_bios = vmx_disabled_by_bios,
.hardware_setup = hardware_setup, .hardware_setup = hardware_setup,
.hardware_unsetup = hardware_unsetup, .hardware_unsetup = hardware_unsetup,
.check_processor_compatibility = vmx_check_processor_compat,
.hardware_enable = hardware_enable, .hardware_enable = hardware_enable,
.hardware_disable = hardware_disable, .hardware_disable = hardware_disable,
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment