Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 172280
b: refs/heads/master
c: 10474ae
h: refs/heads/master
v: v3
  • Loading branch information
Alexander Graf authored and Avi Kivity committed Dec 3, 2009
1 parent 83e4124 commit 18201bd
Show file tree
Hide file tree
Showing 10 changed files with 109 additions and 29 deletions.
2 changes: 1 addition & 1 deletion [refs]
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
---
refs/heads/master: e8b3433a5c062e94e34cadb6144c10689a497bc3
refs/heads/master: 10474ae8945ce08622fd1f3464e55bd817bf2376
8 changes: 5 additions & 3 deletions trunk/arch/ia64/kvm/kvm-ia64.c
Original file line number Diff line number Diff line change
Expand Up @@ -124,7 +124,7 @@ long ia64_pal_vp_create(u64 *vpd, u64 *host_iva, u64 *opt_handler)

static DEFINE_SPINLOCK(vp_lock);

void kvm_arch_hardware_enable(void *garbage)
int kvm_arch_hardware_enable(void *garbage)
{
long status;
long tmp_base;
Expand All @@ -137,15 +137,15 @@ void kvm_arch_hardware_enable(void *garbage)
slot = ia64_itr_entry(0x3, KVM_VMM_BASE, pte, KVM_VMM_SHIFT);
local_irq_restore(saved_psr);
if (slot < 0)
return;
return -EINVAL;

spin_lock(&vp_lock);
status = ia64_pal_vp_init_env(kvm_vsa_base ?
VP_INIT_ENV : VP_INIT_ENV_INITALIZE,
__pa(kvm_vm_buffer), KVM_VM_BUFFER_BASE, &tmp_base);
if (status != 0) {
printk(KERN_WARNING"kvm: Failed to Enable VT Support!!!!\n");
return ;
return -EINVAL;
}

if (!kvm_vsa_base) {
Expand All @@ -154,6 +154,8 @@ void kvm_arch_hardware_enable(void *garbage)
}
spin_unlock(&vp_lock);
ia64_ptr_entry(0x3, slot);

return 0;
}

void kvm_arch_hardware_disable(void *garbage)
Expand Down
3 changes: 2 additions & 1 deletion trunk/arch/powerpc/kvm/powerpc.c
Original file line number Diff line number Diff line change
Expand Up @@ -78,8 +78,9 @@ int kvmppc_emulate_mmio(struct kvm_run *run, struct kvm_vcpu *vcpu)
return r;
}

void kvm_arch_hardware_enable(void *garbage)
int kvm_arch_hardware_enable(void *garbage)
{
return 0;
}

