diff options
author | Laurent Vivier <Laurent.Vivier@bull.net> | 2008-05-30 10:05:53 -0400 |
---|---|---|
committer | Avi Kivity <avi@qumranet.com> | 2008-07-20 05:42:30 -0400 |
commit | 92760499d01ef91518119908eb9b8798b6c9bd3f (patch) | |
tree | a6bd80fbad82589eb5aa98f81edda4537bc1f625 | |
parent | 131d82791b628d4aeafd94ddc74a9b68f3d15a83 (diff) |
KVM: kvm_io_device: extend in_range() to manage len and write attribute
Modify member in_range() of structure kvm_io_device to pass length and the type
of the I/O (write or read).
This modification allows to use kvm_io_device with coalesced MMIO.
Signed-off-by: Laurent Vivier <Laurent.Vivier@bull.net>
Signed-off-by: Avi Kivity <avi@qumranet.com>
-rw-r--r-- | arch/ia64/kvm/kvm-ia64.c | 6 | ||||
-rw-r--r-- | arch/x86/kvm/i8254.c | 6 | ||||
-rw-r--r-- | arch/x86/kvm/i8259.c | 3 | ||||
-rw-r--r-- | arch/x86/kvm/lapic.c | 3 | ||||
-rw-r--r-- | arch/x86/kvm/x86.c | 28 | ||||
-rw-r--r-- | include/linux/kvm_host.h | 3 | ||||
-rw-r--r-- | virt/kvm/ioapic.c | 3 | ||||
-rw-r--r-- | virt/kvm/iodev.h | 8 | ||||
-rw-r--r-- | virt/kvm/kvm_main.c | 5 |
9 files changed, 40 insertions, 25 deletions
diff --git a/arch/ia64/kvm/kvm-ia64.c b/arch/ia64/kvm/kvm-ia64.c index 7c504be57972..bb58df7cc418 100644 --- a/arch/ia64/kvm/kvm-ia64.c +++ b/arch/ia64/kvm/kvm-ia64.c | |||
@@ -195,11 +195,11 @@ int kvm_dev_ioctl_check_extension(long ext) | |||
195 | } | 195 | } |
196 | 196 | ||
197 | static struct kvm_io_device *vcpu_find_mmio_dev(struct kvm_vcpu *vcpu, | 197 | static struct kvm_io_device *vcpu_find_mmio_dev(struct kvm_vcpu *vcpu, |
198 | gpa_t addr) | 198 | gpa_t addr, int len, int is_write) |
199 | { | 199 | { |
200 | struct kvm_io_device *dev; | 200 | struct kvm_io_device *dev; |
201 | 201 | ||
202 | dev = kvm_io_bus_find_dev(&vcpu->kvm->mmio_bus, addr); | 202 | dev = kvm_io_bus_find_dev(&vcpu->kvm->mmio_bus, addr, len, is_write); |
203 | 203 | ||
204 | return dev; | 204 | return dev; |
205 | } | 205 | } |
@@ -231,7 +231,7 @@ static int handle_mmio(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run) | |||
231 | kvm_run->exit_reason = KVM_EXIT_MMIO; | 231 | kvm_run->exit_reason = KVM_EXIT_MMIO; |
232 | return 0; | 232 | return 0; |
233 | mmio: | 233 | mmio: |
234 | mmio_dev = vcpu_find_mmio_dev(vcpu, p->addr); | 234 | mmio_dev = vcpu_find_mmio_dev(vcpu, p->addr, p->size, !p->dir); |
235 | if (mmio_dev) { | 235 | if (mmio_dev) { |
236 | if (!p->dir) | 236 | if (!p->dir) |
237 | kvm_iodevice_write(mmio_dev, p->addr, p->size, | 237 | kvm_iodevice_write(mmio_dev, p->addr, p->size, |
diff --git a/arch/x86/kvm/i8254.c b/arch/x86/kvm/i8254.c index 60074dc66bd7..9e3391e9a1b7 100644 --- a/arch/x86/kvm/i8254.c +++ b/arch/x86/kvm/i8254.c | |||
@@ -460,7 +460,8 @@ static void pit_ioport_read(struct kvm_io_device *this, | |||
460 | mutex_unlock(&pit_state->lock); | 460 | mutex_unlock(&pit_state->lock); |
461 | } | 461 | } |
462 | 462 | ||
463 | static int pit_in_range(struct kvm_io_device *this, gpa_t addr) | 463 | static int pit_in_range(struct kvm_io_device *this, gpa_t addr, |
464 | int len, int is_write) | ||
464 | { | 465 | { |
465 | return ((addr >= KVM_PIT_BASE_ADDRESS) && | 466 | return ((addr >= KVM_PIT_BASE_ADDRESS) && |
466 | (addr < KVM_PIT_BASE_ADDRESS + KVM_PIT_MEM_LENGTH)); | 467 | (addr < KVM_PIT_BASE_ADDRESS + KVM_PIT_MEM_LENGTH)); |
@@ -501,7 +502,8 @@ static void speaker_ioport_read(struct kvm_io_device *this, | |||
501 | mutex_unlock(&pit_state->lock); | 502 | mutex_unlock(&pit_state->lock); |
502 | } | 503 | } |
503 | 504 | ||
504 | static int speaker_in_range(struct kvm_io_device *this, gpa_t addr) | 505 | static int speaker_in_range(struct kvm_io_device *this, gpa_t addr, |
506 | int len, int is_write) | ||
505 | { | 507 | { |
506 | return (addr == KVM_SPEAKER_BASE_ADDRESS); | 508 | return (addr == KVM_SPEAKER_BASE_ADDRESS); |
507 | } | 509 | } |
diff --git a/arch/x86/kvm/i8259.c b/arch/x86/kvm/i8259.c index ab29cf2def47..5857f59ad4aa 100644 --- a/arch/x86/kvm/i8259.c +++ b/arch/x86/kvm/i8259.c | |||
@@ -346,7 +346,8 @@ static u32 elcr_ioport_read(void *opaque, u32 addr1) | |||
346 | return s->elcr; | 346 | return s->elcr; |
347 | } | 347 | } |
348 | 348 | ||
349 | static int picdev_in_range(struct kvm_io_device *this, gpa_t addr) | 349 | static int picdev_in_range(struct kvm_io_device *this, gpa_t addr, |
350 | int len, int is_write) | ||
350 | { | 351 | { |
351 | switch (addr) { | 352 | switch (addr) { |
352 | case 0x20: | 353 | case 0x20: |
diff --git a/arch/x86/kvm/lapic.c b/arch/x86/kvm/lapic.c index e48d19394031..180ba7316da5 100644 --- a/arch/x86/kvm/lapic.c +++ b/arch/x86/kvm/lapic.c | |||
@@ -785,7 +785,8 @@ static void apic_mmio_write(struct kvm_io_device *this, | |||
785 | 785 | ||
786 | } | 786 | } |
787 | 787 | ||
788 | static int apic_mmio_range(struct kvm_io_device *this, gpa_t addr) | 788 | static int apic_mmio_range(struct kvm_io_device *this, gpa_t addr, |
789 | int len, int size) | ||
789 | { | 790 | { |
790 | struct kvm_lapic *apic = (struct kvm_lapic *)this->private; | 791 | struct kvm_lapic *apic = (struct kvm_lapic *)this->private; |
791 | int ret = 0; | 792 | int ret = 0; |
diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c index 4c94fad7f01e..ab3f5552d694 100644 --- a/arch/x86/kvm/x86.c +++ b/arch/x86/kvm/x86.c | |||
@@ -1797,13 +1797,14 @@ static void kvm_init_msr_list(void) | |||
1797 | * Only apic need an MMIO device hook, so shortcut now.. | 1797 | * Only apic need an MMIO device hook, so shortcut now.. |
1798 | */ | 1798 | */ |
1799 | static struct kvm_io_device *vcpu_find_pervcpu_dev(struct kvm_vcpu *vcpu, | 1799 | static struct kvm_io_device *vcpu_find_pervcpu_dev(struct kvm_vcpu *vcpu, |
1800 | gpa_t addr) | 1800 | gpa_t addr, int len, |
1801 | int is_write) | ||
1801 | { | 1802 | { |
1802 | struct kvm_io_device *dev; | 1803 | struct kvm_io_device *dev; |
1803 | 1804 | ||
1804 | if (vcpu->arch.apic) { | 1805 | if (vcpu->arch.apic) { |
1805 | dev = &vcpu->arch.apic->dev; | 1806 | dev = &vcpu->arch.apic->dev; |
1806 | if (dev->in_range(dev, addr)) | 1807 | if (dev->in_range(dev, addr, len, is_write)) |
1807 | return dev; | 1808 | return dev; |
1808 | } | 1809 | } |
1809 | return NULL; | 1810 | return NULL; |
@@ -1811,13 +1812,15 @@ static struct kvm_io_device *vcpu_find_pervcpu_dev(struct kvm_vcpu *vcpu, | |||
1811 | 1812 | ||
1812 | 1813 | ||
1813 | static struct kvm_io_device *vcpu_find_mmio_dev(struct kvm_vcpu *vcpu, | 1814 | static struct kvm_io_device *vcpu_find_mmio_dev(struct kvm_vcpu *vcpu, |
1814 | gpa_t addr) | 1815 | gpa_t addr, int len, |
1816 | int is_write) | ||
1815 | { | 1817 | { |
1816 | struct kvm_io_device *dev; | 1818 | struct kvm_io_device *dev; |
1817 | 1819 | ||
1818 | dev = vcpu_find_pervcpu_dev(vcpu, addr); | 1820 | dev = vcpu_find_pervcpu_dev(vcpu, addr, len, is_write); |
1819 | if (dev == NULL) | 1821 | if (dev == NULL) |
1820 | dev = kvm_io_bus_find_dev(&vcpu->kvm->mmio_bus, addr); | 1822 | dev = kvm_io_bus_find_dev(&vcpu->kvm->mmio_bus, addr, len, |
1823 | is_write); | ||
1821 | return dev; | 1824 | return dev; |
1822 | } | 1825 | } |
1823 | 1826 | ||
@@ -1885,7 +1888,7 @@ mmio: | |||
1885 | * Is this MMIO handled locally? | 1888 | * Is this MMIO handled locally? |
1886 | */ | 1889 | */ |
1887 | mutex_lock(&vcpu->kvm->lock); | 1890 | mutex_lock(&vcpu->kvm->lock); |
1888 | mmio_dev = vcpu_find_mmio_dev(vcpu, gpa); | 1891 | mmio_dev = vcpu_find_mmio_dev(vcpu, gpa, bytes, 0); |
1889 | if (mmio_dev) { | 1892 | if (mmio_dev) { |
1890 | kvm_iodevice_read(mmio_dev, gpa, bytes, val); | 1893 | kvm_iodevice_read(mmio_dev, gpa, bytes, val); |
1891 | mutex_unlock(&vcpu->kvm->lock); | 1894 | mutex_unlock(&vcpu->kvm->lock); |
@@ -1940,7 +1943,7 @@ mmio: | |||
1940 | * Is this MMIO handled locally? | 1943 | * Is this MMIO handled locally? |
1941 | */ | 1944 | */ |
1942 | mutex_lock(&vcpu->kvm->lock); | 1945 | mutex_lock(&vcpu->kvm->lock); |
1943 | mmio_dev = vcpu_find_mmio_dev(vcpu, gpa); | 1946 | mmio_dev = vcpu_find_mmio_dev(vcpu, gpa, bytes, 1); |
1944 | if (mmio_dev) { | 1947 | if (mmio_dev) { |
1945 | kvm_iodevice_write(mmio_dev, gpa, bytes, val); | 1948 | kvm_iodevice_write(mmio_dev, gpa, bytes, val); |
1946 | mutex_unlock(&vcpu->kvm->lock); | 1949 | mutex_unlock(&vcpu->kvm->lock); |
@@ -2317,9 +2320,10 @@ static void pio_string_write(struct kvm_io_device *pio_dev, | |||
2317 | } | 2320 | } |
2318 | 2321 | ||
2319 | static struct kvm_io_device *vcpu_find_pio_dev(struct kvm_vcpu *vcpu, | 2322 | static struct kvm_io_device *vcpu_find_pio_dev(struct kvm_vcpu *vcpu, |
2320 | gpa_t addr) | 2323 | gpa_t addr, int len, |
2324 | int is_write) | ||
2321 | { | 2325 | { |
2322 | return kvm_io_bus_find_dev(&vcpu->kvm->pio_bus, addr); | 2326 | return kvm_io_bus_find_dev(&vcpu->kvm->pio_bus, addr, len, is_write); |
2323 | } | 2327 | } |
2324 | 2328 | ||
2325 | int kvm_emulate_pio(struct kvm_vcpu *vcpu, struct kvm_run *run, int in, | 2329 | int kvm_emulate_pio(struct kvm_vcpu *vcpu, struct kvm_run *run, int in, |
@@ -2351,7 +2355,7 @@ int kvm_emulate_pio(struct kvm_vcpu *vcpu, struct kvm_run *run, int in, | |||
2351 | 2355 | ||
2352 | kvm_x86_ops->skip_emulated_instruction(vcpu); | 2356 | kvm_x86_ops->skip_emulated_instruction(vcpu); |
2353 | 2357 | ||
2354 | pio_dev = vcpu_find_pio_dev(vcpu, port); | 2358 | pio_dev = vcpu_find_pio_dev(vcpu, port, size, !in); |
2355 | if (pio_dev) { | 2359 | if (pio_dev) { |
2356 | kernel_pio(pio_dev, vcpu, vcpu->arch.pio_data); | 2360 | kernel_pio(pio_dev, vcpu, vcpu->arch.pio_data); |
2357 | complete_pio(vcpu); | 2361 | complete_pio(vcpu); |
@@ -2433,7 +2437,9 @@ int kvm_emulate_pio_string(struct kvm_vcpu *vcpu, struct kvm_run *run, int in, | |||
2433 | } | 2437 | } |
2434 | } | 2438 | } |
2435 | 2439 | ||
2436 | pio_dev = vcpu_find_pio_dev(vcpu, port); | 2440 | pio_dev = vcpu_find_pio_dev(vcpu, port, |
2441 | vcpu->arch.pio.cur_count, | ||
2442 | !vcpu->arch.pio.in); | ||
2437 | if (!vcpu->arch.pio.in) { | 2443 | if (!vcpu->arch.pio.in) { |
2438 | /* string PIO write */ | 2444 | /* string PIO write */ |
2439 | ret = pio_copy_data(vcpu); | 2445 | ret = pio_copy_data(vcpu); |
diff --git a/include/linux/kvm_host.h b/include/linux/kvm_host.h index 865dcbcb891f..499ff0604234 100644 --- a/include/linux/kvm_host.h +++ b/include/linux/kvm_host.h | |||
@@ -52,7 +52,8 @@ struct kvm_io_bus { | |||
52 | 52 | ||
53 | void kvm_io_bus_init(struct kvm_io_bus *bus); | 53 | void kvm_io_bus_init(struct kvm_io_bus *bus); |
54 | void kvm_io_bus_destroy(struct kvm_io_bus *bus); | 54 | void kvm_io_bus_destroy(struct kvm_io_bus *bus); |
55 | struct kvm_io_device *kvm_io_bus_find_dev(struct kvm_io_bus *bus, gpa_t addr); | 55 | struct kvm_io_device *kvm_io_bus_find_dev(struct kvm_io_bus *bus, |
56 | gpa_t addr, int len, int is_write); | ||
56 | void kvm_io_bus_register_dev(struct kvm_io_bus *bus, | 57 | void kvm_io_bus_register_dev(struct kvm_io_bus *bus, |
57 | struct kvm_io_device *dev); | 58 | struct kvm_io_device *dev); |
58 | 59 | ||
diff --git a/virt/kvm/ioapic.c b/virt/kvm/ioapic.c index d0c668c6959e..c0d22870ee9c 100644 --- a/virt/kvm/ioapic.c +++ b/virt/kvm/ioapic.c | |||
@@ -307,7 +307,8 @@ void kvm_ioapic_update_eoi(struct kvm *kvm, int vector) | |||
307 | __kvm_ioapic_update_eoi(ioapic, i); | 307 | __kvm_ioapic_update_eoi(ioapic, i); |
308 | } | 308 | } |
309 | 309 | ||
310 | static int ioapic_in_range(struct kvm_io_device *this, gpa_t addr) | 310 | static int ioapic_in_range(struct kvm_io_device *this, gpa_t addr, |
311 | int len, int is_write) | ||
311 | { | 312 | { |
312 | struct kvm_ioapic *ioapic = (struct kvm_ioapic *)this->private; | 313 | struct kvm_ioapic *ioapic = (struct kvm_ioapic *)this->private; |
313 | 314 | ||
diff --git a/virt/kvm/iodev.h b/virt/kvm/iodev.h index c14e642027b2..55e8846ac3a6 100644 --- a/virt/kvm/iodev.h +++ b/virt/kvm/iodev.h | |||
@@ -27,7 +27,8 @@ struct kvm_io_device { | |||
27 | gpa_t addr, | 27 | gpa_t addr, |
28 | int len, | 28 | int len, |
29 | const void *val); | 29 | const void *val); |
30 | int (*in_range)(struct kvm_io_device *this, gpa_t addr); | 30 | int (*in_range)(struct kvm_io_device *this, gpa_t addr, int len, |
31 | int is_write); | ||
31 | void (*destructor)(struct kvm_io_device *this); | 32 | void (*destructor)(struct kvm_io_device *this); |
32 | 33 | ||
33 | void *private; | 34 | void *private; |
@@ -49,9 +50,10 @@ static inline void kvm_iodevice_write(struct kvm_io_device *dev, | |||
49 | dev->write(dev, addr, len, val); | 50 | dev->write(dev, addr, len, val); |
50 | } | 51 | } |
51 | 52 | ||
52 | static inline int kvm_iodevice_inrange(struct kvm_io_device *dev, gpa_t addr) | 53 | static inline int kvm_iodevice_inrange(struct kvm_io_device *dev, |
54 | gpa_t addr, int len, int is_write) | ||
53 | { | 55 | { |
54 | return dev->in_range(dev, addr); | 56 | return dev->in_range(dev, addr, len, is_write); |
55 | } | 57 | } |
56 | 58 | ||
57 | static inline void kvm_iodevice_destructor(struct kvm_io_device *dev) | 59 | 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 83a0e5ce6037..9330fad2b918 100644 --- a/virt/kvm/kvm_main.c +++ b/virt/kvm/kvm_main.c | |||
@@ -1350,14 +1350,15 @@ void kvm_io_bus_destroy(struct kvm_io_bus *bus) | |||
1350 | } | 1350 | } |
1351 | } | 1351 | } |
1352 | 1352 | ||
1353 | struct kvm_io_device *kvm_io_bus_find_dev(struct kvm_io_bus *bus, gpa_t addr) | 1353 | struct kvm_io_device *kvm_io_bus_find_dev(struct kvm_io_bus *bus, |
1354 | gpa_t addr, int len, int is_write) | ||
1354 | { | 1355 | { |
1355 | int i; | 1356 | int i; |
1356 | 1357 | ||
1357 | for (i = 0; i < bus->dev_count; i++) { | 1358 | for (i = 0; i < bus->dev_count; i++) { |
1358 | struct kvm_io_device *pos = bus->devs[i]; | 1359 | struct kvm_io_device *pos = bus->devs[i]; |
1359 | 1360 | ||
1360 | if (pos->in_range(pos, addr)) | 1361 | if (pos->in_range(pos, addr, len, is_write)) |
1361 | return pos; | 1362 | return pos; |
1362 | } | 1363 | } |
1363 | 1364 | ||