mirror of
https://github.com/torvalds/linux.git
synced 2024-11-12 07:01:57 +00:00
KVM: Portability: Split kvm_vm_ioctl v3
This patch splits kvm_vm_ioctl into archtecture independent parts, and x86 specific parts which go to kvm_arch_vcpu_ioctl in x86.c. The patch is unchanged since last submission. Common ioctls for all architectures are: KVM_CREATE_VCPU, KVM_GET_DIRTY_LOG, KVM_SET_USER_MEMORY_REGION x86 specific ioctls are: KVM_SET_MEMORY_REGION, KVM_GET/SET_NR_MMU_PAGES, KVM_SET_MEMORY_ALIAS, KVM_CREATE_IRQCHIP, KVM_CREATE_IRQ_LINE, KVM_GET/SET_IRQCHIP KVM_SET_TSS_ADDR Signed-off-by: Carsten Otte <cotte@de.ibm.com> Reviewed-by: Christian Borntraeger <borntraeger@de.ibm.com> Acked-by: Hollis Blanchard <hollisb@us.ibm.com> Signed-off-by: Avi Kivity <avi@qumranet.com>
This commit is contained in:
parent
b733bfb524
commit
1fe779f8ec
@ -620,6 +620,13 @@ long kvm_arch_vcpu_ioctl(struct file *filp,
|
|||||||
unsigned int ioctl, unsigned long arg);
|
unsigned int ioctl, unsigned long arg);
|
||||||
void kvm_arch_vcpu_load(struct kvm_vcpu *vcpu, int cpu);
|
void kvm_arch_vcpu_load(struct kvm_vcpu *vcpu, int cpu);
|
||||||
void kvm_arch_vcpu_put(struct kvm_vcpu *vcpu);
|
void kvm_arch_vcpu_put(struct kvm_vcpu *vcpu);
|
||||||
|
int kvm_vm_ioctl_set_memory_region(struct kvm *kvm,
|
||||||
|
struct
|
||||||
|
kvm_userspace_memory_region *mem,
|
||||||
|
int user_alloc);
|
||||||
|
long kvm_arch_vm_ioctl(struct file *filp,
|
||||||
|
unsigned int ioctl, unsigned long arg);
|
||||||
|
void kvm_arch_destroy_vm(struct kvm *kvm);
|
||||||
|
|
||||||
__init void kvm_arch_init(void);
|
__init void kvm_arch_init(void);
|
||||||
|
|
||||||
|
@ -792,36 +792,16 @@ out:
|
|||||||
}
|
}
|
||||||
EXPORT_SYMBOL_GPL(kvm_set_memory_region);
|
EXPORT_SYMBOL_GPL(kvm_set_memory_region);
|
||||||
|
|
||||||
static int kvm_vm_ioctl_set_memory_region(struct kvm *kvm,
|
int kvm_vm_ioctl_set_memory_region(struct kvm *kvm,
|
||||||
struct
|
struct
|
||||||
kvm_userspace_memory_region *mem,
|
kvm_userspace_memory_region *mem,
|
||||||
int user_alloc)
|
int user_alloc)
|
||||||
{
|
{
|
||||||
if (mem->slot >= KVM_MEMORY_SLOTS)
|
if (mem->slot >= KVM_MEMORY_SLOTS)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
return kvm_set_memory_region(kvm, mem, user_alloc);
|
return kvm_set_memory_region(kvm, mem, user_alloc);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int kvm_vm_ioctl_set_nr_mmu_pages(struct kvm *kvm,
|
|
||||||
u32 kvm_nr_mmu_pages)
|
|
||||||
{
|
|
||||||
if (kvm_nr_mmu_pages < KVM_MIN_ALLOC_MMU_PAGES)
|
|
||||||
return -EINVAL;
|
|
||||||
|
|
||||||
mutex_lock(&kvm->lock);
|
|
||||||
|
|
||||||
kvm_mmu_change_mmu_pages(kvm, kvm_nr_mmu_pages);
|
|
||||||
kvm->n_requested_mmu_pages = kvm_nr_mmu_pages;
|
|
||||||
|
|
||||||
mutex_unlock(&kvm->lock);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int kvm_vm_ioctl_get_nr_mmu_pages(struct kvm *kvm)
|
|
||||||
{
|
|
||||||
return kvm->n_alloc_mmu_pages;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Get (and clear) the dirty memory log for a memory slot.
|
* Get (and clear) the dirty memory log for a memory slot.
|
||||||
*/
|
*/
|
||||||
@ -867,111 +847,6 @@ out:
|
|||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
* Set a new alias region. Aliases map a portion of physical memory into
|
|
||||||
* another portion. This is useful for memory windows, for example the PC
|
|
||||||
* VGA region.
|
|
||||||
*/
|
|
||||||
static int kvm_vm_ioctl_set_memory_alias(struct kvm *kvm,
|
|
||||||
struct kvm_memory_alias *alias)
|
|
||||||
{
|
|
||||||
int r, n;
|
|
||||||
struct kvm_mem_alias *p;
|
|
||||||
|
|
||||||
r = -EINVAL;
|
|
||||||
/* General sanity checks */
|
|
||||||
if (alias->memory_size & (PAGE_SIZE - 1))
|
|
||||||
goto out;
|
|
||||||
if (alias->guest_phys_addr & (PAGE_SIZE - 1))
|
|
||||||
goto out;
|
|
||||||
if (alias->slot >= KVM_ALIAS_SLOTS)
|
|
||||||
goto out;
|
|
||||||
if (alias->guest_phys_addr + alias->memory_size
|
|
||||||
< alias->guest_phys_addr)
|
|
||||||
goto out;
|
|
||||||
if (alias->target_phys_addr + alias->memory_size
|
|
||||||
< alias->target_phys_addr)
|
|
||||||
goto out;
|
|
||||||
|
|
||||||
mutex_lock(&kvm->lock);
|
|
||||||
|
|
||||||
p = &kvm->aliases[alias->slot];
|
|
||||||
p->base_gfn = alias->guest_phys_addr >> PAGE_SHIFT;
|
|
||||||
p->npages = alias->memory_size >> PAGE_SHIFT;
|
|
||||||
p->target_gfn = alias->target_phys_addr >> PAGE_SHIFT;
|
|
||||||
|
|
||||||
for (n = KVM_ALIAS_SLOTS; n > 0; --n)
|
|
||||||
if (kvm->aliases[n - 1].npages)
|
|
||||||
break;
|
|
||||||
kvm->naliases = n;
|
|
||||||
|
|
||||||
kvm_mmu_zap_all(kvm);
|
|
||||||
|
|
||||||
mutex_unlock(&kvm->lock);
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
out:
|
|
||||||
return r;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int kvm_vm_ioctl_get_irqchip(struct kvm *kvm, struct kvm_irqchip *chip)
|
|
||||||
{
|
|
||||||
int r;
|
|
||||||
|
|
||||||
r = 0;
|
|
||||||
switch (chip->chip_id) {
|
|
||||||
case KVM_IRQCHIP_PIC_MASTER:
|
|
||||||
memcpy(&chip->chip.pic,
|
|
||||||
&pic_irqchip(kvm)->pics[0],
|
|
||||||
sizeof(struct kvm_pic_state));
|
|
||||||
break;
|
|
||||||
case KVM_IRQCHIP_PIC_SLAVE:
|
|
||||||
memcpy(&chip->chip.pic,
|
|
||||||
&pic_irqchip(kvm)->pics[1],
|
|
||||||
sizeof(struct kvm_pic_state));
|
|
||||||
break;
|
|
||||||
case KVM_IRQCHIP_IOAPIC:
|
|
||||||
memcpy(&chip->chip.ioapic,
|
|
||||||
ioapic_irqchip(kvm),
|
|
||||||
sizeof(struct kvm_ioapic_state));
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
r = -EINVAL;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
return r;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int kvm_vm_ioctl_set_irqchip(struct kvm *kvm, struct kvm_irqchip *chip)
|
|
||||||
{
|
|
||||||
int r;
|
|
||||||
|
|
||||||
r = 0;
|
|
||||||
switch (chip->chip_id) {
|
|
||||||
case KVM_IRQCHIP_PIC_MASTER:
|
|
||||||
memcpy(&pic_irqchip(kvm)->pics[0],
|
|
||||||
&chip->chip.pic,
|
|
||||||
sizeof(struct kvm_pic_state));
|
|
||||||
break;
|
|
||||||
case KVM_IRQCHIP_PIC_SLAVE:
|
|
||||||
memcpy(&pic_irqchip(kvm)->pics[1],
|
|
||||||
&chip->chip.pic,
|
|
||||||
sizeof(struct kvm_pic_state));
|
|
||||||
break;
|
|
||||||
case KVM_IRQCHIP_IOAPIC:
|
|
||||||
memcpy(ioapic_irqchip(kvm),
|
|
||||||
&chip->chip.ioapic,
|
|
||||||
sizeof(struct kvm_ioapic_state));
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
r = -EINVAL;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
kvm_pic_update_irq(pic_irqchip(kvm));
|
|
||||||
return r;
|
|
||||||
}
|
|
||||||
|
|
||||||
int is_error_page(struct page *page)
|
int is_error_page(struct page *page)
|
||||||
{
|
{
|
||||||
return page == bad_page;
|
return page == bad_page;
|
||||||
@ -2661,16 +2536,6 @@ static int create_vcpu_fd(struct kvm_vcpu *vcpu)
|
|||||||
return fd;
|
return fd;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int kvm_vm_ioctl_set_tss_addr(struct kvm *kvm, unsigned long addr)
|
|
||||||
{
|
|
||||||
int ret;
|
|
||||||
|
|
||||||
if (addr > (unsigned int)(-3 * PAGE_SIZE))
|
|
||||||
return -1;
|
|
||||||
ret = kvm_x86_ops->set_tss_addr(kvm, addr);
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Creates some virtual cpus. Good luck creating more than one.
|
* Creates some virtual cpus. Good luck creating more than one.
|
||||||
*/
|
*/
|
||||||
@ -2964,35 +2829,14 @@ static long kvm_vm_ioctl(struct file *filp,
|
|||||||
{
|
{
|
||||||
struct kvm *kvm = filp->private_data;
|
struct kvm *kvm = filp->private_data;
|
||||||
void __user *argp = (void __user *)arg;
|
void __user *argp = (void __user *)arg;
|
||||||
int r = -EINVAL;
|
int r;
|
||||||
|
|
||||||
switch (ioctl) {
|
switch (ioctl) {
|
||||||
case KVM_SET_TSS_ADDR:
|
|
||||||
r = kvm_vm_ioctl_set_tss_addr(kvm, arg);
|
|
||||||
if (r < 0)
|
|
||||||
goto out;
|
|
||||||
break;
|
|
||||||
case KVM_CREATE_VCPU:
|
case KVM_CREATE_VCPU:
|
||||||
r = kvm_vm_ioctl_create_vcpu(kvm, arg);
|
r = kvm_vm_ioctl_create_vcpu(kvm, arg);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
goto out;
|
goto out;
|
||||||
break;
|
break;
|
||||||
case KVM_SET_MEMORY_REGION: {
|
|
||||||
struct kvm_memory_region kvm_mem;
|
|
||||||
struct kvm_userspace_memory_region kvm_userspace_mem;
|
|
||||||
|
|
||||||
r = -EFAULT;
|
|
||||||
if (copy_from_user(&kvm_mem, argp, sizeof kvm_mem))
|
|
||||||
goto out;
|
|
||||||
kvm_userspace_mem.slot = kvm_mem.slot;
|
|
||||||
kvm_userspace_mem.flags = kvm_mem.flags;
|
|
||||||
kvm_userspace_mem.guest_phys_addr = kvm_mem.guest_phys_addr;
|
|
||||||
kvm_userspace_mem.memory_size = kvm_mem.memory_size;
|
|
||||||
r = kvm_vm_ioctl_set_memory_region(kvm, &kvm_userspace_mem, 0);
|
|
||||||
if (r)
|
|
||||||
goto out;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case KVM_SET_USER_MEMORY_REGION: {
|
case KVM_SET_USER_MEMORY_REGION: {
|
||||||
struct kvm_userspace_memory_region kvm_userspace_mem;
|
struct kvm_userspace_memory_region kvm_userspace_mem;
|
||||||
|
|
||||||
@ -3006,14 +2850,6 @@ static long kvm_vm_ioctl(struct file *filp,
|
|||||||
goto out;
|
goto out;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case KVM_SET_NR_MMU_PAGES:
|
|
||||||
r = kvm_vm_ioctl_set_nr_mmu_pages(kvm, arg);
|
|
||||||
if (r)
|
|
||||||
goto out;
|
|
||||||
break;
|
|
||||||
case KVM_GET_NR_MMU_PAGES:
|
|
||||||
r = kvm_vm_ioctl_get_nr_mmu_pages(kvm);
|
|
||||||
break;
|
|
||||||
case KVM_GET_DIRTY_LOG: {
|
case KVM_GET_DIRTY_LOG: {
|
||||||
struct kvm_dirty_log log;
|
struct kvm_dirty_log log;
|
||||||
|
|
||||||
@ -3025,87 +2861,8 @@ static long kvm_vm_ioctl(struct file *filp,
|
|||||||
goto out;
|
goto out;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case KVM_SET_MEMORY_ALIAS: {
|
|
||||||
struct kvm_memory_alias alias;
|
|
||||||
|
|
||||||
r = -EFAULT;
|
|
||||||
if (copy_from_user(&alias, argp, sizeof alias))
|
|
||||||
goto out;
|
|
||||||
r = kvm_vm_ioctl_set_memory_alias(kvm, &alias);
|
|
||||||
if (r)
|
|
||||||
goto out;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case KVM_CREATE_IRQCHIP:
|
|
||||||
r = -ENOMEM;
|
|
||||||
kvm->vpic = kvm_create_pic(kvm);
|
|
||||||
if (kvm->vpic) {
|
|
||||||
r = kvm_ioapic_init(kvm);
|
|
||||||
if (r) {
|
|
||||||
kfree(kvm->vpic);
|
|
||||||
kvm->vpic = NULL;
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
} else
|
|
||||||
goto out;
|
|
||||||
break;
|
|
||||||
case KVM_IRQ_LINE: {
|
|
||||||
struct kvm_irq_level irq_event;
|
|
||||||
|
|
||||||
r = -EFAULT;
|
|
||||||
if (copy_from_user(&irq_event, argp, sizeof irq_event))
|
|
||||||
goto out;
|
|
||||||
if (irqchip_in_kernel(kvm)) {
|
|
||||||
mutex_lock(&kvm->lock);
|
|
||||||
if (irq_event.irq < 16)
|
|
||||||
kvm_pic_set_irq(pic_irqchip(kvm),
|
|
||||||
irq_event.irq,
|
|
||||||
irq_event.level);
|
|
||||||
kvm_ioapic_set_irq(kvm->vioapic,
|
|
||||||
irq_event.irq,
|
|
||||||
irq_event.level);
|
|
||||||
mutex_unlock(&kvm->lock);
|
|
||||||
r = 0;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case KVM_GET_IRQCHIP: {
|
|
||||||
/* 0: PIC master, 1: PIC slave, 2: IOAPIC */
|
|
||||||
struct kvm_irqchip chip;
|
|
||||||
|
|
||||||
r = -EFAULT;
|
|
||||||
if (copy_from_user(&chip, argp, sizeof chip))
|
|
||||||
goto out;
|
|
||||||
r = -ENXIO;
|
|
||||||
if (!irqchip_in_kernel(kvm))
|
|
||||||
goto out;
|
|
||||||
r = kvm_vm_ioctl_get_irqchip(kvm, &chip);
|
|
||||||
if (r)
|
|
||||||
goto out;
|
|
||||||
r = -EFAULT;
|
|
||||||
if (copy_to_user(argp, &chip, sizeof chip))
|
|
||||||
goto out;
|
|
||||||
r = 0;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case KVM_SET_IRQCHIP: {
|
|
||||||
/* 0: PIC master, 1: PIC slave, 2: IOAPIC */
|
|
||||||
struct kvm_irqchip chip;
|
|
||||||
|
|
||||||
r = -EFAULT;
|
|
||||||
if (copy_from_user(&chip, argp, sizeof chip))
|
|
||||||
goto out;
|
|
||||||
r = -ENXIO;
|
|
||||||
if (!irqchip_in_kernel(kvm))
|
|
||||||
goto out;
|
|
||||||
r = kvm_vm_ioctl_set_irqchip(kvm, &chip);
|
|
||||||
if (r)
|
|
||||||
goto out;
|
|
||||||
r = 0;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
default:
|
default:
|
||||||
;
|
r = kvm_arch_vm_ioctl(filp, ioctl, arg);
|
||||||
}
|
}
|
||||||
out:
|
out:
|
||||||
return r;
|
return r;
|
||||||
|
@ -300,6 +300,264 @@ out:
|
|||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int kvm_vm_ioctl_set_tss_addr(struct kvm *kvm, unsigned long addr)
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
if (addr > (unsigned int)(-3 * PAGE_SIZE))
|
||||||
|
return -1;
|
||||||
|
ret = kvm_x86_ops->set_tss_addr(kvm, addr);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int kvm_vm_ioctl_set_nr_mmu_pages(struct kvm *kvm,
|
||||||
|
u32 kvm_nr_mmu_pages)
|
||||||
|
{
|
||||||
|
if (kvm_nr_mmu_pages < KVM_MIN_ALLOC_MMU_PAGES)
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
mutex_lock(&kvm->lock);
|
||||||
|
|
||||||
|
kvm_mmu_change_mmu_pages(kvm, kvm_nr_mmu_pages);
|
||||||
|
kvm->n_requested_mmu_pages = kvm_nr_mmu_pages;
|
||||||
|
|
||||||
|
mutex_unlock(&kvm->lock);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int kvm_vm_ioctl_get_nr_mmu_pages(struct kvm *kvm)
|
||||||
|
{
|
||||||
|
return kvm->n_alloc_mmu_pages;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Set a new alias region. Aliases map a portion of physical memory into
|
||||||
|
* another portion. This is useful for memory windows, for example the PC
|
||||||
|
* VGA region.
|
||||||
|
*/
|
||||||
|
static int kvm_vm_ioctl_set_memory_alias(struct kvm *kvm,
|
||||||
|
struct kvm_memory_alias *alias)
|
||||||
|
{
|
||||||
|
int r, n;
|
||||||
|
struct kvm_mem_alias *p;
|
||||||
|
|
||||||
|
r = -EINVAL;
|
||||||
|
/* General sanity checks */
|
||||||
|
if (alias->memory_size & (PAGE_SIZE - 1))
|
||||||
|
goto out;
|
||||||
|
if (alias->guest_phys_addr & (PAGE_SIZE - 1))
|
||||||
|
goto out;
|
||||||
|
if (alias->slot >= KVM_ALIAS_SLOTS)
|
||||||
|
goto out;
|
||||||
|
if (alias->guest_phys_addr + alias->memory_size
|
||||||
|
< alias->guest_phys_addr)
|
||||||
|
goto out;
|
||||||
|
if (alias->target_phys_addr + alias->memory_size
|
||||||
|
< alias->target_phys_addr)
|
||||||
|
goto out;
|
||||||
|
|
||||||
|
mutex_lock(&kvm->lock);
|
||||||
|
|
||||||
|
p = &kvm->aliases[alias->slot];
|
||||||
|
p->base_gfn = alias->guest_phys_addr >> PAGE_SHIFT;
|
||||||
|
p->npages = alias->memory_size >> PAGE_SHIFT;
|
||||||
|
p->target_gfn = alias->target_phys_addr >> PAGE_SHIFT;
|
||||||
|
|
||||||
|
for (n = KVM_ALIAS_SLOTS; n > 0; --n)
|
||||||
|
if (kvm->aliases[n - 1].npages)
|
||||||
|
break;
|
||||||
|
kvm->naliases = n;
|
||||||
|
|
||||||
|
kvm_mmu_zap_all(kvm);
|
||||||
|
|
||||||
|
mutex_unlock(&kvm->lock);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
out:
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int kvm_vm_ioctl_get_irqchip(struct kvm *kvm, struct kvm_irqchip *chip)
|
||||||
|
{
|
||||||
|
int r;
|
||||||
|
|
||||||
|
r = 0;
|
||||||
|
switch (chip->chip_id) {
|
||||||
|
case KVM_IRQCHIP_PIC_MASTER:
|
||||||
|
memcpy(&chip->chip.pic,
|
||||||
|
&pic_irqchip(kvm)->pics[0],
|
||||||
|
sizeof(struct kvm_pic_state));
|
||||||
|
break;
|
||||||
|
case KVM_IRQCHIP_PIC_SLAVE:
|
||||||
|
memcpy(&chip->chip.pic,
|
||||||
|
&pic_irqchip(kvm)->pics[1],
|
||||||
|
sizeof(struct kvm_pic_state));
|
||||||
|
break;
|
||||||
|
case KVM_IRQCHIP_IOAPIC:
|
||||||
|
memcpy(&chip->chip.ioapic,
|
||||||
|
ioapic_irqchip(kvm),
|
||||||
|
sizeof(struct kvm_ioapic_state));
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
r = -EINVAL;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int kvm_vm_ioctl_set_irqchip(struct kvm *kvm, struct kvm_irqchip *chip)
|
||||||
|
{
|
||||||
|
int r;
|
||||||
|
|
||||||
|
r = 0;
|
||||||
|
switch (chip->chip_id) {
|
||||||
|
case KVM_IRQCHIP_PIC_MASTER:
|
||||||
|
memcpy(&pic_irqchip(kvm)->pics[0],
|
||||||
|
&chip->chip.pic,
|
||||||
|
sizeof(struct kvm_pic_state));
|
||||||
|
break;
|
||||||
|
case KVM_IRQCHIP_PIC_SLAVE:
|
||||||
|
memcpy(&pic_irqchip(kvm)->pics[1],
|
||||||
|
&chip->chip.pic,
|
||||||
|
sizeof(struct kvm_pic_state));
|
||||||
|
break;
|
||||||
|
case KVM_IRQCHIP_IOAPIC:
|
||||||
|
memcpy(ioapic_irqchip(kvm),
|
||||||
|
&chip->chip.ioapic,
|
||||||
|
sizeof(struct kvm_ioapic_state));
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
r = -EINVAL;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
kvm_pic_update_irq(pic_irqchip(kvm));
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
long kvm_arch_vm_ioctl(struct file *filp,
|
||||||
|
unsigned int ioctl, unsigned long arg)
|
||||||
|
{
|
||||||
|
struct kvm *kvm = filp->private_data;
|
||||||
|
void __user *argp = (void __user *)arg;
|
||||||
|
int r = -EINVAL;
|
||||||
|
|
||||||
|
switch (ioctl) {
|
||||||
|
case KVM_SET_TSS_ADDR:
|
||||||
|
r = kvm_vm_ioctl_set_tss_addr(kvm, arg);
|
||||||
|
if (r < 0)
|
||||||
|
goto out;
|
||||||
|
break;
|
||||||
|
case KVM_SET_MEMORY_REGION: {
|
||||||
|
struct kvm_memory_region kvm_mem;
|
||||||
|
struct kvm_userspace_memory_region kvm_userspace_mem;
|
||||||
|
|
||||||
|
r = -EFAULT;
|
||||||
|
if (copy_from_user(&kvm_mem, argp, sizeof kvm_mem))
|
||||||
|
goto out;
|
||||||
|
kvm_userspace_mem.slot = kvm_mem.slot;
|
||||||
|
kvm_userspace_mem.flags = kvm_mem.flags;
|
||||||
|
kvm_userspace_mem.guest_phys_addr = kvm_mem.guest_phys_addr;
|
||||||
|
kvm_userspace_mem.memory_size = kvm_mem.memory_size;
|
||||||
|
r = kvm_vm_ioctl_set_memory_region(kvm, &kvm_userspace_mem, 0);
|
||||||
|
if (r)
|
||||||
|
goto out;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case KVM_SET_NR_MMU_PAGES:
|
||||||
|
r = kvm_vm_ioctl_set_nr_mmu_pages(kvm, arg);
|
||||||
|
if (r)
|
||||||
|
goto out;
|
||||||
|
break;
|
||||||
|
case KVM_GET_NR_MMU_PAGES:
|
||||||
|
r = kvm_vm_ioctl_get_nr_mmu_pages(kvm);
|
||||||
|
break;
|
||||||
|
case KVM_SET_MEMORY_ALIAS: {
|
||||||
|
struct kvm_memory_alias alias;
|
||||||
|
|
||||||
|
r = -EFAULT;
|
||||||
|
if (copy_from_user(&alias, argp, sizeof alias))
|
||||||
|
goto out;
|
||||||
|
r = kvm_vm_ioctl_set_memory_alias(kvm, &alias);
|
||||||
|
if (r)
|
||||||
|
goto out;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case KVM_CREATE_IRQCHIP:
|
||||||
|
r = -ENOMEM;
|
||||||
|
kvm->vpic = kvm_create_pic(kvm);
|
||||||
|
if (kvm->vpic) {
|
||||||
|
r = kvm_ioapic_init(kvm);
|
||||||
|
if (r) {
|
||||||
|
kfree(kvm->vpic);
|
||||||
|
kvm->vpic = NULL;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
} else
|
||||||
|
goto out;
|
||||||
|
break;
|
||||||
|
case KVM_IRQ_LINE: {
|
||||||
|
struct kvm_irq_level irq_event;
|
||||||
|
|
||||||
|
r = -EFAULT;
|
||||||
|
if (copy_from_user(&irq_event, argp, sizeof irq_event))
|
||||||
|
goto out;
|
||||||
|
if (irqchip_in_kernel(kvm)) {
|
||||||
|
mutex_lock(&kvm->lock);
|
||||||
|
if (irq_event.irq < 16)
|
||||||
|
kvm_pic_set_irq(pic_irqchip(kvm),
|
||||||
|
irq_event.irq,
|
||||||
|
irq_event.level);
|
||||||
|
kvm_ioapic_set_irq(kvm->vioapic,
|
||||||
|
irq_event.irq,
|
||||||
|
irq_event.level);
|
||||||
|
mutex_unlock(&kvm->lock);
|
||||||
|
r = 0;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case KVM_GET_IRQCHIP: {
|
||||||
|
/* 0: PIC master, 1: PIC slave, 2: IOAPIC */
|
||||||
|
struct kvm_irqchip chip;
|
||||||
|
|
||||||
|
r = -EFAULT;
|
||||||
|
if (copy_from_user(&chip, argp, sizeof chip))
|
||||||
|
goto out;
|
||||||
|
r = -ENXIO;
|
||||||
|
if (!irqchip_in_kernel(kvm))
|
||||||
|
goto out;
|
||||||
|
r = kvm_vm_ioctl_get_irqchip(kvm, &chip);
|
||||||
|
if (r)
|
||||||
|
goto out;
|
||||||
|
r = -EFAULT;
|
||||||
|
if (copy_to_user(argp, &chip, sizeof chip))
|
||||||
|
goto out;
|
||||||
|
r = 0;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case KVM_SET_IRQCHIP: {
|
||||||
|
/* 0: PIC master, 1: PIC slave, 2: IOAPIC */
|
||||||
|
struct kvm_irqchip chip;
|
||||||
|
|
||||||
|
r = -EFAULT;
|
||||||
|
if (copy_from_user(&chip, argp, sizeof chip))
|
||||||
|
goto out;
|
||||||
|
r = -ENXIO;
|
||||||
|
if (!irqchip_in_kernel(kvm))
|
||||||
|
goto out;
|
||||||
|
r = kvm_vm_ioctl_set_irqchip(kvm, &chip);
|
||||||
|
if (r)
|
||||||
|
goto out;
|
||||||
|
r = 0;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
;
|
||||||
|
}
|
||||||
|
out:
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
static __init void kvm_init_msr_list(void)
|
static __init void kvm_init_msr_list(void)
|
||||||
{
|
{
|
||||||
u32 dummy[2];
|
u32 dummy[2];
|
||||||
|
Loading…
Reference in New Issue
Block a user