@@ -480,6 +480,16 @@ struct kvm_coalesced_mmio_zone {
};
};
+struct kvm_coalesced_mmio_zone2 {
+ __u64 addr;
+ __u32 size;
+ union {
+ __u32 pad;
+ __u32 pio;
+ };
+ int buffer_fd;
+};
+
struct kvm_coalesced_mmio {
__u64 phys_addr;
__u32 len;
@@ -933,6 +943,7 @@ struct kvm_enable_cap {
#define KVM_CAP_PRE_FAULT_MEMORY 236
#define KVM_CAP_X86_APIC_BUS_CYCLES_NS 237
#define KVM_CAP_X86_GUEST_MODE 238
+#define KVM_CAP_COALESCED_MMIO2 239
struct kvm_irq_routing_irqchip {
__u32 irqchip;
@@ -1573,6 +1584,11 @@ struct kvm_pre_fault_memory {
__u64 padding[5];
};
+/* Available with KVM_CAP_COALESCED_MMIO2 */
#define KVM_CREATE_COALESCED_MMIO_BUFFER _IO(KVMIO, 0xd6)
+#define KVM_REGISTER_COALESCED_MMIO2 \
+ _IOW(KVMIO, 0xd7, struct kvm_coalesced_mmio_zone2)
+#define KVM_UNREGISTER_COALESCED_MMIO2 \
+ _IOW(KVMIO, 0xd8, struct kvm_coalesced_mmio_zone2)
#endif /* __LINUX_KVM_H */
@@ -17,6 +17,7 @@
#include <linux/kvm.h>
#include <linux/anon_inodes.h>
#include <linux/poll.h>
+#include <linux/file.h>
#include "coalesced_mmio.h"
@@ -279,19 +280,40 @@ int kvm_vm_ioctl_create_coalesced_mmio_buffer(struct kvm *kvm)
}
int kvm_vm_ioctl_register_coalesced_mmio(struct kvm *kvm,
- struct kvm_coalesced_mmio_zone *zone)
+ struct kvm_coalesced_mmio_zone2 *zone,
+ bool use_buffer_fd)
{
- int ret;
+ int ret = 0;
+ struct file *file;
struct kvm_coalesced_mmio_dev *dev;
struct kvm_coalesced_mmio_buffer_dev *buffer_dev = NULL;
if (zone->pio != 1 && zone->pio != 0)
return -EINVAL;
+ if (use_buffer_fd) {
+ file = fget(zone->buffer_fd);
+ if (!file)
+ return -EBADF;
+
+ if (file->f_op != &coalesced_mmio_buffer_ops) {
+ fput(file);
+ return -EINVAL;
+ }
+
+ buffer_dev = file->private_data;
+ if (!buffer_dev->ring) {
+ fput(file);
+ return -ENOBUFS;
+ }
+ }
+
dev = kzalloc(sizeof(struct kvm_coalesced_mmio_dev),
GFP_KERNEL_ACCOUNT);
- if (!dev)
- return -ENOMEM;
+ if (!dev) {
+ ret = -ENOMEM;
+ goto out_free_file;
+ }
kvm_iodevice_init(&dev->dev, &coalesced_mmio_ops);
dev->kvm = kvm;
@@ -307,17 +329,20 @@ int kvm_vm_ioctl_register_coalesced_mmio(struct kvm *kvm,
list_add_tail(&dev->list, &kvm->coalesced_zones);
mutex_unlock(&kvm->slots_lock);
- return 0;
+ goto out_free_file;
out_free_dev:
mutex_unlock(&kvm->slots_lock);
kfree(dev);
+out_free_file:
+ if (use_buffer_fd)
+ fput(file);
return ret;
}
int kvm_vm_ioctl_unregister_coalesced_mmio(struct kvm *kvm,
- struct kvm_coalesced_mmio_zone *zone)
+ struct kvm_coalesced_mmio_zone2 *zone)
{
struct kvm_coalesced_mmio_dev *dev, *tmp;
int r;
@@ -19,7 +19,7 @@ struct kvm_coalesced_mmio_dev {
struct list_head list;
struct kvm_io_device dev;
struct kvm *kvm;
- struct kvm_coalesced_mmio_zone zone;
+ struct kvm_coalesced_mmio_zone2 zone;
struct kvm_coalesced_mmio_buffer_dev *buffer_dev;
};
@@ -34,9 +34,10 @@ struct kvm_coalesced_mmio_buffer_dev {
int kvm_coalesced_mmio_init(struct kvm *kvm);
void kvm_coalesced_mmio_free(struct kvm *kvm);
int kvm_vm_ioctl_register_coalesced_mmio(struct kvm *kvm,
- struct kvm_coalesced_mmio_zone *zone);
+ struct kvm_coalesced_mmio_zone2 *zone,
+ bool use_buffer_fd);
int kvm_vm_ioctl_unregister_coalesced_mmio(struct kvm *kvm,
- struct kvm_coalesced_mmio_zone *zone);
+ struct kvm_coalesced_mmio_zone2 *zone);
int kvm_vm_ioctl_create_coalesced_mmio_buffer(struct kvm *kvm);
#else
@@ -4892,6 +4892,7 @@ static int kvm_vm_ioctl_check_extension_generic(struct kvm *kvm, long arg)
#ifdef CONFIG_KVM_MMIO
case KVM_CAP_COALESCED_MMIO:
return KVM_COALESCED_MMIO_PAGE_OFFSET;
+ case KVM_CAP_COALESCED_MMIO2:
case KVM_CAP_COALESCED_PIO:
return 1;
#endif
@@ -5230,15 +5231,48 @@ static long kvm_vm_ioctl(struct file *filp,
#ifdef CONFIG_KVM_MMIO
case KVM_REGISTER_COALESCED_MMIO: {
struct kvm_coalesced_mmio_zone zone;
+ struct kvm_coalesced_mmio_zone2 zone2;
r = -EFAULT;
if (copy_from_user(&zone, argp, sizeof(zone)))
goto out;
- r = kvm_vm_ioctl_register_coalesced_mmio(kvm, &zone);
+
+ zone2.addr = zone.addr;
+ zone2.size = zone.size;
+ zone2.pio = zone.pio;
+ zone2.buffer_fd = -1;
+
+ r = kvm_vm_ioctl_register_coalesced_mmio(kvm, &zone2, false);
+ break;
+ }
+ case KVM_REGISTER_COALESCED_MMIO2: {
+ struct kvm_coalesced_mmio_zone2 zone;
+
+ r = -EFAULT;
+ if (copy_from_user(&zone, argp, sizeof(zone)))
+ goto out;
+
+ r = kvm_vm_ioctl_register_coalesced_mmio(kvm, &zone, true);
break;
}
case KVM_UNREGISTER_COALESCED_MMIO: {
struct kvm_coalesced_mmio_zone zone;
+ struct kvm_coalesced_mmio_zone2 zone2;
+
+ r = -EFAULT;
+ if (copy_from_user(&zone, argp, sizeof(zone)))
+ goto out;
+
+ zone2.addr = zone.addr;
+ zone2.size = zone.size;
+ zone2.pio = zone.pio;
+ zone2.buffer_fd = -1;
+
+ r = kvm_vm_ioctl_unregister_coalesced_mmio(kvm, &zone2);
+ break;
+ }
+ case KVM_UNREGISTER_COALESCED_MMIO2: {
+ struct kvm_coalesced_mmio_zone2 zone;
r = -EFAULT;
if (copy_from_user(&zone, argp, sizeof(zone)))