Implement virt_hypervisor in kvm, and add support for creating virtual devices. Signed-off-by: Michael S. Tsirkin <mst@xxxxxxxxxx> --- include/linux/kvm.h | 13 ++++++++++++ include/linux/kvm_host.h | 3 ++ virt/kvm/kvm_main.c | 47 ++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 63 insertions(+), 0 deletions(-) diff --git a/include/linux/kvm.h b/include/linux/kvm.h index 8cc1379..8f6cc79 100644 --- a/include/linux/kvm.h +++ b/include/linux/kvm.h @@ -487,6 +487,8 @@ struct kvm_irq_routing { #define KVM_REINJECT_CONTROL _IO(KVMIO, 0x71) #define KVM_DEASSIGN_PCI_DEVICE _IOW(KVMIO, 0x72, \ struct kvm_assigned_pci_dev) +#define KVM_CREATE_VIRT_DEVICE _IOW(KVMIO, 0x73, \ + struct kvm_create_virt_device) /* * ioctls for vcpu fds @@ -602,6 +604,17 @@ struct kvm_assigned_irq { }; }; +struct kvm_create_virt_device { + __s32 flags; /* flags from open(2). Only O_CLOEXEC supported for now. */ + __u32 id_len; + union { + __u32 reserved[12]; + }; + /* Followed by up to MAX_ID_LEN byte id. */ +}; + +#define KVM_VIRT_DEVICE_MAX_ID_LEN 200 + #define KVM_DEV_ASSIGN_ENABLE_IOMMU (1 << 0) #define KVM_DEV_IRQ_ASSIGN_MSI_ACTION KVM_DEV_IRQ_ASSIGN_ENABLE_MSI diff --git a/include/linux/kvm_host.h b/include/linux/kvm_host.h index 894a56e..7131851 100644 --- a/include/linux/kvm_host.h +++ b/include/linux/kvm_host.h @@ -26,6 +26,8 @@ #include <asm/kvm_host.h> +#include <linux/virt.h> + /* * vcpu->requests bit members */ @@ -152,6 +154,7 @@ struct kvm { unsigned long mmu_notifier_seq; long mmu_notifier_count; #endif + struct virt_hypervisor hypervisor; }; /* The guest did something we don't support. */ diff --git a/virt/kvm/kvm_main.c b/virt/kvm/kvm_main.c index 1ecbe23..c0487f0 100644 --- a/virt/kvm/kvm_main.c +++ b/virt/kvm/kvm_main.c @@ -766,6 +766,24 @@ static void kvm_mmu_notifier_release(struct mmu_notifier *mn, kvm_arch_flush_shadow(kvm); } +static void kvm_hypervisor_get(struct virt_hypervisor *h) +{ + struct kvm *kvm = container_of(h, struct kvm, hypervisor); + kvm_get_kvm(kvm); +} + +static void kvm_hypervisor_put(struct virt_hypervisor *h) +{ + struct kvm *kvm = container_of(h, struct kvm, hypervisor); + kvm_put_kvm(kvm); +} +static int kvm_hypervisor_set_irq(struct virt_hypervisor *h, + int source, int irq, int level) +{ + struct kvm *kvm = container_of(h, struct kvm, hypervisor); + return kvm_set_irq(kvm, source, irq, level); +} + static const struct mmu_notifier_ops kvm_mmu_notifier_ops = { .invalidate_page = kvm_mmu_notifier_invalidate_page, .invalidate_range_start = kvm_mmu_notifier_invalidate_range_start, @@ -828,6 +846,10 @@ static struct kvm *kvm_create_vm(void) #ifdef KVM_COALESCED_MMIO_PAGE_OFFSET kvm_coalesced_mmio_init(kvm); #endif + kvm->hypervisor.get = kvm_hypervisor_get; + kvm->hypervisor.put = kvm_hypervisor_put; + kvm->hypervisor.set_irq = kvm_hypervisor_set_irq; + virt_hypervisor_register(&kvm->hypervisor); out: return kvm; } @@ -865,6 +887,7 @@ static void kvm_destroy_vm(struct kvm *kvm) { struct mm_struct *mm = kvm->mm; + virt_hypervisor_unregister(&kvm->hypervisor); kvm_arch_sync_events(kvm); spin_lock(&kvm_lock); list_del(&kvm->vm_list); @@ -1917,6 +1940,30 @@ static long kvm_vm_ioctl(struct file *filp, vfree(entries); break; } + case KVM_CREATE_VIRT_DEVICE: { + struct kvm_create_virt_device d; + u8 *id; + r = -EFAULT; + if (copy_from_user(&d, argp, sizeof d)) + goto out; + r = -EINVAL; + if (d.id_len > KVM_VIRT_DEVICE_MAX_ID_LEN) + goto out; + if (d.flags & ~O_CLOEXEC) + goto out; + r = -ENOMEM; + id = kmalloc(d.id_len, GFP_KERNEL); + if (!id) + goto out_free_id; + r = -EFAULT; + if (copy_from_user(id, argp + sizeof d, d.id_len)) + goto out_free_id; + r = virt_device_create(&kvm->hypervisor, d.flags, + id, d.id_len); + out_free_id: + kfree(id); + break; + } #endif default: r = kvm_arch_vm_ioctl(filp, ioctl, arg); -- 1.6.3.1.175.g3be7e0 -- To unsubscribe from this list: send the line "unsubscribe kvm" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html