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, |