KVM: remove in_range from io devices
This changes bus accesses to use high-level kvm_io_bus_read/kvm_io_bus_write functions. in_range now becomes unused so it is removed from device ops in favor of read/write callbacks performing range checks internally. This allows aliasing (mostly for in-kernel virtio), as well as better error handling by making it possible to pass errors up to userspace. Signed-off-by: Michael S. Tsirkin <mst@redhat.com> Signed-off-by: Avi Kivity <avi@redhat.com>
This commit is contained in:

committed by
Avi Kivity

parent
6c47469453
commit
bda9020e24
@@ -19,18 +19,14 @@ static inline struct kvm_coalesced_mmio_dev *to_mmio(struct kvm_io_device *dev)
|
||||
return container_of(dev, struct kvm_coalesced_mmio_dev, dev);
|
||||
}
|
||||
|
||||
static int coalesced_mmio_in_range(struct kvm_io_device *this,
|
||||
gpa_t addr, int len, int is_write)
|
||||
static int coalesced_mmio_in_range(struct kvm_coalesced_mmio_dev *dev,
|
||||
gpa_t addr, int len)
|
||||
{
|
||||
struct kvm_coalesced_mmio_dev *dev = to_mmio(this);
|
||||
struct kvm_coalesced_mmio_zone *zone;
|
||||
struct kvm_coalesced_mmio_ring *ring;
|
||||
unsigned avail;
|
||||
int i;
|
||||
|
||||
if (!is_write)
|
||||
return 0;
|
||||
|
||||
/* Are we able to batch it ? */
|
||||
|
||||
/* last is the first free entry
|
||||
@@ -60,11 +56,13 @@ static int coalesced_mmio_in_range(struct kvm_io_device *this,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void coalesced_mmio_write(struct kvm_io_device *this,
|
||||
gpa_t addr, int len, const void *val)
|
||||
static int coalesced_mmio_write(struct kvm_io_device *this,
|
||||
gpa_t addr, int len, const void *val)
|
||||
{
|
||||
struct kvm_coalesced_mmio_dev *dev = to_mmio(this);
|
||||
struct kvm_coalesced_mmio_ring *ring = dev->kvm->coalesced_mmio_ring;
|
||||
if (!coalesced_mmio_in_range(dev, addr, len))
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
spin_lock(&dev->lock);
|
||||
|
||||
@@ -76,6 +74,7 @@ static void coalesced_mmio_write(struct kvm_io_device *this,
|
||||
smp_wmb();
|
||||
ring->last = (ring->last + 1) % KVM_COALESCED_MMIO_MAX;
|
||||
spin_unlock(&dev->lock);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void coalesced_mmio_destructor(struct kvm_io_device *this)
|
||||
@@ -87,7 +86,6 @@ static void coalesced_mmio_destructor(struct kvm_io_device *this)
|
||||
|
||||
static const struct kvm_io_device_ops coalesced_mmio_ops = {
|
||||
.write = coalesced_mmio_write,
|
||||
.in_range = coalesced_mmio_in_range,
|
||||
.destructor = coalesced_mmio_destructor,
|
||||
};
|
||||
|
||||
|
@@ -227,20 +227,19 @@ static inline struct kvm_ioapic *to_ioapic(struct kvm_io_device *dev)
|
||||
return container_of(dev, struct kvm_ioapic, dev);
|
||||
}
|
||||
|
||||
static int ioapic_in_range(struct kvm_io_device *this, gpa_t addr,
|
||||
int len, int is_write)
|
||||
static inline int ioapic_in_range(struct kvm_ioapic *ioapic, gpa_t addr)
|
||||
{
|
||||
struct kvm_ioapic *ioapic = to_ioapic(this);
|
||||
|
||||
return ((addr >= ioapic->base_address &&
|
||||
(addr < ioapic->base_address + IOAPIC_MEM_LENGTH)));
|
||||
}
|
||||
|
||||
static void ioapic_mmio_read(struct kvm_io_device *this, gpa_t addr, int len,
|
||||
void *val)
|
||||
static int ioapic_mmio_read(struct kvm_io_device *this, gpa_t addr, int len,
|
||||
void *val)
|
||||
{
|
||||
struct kvm_ioapic *ioapic = to_ioapic(this);
|
||||
u32 result;
|
||||
if (!ioapic_in_range(ioapic, addr))
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
ioapic_debug("addr %lx\n", (unsigned long)addr);
|
||||
ASSERT(!(addr & 0xf)); /* check alignment */
|
||||
@@ -273,13 +272,16 @@ static void ioapic_mmio_read(struct kvm_io_device *this, gpa_t addr, int len,
|
||||
printk(KERN_WARNING "ioapic: wrong length %d\n", len);
|
||||
}
|
||||
mutex_unlock(&ioapic->kvm->irq_lock);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void ioapic_mmio_write(struct kvm_io_device *this, gpa_t addr, int len,
|
||||
const void *val)
|
||||
static int ioapic_mmio_write(struct kvm_io_device *this, gpa_t addr, int len,
|
||||
const void *val)
|
||||
{
|
||||
struct kvm_ioapic *ioapic = to_ioapic(this);
|
||||
u32 data;
|
||||
if (!ioapic_in_range(ioapic, addr))
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
ioapic_debug("ioapic_mmio_write addr=%p len=%d val=%p\n",
|
||||
(void*)addr, len, val);
|
||||
@@ -290,7 +292,7 @@ static void ioapic_mmio_write(struct kvm_io_device *this, gpa_t addr, int len,
|
||||
data = *(u32 *) val;
|
||||
else {
|
||||
printk(KERN_WARNING "ioapic: Unsupported size %d\n", len);
|
||||
return;
|
||||
return 0;
|
||||
}
|
||||
|
||||
addr &= 0xff;
|
||||
@@ -312,6 +314,7 @@ static void ioapic_mmio_write(struct kvm_io_device *this, gpa_t addr, int len,
|
||||
break;
|
||||
}
|
||||
mutex_unlock(&ioapic->kvm->irq_lock);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void kvm_ioapic_reset(struct kvm_ioapic *ioapic)
|
||||
@@ -329,7 +332,6 @@ void kvm_ioapic_reset(struct kvm_ioapic *ioapic)
|
||||
static const struct kvm_io_device_ops ioapic_mmio_ops = {
|
||||
.read = ioapic_mmio_read,
|
||||
.write = ioapic_mmio_write,
|
||||
.in_range = ioapic_in_range,
|
||||
};
|
||||
|
||||
int kvm_ioapic_init(struct kvm *kvm)
|
||||
|
@@ -17,23 +17,24 @@
|
||||
#define __KVM_IODEV_H__
|
||||
|
||||
#include <linux/kvm_types.h>
|
||||
#include <asm/errno.h>
|
||||
|
||||
struct kvm_io_device;
|
||||
|
||||
/**
|
||||
* kvm_io_device_ops are called under kvm slots_lock.
|
||||
* read and write handlers return 0 if the transaction has been handled,
|
||||
* or non-zero to have it passed to the next device.
|
||||
**/
|
||||
struct kvm_io_device_ops {
|
||||
void (*read)(struct kvm_io_device *this,
|
||||
int (*read)(struct kvm_io_device *this,
|
||||
gpa_t addr,
|
||||
int len,
|
||||
void *val);
|
||||
int (*write)(struct kvm_io_device *this,
|
||||
gpa_t addr,
|
||||
int len,
|
||||
void *val);
|
||||
void (*write)(struct kvm_io_device *this,
|
||||
gpa_t addr,
|
||||
int len,
|
||||
const void *val);
|
||||
int (*in_range)(struct kvm_io_device *this, gpa_t addr, int len,
|
||||
int is_write);
|
||||
const void *val);
|
||||
void (*destructor)(struct kvm_io_device *this);
|
||||
};
|
||||
|
||||
@@ -48,26 +49,16 @@ static inline void kvm_iodevice_init(struct kvm_io_device *dev,
|
||||
dev->ops = ops;
|
||||
}
|
||||
|
||||
static inline void kvm_iodevice_read(struct kvm_io_device *dev,
|
||||
gpa_t addr,
|
||||
int len,
|
||||
void *val)
|
||||
static inline int kvm_iodevice_read(struct kvm_io_device *dev,
|
||||
gpa_t addr, int l, void *v)
|
||||
{
|
||||
dev->ops->read(dev, addr, len, val);
|
||||
return dev->ops->read ? dev->ops->read(dev, addr, l, v) : -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
static inline void kvm_iodevice_write(struct kvm_io_device *dev,
|
||||
gpa_t addr,
|
||||
int len,
|
||||
const void *val)
|
||||
static inline int kvm_iodevice_write(struct kvm_io_device *dev,
|
||||
gpa_t addr, int l, const void *v)
|
||||
{
|
||||
dev->ops->write(dev, addr, len, val);
|
||||
}
|
||||
|
||||
static inline int kvm_iodevice_in_range(struct kvm_io_device *dev,
|
||||
gpa_t addr, int len, int is_write)
|
||||
{
|
||||
return dev->ops->in_range(dev, addr, len, is_write);
|
||||
return dev->ops->write ? dev->ops->write(dev, addr, l, v) : -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
static inline void kvm_iodevice_destructor(struct kvm_io_device *dev)
|
||||
|
@@ -2512,19 +2512,25 @@ void kvm_io_bus_destroy(struct kvm_io_bus *bus)
|
||||
}
|
||||
}
|
||||
|
||||
struct kvm_io_device *kvm_io_bus_find_dev(struct kvm_io_bus *bus,
|
||||
gpa_t addr, int len, int is_write)
|
||||
/* kvm_io_bus_write - called under kvm->slots_lock */
|
||||
int kvm_io_bus_write(struct kvm_io_bus *bus, gpa_t addr,
|
||||
int len, const void *val)
|
||||
{
|
||||
int i;
|
||||
for (i = 0; i < bus->dev_count; i++)
|
||||
if (!kvm_iodevice_write(bus->devs[i], addr, len, val))
|
||||
return 0;
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
for (i = 0; i < bus->dev_count; i++) {
|
||||
struct kvm_io_device *pos = bus->devs[i];
|
||||
|
||||
if (kvm_iodevice_in_range(pos, addr, len, is_write))
|
||||
return pos;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
/* kvm_io_bus_read - called under kvm->slots_lock */
|
||||
int kvm_io_bus_read(struct kvm_io_bus *bus, gpa_t addr, int len, void *val)
|
||||
{
|
||||
int i;
|
||||
for (i = 0; i < bus->dev_count; i++)
|
||||
if (!kvm_iodevice_read(bus->devs[i], addr, len, val))
|
||||
return 0;
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
void kvm_io_bus_register_dev(struct kvm *kvm, struct kvm_io_bus *bus,
|
||||
|
Reference in New Issue
Block a user