void kvm_arch_hardware_disable(void *garbage)
Expand Down
3 changes: 2 additions & 1 deletion trunk/arch/s390/kvm/kvm-s390.c
Original file line number Diff line number Diff line change
Expand Up @@ -74,9 +74,10 @@ struct kvm_stats_debugfs_item debugfs_entries[] = {
static unsigned long long *facilities;

/* Section: not file related */
void kvm_arch_hardware_enable(void *garbage)
int kvm_arch_hardware_enable(void *garbage)
{
/* every s390 is virtualization enabled ;-) */
return 0;
}

void kvm_arch_hardware_disable(void *garbage)
Expand Down
2 changes: 1 addition & 1 deletion trunk/arch/x86/include/asm/kvm_host.h
Original file line number Diff line number Diff line change
Expand Up @@ -459,7 +459,7 @@ struct descriptor_table {
struct kvm_x86_ops {
int (*cpu_has_kvm_support)(void); /* __init */
int (*disabled_by_bios)(void); /* __init */
void (*hardware_enable)(void *dummy); /* __init */
int (*hardware_enable)(void *dummy);
void (*hardware_disable)(void *dummy);
void (*check_processor_compatibility)(void *rtn);
int (*hardware_setup)(void); /* __init */
Expand Down
13 changes: 9 additions & 4 deletions trunk/arch/x86/kvm/svm.c
Original file line number Diff line number Diff line change
Expand Up @@ -316,7 +316,7 @@ static void svm_hardware_disable(void *garbage)
cpu_svm_disable();
}

static void svm_hardware_enable(void *garbage)
static int svm_hardware_enable(void *garbage)
{

struct svm_cpu_data *svm_data;
Expand All @@ -325,16 +325,20 @@ static void svm_hardware_enable(void *garbage)
struct desc_struct *gdt;
int me = raw_smp_processor_id();

rdmsrl(MSR_EFER, efer);
if (efer & EFER_SVME)
return -EBUSY;

if (!has_svm()) {
printk(KERN_ERR "svm_cpu_init: err EOPNOTSUPP on %d\n", me);
return;
return -EINVAL;
}
svm_data = per_cpu(svm_data, me);

if (!svm_data) {
printk(KERN_ERR "svm_cpu_init: svm_data is NULL on %d\n",
me);
return;
return -EINVAL;
}

svm_data->asid_generation = 1;
Expand All @@ -345,11 +349,12 @@ static void svm_hardware_enable(void *garbage)
gdt = (struct desc_struct *)gdt_descr.base;
svm_data->tss_desc = (struct kvm_ldttss_desc *)(gdt + GDT_ENTRY_TSS);

rdmsrl(MSR_EFER, efer);
wrmsrl(MSR_EFER, efer | EFER_SVME);

wrmsrl(MSR_VM_HSAVE_PA,
page_to_pfn(svm_data->save_area) << PAGE_SHIFT);

return 0;
}

static void svm_cpu_uninit(int cpu)
Expand Down
11 changes: 8 additions & 3 deletions trunk/arch/x86/kvm/vmx.c
Original file line number Diff line number Diff line change
Expand Up @@ -1138,12 +1138,15 @@ static __init int vmx_disabled_by_bios(void)
/* locked but not enabled */
}

static void hardware_enable(void *garbage)
static int hardware_enable(void *garbage)
{
int cpu = raw_smp_processor_id();
u64 phys_addr = __pa(per_cpu(vmxarea, cpu));
u64 old;

if (read_cr4() & X86_CR4_VMXE)
return -EBUSY;

INIT_LIST_HEAD(&per_cpu(vcpus_on_cpu, cpu));
rdmsrl(MSR_IA32_FEATURE_CONTROL, old);
if ((old & (FEATURE_CONTROL_LOCKED |
Expand All @@ -1158,6 +1161,10 @@ static void hardware_enable(void *garbage)
asm volatile (ASM_VMX_VMXON_RAX
: : "a"(&phys_addr), "m"(phys_addr)
: "memory", "cc");

ept_sync_global();

return 0;
}

static void vmclear_local_vcpus(void)
Expand Down Expand Up @@ -4040,8 +4047,6 @@ static int __init vmx_init(void)
if (bypass_guest_pf)
kvm_mmu_set_nonpresent_ptes(~0xffeull, 0ull);

ept_sync_global();

return 0;

out3:
Expand Down
4 changes: 2 additions & 2 deletions trunk/arch/x86/kvm/x86.c
Original file line number Diff line number Diff line change
Expand Up @@ -4691,9 +4691,9 @@ int kvm_arch_vcpu_reset(struct kvm_vcpu *vcpu)
return kvm_x86_ops->vcpu_reset(vcpu);
}

void kvm_arch_hardware_enable(void *garbage)
int kvm_arch_hardware_enable(void *garbage)
{
kvm_x86_ops->hardware_enable(garbage);
return kvm_x86_ops->hardware_enable(garbage);
}

void kvm_arch_hardware_disable(void *garbage)
Expand Down
2 changes: 1 addition & 1 deletion trunk/include/linux/kvm_host.h
Original file line number Diff line number Diff line change
Expand Up @@ -345,7 +345,7 @@ int kvm_arch_vcpu_setup(struct kvm_vcpu *vcpu);
void kvm_arch_vcpu_destroy(struct kvm_vcpu *vcpu);

int kvm_arch_vcpu_reset(struct kvm_vcpu *vcpu);
void kvm_arch_hardware_enable(void *garbage);
int kvm_arch_hardware_enable(void *garbage);
void kvm_arch_hardware_disable(void *garbage);
int kvm_arch_hardware_setup(void);
void kvm_arch_hardware_unsetup(void);
Expand Down
90 changes: 78 additions & 12 deletions trunk/virt/kvm/kvm_main.c
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,8 @@ DEFINE_SPINLOCK(kvm_lock);
LIST_HEAD(vm_list);

static cpumask_var_t cpus_hardware_enabled;
static int kvm_usage_count = 0;
static atomic_t hardware_enable_failed;

struct kmem_cache *kvm_vcpu_cache;
EXPORT_SYMBOL_GPL(kvm_vcpu_cache);
Expand All @@ -79,6 +81,8 @@ struct dentry *kvm_debugfs_dir;

static long kvm_vcpu_ioctl(struct file *file, unsigned int ioctl,
unsigned long arg);
static int hardware_enable_all(void);
static void hardware_disable_all(void);

static bool kvm_rebooting;

Expand Down Expand Up @@ -339,13 +343,19 @@ static const struct mmu_notifier_ops kvm_mmu_notifier_ops = {

static struct kvm *kvm_create_vm(void)
{
int r = 0;
struct kvm *kvm = kvm_arch_create_vm();
#ifdef KVM_COALESCED_MMIO_PAGE_OFFSET
struct page *page;
#endif

if (IS_ERR(kvm))
goto out;

r = hardware_enable_all();
if (r)
goto out_err_nodisable;

#ifdef CONFIG_HAVE_KVM_IRQCHIP
INIT_HLIST_HEAD(&kvm->mask_notifier_list);
INIT_HLIST_HEAD(&kvm->irq_ack_notifier_list);
Expand All @@ -354,24 +364,22 @@ static struct kvm *kvm_create_vm(void)
#ifdef KVM_COALESCED_MMIO_PAGE_OFFSET
page = alloc_page(GFP_KERNEL | __GFP_ZERO);
if (!page) {
kfree(kvm);
return ERR_PTR(-ENOMEM);
r = -ENOMEM;
goto out_err;
}
kvm->coalesced_mmio_ring =
(struct kvm_coalesced_mmio_ring *)page_address(page);
#endif

#if defined(CONFIG_MMU_NOTIFIER) && defined(KVM_ARCH_WANT_MMU_NOTIFIER)
{
int err;
kvm->mmu_notifier.ops = &kvm_mmu_notifier_ops;
err = mmu_notifier_register(&kvm->mmu_notifier, current->mm);
if (err) {
r = mmu_notifier_register(&kvm->mmu_notifier, current->mm);
if (r) {
#ifdef KVM_COALESCED_MMIO_PAGE_OFFSET
put_page(page);
#endif
kfree(kvm);
return ERR_PTR(err);
goto out_err;
}
}
#endif
Expand All @@ -395,6 +403,12 @@ static struct kvm *kvm_create_vm(void)
#endif
out:
return kvm;

out_err:
hardware_disable_all();
out_err_nodisable:
kfree(kvm);
return ERR_PTR(r);
}

/*
Expand Down Expand Up @@ -453,6 +467,7 @@ static void kvm_destroy_vm(struct kvm *kvm)
kvm_arch_flush_shadow(kvm);
#endif
kvm_arch_destroy_vm(kvm);
hardware_disable_all();
mmdrop(mm);
}

Expand Down Expand Up @@ -1644,11 +1659,21 @@ static struct miscdevice kvm_dev = {
static void hardware_enable(void *junk)
{
int cpu = raw_smp_processor_id();
int r;

if (cpumask_test_cpu(cpu, cpus_hardware_enabled))
return;

cpumask_set_cpu(cpu, cpus_hardware_enabled);
kvm_arch_hardware_enable(NULL);

r = kvm_arch_hardware_enable(NULL);

if (r) {
cpumask_clear_cpu(cpu, cpus_hardware_enabled);
atomic_inc(&hardware_enable_failed);
printk(KERN_INFO "kvm: enabling virtualization on "
"CPU%d failed\n", cpu);
}
}

static void hardware_disable(void *junk)
Expand All @@ -1661,11 +1686,52 @@ static void hardware_disable(void *junk)
kvm_arch_hardware_disable(NULL);
}

static void hardware_disable_all_nolock(void)
{
BUG_ON(!kvm_usage_count);

kvm_usage_count--;
if (!kvm_usage_count)
on_each_cpu(hardware_disable, NULL, 1);
}

static void hardware_disable_all(void)
{
spin_lock(&kvm_lock);
hardware_disable_all_nolock();
spin_unlock(&kvm_lock);
}

static int hardware_enable_all(void)
{
int r = 0;

spin_lock(&kvm_lock);

kvm_usage_count++;
if (kvm_usage_count == 1) {
atomic_set(&hardware_enable_failed, 0);
on_each_cpu(hardware_enable, NULL, 1);

if (atomic_read(&hardware_enable_failed)) {
hardware_disable_all_nolock();
r = -EBUSY;
}
}

spin_unlock(&kvm_lock);

return r;
}

static int kvm_cpu_hotplug(struct notifier_block *notifier, unsigned long val,
void *v)
{
int cpu = (long)v;

if (!kvm_usage_count)
return NOTIFY_OK;

val &= ~CPU_TASKS_FROZEN;
switch (val) {
case CPU_DYING:
Expand Down Expand Up @@ -1868,13 +1934,15 @@ static void kvm_exit_debug(void)

static int kvm_suspend(struct sys_device *dev, pm_message_t state)
{
hardware_disable(NULL);
if (kvm_usage_count)
hardware_disable(NULL);
return 0;
}

static int kvm_resume(struct sys_device *dev)
{
hardware_enable(NULL);
if (kvm_usage_count)
hardware_enable(NULL);
return 0;
}

Expand Down Expand Up @@ -1949,7 +2017,6 @@ int kvm_init(void *opaque, unsigned int vcpu_size,
goto out_free_1;
}

on_each_cpu(hardware_enable, NULL, 1);
r = register_cpu_notifier(&kvm_cpu_notifier);
if (r)
goto out_free_2;
Expand Down Expand Up @@ -1999,7 +2066,6 @@ int kvm_init(void *opaque, unsigned int vcpu_size,
unregister_reboot_notifier(&kvm_reboot_notifier);
unregister_cpu_notifier(&kvm_cpu_notifier);
out_free_2:
on_each_cpu(hardware_disable, NULL, 1);
out_free_1:
kvm_arch_hardware_unsetup();
out_free_0a:
Expand Down

0 comments on commit 18201bd

Please sign in to comment.