Commit fb3f0f51 authored by Rusty Russell's avatar Rusty Russell Committed by Avi Kivity

KVM: Dynamically allocate vcpus

This patch converts the vcpus array in "struct kvm" to a pointer
array, and changes the "vcpu_create" and "vcpu_setup" hooks into one
"vcpu_create" call which does the allocation and initialization of the
vcpu (calling back into the kvm_vcpu_init core helper).
Signed-off-by: default avatarRusty Russell <rusty@rustcorp.com.au>
Signed-off-by: default avatarAvi Kivity <avi@qumranet.com>
parent a2fa3e9f
...@@ -300,10 +300,8 @@ void kvm_io_bus_register_dev(struct kvm_io_bus *bus, ...@@ -300,10 +300,8 @@ void kvm_io_bus_register_dev(struct kvm_io_bus *bus,
struct kvm_io_device *dev); struct kvm_io_device *dev);
struct kvm_vcpu { struct kvm_vcpu {
int valid;
struct kvm *kvm; struct kvm *kvm;
int vcpu_id; int vcpu_id;
void *_priv;
struct mutex mutex; struct mutex mutex;
int cpu; int cpu;
u64 host_tsc; u64 host_tsc;
...@@ -404,8 +402,7 @@ struct kvm { ...@@ -404,8 +402,7 @@ struct kvm {
struct list_head active_mmu_pages; struct list_head active_mmu_pages;
int n_free_mmu_pages; int n_free_mmu_pages;
struct hlist_head mmu_page_hash[KVM_NUM_MMU_PAGES]; struct hlist_head mmu_page_hash[KVM_NUM_MMU_PAGES];
int nvcpus; struct kvm_vcpu *vcpus[KVM_MAX_VCPUS];
struct kvm_vcpu vcpus[KVM_MAX_VCPUS];
int memory_config_version; int memory_config_version;
int busy; int busy;
unsigned long rmap_overflow; unsigned long rmap_overflow;
...@@ -428,7 +425,8 @@ struct kvm_arch_ops { ...@@ -428,7 +425,8 @@ struct kvm_arch_ops {
int (*hardware_setup)(void); /* __init */ int (*hardware_setup)(void); /* __init */
void (*hardware_unsetup)(void); /* __exit */ void (*hardware_unsetup)(void); /* __exit */
int (*vcpu_create)(struct kvm_vcpu *vcpu); /* Create, but do not attach this VCPU */
struct kvm_vcpu *(*vcpu_create)(struct kvm *kvm, unsigned id);
void (*vcpu_free)(struct kvm_vcpu *vcpu); void (*vcpu_free)(struct kvm_vcpu *vcpu);
void (*vcpu_load)(struct kvm_vcpu *vcpu); void (*vcpu_load)(struct kvm_vcpu *vcpu);
...@@ -470,7 +468,6 @@ struct kvm_arch_ops { ...@@ -470,7 +468,6 @@ struct kvm_arch_ops {
void (*inject_gp)(struct kvm_vcpu *vcpu, unsigned err_code); void (*inject_gp)(struct kvm_vcpu *vcpu, unsigned err_code);
int (*run)(struct kvm_vcpu *vcpu, struct kvm_run *run); int (*run)(struct kvm_vcpu *vcpu, struct kvm_run *run);
int (*vcpu_setup)(struct kvm_vcpu *vcpu);
void (*skip_emulated_instruction)(struct kvm_vcpu *vcpu); void (*skip_emulated_instruction)(struct kvm_vcpu *vcpu);
void (*patch_hypercall)(struct kvm_vcpu *vcpu, void (*patch_hypercall)(struct kvm_vcpu *vcpu,
unsigned char *hypercall_addr); unsigned char *hypercall_addr);
...@@ -481,6 +478,9 @@ extern struct kvm_arch_ops *kvm_arch_ops; ...@@ -481,6 +478,9 @@ extern struct kvm_arch_ops *kvm_arch_ops;
#define kvm_printf(kvm, fmt ...) printk(KERN_DEBUG fmt) #define kvm_printf(kvm, fmt ...) printk(KERN_DEBUG fmt)
#define vcpu_printf(vcpu, fmt...) kvm_printf(vcpu->kvm, fmt) #define vcpu_printf(vcpu, fmt...) kvm_printf(vcpu->kvm, fmt)
int kvm_vcpu_init(struct kvm_vcpu *vcpu, struct kvm *kvm, unsigned id);
void kvm_vcpu_uninit(struct kvm_vcpu *vcpu);
int kvm_init_arch(struct kvm_arch_ops *ops, struct module *module); int kvm_init_arch(struct kvm_arch_ops *ops, struct module *module);
void kvm_exit_arch(void); void kvm_exit_arch(void);
......
...@@ -266,8 +266,10 @@ void kvm_flush_remote_tlbs(struct kvm *kvm) ...@@ -266,8 +266,10 @@ void kvm_flush_remote_tlbs(struct kvm *kvm)
atomic_set(&completed, 0); atomic_set(&completed, 0);
cpus_clear(cpus); cpus_clear(cpus);
needed = 0; needed = 0;
for (i = 0; i < kvm->nvcpus; ++i) { for (i = 0; i < KVM_MAX_VCPUS; ++i) {
vcpu = &kvm->vcpus[i]; vcpu = kvm->vcpus[i];
if (!vcpu)
continue;
if (test_and_set_bit(KVM_TLB_FLUSH, &vcpu->requests)) if (test_and_set_bit(KVM_TLB_FLUSH, &vcpu->requests))
continue; continue;
cpu = vcpu->cpu; cpu = vcpu->cpu;
...@@ -291,10 +293,61 @@ void kvm_flush_remote_tlbs(struct kvm *kvm) ...@@ -291,10 +293,61 @@ void kvm_flush_remote_tlbs(struct kvm *kvm)
} }
} }
int kvm_vcpu_init(struct kvm_vcpu *vcpu, struct kvm *kvm, unsigned id)
{
struct page *page;
int r;
mutex_init(&vcpu->mutex);
vcpu->cpu = -1;
vcpu->mmu.root_hpa = INVALID_PAGE;
vcpu->kvm = kvm;
vcpu->vcpu_id = id;
page = alloc_page(GFP_KERNEL | __GFP_ZERO);
if (!page) {
r = -ENOMEM;
goto fail;
}
vcpu->run = page_address(page);
page = alloc_page(GFP_KERNEL | __GFP_ZERO);
if (!page) {
r = -ENOMEM;
goto fail_free_run;
}
vcpu->pio_data = page_address(page);
vcpu->host_fx_image = (char*)ALIGN((hva_t)vcpu->fx_buf,
FX_IMAGE_ALIGN);
vcpu->guest_fx_image = vcpu->host_fx_image + FX_IMAGE_SIZE;
r = kvm_mmu_create(vcpu);
if (r < 0)
goto fail_free_pio_data;
return 0;
fail_free_pio_data:
free_page((unsigned long)vcpu->pio_data);
fail_free_run:
free_page((unsigned long)vcpu->run);
fail:
return -ENOMEM;
}
EXPORT_SYMBOL_GPL(kvm_vcpu_init);
void kvm_vcpu_uninit(struct kvm_vcpu *vcpu)
{
kvm_mmu_destroy(vcpu);
free_page((unsigned long)vcpu->pio_data);
free_page((unsigned long)vcpu->run);
}
EXPORT_SYMBOL_GPL(kvm_vcpu_uninit);
static struct kvm *kvm_create_vm(void) static struct kvm *kvm_create_vm(void)
{ {
struct kvm *kvm = kzalloc(sizeof(struct kvm), GFP_KERNEL); struct kvm *kvm = kzalloc(sizeof(struct kvm), GFP_KERNEL);
int i;
if (!kvm) if (!kvm)
return ERR_PTR(-ENOMEM); return ERR_PTR(-ENOMEM);
...@@ -303,14 +356,6 @@ static struct kvm *kvm_create_vm(void) ...@@ -303,14 +356,6 @@ static struct kvm *kvm_create_vm(void)
spin_lock_init(&kvm->lock); spin_lock_init(&kvm->lock);
INIT_LIST_HEAD(&kvm->active_mmu_pages); INIT_LIST_HEAD(&kvm->active_mmu_pages);
kvm_io_bus_init(&kvm->mmio_bus); kvm_io_bus_init(&kvm->mmio_bus);
for (i = 0; i < KVM_MAX_VCPUS; ++i) {
struct kvm_vcpu *vcpu = &kvm->vcpus[i];
mutex_init(&vcpu->mutex);
vcpu->cpu = -1;
vcpu->kvm = kvm;
vcpu->mmu.root_hpa = INVALID_PAGE;
}
spin_lock(&kvm_lock); spin_lock(&kvm_lock);
list_add(&kvm->vm_list, &vm_list); list_add(&kvm->vm_list, &vm_list);
spin_unlock(&kvm_lock); spin_unlock(&kvm_lock);
...@@ -367,30 +412,11 @@ static void free_pio_guest_pages(struct kvm_vcpu *vcpu) ...@@ -367,30 +412,11 @@ static void free_pio_guest_pages(struct kvm_vcpu *vcpu)
static void kvm_unload_vcpu_mmu(struct kvm_vcpu *vcpu) static void kvm_unload_vcpu_mmu(struct kvm_vcpu *vcpu)
{ {
if (!vcpu->valid)
return;
vcpu_load(vcpu); vcpu_load(vcpu);
kvm_mmu_unload(vcpu); kvm_mmu_unload(vcpu);
vcpu_put(vcpu); vcpu_put(vcpu);
} }
static void kvm_free_vcpu(struct kvm_vcpu *vcpu)
{
if (!vcpu->valid)
return;
vcpu_load(vcpu);
kvm_mmu_destroy(vcpu);
vcpu_put(vcpu);
kvm_arch_ops->vcpu_free(vcpu);
free_page((unsigned long)vcpu->run);
vcpu->run = NULL;
free_page((unsigned long)vcpu->pio_data);
vcpu->pio_data = NULL;
free_pio_guest_pages(vcpu);
}
static void kvm_free_vcpus(struct kvm *kvm) static void kvm_free_vcpus(struct kvm *kvm)
{ {
unsigned int i; unsigned int i;
...@@ -399,9 +425,15 @@ static void kvm_free_vcpus(struct kvm *kvm) ...@@ -399,9 +425,15 @@ static void kvm_free_vcpus(struct kvm *kvm)
* Unpin any mmu pages first. * Unpin any mmu pages first.
*/ */
for (i = 0; i < KVM_MAX_VCPUS; ++i) for (i = 0; i < KVM_MAX_VCPUS; ++i)
kvm_unload_vcpu_mmu(&kvm->vcpus[i]); if (kvm->vcpus[i])
for (i = 0; i < KVM_MAX_VCPUS; ++i) kvm_unload_vcpu_mmu(kvm->vcpus[i]);
kvm_free_vcpu(&kvm->vcpus[i]); for (i = 0; i < KVM_MAX_VCPUS; ++i) {
if (kvm->vcpus[i]) {
kvm_arch_ops->vcpu_free(kvm->vcpus[i]);
kvm->vcpus[i] = NULL;
}
}
} }
static int kvm_dev_release(struct inode *inode, struct file *filp) static int kvm_dev_release(struct inode *inode, struct file *filp)
...@@ -2372,77 +2404,47 @@ static int kvm_vm_ioctl_create_vcpu(struct kvm *kvm, int n) ...@@ -2372,77 +2404,47 @@ static int kvm_vm_ioctl_create_vcpu(struct kvm *kvm, int n)
{ {
int r; int r;
struct kvm_vcpu *vcpu; struct kvm_vcpu *vcpu;
struct page *page;
r = -EINVAL;
if (!valid_vcpu(n)) if (!valid_vcpu(n))
goto out; return -EINVAL;
vcpu = &kvm->vcpus[n];
vcpu->vcpu_id = n;
mutex_lock(&vcpu->mutex);
if (vcpu->valid) {
mutex_unlock(&vcpu->mutex);
return -EEXIST;
}
page = alloc_page(GFP_KERNEL | __GFP_ZERO);
r = -ENOMEM;
if (!page)
goto out_unlock;
vcpu->run = page_address(page);
page = alloc_page(GFP_KERNEL | __GFP_ZERO);
r = -ENOMEM;
if (!page)
goto out_free_run;
vcpu->pio_data = page_address(page);
vcpu->host_fx_image = (char*)ALIGN((hva_t)vcpu->fx_buf,
FX_IMAGE_ALIGN);
vcpu->guest_fx_image = vcpu->host_fx_image + FX_IMAGE_SIZE;
vcpu->cr0 = 0x10;
r = kvm_arch_ops->vcpu_create(vcpu);
if (r < 0)
goto out_free_vcpus;
r = kvm_mmu_create(vcpu); vcpu = kvm_arch_ops->vcpu_create(kvm, n);
if (r < 0) if (IS_ERR(vcpu))
goto out_free_vcpus; return PTR_ERR(vcpu);
kvm_arch_ops->vcpu_load(vcpu); vcpu_load(vcpu);
r = kvm_mmu_setup(vcpu); r = kvm_mmu_setup(vcpu);
if (r >= 0)
r = kvm_arch_ops->vcpu_setup(vcpu);
vcpu_put(vcpu); vcpu_put(vcpu);
if (r < 0) if (r < 0)
goto out_free_vcpus; goto free_vcpu;
spin_lock(&kvm->lock);
if (kvm->vcpus[n]) {
r = -EEXIST;
spin_unlock(&kvm->lock);
goto mmu_unload;
}
kvm->vcpus[n] = vcpu;
spin_unlock(&kvm->lock);
/* Now it's all set up, let userspace reach it */
r = create_vcpu_fd(vcpu); r = create_vcpu_fd(vcpu);
if (r < 0) if (r < 0)
goto out_free_vcpus; goto unlink;
return r;
spin_lock(&kvm_lock);
if (n >= kvm->nvcpus)
kvm->nvcpus = n + 1;
spin_unlock(&kvm_lock);
vcpu->valid = 1; unlink:
spin_lock(&kvm->lock);
kvm->vcpus[n] = NULL;
spin_unlock(&kvm->lock);
return r; mmu_unload:
vcpu_load(vcpu);
kvm_mmu_unload(vcpu);
vcpu_put(vcpu);
out_free_vcpus: free_vcpu:
kvm_free_vcpu(vcpu); kvm_arch_ops->vcpu_free(vcpu);
out_free_run:
free_page((unsigned long)vcpu->run);
vcpu->run = NULL;
out_unlock:
mutex_unlock(&vcpu->mutex);
out:
return r; return r;
} }
...@@ -2935,9 +2937,12 @@ static void decache_vcpus_on_cpu(int cpu) ...@@ -2935,9 +2937,12 @@ static void decache_vcpus_on_cpu(int cpu)
int i; int i;
spin_lock(&kvm_lock); spin_lock(&kvm_lock);
list_for_each_entry(vm, &vm_list, vm_list) list_for_each_entry(vm, &vm_list, vm_list) {
spin_lock(&vm->lock);
for (i = 0; i < KVM_MAX_VCPUS; ++i) { for (i = 0; i < KVM_MAX_VCPUS; ++i) {
vcpu = &vm->vcpus[i]; vcpu = vm->vcpus[i];
if (!vcpu)
continue;
/* /*
* If the vcpu is locked, then it is running on some * If the vcpu is locked, then it is running on some
* other cpu and therefore it is not cached on the * other cpu and therefore it is not cached on the
...@@ -2954,6 +2959,8 @@ static void decache_vcpus_on_cpu(int cpu) ...@@ -2954,6 +2959,8 @@ static void decache_vcpus_on_cpu(int cpu)
mutex_unlock(&vcpu->mutex); mutex_unlock(&vcpu->mutex);
} }
} }
spin_unlock(&vm->lock);
}
spin_unlock(&kvm_lock); spin_unlock(&kvm_lock);
} }
...@@ -3078,8 +3085,9 @@ static u64 stat_get(void *_offset) ...@@ -3078,8 +3085,9 @@ static u64 stat_get(void *_offset)
spin_lock(&kvm_lock); spin_lock(&kvm_lock);
list_for_each_entry(kvm, &vm_list, vm_list) list_for_each_entry(kvm, &vm_list, vm_list)
for (i = 0; i < KVM_MAX_VCPUS; ++i) { for (i = 0; i < KVM_MAX_VCPUS; ++i) {
vcpu = &kvm->vcpus[i]; vcpu = kvm->vcpus[i];
total += *(u32 *)((void *)vcpu + offset); if (vcpu)
total += *(u32 *)((void *)vcpu + offset);
} }
spin_unlock(&kvm_lock); spin_unlock(&kvm_lock);
return total; return total;
......
...@@ -23,7 +23,7 @@ static const u32 host_save_user_msrs[] = { ...@@ -23,7 +23,7 @@ static const u32 host_save_user_msrs[] = {
struct kvm_vcpu; struct kvm_vcpu;
struct vcpu_svm { struct vcpu_svm {
struct kvm_vcpu *vcpu; struct kvm_vcpu vcpu;
struct vmcb *vmcb; struct vmcb *vmcb;
unsigned long vmcb_pa; unsigned long vmcb_pa;
struct svm_cpu_data *svm_data; struct svm_cpu_data *svm_data;
......
...@@ -51,7 +51,7 @@ MODULE_LICENSE("GPL"); ...@@ -51,7 +51,7 @@ MODULE_LICENSE("GPL");
static inline struct vcpu_svm *to_svm(struct kvm_vcpu *vcpu) static inline struct vcpu_svm *to_svm(struct kvm_vcpu *vcpu)
{ {
return (struct vcpu_svm*)vcpu->_priv; return container_of(vcpu, struct vcpu_svm, vcpu);
} }
unsigned long iopm_base; unsigned long iopm_base;
...@@ -466,11 +466,6 @@ static void init_sys_seg(struct vmcb_seg *seg, uint32_t type) ...@@ -466,11 +466,6 @@ static void init_sys_seg(struct vmcb_seg *seg, uint32_t type)
seg->base = 0; seg->base = 0;
} }
static int svm_vcpu_setup(struct kvm_vcpu *vcpu)
{
return 0;
}
static void init_vmcb(struct vmcb *vmcb) static void init_vmcb(struct vmcb *vmcb)
{ {
struct vmcb_control_area *control = &vmcb->control; struct vmcb_control_area *control = &vmcb->control;
...@@ -576,19 +571,27 @@ static void init_vmcb(struct vmcb *vmcb) ...@@ -576,19 +571,27 @@ static void init_vmcb(struct vmcb *vmcb)
/* rdx = ?? */ /* rdx = ?? */
} }
static int svm_create_vcpu(struct kvm_vcpu *vcpu) static struct kvm_vcpu *svm_create_vcpu(struct kvm *kvm, unsigned int id)
{ {
struct vcpu_svm *svm; struct vcpu_svm *svm;
struct page *page; struct page *page;
int r; int err;
r = -ENOMEM;
svm = kzalloc(sizeof *svm, GFP_KERNEL); svm = kzalloc(sizeof *svm, GFP_KERNEL);
if (!svm) if (!svm) {
goto out1; err = -ENOMEM;
goto out;
}
err = kvm_vcpu_init(&svm->vcpu, kvm, id);
if (err)
goto free_svm;
page = alloc_page(GFP_KERNEL); page = alloc_page(GFP_KERNEL);
if (!page) if (!page) {
goto out2; err = -ENOMEM;
goto uninit;
}
svm->vmcb = page_address(page); svm->vmcb = page_address(page);
clear_page(svm->vmcb); clear_page(svm->vmcb);
...@@ -597,33 +600,29 @@ static int svm_create_vcpu(struct kvm_vcpu *vcpu) ...@@ -597,33 +600,29 @@ static int svm_create_vcpu(struct kvm_vcpu *vcpu)
memset(svm->db_regs, 0, sizeof(svm->db_regs)); memset(svm->db_regs, 0, sizeof(svm->db_regs));
init_vmcb(svm->vmcb); init_vmcb(svm->vmcb);
svm->vcpu = vcpu; fx_init(&svm->vcpu);
vcpu->_priv = svm; svm->vcpu.fpu_active = 1;
svm->vcpu.apic_base = 0xfee00000 | MSR_IA32_APICBASE_ENABLE;
if (svm->vcpu.vcpu_id == 0)
svm->vcpu.apic_base |= MSR_IA32_APICBASE_BSP;
fx_init(vcpu); return &svm->vcpu;
vcpu->fpu_active = 1;
vcpu->apic_base = 0xfee00000 | MSR_IA32_APICBASE_ENABLE;
if (vcpu->vcpu_id == 0)
vcpu->apic_base |= MSR_IA32_APICBASE_BSP;
return 0; uninit:
kvm_vcpu_uninit(&svm->vcpu);
out2: free_svm:
kfree(svm); kfree(svm);
out1: out:
return r; return ERR_PTR(err);
} }
static void svm_free_vcpu(struct kvm_vcpu *vcpu) static void svm_free_vcpu(struct kvm_vcpu *vcpu)
{ {
struct vcpu_svm *svm = to_svm(vcpu); struct vcpu_svm *svm = to_svm(vcpu);
if (!svm) __free_page(pfn_to_page(svm->vmcb_pa >> PAGE_SHIFT));
return; kvm_vcpu_uninit(vcpu);
if (svm->vmcb)
__free_page(pfn_to_page(svm->vmcb_pa >> PAGE_SHIFT));
kfree(svm); kfree(svm);
vcpu->_priv = NULL;
} }
static void svm_vcpu_load(struct kvm_vcpu *vcpu) static void svm_vcpu_load(struct kvm_vcpu *vcpu)
...@@ -1591,34 +1590,33 @@ static int svm_vcpu_run(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run) ...@@ -1591,34 +1590,33 @@ static int svm_vcpu_run(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
#endif #endif
#ifdef CONFIG_X86_64 #ifdef CONFIG_X86_64
"mov %c[rbx](%[vcpu]), %%rbx \n\t" "mov %c[rbx](%[svm]), %%rbx \n\t"
"mov %c[rcx](%[vcpu]), %%rcx \n\t" "mov %c[rcx](%[svm]), %%rcx \n\t"
"mov %c[rdx](%[vcpu]), %%rdx \n\t" "mov %c[rdx](%[svm]), %%rdx \n\t"
"mov %c[rsi](%[vcpu]), %%rsi \n\t" "mov %c[rsi](%[svm]), %%rsi \n\t"
"mov %c[rdi](%[vcpu]), %%rdi \n\t" "mov %c[rdi](%[svm]), %%rdi \n\t"
"mov %c[rbp](%[vcpu]), %%rbp \n\t" "mov %c[rbp](%[svm]), %%rbp \n\t"
"mov %c[r8](%[vcpu]), %%r8 \n\t" "mov %c[r8](%[svm]), %%r8 \n\t"
"mov %c[r9](%[vcpu]), %%r9 \n\t" "mov %c[r9](%[svm]), %%r9 \n\t"
"mov %c[r10](%[vcpu]), %%r10 \n\t" "mov %c[r10](%[svm]), %%r10 \n\t"
"mov %c[r11](%[vcpu]), %%r11 \n\t" "mov %c[r11](%[svm]), %%r11 \n\t"
"mov %c[r12](%[vcpu]), %%r12 \n\t" "mov %c[r12](%[svm]), %%r12 \n\t"
"mov %c[r13](%[vcpu]), %%r13 \n\t" "mov %c[r13](%[svm]), %%r13 \n\t"
"mov %c[r14](%[vcpu]), %%r14 \n\t" "mov %c[r14](%[svm]), %%r14 \n\t"
"mov %c[r15](%[vcpu]), %%r15 \n\t" "mov %c[r15](%[svm]), %%r15 \n\t"
#else #else
"mov %c[rbx](%[vcpu]), %%ebx \n\t" "mov %c[rbx](%[svm]), %%ebx \n\t"
"mov %c[rcx](%[vcpu]), %%ecx \n\t" "mov %c[rcx](%[svm]), %%ecx \n\t"
"mov %c[rdx](%[vcpu]), %%edx \n\t" "mov %c[rdx](%[svm]), %%edx \n\t"
"mov %c[rsi](%[vcpu]), %%esi \n\t" "mov %c[rsi](%[svm]), %%esi \n\t"
"mov %c[rdi](%[vcpu]), %%edi \n\t" "mov %c[rdi](%[svm]), %%edi \n\t"
"mov %c[rbp](%[vcpu]), %%ebp \n\t" "mov %c[rbp](%[svm]), %%ebp \n\t"
#endif #endif
#ifdef CONFIG_X86_64 #ifdef CONFIG_X86_64
/* Enter guest mode */ /* Enter guest mode */
"push %%rax \n\t" "push %%rax \n\t"
"mov %c[svm](%[vcpu]), %%rax \n\t" "mov %c[vmcb](%[svm]), %%rax \n\t"
"mov %c[vmcb](%%rax), %%rax \n\t"
SVM_VMLOAD "\n\t" SVM_VMLOAD "\n\t"
SVM_VMRUN "\n\t" SVM_VMRUN "\n\t"
SVM_VMSAVE "\n\t" SVM_VMSAVE "\n\t"
...@@ -1626,8 +1624,7 @@ static int svm_vcpu_run(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run) ...@@ -1626,8 +1624,7 @@ static int svm_vcpu_run(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
#else #else
/* Enter guest mode */ /* Enter guest mode */
"push %%eax \n\t" "push %%eax \n\t"
"mov %c[svm](%[vcpu]), %%eax \n\t" "mov %c[vmcb](%[svm]), %%eax \n\t"
"mov %c[vmcb](%%eax), %%eax \n\t"
SVM_VMLOAD "\n\t" SVM_VMLOAD "\n\t"
SVM_VMRUN "\n\t" SVM_VMRUN "\n\t"
SVM_VMSAVE "\n\t" SVM_VMSAVE "\n\t"
...@@ -1636,55 +1633,54 @@ static int svm_vcpu_run(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run) ...@@ -1636,55 +1633,54 @@ static int svm_vcpu_run(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
/* Save guest registers, load host registers */ /* Save guest registers, load host registers */
#ifdef CONFIG_X86_64 #ifdef CONFIG_X86_64
"mov %%rbx, %c[rbx](%[vcpu]) \n\t" "mov %%rbx, %c[rbx](%[svm]) \n\t"
"mov %%rcx, %c[rcx](%[vcpu]) \n\t" "mov %%rcx, %c[rcx](%[svm]) \n\t"
"mov %%rdx, %c[rdx](%[vcpu]) \n\t" "mov %%rdx, %c[rdx](%[svm]) \n\t"
"mov %%rsi, %c[rsi](%[vcpu]) \n\t" "mov %%rsi, %c[rsi](%[svm]) \n\t"
"mov %%rdi, %c[rdi](%[vcpu]) \n\t" "mov %%rdi, %c[rdi](%[svm]) \n\t"
"mov %%rbp, %c[rbp](%[vcpu]) \n\t" "mov %%rbp, %c[rbp](%[svm]) \n\t"
"mov %%r8, %c[r8](%[vcpu]) \n\t" "mov %%r8, %c[r8](%[svm]) \n\t"
"mov %%r9, %c[r9](%[vcpu]) \n\t" "mov %%r9, %c[r9](%[svm]) \n\t"
"mov %%r10, %c[r10](%[vcpu]) \n\t" "mov %%r10, %c[r10](%[svm]) \n\t"
"mov %%r11, %c[r11](%[vcpu]) \n\t" "mov %%r11, %c[r11](%[svm]) \n\t"
"mov %%r12, %c[r12](%[vcpu]) \n\t" "mov %%r12, %c[r12](%[svm]) \n\t"
"mov %%r13, %c[r13](%[vcpu]) \n\t" "mov %%r13, %c[r13](%[svm]) \n\t"
"mov %%r14, %c[r14](%[vcpu]) \n\t" "mov %%r14, %c[r14](%[svm]) \n\t"
"mov %%r15, %c[r15](%[vcpu]) \n\t" "mov %%r15, %c[r15](%[svm]) \n\t"
"pop %%r15; pop %%r14; pop %%r13; pop %%r12;" "pop %%r15; pop %%r14; pop %%r13; pop %%r12;"
"pop %%r11; pop %%r10; pop %%r9; pop %%r8;" "pop %%r11; pop %%r10; pop %%r9; pop %%r8;"
"pop %%rbp; pop %%rdi; pop %%rsi;" "pop %%rbp; pop %%rdi; pop %%rsi;"
"pop %%rdx; pop %%rcx; pop %%rbx; \n\t" "pop %%rdx; pop %%rcx; pop %%rbx; \n\t"
#else #else
"mov %%ebx, %c[rbx](%[vcpu]) \n\t" "mov %%ebx, %c[rbx](%[svm]) \n\t"
"mov %%ecx, %c[rcx](%[vcpu]) \n\t" "mov %%ecx, %c[rcx](%[svm]) \n\t"
"mov %%edx, %c[rdx](%[vcpu]) \n\t" "mov %%edx, %c[rdx](%[svm]) \n\t"
"mov %%esi, %c[rsi](%[vcpu]) \n\t" "mov %%esi, %c[rsi](%[svm]) \n\t"
"mov %%edi, %c[rdi](%[vcpu]) \n\t" "mov %%edi, %c[rdi](%[svm]) \n\t"
"mov %%ebp, %c[rbp](%[vcpu]) \n\t" "mov %%ebp, %c[rbp](%[svm]) \n\t"
"pop %%ebp; pop %%edi; pop %%esi;" "pop %%ebp; pop %%edi; pop %%esi;"
"pop %%edx; pop %%ecx; pop %%ebx; \n\t" "pop %%edx; pop %%ecx; pop %%ebx; \n\t"
#endif #endif
: :
: [vcpu]"a"(vcpu), : [svm]"a"(svm),
[svm]"i"(offsetof(struct kvm_vcpu, _priv)),
[vmcb]"i"(offsetof(struct vcpu_svm, vmcb_pa)), [vmcb]"i"(offsetof(struct vcpu_svm, vmcb_pa)),
[rbx]"i"(offsetof(struct kvm_vcpu, regs[VCPU_REGS_RBX])), [rbx]"i"(offsetof(struct vcpu_svm,vcpu.regs[VCPU_REGS_RBX])),
[rcx]"i"(offsetof(struct kvm_vcpu, regs[VCPU_REGS_RCX])), [rcx]"i"(offsetof(struct vcpu_svm,vcpu.regs[VCPU_REGS_RCX])),
[rdx]"i"(offsetof(struct kvm_vcpu, regs[VCPU_REGS_RDX])), [rdx]"i"(offsetof(struct vcpu_svm,vcpu.regs[VCPU_REGS_RDX])),
[rsi]"i"(offsetof(struct kvm_vcpu, regs[VCPU_REGS_RSI])), [rsi]"i"(offsetof(struct vcpu_svm,vcpu.regs[VCPU_REGS_RSI])),
[rdi]"i"(offsetof(struct kvm_vcpu, regs[VCPU_REGS_RDI])), [rdi]"i"(offsetof(struct vcpu_svm,vcpu.regs[VCPU_REGS_RDI])),
[rbp]"i"(offsetof(struct kvm_vcpu, regs[VCPU_REGS_RBP])) [rbp]"i"(offsetof(struct vcpu_svm,vcpu.regs[VCPU_REGS_RBP]))
#ifdef CONFIG_X86_64 #ifdef CONFIG_X86_64
,[r8 ]"i"(offsetof(struct kvm_vcpu, regs[VCPU_REGS_R8 ])), ,[r8 ]"i"(offsetof(struct vcpu_svm,vcpu.regs[VCPU_REGS_R8])),
[r9 ]"i"(offsetof(struct kvm_vcpu, regs[VCPU_REGS_R9 ])), [r9 ]"i"(offsetof(struct vcpu_svm,vcpu.regs[VCPU_REGS_R9 ])),
[r10]"i"(offsetof(struct kvm_vcpu, regs[VCPU_REGS_R10])), [r10]"i"(offsetof(struct vcpu_svm,vcpu.regs[VCPU_REGS_R10])),
[r11]"i"(offsetof(struct kvm_vcpu, regs[VCPU_REGS_R11])), [r11]"i"(offsetof(struct vcpu_svm,vcpu.regs[VCPU_REGS_R11])),
[r12]"i"(offsetof(struct kvm_vcpu, regs[VCPU_REGS_R12])), [r12]"i"(offsetof(struct vcpu_svm,vcpu.regs[VCPU_REGS_R12])),
[r13]"i"(offsetof(struct kvm_vcpu, regs[VCPU_REGS_R13])), [r13]"i"(offsetof(struct vcpu_svm,vcpu.regs[VCPU_REGS_R13])),
[r14]"i"(offsetof(struct kvm_vcpu, regs[VCPU_REGS_R14])), [r14]"i"(offsetof(struct vcpu_svm,vcpu.regs[VCPU_REGS_R14])),
[r15]"i"(offsetof(struct kvm_vcpu, regs[VCPU_REGS_R15])) [r15]"i"(offsetof(struct vcpu_svm,vcpu.regs[VCPU_REGS_R15]))
#endif #endif
: "cc", "memory" ); : "cc", "memory" );
...@@ -1865,7 +1861,6 @@ static struct kvm_arch_ops svm_arch_ops = { ...@@ -1865,7 +1861,6 @@ static struct kvm_arch_ops svm_arch_ops = {
.run = svm_vcpu_run, .run = svm_vcpu_run,
.skip_emulated_instruction = skip_emulated_instruction, .skip_emulated_instruction = skip_emulated_instruction,
.vcpu_setup = svm_vcpu_setup,
.patch_hypercall = svm_patch_hypercall, .patch_hypercall = svm_patch_hypercall,
}; };
......
...@@ -39,7 +39,7 @@ struct vmcs { ...@@ -39,7 +39,7 @@ struct vmcs {
}; };
struct vcpu_vmx { struct vcpu_vmx {
struct kvm_vcpu *vcpu; struct kvm_vcpu vcpu;
int launched; int launched;
struct kvm_msr_entry *guest_msrs; struct kvm_msr_entry *guest_msrs;
struct kvm_msr_entry *host_msrs; struct kvm_msr_entry *host_msrs;
...@@ -60,7 +60,7 @@ struct vcpu_vmx { ...@@ -60,7 +60,7 @@ struct vcpu_vmx {
static inline struct vcpu_vmx *to_vmx(struct kvm_vcpu *vcpu) static inline struct vcpu_vmx *to_vmx(struct kvm_vcpu *vcpu)
{ {
return (struct vcpu_vmx*)vcpu->_priv; return container_of(vcpu, struct vcpu_vmx, vcpu);
} }
static int init_rmode_tss(struct kvm *kvm); static int init_rmode_tss(struct kvm *kvm);
...@@ -2302,46 +2302,62 @@ static void vmx_free_vmcs(struct kvm_vcpu *vcpu) ...@@ -2302,46 +2302,62 @@ static void vmx_free_vmcs(struct kvm_vcpu *vcpu)
static void vmx_free_vcpu(struct kvm_vcpu *vcpu) static void vmx_free_vcpu(struct kvm_vcpu *vcpu)
{ {
struct vcpu_vmx *vmx = to_vmx(vcpu);
vmx_free_vmcs(vcpu); vmx_free_vmcs(vcpu);
kfree(vmx->host_msrs);
kfree(vmx->guest_msrs);
kvm_vcpu_uninit(vcpu);
kfree(vmx);
} }
static int vmx_create_vcpu(struct kvm_vcpu *vcpu) static struct kvm_vcpu *vmx_create_vcpu(struct kvm *kvm, unsigned int id)
{ {
struct vcpu_vmx *vmx; int err;
struct vcpu_vmx *vmx = kzalloc(sizeof(*vmx), GFP_KERNEL);
vmx = kzalloc(sizeof(*vmx), GFP_KERNEL);
if (!vmx) if (!vmx)
return -ENOMEM; return ERR_PTR(-ENOMEM);
err = kvm_vcpu_init(&vmx->vcpu, kvm, id);
if (err)
goto free_vcpu;
vmx->guest_msrs = kmalloc(PAGE_SIZE, GFP_KERNEL); vmx->guest_msrs = kmalloc(PAGE_SIZE, GFP_KERNEL);
if (!vmx->guest_msrs) if (!vmx->guest_msrs) {
goto out_free; err = -ENOMEM;
goto uninit_vcpu;
}
vmx->host_msrs = kmalloc(PAGE_SIZE, GFP_KERNEL); vmx->host_msrs = kmalloc(PAGE_SIZE, GFP_KERNEL);
if (!vmx->host_msrs) if (!vmx->host_msrs)
goto out_free; goto free_guest_msrs;
vmx->vmcs = alloc_vmcs(); vmx->vmcs = alloc_vmcs();
if (!vmx->vmcs) if (!vmx->vmcs)
goto out_free; goto free_msrs;
vmcs_clear(vmx->vmcs); vmcs_clear(vmx->vmcs);
vmx->vcpu = vcpu; vmx_vcpu_load(&vmx->vcpu);
vcpu->_priv = vmx; err = vmx_vcpu_setup(&vmx->vcpu);
vmx_vcpu_put(&vmx->vcpu);
return 0; if (err)
goto free_vmcs;
out_free:
if (vmx->host_msrs) return &vmx->vcpu;
kfree(vmx->host_msrs);
free_vmcs:
if (vmx->guest_msrs) free_vmcs(vmx->vmcs);
kfree(vmx->guest_msrs); free_msrs:
kfree(vmx->host_msrs);
free_guest_msrs:
kfree(vmx->guest_msrs);
uninit_vcpu:
kvm_vcpu_uninit(&vmx->vcpu);
free_vcpu:
kfree(vmx); kfree(vmx);
return ERR_PTR(err);
return -ENOMEM;
} }
static struct kvm_arch_ops vmx_arch_ops = { static struct kvm_arch_ops vmx_arch_ops = {
...@@ -2389,7 +2405,6 @@ static struct kvm_arch_ops vmx_arch_ops = { ...@@ -2389,7 +2405,6 @@ static struct kvm_arch_ops vmx_arch_ops = {
.run = vmx_vcpu_run, .run = vmx_vcpu_run,
.skip_emulated_instruction = skip_emulated_instruction, .skip_emulated_instruction = skip_emulated_instruction,
.vcpu_setup = vmx_vcpu_setup,
.patch_hypercall = vmx_patch_hypercall, .patch_hypercall = vmx_patch_hypercall,
}; };
......
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