diff options
author | Alexander Graf <agraf@suse.de> | 2009-09-15 05:37:46 -0400 |
---|---|---|
committer | Avi Kivity <avi@redhat.com> | 2009-12-03 02:32:10 -0500 |
commit | 10474ae8945ce08622fd1f3464e55bd817bf2376 (patch) | |
tree | d390843b5107e600fbbf745eb24d85d745fe449f /arch | |
parent | e8b3433a5c062e94e34cadb6144c10689a497bc3 (diff) |
KVM: Activate Virtualization On Demand
X86 CPUs need to have some magic happening to enable the virtualization
extensions on them. This magic can result in unpleasant results for
users, like blocking other VMMs from working (vmx) or using invalid TLB
entries (svm).
Currently KVM activates virtualization when the respective kernel module
is loaded. This blocks us from autoloading KVM modules without breaking
other VMMs.
To circumvent this problem at least a bit, this patch introduces on
demand activation of virtualization. This means, that instead
virtualization is enabled on creation of the first virtual machine
and disabled on destruction of the last one.
So using this, KVM can be easily autoloaded, while keeping other
hypervisors usable.
Signed-off-by: Alexander Graf <agraf@suse.de>
Signed-off-by: Marcelo Tosatti <mtosatti@redhat.com>
Signed-off-by: Avi Kivity <avi@redhat.com>
Diffstat (limited to 'arch')
-rw-r--r-- | arch/ia64/kvm/kvm-ia64.c | 8 | ||||
-rw-r--r-- | arch/powerpc/kvm/powerpc.c | 3 | ||||
-rw-r--r-- | arch/s390/kvm/kvm-s390.c | 3 | ||||
-rw-r--r-- | arch/x86/include/asm/kvm_host.h | 2 | ||||
-rw-r--r-- | arch/x86/kvm/svm.c | 13 | ||||
-rw-r--r-- | arch/x86/kvm/vmx.c | 11 | ||||
-rw-r--r-- | arch/x86/kvm/x86.c | 4 |
7 files changed, 29 insertions, 15 deletions
diff --git a/arch/ia64/kvm/kvm-ia64.c b/arch/ia64/kvm/kvm-ia64.c index f6471c882667..5fdeec5fddcf 100644 --- a/arch/ia64/kvm/kvm-ia64.c +++ b/arch/ia64/kvm/kvm-ia64.c | |||
@@ -124,7 +124,7 @@ long ia64_pal_vp_create(u64 *vpd, u64 *host_iva, u64 *opt_handler) | |||
124 | 124 | ||
125 | static DEFINE_SPINLOCK(vp_lock); | 125 | static DEFINE_SPINLOCK(vp_lock); |
126 | 126 | ||
127 | void kvm_arch_hardware_enable(void *garbage) | 127 | int kvm_arch_hardware_enable(void *garbage) |
128 | { | 128 | { |
129 | long status; | 129 | long status; |
130 | long tmp_base; | 130 | long tmp_base; |
@@ -137,7 +137,7 @@ void kvm_arch_hardware_enable(void *garbage) | |||
137 | slot = ia64_itr_entry(0x3, KVM_VMM_BASE, pte, KVM_VMM_SHIFT); | 137 | slot = ia64_itr_entry(0x3, KVM_VMM_BASE, pte, KVM_VMM_SHIFT); |
138 | local_irq_restore(saved_psr); | 138 | local_irq_restore(saved_psr); |
139 | if (slot < 0) | 139 | if (slot < 0) |
140 | return; | 140 | return -EINVAL; |
141 | 141 | ||
142 | spin_lock(&vp_lock); | 142 | spin_lock(&vp_lock); |
143 | status = ia64_pal_vp_init_env(kvm_vsa_base ? | 143 | status = ia64_pal_vp_init_env(kvm_vsa_base ? |
@@ -145,7 +145,7 @@ void kvm_arch_hardware_enable(void *garbage) | |||
145 | __pa(kvm_vm_buffer), KVM_VM_BUFFER_BASE, &tmp_base); | 145 | __pa(kvm_vm_buffer), KVM_VM_BUFFER_BASE, &tmp_base); |
146 | if (status != 0) { | 146 | if (status != 0) { |
147 | printk(KERN_WARNING"kvm: Failed to Enable VT Support!!!!\n"); | 147 | printk(KERN_WARNING"kvm: Failed to Enable VT Support!!!!\n"); |
148 | return ; | 148 | return -EINVAL; |
149 | } | 149 | } |
150 | 150 | ||
151 | if (!kvm_vsa_base) { | 151 | if (!kvm_vsa_base) { |
@@ -154,6 +154,8 @@ void kvm_arch_hardware_enable(void *garbage) | |||
154 | } | 154 | } |
155 | spin_unlock(&vp_lock); | 155 | spin_unlock(&vp_lock); |
156 | ia64_ptr_entry(0x3, slot); | 156 | ia64_ptr_entry(0x3, slot); |
157 | |||
158 | return 0; | ||
157 | } | 159 | } |
158 | 160 | ||
159 | void kvm_arch_hardware_disable(void *garbage) | 161 | void kvm_arch_hardware_disable(void *garbage) |
diff --git a/arch/powerpc/kvm/powerpc.c b/arch/powerpc/kvm/powerpc.c index 95af62217b6b..5902bbc2411e 100644 --- a/arch/powerpc/kvm/powerpc.c +++ b/arch/powerpc/kvm/powerpc.c | |||
@@ -78,8 +78,9 @@ int kvmppc_emulate_mmio(struct kvm_run *run, struct kvm_vcpu *vcpu) | |||
78 | return r; | 78 | return r; |
79 | } | 79 | } |
80 | 80 | ||
81 | void kvm_arch_hardware_enable(void *garbage) | 81 | int kvm_arch_hardware_enable(void *garbage) |
82 | { | 82 | { |
83 | return 0; | ||
83 | } | 84 | } |
84 | 85 | ||
85 | void kvm_arch_hardware_disable(void *garbage) | 86 | void kvm_arch_hardware_disable(void *garbage) |
diff --git a/arch/s390/kvm/kvm-s390.c b/arch/s390/kvm/kvm-s390.c index 00e2ce8e91f5..544505893c9f 100644 --- a/arch/s390/kvm/kvm-s390.c +++ b/arch/s390/kvm/kvm-s390.c | |||
@@ -74,9 +74,10 @@ struct kvm_stats_debugfs_item debugfs_entries[] = { | |||
74 | static unsigned long long *facilities; | 74 | static unsigned long long *facilities; |
75 | 75 | ||
76 | /* Section: not file related */ | 76 | /* Section: not file related */ |
77 | void kvm_arch_hardware_enable(void *garbage) | 77 | int kvm_arch_hardware_enable(void *garbage) |
78 | { | 78 | { |
79 | /* every s390 is virtualization enabled ;-) */ | 79 | /* every s390 is virtualization enabled ;-) */ |
80 | return 0; | ||
80 | } | 81 | } |
81 | 82 | ||
82 | void kvm_arch_hardware_disable(void *garbage) | 83 | void kvm_arch_hardware_disable(void *garbage) |
diff --git a/arch/x86/include/asm/kvm_host.h b/arch/x86/include/asm/kvm_host.h index a46e2dd9aca8..295c7c4d9c90 100644 --- a/arch/x86/include/asm/kvm_host.h +++ b/arch/x86/include/asm/kvm_host.h | |||
@@ -459,7 +459,7 @@ struct descriptor_table { | |||
459 | struct kvm_x86_ops { | 459 | struct kvm_x86_ops { |
460 | int (*cpu_has_kvm_support)(void); /* __init */ | 460 | int (*cpu_has_kvm_support)(void); /* __init */ |
461 | int (*disabled_by_bios)(void); /* __init */ | 461 | int (*disabled_by_bios)(void); /* __init */ |
462 | void (*hardware_enable)(void *dummy); /* __init */ | 462 | int (*hardware_enable)(void *dummy); |
463 | void (*hardware_disable)(void *dummy); | 463 | void (*hardware_disable)(void *dummy); |
464 | void (*check_processor_compatibility)(void *rtn); | 464 | void (*check_processor_compatibility)(void *rtn); |
465 | int (*hardware_setup)(void); /* __init */ | 465 | int (*hardware_setup)(void); /* __init */ |
diff --git a/arch/x86/kvm/svm.c b/arch/x86/kvm/svm.c index f54c4f9d2865..59fe4d54da11 100644 --- a/arch/x86/kvm/svm.c +++ b/arch/x86/kvm/svm.c | |||
@@ -316,7 +316,7 @@ static void svm_hardware_disable(void *garbage) | |||
316 | cpu_svm_disable(); | 316 | cpu_svm_disable(); |
317 | } | 317 | } |
318 | 318 | ||
319 | static void svm_hardware_enable(void *garbage) | 319 | static int svm_hardware_enable(void *garbage) |
320 | { | 320 | { |
321 | 321 | ||
322 | struct svm_cpu_data *svm_data; | 322 | struct svm_cpu_data *svm_data; |
@@ -325,16 +325,20 @@ static void svm_hardware_enable(void *garbage) | |||
325 | struct desc_struct *gdt; | 325 | struct desc_struct *gdt; |
326 | int me = raw_smp_processor_id(); | 326 | int me = raw_smp_processor_id(); |
327 | 327 | ||
328 | rdmsrl(MSR_EFER, efer); | ||
329 | if (efer & EFER_SVME) | ||
330 | return -EBUSY; | ||
331 | |||
328 | if (!has_svm()) { | 332 | if (!has_svm()) { |
329 | printk(KERN_ERR "svm_cpu_init: err EOPNOTSUPP on %d\n", me); | 333 | printk(KERN_ERR "svm_cpu_init: err EOPNOTSUPP on %d\n", me); |
330 | return; | 334 | return -EINVAL; |
331 | } | 335 | } |
332 | svm_data = per_cpu(svm_data, me); | 336 | svm_data = per_cpu(svm_data, me); |
333 | 337 | ||
334 | if (!svm_data) { | 338 | if (!svm_data) { |
335 | printk(KERN_ERR "svm_cpu_init: svm_data is NULL on %d\n", | 339 | printk(KERN_ERR "svm_cpu_init: svm_data is NULL on %d\n", |
336 | me); | 340 | me); |
337 | return; | 341 | return -EINVAL; |
338 | } | 342 | } |
339 | 343 | ||
340 | svm_data->asid_generation = 1; | 344 | svm_data->asid_generation = 1; |
@@ -345,11 +349,12 @@ static void svm_hardware_enable(void *garbage) | |||
345 | gdt = (struct desc_struct *)gdt_descr.base; | 349 | gdt = (struct desc_struct *)gdt_descr.base; |
346 | svm_data->tss_desc = (struct kvm_ldttss_desc *)(gdt + GDT_ENTRY_TSS); | 350 | svm_data->tss_desc = (struct kvm_ldttss_desc *)(gdt + GDT_ENTRY_TSS); |
347 | 351 | ||
348 | rdmsrl(MSR_EFER, efer); | ||
349 | wrmsrl(MSR_EFER, efer | EFER_SVME); | 352 | wrmsrl(MSR_EFER, efer | EFER_SVME); |
350 | 353 | ||
351 | wrmsrl(MSR_VM_HSAVE_PA, | 354 | wrmsrl(MSR_VM_HSAVE_PA, |
352 | page_to_pfn(svm_data->save_area) << PAGE_SHIFT); | 355 | page_to_pfn(svm_data->save_area) << PAGE_SHIFT); |
356 | |||
357 | return 0; | ||
353 | } | 358 | } |
354 | 359 | ||
355 | static void svm_cpu_uninit(int cpu) | 360 | static void svm_cpu_uninit(int cpu) |
diff --git a/arch/x86/kvm/vmx.c b/arch/x86/kvm/vmx.c index 73cb5dd960cf..a187570e4837 100644 --- a/arch/x86/kvm/vmx.c +++ b/arch/x86/kvm/vmx.c | |||
@@ -1138,12 +1138,15 @@ static __init int vmx_disabled_by_bios(void) | |||
1138 | /* locked but not enabled */ | 1138 | /* locked but not enabled */ |
1139 | } | 1139 | } |
1140 | 1140 | ||
1141 | static void hardware_enable(void *garbage) | 1141 | static int hardware_enable(void *garbage) |
1142 | { | 1142 | { |
1143 | int cpu = raw_smp_processor_id(); | 1143 | int cpu = raw_smp_processor_id(); |
1144 | u64 phys_addr = __pa(per_cpu(vmxarea, cpu)); | 1144 | u64 phys_addr = __pa(per_cpu(vmxarea, cpu)); |
1145 | u64 old; | 1145 | u64 old; |
1146 | 1146 | ||
1147 | if (read_cr4() & X86_CR4_VMXE) | ||
1148 | return -EBUSY; | ||
1149 | |||
1147 | INIT_LIST_HEAD(&per_cpu(vcpus_on_cpu, cpu)); | 1150 | INIT_LIST_HEAD(&per_cpu(vcpus_on_cpu, cpu)); |
1148 | rdmsrl(MSR_IA32_FEATURE_CONTROL, old); | 1151 | rdmsrl(MSR_IA32_FEATURE_CONTROL, old); |
1149 | if ((old & (FEATURE_CONTROL_LOCKED | | 1152 | if ((old & (FEATURE_CONTROL_LOCKED | |
@@ -1158,6 +1161,10 @@ static void hardware_enable(void *garbage) | |||
1158 | asm volatile (ASM_VMX_VMXON_RAX | 1161 | asm volatile (ASM_VMX_VMXON_RAX |
1159 | : : "a"(&phys_addr), "m"(phys_addr) | 1162 | : : "a"(&phys_addr), "m"(phys_addr) |
1160 | : "memory", "cc"); | 1163 | : "memory", "cc"); |
1164 | |||
1165 | ept_sync_global(); | ||
1166 | |||
1167 | return 0; | ||
1161 | } | 1168 | } |
1162 | 1169 | ||
1163 | static void vmclear_local_vcpus(void) | 1170 | static void vmclear_local_vcpus(void) |
@@ -4040,8 +4047,6 @@ static int __init vmx_init(void) | |||
4040 | if (bypass_guest_pf) | 4047 | if (bypass_guest_pf) |
4041 | kvm_mmu_set_nonpresent_ptes(~0xffeull, 0ull); | 4048 | kvm_mmu_set_nonpresent_ptes(~0xffeull, 0ull); |
4042 | 4049 | ||
4043 | ept_sync_global(); | ||
4044 | |||
4045 | return 0; | 4050 | return 0; |
4046 | 4051 | ||
4047 | out3: | 4052 | out3: |
diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c index 829e3063e2ab..3d83de8bcbf4 100644 --- a/arch/x86/kvm/x86.c +++ b/arch/x86/kvm/x86.c | |||
@@ -4691,9 +4691,9 @@ int kvm_arch_vcpu_reset(struct kvm_vcpu *vcpu) | |||
4691 | return kvm_x86_ops->vcpu_reset(vcpu); | 4691 | return kvm_x86_ops->vcpu_reset(vcpu); |
4692 | } | 4692 | } |
4693 | 4693 | ||
4694 | void kvm_arch_hardware_enable(void *garbage) | 4694 | int kvm_arch_hardware_enable(void *garbage) |
4695 | { | 4695 | { |
4696 | kvm_x86_ops->hardware_enable(garbage); | 4696 | return kvm_x86_ops->hardware_enable(garbage); |
4697 | } | 4697 | } |
4698 | 4698 | ||
4699 | void kvm_arch_hardware_disable(void *garbage) | 4699 | void kvm_arch_hardware_disable(void *garbage) |