diff options
| author | Michael S. Tsirkin <mst@redhat.com> | 2009-06-29 15:24:32 -0400 |
|---|---|---|
| committer | Avi Kivity <avi@redhat.com> | 2009-09-10 01:33:05 -0400 |
| commit | bda9020e2463ec94db9f97e8615f3bae22069838 (patch) | |
| tree | 48125316d4c0f419a35aefdfbf665d30ad0c55ca /virt | |
| parent | 6c474694530f377507f9aca438c17206e051e6e7 (diff) | |
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>
Diffstat (limited to 'virt')
| -rw-r--r-- | virt/kvm/coalesced_mmio.c | 16 | ||||
| -rw-r--r-- | virt/kvm/ioapic.c | 22 | ||||
| -rw-r--r-- | virt/kvm/iodev.h | 39 | ||||
| -rw-r--r-- | virt/kvm/kvm_main.c | 26 |
4 files changed, 50 insertions, 53 deletions
diff --git a/virt/kvm/coalesced_mmio.c b/virt/kvm/coalesced_mmio.c index 7b7cc9fe5ee3..0352f81ecc0b 100644 --- a/virt/kvm/coalesced_mmio.c +++ b/virt/kvm/coalesced_mmio.c | |||
| @@ -19,18 +19,14 @@ static inline struct kvm_coalesced_mmio_dev *to_mmio(struct kvm_io_device *dev) | |||
| 19 | return container_of(dev, struct kvm_coalesced_mmio_dev, dev); | 19 | return container_of(dev, struct kvm_coalesced_mmio_dev, dev); |
| 20 | } | 20 | } |
| 21 | 21 | ||
| 22 | static int coalesced_mmio_in_range(struct kvm_io_device *this, | 22 | static int coalesced_mmio_in_range(struct kvm_coalesced_mmio_dev *dev, |
| 23 | gpa_t addr, int len, int is_write) | 23 | gpa_t addr, int len) |
| 24 | { | 24 | { |
| 25 | struct kvm_coalesced_mmio_dev *dev = to_mmio(this); | ||
| 26 | struct kvm_coalesced_mmio_zone *zone; | 25 | struct kvm_coalesced_mmio_zone *zone; |
| 27 | struct kvm_coalesced_mmio_ring *ring; | 26 | struct kvm_coalesced_mmio_ring *ring; |
| 28 | unsigned avail; | 27 | unsigned avail; |
| 29 | int i; | 28 | int i; |
| 30 | 29 | ||
| 31 | if (!is_write) | ||
| 32 | return 0; | ||
| 33 | |||
| 34 | /* Are we able to batch it ? */ | 30 | /* Are we able to batch it ? */ |
| 35 | 31 | ||
| 36 | /* last is the first free entry | 32 | /* last is the first free entry |
| @@ -60,11 +56,13 @@ static int coalesced_mmio_in_range(struct kvm_io_device *this, | |||
| 60 | return 0; | 56 | return 0; |
| 61 | } | 57 | } |
| 62 | 58 | ||
| 63 | static void coalesced_mmio_write(struct kvm_io_device *this, | 59 | static int coalesced_mmio_write(struct kvm_io_device *this, |
| 64 | gpa_t addr, int len, const void *val) | 60 | gpa_t addr, int len, const void *val) |
| 65 | { | 61 | { |
| 66 | struct kvm_coalesced_mmio_dev *dev = to_mmio(this); | 62 | struct kvm_coalesced_mmio_dev *dev = to_mmio(this); |
| 67 | struct kvm_coalesced_mmio_ring *ring = dev->kvm->coalesced_mmio_ring; | 63 | struct kvm_coalesced_mmio_ring *ring = dev->kvm->coalesced_mmio_ring; |
| 64 | if (!coalesced_mmio_in_range(dev, addr, len)) | ||
| 65 | return -EOPNOTSUPP; | ||
| 68 | 66 | ||
| 69 | spin_lock(&dev->lock); | 67 | spin_lock(&dev->lock); |
| 70 | 68 | ||
| @@ -76,6 +74,7 @@ static void coalesced_mmio_write(struct kvm_io_device *this, | |||
| 76 | smp_wmb(); | 74 | smp_wmb(); |
| 77 | ring->last = (ring->last + 1) % KVM_COALESCED_MMIO_MAX; | 75 | ring->last = (ring->last + 1) % KVM_COALESCED_MMIO_MAX; |
| 78 | spin_unlock(&dev->lock); | 76 | spin_unlock(&dev->lock); |
| 77 | return 0; | ||
| 79 | } | 78 | } |
| 80 | 79 | ||
| 81 | static void coalesced_mmio_destructor(struct kvm_io_device *this) | 80 | static void coalesced_mmio_destructor(struct kvm_io_device *this) |
| @@ -87,7 +86,6 @@ static void coalesced_mmio_destructor(struct kvm_io_device *this) | |||
| 87 | 86 | ||
| 88 | static const struct kvm_io_device_ops coalesced_mmio_ops = { | 87 | static const struct kvm_io_device_ops coalesced_mmio_ops = { |
| 89 | .write = coalesced_mmio_write, | 88 | .write = coalesced_mmio_write, |
| 90 | .in_range = coalesced_mmio_in_range, | ||
| 91 | .destructor = coalesced_mmio_destructor, | 89 | .destructor = coalesced_mmio_destructor, |
| 92 | }; | 90 | }; |
| 93 | 91 | ||
diff --git a/virt/kvm/ioapic.c b/virt/kvm/ioapic.c index 0eca54e06326..ddf6aa998b18 100644 --- a/virt/kvm/ioapic.c +++ b/virt/kvm/ioapic.c | |||
| @@ -227,20 +227,19 @@ static inline struct kvm_ioapic *to_ioapic(struct kvm_io_device *dev) | |||
| 227 | return container_of(dev, struct kvm_ioapic, dev); | 227 | return container_of(dev, struct kvm_ioapic, dev); |
| 228 | } | 228 | } |
| 229 | 229 | ||
| 230 | static int ioapic_in_range(struct kvm_io_device *this, gpa_t addr, | 230 | static inline int ioapic_in_range(struct kvm_ioapic *ioapic, gpa_t addr) |
| 231 | int len, int is_write) | ||
| 232 | { | 231 | { |
| 233 | struct kvm_ioapic *ioapic = to_ioapic(this); | ||
| 234 | |||
| 235 | return ((addr >= ioapic->base_address && | 232 | return ((addr >= ioapic->base_address && |
| 236 | (addr < ioapic->base_address + IOAPIC_MEM_LENGTH))); | 233 | (addr < ioapic->base_address + IOAPIC_MEM_LENGTH))); |
| 237 | } | 234 | } |
| 238 | 235 | ||
| 239 | static void ioapic_mmio_read(struct kvm_io_device *this, gpa_t addr, int len, | 236 | static int ioapic_mmio_read(struct kvm_io_device *this, gpa_t addr, int len, |
| 240 | void *val) | 237 | void *val) |
| 241 | { | 238 | { |
| 242 | struct kvm_ioapic *ioapic = to_ioapic(this); | 239 | struct kvm_ioapic *ioapic = to_ioapic(this); |
| 243 | u32 result; | 240 | u32 result; |
| 241 | if (!ioapic_in_range(ioapic, addr)) | ||
| 242 | return -EOPNOTSUPP; | ||
| 244 | 243 | ||
| 245 | ioapic_debug("addr %lx\n", (unsigned long)addr); | 244 | ioapic_debug("addr %lx\n", (unsigned long)addr); |
| 246 | ASSERT(!(addr & 0xf)); /* check alignment */ | 245 | ASSERT(!(addr & 0xf)); /* check alignment */ |
| @@ -273,13 +272,16 @@ static void ioapic_mmio_read(struct kvm_io_device *this, gpa_t addr, int len, | |||
| 273 | printk(KERN_WARNING "ioapic: wrong length %d\n", len); | 272 | printk(KERN_WARNING "ioapic: wrong length %d\n", len); |
| 274 | } | 273 | } |
| 275 | mutex_unlock(&ioapic->kvm->irq_lock); | 274 | mutex_unlock(&ioapic->kvm->irq_lock); |
| 275 | return 0; | ||
| 276 | } | 276 | } |
| 277 | 277 | ||
| 278 | static void ioapic_mmio_write(struct kvm_io_device *this, gpa_t addr, int len, | 278 | static int ioapic_mmio_write(struct kvm_io_device *this, gpa_t addr, int len, |
| 279 | const void *val) | 279 | const void *val) |
| 280 | { | 280 | { |
| 281 | struct kvm_ioapic *ioapic = to_ioapic(this); | 281 | struct kvm_ioapic *ioapic = to_ioapic(this); |
| 282 | u32 data; | 282 | u32 data; |
| 283 | if (!ioapic_in_range(ioapic, addr)) | ||
| 284 | return -EOPNOTSUPP; | ||
| 283 | 285 | ||
| 284 | ioapic_debug("ioapic_mmio_write addr=%p len=%d val=%p\n", | 286 | ioapic_debug("ioapic_mmio_write addr=%p len=%d val=%p\n", |
| 285 | (void*)addr, len, val); | 287 | (void*)addr, len, val); |
| @@ -290,7 +292,7 @@ static void ioapic_mmio_write(struct kvm_io_device *this, gpa_t addr, int len, | |||
| 290 | data = *(u32 *) val; | 292 | data = *(u32 *) val; |
| 291 | else { | 293 | else { |
| 292 | printk(KERN_WARNING "ioapic: Unsupported size %d\n", len); | 294 | printk(KERN_WARNING "ioapic: Unsupported size %d\n", len); |
| 293 | return; | 295 | return 0; |
| 294 | } | 296 | } |
| 295 | 297 | ||
| 296 | addr &= 0xff; | 298 | addr &= 0xff; |
| @@ -312,6 +314,7 @@ static void ioapic_mmio_write(struct kvm_io_device *this, gpa_t addr, int len, | |||
| 312 | break; | 314 | break; |
| 313 | } | 315 | } |
| 314 | mutex_unlock(&ioapic->kvm->irq_lock); | 316 | mutex_unlock(&ioapic->kvm->irq_lock); |
| 317 | return 0; | ||
| 315 | } | 318 | } |
| 316 | 319 | ||
| 317 | void kvm_ioapic_reset(struct kvm_ioapic *ioapic) | 320 | void kvm_ioapic_reset(struct kvm_ioapic *ioapic) |
| @@ -329,7 +332,6 @@ void kvm_ioapic_reset(struct kvm_ioapic *ioapic) | |||
| 329 | static const struct kvm_io_device_ops ioapic_mmio_ops = { | 332 | static const struct kvm_io_device_ops ioapic_mmio_ops = { |
| 330 | .read = ioapic_mmio_read, | 333 | .read = ioapic_mmio_read, |
| 331 | .write = ioapic_mmio_write, | 334 | .write = ioapic_mmio_write, |
| 332 | .in_range = ioapic_in_range, | ||
| 333 | }; | 335 | }; |
| 334 | 336 | ||
| 335 | int kvm_ioapic_init(struct kvm *kvm) | 337 | int kvm_ioapic_init(struct kvm *kvm) |
diff --git a/virt/kvm/iodev.h b/virt/kvm/iodev.h index 06e38b23fa61..12fd3caffd2b 100644 --- a/virt/kvm/iodev.h +++ b/virt/kvm/iodev.h | |||
| @@ -17,23 +17,24 @@ | |||
| 17 | #define __KVM_IODEV_H__ | 17 | #define __KVM_IODEV_H__ |
| 18 | 18 | ||
| 19 | #include <linux/kvm_types.h> | 19 | #include <linux/kvm_types.h> |
| 20 | #include <asm/errno.h> | ||
| 20 | 21 | ||
| 21 | struct kvm_io_device; | 22 | struct kvm_io_device; |
| 22 | 23 | ||
| 23 | /** | 24 | /** |
| 24 | * kvm_io_device_ops are called under kvm slots_lock. | 25 | * kvm_io_device_ops are called under kvm slots_lock. |
| 26 | * read and write handlers return 0 if the transaction has been handled, | ||
| 27 | * or non-zero to have it passed to the next device. | ||
| 25 | **/ | 28 | **/ |
| 26 | struct kvm_io_device_ops { | 29 | struct kvm_io_device_ops { |
| 27 | void (*read)(struct kvm_io_device *this, | 30 | int (*read)(struct kvm_io_device *this, |
| 31 | gpa_t addr, | ||
| 32 | int len, | ||
| 33 | void *val); | ||
| 34 | int (*write)(struct kvm_io_device *this, | ||
| 28 | gpa_t addr, | 35 | gpa_t addr, |
| 29 | int len, | 36 | int len, |
| 30 | void *val); | 37 | const void *val); |
| 31 | void (*write)(struct kvm_io_device *this, | ||
| 32 | gpa_t addr, | ||
| 33 | int len, | ||
| 34 | const void *val); | ||
| 35 | int (*in_range)(struct kvm_io_device *this, gpa_t addr, int len, | ||
| 36 | int is_write); | ||
| 37 | void (*destructor)(struct kvm_io_device *this); | 38 | void (*destructor)(struct kvm_io_device *this); |
| 38 | }; | 39 | }; |
| 39 | 40 | ||
| @@ -48,26 +49,16 @@ static inline void kvm_iodevice_init(struct kvm_io_device *dev, | |||
| 48 | dev->ops = ops; | 49 | dev->ops = ops; |
| 49 | } | 50 | } |
| 50 | 51 | ||
| 51 | static inline void kvm_iodevice_read(struct kvm_io_device *dev, | 52 | static inline int kvm_iodevice_read(struct kvm_io_device *dev, |
| 52 | gpa_t addr, | 53 | gpa_t addr, int l, void *v) |
| 53 | int len, | ||
| 54 | void *val) | ||
| 55 | { | 54 | { |
| 56 | dev->ops->read(dev, addr, len, val); | 55 | return dev->ops->read ? dev->ops->read(dev, addr, l, v) : -EOPNOTSUPP; |
| 57 | } | 56 | } |
| 58 | 57 | ||
| 59 | static inline void kvm_iodevice_write(struct kvm_io_device *dev, | 58 | static inline int kvm_iodevice_write(struct kvm_io_device *dev, |
| 60 | gpa_t addr, | 59 | gpa_t addr, int l, const void *v) |
| 61 | int len, | ||
| 62 | const void *val) | ||
| 63 | { | 60 | { |
| 64 | dev->ops->write(dev, addr, len, val); | 61 | return dev->ops->write ? dev->ops->write(dev, addr, l, v) : -EOPNOTSUPP; |
| 65 | } | ||
| 66 | |||
| 67 | static inline int kvm_iodevice_in_range(struct kvm_io_device *dev, | ||
| 68 | gpa_t addr, int len, int is_write) | ||
| 69 | { | ||
| 70 | return dev->ops->in_range(dev, addr, len, is_write); | ||
| 71 | } | 62 | } |
| 72 | 63 | ||
| 73 | static inline void kvm_iodevice_destructor(struct kvm_io_device *dev) | 64 | static inline void kvm_iodevice_destructor(struct kvm_io_device *dev) |
diff --git a/virt/kvm/kvm_main.c b/virt/kvm/kvm_main.c index 0edc366ecf89..594606526620 100644 --- a/virt/kvm/kvm_main.c +++ b/virt/kvm/kvm_main.c | |||
| @@ -2512,19 +2512,25 @@ void kvm_io_bus_destroy(struct kvm_io_bus *bus) | |||
| 2512 | } | 2512 | } |
| 2513 | } | 2513 | } |
| 2514 | 2514 | ||
| 2515 | struct kvm_io_device *kvm_io_bus_find_dev(struct kvm_io_bus *bus, | 2515 | /* kvm_io_bus_write - called under kvm->slots_lock */ |
| 2516 | gpa_t addr, int len, int is_write) | 2516 | int kvm_io_bus_write(struct kvm_io_bus *bus, gpa_t addr, |
| 2517 | int len, const void *val) | ||
| 2517 | { | 2518 | { |
| 2518 | int i; | 2519 | int i; |
| 2520 | for (i = 0; i < bus->dev_count; i++) | ||
| 2521 | if (!kvm_iodevice_write(bus->devs[i], addr, len, val)) | ||
| 2522 | return 0; | ||
| 2523 | return -EOPNOTSUPP; | ||
| 2524 | } | ||
| 2519 | 2525 | ||
| 2520 | for (i = 0; i < bus->dev_count; i++) { | 2526 | /* kvm_io_bus_read - called under kvm->slots_lock */ |
| 2521 | struct kvm_io_device *pos = bus->devs[i]; | 2527 | int kvm_io_bus_read(struct kvm_io_bus *bus, gpa_t addr, int len, void *val) |
| 2522 | 2528 | { | |
| 2523 | if (kvm_iodevice_in_range(pos, addr, len, is_write)) | 2529 | int i; |
| 2524 | return pos; | 2530 | for (i = 0; i < bus->dev_count; i++) |
| 2525 | } | 2531 | if (!kvm_iodevice_read(bus->devs[i], addr, len, val)) |
| 2526 | 2532 | return 0; | |
| 2527 | return NULL; | 2533 | return -EOPNOTSUPP; |
| 2528 | } | 2534 | } |
| 2529 | 2535 | ||
| 2530 | void kvm_io_bus_register_dev(struct kvm *kvm, struct kvm_io_bus *bus, | 2536 | void kvm_io_bus_register_dev(struct kvm *kvm, struct kvm_io_bus *bus, |
