aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMarc Zyngier <marc.zyngier@arm.com>2014-05-27 11:24:19 +0100
committerWill Deacon <will.deacon@arm.com>2015-06-01 16:39:55 +0100
commit4123ca555b1d466b08c630763a378b4d53de9ec5 (patch)
tree65d4aa0bf3dce7b05026790ec35bd68dc3a5e5a3
parentfc9d8ec3e459b744c012b9c82924aa397099ab19 (diff)
downloadkvmtool-4123ca555b1d466b08c630763a378b4d53de9ec5.tar.gz
kvmtool: virtio: pass trapped vcpu to IO accessors
The recent introduction of bi-endianness on arm/arm64 had the odd effect of breaking virtio-pci support on these platforms, as the device endian field defaults to being VIRTIO_ENDIAN_HOST, which is the wrong thing to have on a bi-endian capable architecture. The fix is to check for the endianness on the ioport path the same way we do it for mmio, which implies passing the vcpu all the way down. Patch is a bit ugly, but aligns MMIO and ioport nicely. Tested on arm64 and x86. Acked-by: Will Deacon <will.deacon@arm.com> Signed-off-by: Marc Zyngier <marc.zyngier@arm.com> Signed-off-by: Pekka Enberg <penberg@kernel.org>
-rw-r--r--arm/include/arm-common/kvm-cpu-arch.h2
-rw-r--r--arm/kvm-cpu.c2
-rw-r--r--hw/i8042.c6
-rw-r--r--hw/pci-shmem.c4
-rw-r--r--hw/rtc.c8
-rw-r--r--hw/serial.c10
-rw-r--r--hw/vesa.c4
-rw-r--r--include/kvm/ioport.h5
-rw-r--r--include/kvm/kvm.h2
-rw-r--r--ioport.c7
-rw-r--r--kvm-cpu.c2
-rw-r--r--pci.c12
-rw-r--r--powerpc/include/kvm/kvm-cpu-arch.h2
-rw-r--r--powerpc/spapr_pci.h2
-rw-r--r--virtio/pci.c13
-rw-r--r--x86/include/kvm/kvm-cpu-arch.h4
-rw-r--r--x86/ioport.c10
17 files changed, 52 insertions, 43 deletions
diff --git a/arm/include/arm-common/kvm-cpu-arch.h b/arm/include/arm-common/kvm-cpu-arch.h
index 355a02d7..83cd8b83 100644
--- a/arm/include/arm-common/kvm-cpu-arch.h
+++ b/arm/include/arm-common/kvm-cpu-arch.h
@@ -36,7 +36,7 @@ struct kvm_arm_target {
int kvm_cpu__register_kvm_arm_target(struct kvm_arm_target *target);
-static inline bool kvm_cpu__emulate_io(struct kvm *kvm, u16 port, void *data,
+static inline bool kvm_cpu__emulate_io(struct kvm_cpu *vcpu, u16 port, void *data,
int direction, int size, u32 count)
{
return false;
diff --git a/arm/kvm-cpu.c b/arm/kvm-cpu.c
index 53afa359..aeaa4cfb 100644
--- a/arm/kvm-cpu.c
+++ b/arm/kvm-cpu.c
@@ -106,7 +106,7 @@ bool kvm_cpu__emulate_mmio(struct kvm_cpu *vcpu, u64 phys_addr, u8 *data,
} else if (arm_addr_in_ioport_region(phys_addr)) {
int direction = is_write ? KVM_EXIT_IO_OUT : KVM_EXIT_IO_IN;
u16 port = (phys_addr - KVM_IOPORT_AREA) & USHRT_MAX;
- return kvm__emulate_io(vcpu->kvm, port, data, direction, len, 1);
+ return kvm__emulate_io(vcpu, port, data, direction, len, 1);
} else if (arm_addr_in_pci_region(phys_addr)) {
return kvm__emulate_mmio(vcpu, phys_addr, data, len, is_write);
}
diff --git a/hw/i8042.c b/hw/i8042.c
index 4a12ee74..3801e20a 100644
--- a/hw/i8042.c
+++ b/hw/i8042.c
@@ -295,7 +295,7 @@ static void kbd_reset(void)
/*
* Called when the OS has written to one of the keyboard's ports (0x60 or 0x64)
*/
-static bool kbd_in(struct ioport *ioport, struct kvm *kvm, u16 port, void *data, int size)
+static bool kbd_in(struct ioport *ioport, struct kvm_cpu *vcpu, u16 port, void *data, int size)
{
switch (port) {
case I8042_COMMAND_REG: {
@@ -319,12 +319,12 @@ static bool kbd_in(struct ioport *ioport, struct kvm *kvm, u16 port, void *data,
return true;
}
-static bool kbd_out(struct ioport *ioport, struct kvm *kvm, u16 port, void *data, int size)
+static bool kbd_out(struct ioport *ioport, struct kvm_cpu *vcpu, u16 port, void *data, int size)
{
switch (port) {
case I8042_COMMAND_REG: {
u8 value = ioport__read8(data);
- kbd_write_command(kvm, value);
+ kbd_write_command(vcpu->kvm, value);
break;
}
case I8042_DATA_REG: {
diff --git a/hw/pci-shmem.c b/hw/pci-shmem.c
index 4b837ebf..457e960c 100644
--- a/hw/pci-shmem.c
+++ b/hw/pci-shmem.c
@@ -63,7 +63,7 @@ int pci_shmem__register_mem(struct shmem_info *si)
return 0;
}
-static bool shmem_pci__io_in(struct ioport *ioport, struct kvm *kvm, u16 port, void *data, int size)
+static bool shmem_pci__io_in(struct ioport *ioport, struct kvm_cpu *vcpu, u16 port, void *data, int size)
{
u16 offset = port - ivshmem_registers;
@@ -82,7 +82,7 @@ static bool shmem_pci__io_in(struct ioport *ioport, struct kvm *kvm, u16 port, v
return true;
}
-static bool shmem_pci__io_out(struct ioport *ioport, struct kvm *kvm, u16 port, void *data, int size)
+static bool shmem_pci__io_out(struct ioport *ioport, struct kvm_cpu *vcpu, u16 port, void *data, int size)
{
u16 offset = port - ivshmem_registers;
diff --git a/hw/rtc.c b/hw/rtc.c
index 5232bd79..0649b5df 100644
--- a/hw/rtc.c
+++ b/hw/rtc.c
@@ -37,7 +37,7 @@ static inline unsigned char bin2bcd(unsigned val)
return ((val / 10) << 4) + val % 10;
}
-static bool cmos_ram_data_in(struct ioport *ioport, struct kvm *kvm, u16 port, void *data, int size)
+static bool cmos_ram_data_in(struct ioport *ioport, struct kvm_cpu *vcpu, u16 port, void *data, int size)
{
struct tm *tm;
time_t ti;
@@ -91,7 +91,7 @@ static bool cmos_ram_data_in(struct ioport *ioport, struct kvm *kvm, u16 port, v
return true;
}
-static bool cmos_ram_data_out(struct ioport *ioport, struct kvm *kvm, u16 port, void *data, int size)
+static bool cmos_ram_data_out(struct ioport *ioport, struct kvm_cpu *vcpu, u16 port, void *data, int size)
{
switch (rtc.cmos_idx) {
case RTC_REG_C:
@@ -111,11 +111,11 @@ static struct ioport_operations cmos_ram_data_ioport_ops = {
.io_in = cmos_ram_data_in,
};
-static bool cmos_ram_index_out(struct ioport *ioport, struct kvm *kvm, u16 port, void *data, int size)
+static bool cmos_ram_index_out(struct ioport *ioport, struct kvm_cpu *vcpu, u16 port, void *data, int size)
{
u8 value = ioport__read8(data);
- kvm->nmi_disabled = value & (1UL << 7);
+ vcpu->kvm->nmi_disabled = value & (1UL << 7);
rtc.cmos_idx = value & ~(1UL << 7);
return true;
diff --git a/hw/serial.c b/hw/serial.c
index 3b5540c5..60147de1 100644
--- a/hw/serial.c
+++ b/hw/serial.c
@@ -218,7 +218,7 @@ void serial8250__inject_sysrq(struct kvm *kvm, char sysrq)
sysrq_pending = sysrq;
}
-static bool serial8250_out(struct ioport *ioport, struct kvm *kvm, u16 port,
+static bool serial8250_out(struct ioport *ioport, struct kvm_cpu *vcpu, u16 port,
void *data, int size)
{
struct serial8250_device *dev = ioport->priv;
@@ -251,7 +251,7 @@ static bool serial8250_out(struct ioport *ioport, struct kvm *kvm, u16 port,
dev->lsr &= ~UART_LSR_TEMT;
if (dev->txcnt == FIFO_LEN / 2)
dev->lsr &= ~UART_LSR_THRE;
- serial8250_flush_tx(kvm, dev);
+ serial8250_flush_tx(vcpu->kvm, dev);
} else {
/* Should never happpen */
dev->lsr &= ~(UART_LSR_TEMT | UART_LSR_THRE);
@@ -286,7 +286,7 @@ static bool serial8250_out(struct ioport *ioport, struct kvm *kvm, u16 port,
break;
}
- serial8250_update_irq(kvm, dev);
+ serial8250_update_irq(vcpu->kvm, dev);
mutex_unlock(&dev->mutex);
@@ -312,7 +312,7 @@ static void serial8250_rx(struct serial8250_device *dev, void *data)
}
}
-static bool serial8250_in(struct ioport *ioport, struct kvm *kvm, u16 port, void *data, int size)
+static bool serial8250_in(struct ioport *ioport, struct kvm_cpu *vcpu, u16 port, void *data, int size)
{
struct serial8250_device *dev = ioport->priv;
u16 offset;
@@ -358,7 +358,7 @@ static bool serial8250_in(struct ioport *ioport, struct kvm *kvm, u16 port, void
break;
}
- serial8250_update_irq(kvm, dev);
+ serial8250_update_irq(vcpu->kvm, dev);
mutex_unlock(&dev->mutex);
diff --git a/hw/vesa.c b/hw/vesa.c
index a0b15a77..a9a1d3e2 100644
--- a/hw/vesa.c
+++ b/hw/vesa.c
@@ -18,12 +18,12 @@
#include <inttypes.h>
#include <unistd.h>
-static bool vesa_pci_io_in(struct ioport *ioport, struct kvm *kvm, u16 port, void *data, int size)
+static bool vesa_pci_io_in(struct ioport *ioport, struct kvm_cpu *vcpu, u16 port, void *data, int size)
{
return true;
}
-static bool vesa_pci_io_out(struct ioport *ioport, struct kvm *kvm, u16 port, void *data, int size)
+static bool vesa_pci_io_out(struct ioport *ioport, struct kvm_cpu *vcpu, u16 port, void *data, int size)
{
return true;
}
diff --git a/include/kvm/ioport.h b/include/kvm/ioport.h
index f639c2e8..18da47ce 100644
--- a/include/kvm/ioport.h
+++ b/include/kvm/ioport.h
@@ -2,6 +2,7 @@
#define KVM__IOPORT_H
#include "kvm/devices.h"
+#include "kvm/kvm-cpu.h"
#include "kvm/rbtree-interval.h"
#include <stdbool.h>
@@ -27,8 +28,8 @@ struct ioport {
};
struct ioport_operations {
- bool (*io_in)(struct ioport *ioport, struct kvm *kvm, u16 port, void *data, int size);
- bool (*io_out)(struct ioport *ioport, struct kvm *kvm, u16 port, void *data, int size);
+ bool (*io_in)(struct ioport *ioport, struct kvm_cpu *vcpu, u16 port, void *data, int size);
+ bool (*io_out)(struct ioport *ioport, struct kvm_cpu *vcpu, u16 port, void *data, int size);
void (*generate_fdt_node)(struct ioport *ioport, void *fdt,
void (*generate_irq_prop)(void *fdt, u8 irq));
};
diff --git a/include/kvm/kvm.h b/include/kvm/kvm.h
index f1b71a02..058dd919 100644
--- a/include/kvm/kvm.h
+++ b/include/kvm/kvm.h
@@ -83,7 +83,7 @@ int kvm_timer__init(struct kvm *kvm);
int kvm_timer__exit(struct kvm *kvm);
void kvm__irq_line(struct kvm *kvm, int irq, int level);
void kvm__irq_trigger(struct kvm *kvm, int irq);
-bool kvm__emulate_io(struct kvm *kvm, u16 port, void *data, int direction, int size, u32 count);
+bool kvm__emulate_io(struct kvm_cpu *vcpu, u16 port, void *data, int direction, int size, u32 count);
bool kvm__emulate_mmio(struct kvm_cpu *vcpu, u64 phys_addr, u8 *data, u32 len, u8 is_write);
int kvm__register_mem(struct kvm *kvm, u64 guest_phys, u64 size, void *userspace_addr);
int kvm__register_mmio(struct kvm *kvm, u64 phys_addr, u64 phys_addr_len, bool coalesce,
diff --git a/ioport.c b/ioport.c
index be95e497..5bfb7e22 100644
--- a/ioport.c
+++ b/ioport.c
@@ -172,12 +172,13 @@ static void ioport_error(u16 port, void *data, int direction, int size, u32 coun
fprintf(stderr, "IO error: %s port=%x, size=%d, count=%u\n", to_direction(direction), port, size, count);
}
-bool kvm__emulate_io(struct kvm *kvm, u16 port, void *data, int direction, int size, u32 count)
+bool kvm__emulate_io(struct kvm_cpu *vcpu, u16 port, void *data, int direction, int size, u32 count)
{
struct ioport_operations *ops;
bool ret = false;
struct ioport *entry;
void *ptr = data;
+ struct kvm *kvm = vcpu->kvm;
br_read_lock();
entry = ioport_search(&ioport_tree, port);
@@ -188,9 +189,9 @@ bool kvm__emulate_io(struct kvm *kvm, u16 port, void *data, int direction, int s
while (count--) {
if (direction == KVM_EXIT_IO_IN && ops->io_in)
- ret = ops->io_in(entry, kvm, port, ptr, size);
+ ret = ops->io_in(entry, vcpu, port, ptr, size);
else if (ops->io_out)
- ret = ops->io_out(entry, kvm, port, ptr, size);
+ ret = ops->io_out(entry, vcpu, port, ptr, size);
ptr += size;
}
diff --git a/kvm-cpu.c b/kvm-cpu.c
index 9575b321..ee0a8ec5 100644
--- a/kvm-cpu.c
+++ b/kvm-cpu.c
@@ -123,7 +123,7 @@ int kvm_cpu__start(struct kvm_cpu *cpu)
case KVM_EXIT_IO: {
bool ret;
- ret = kvm_cpu__emulate_io(cpu->kvm,
+ ret = kvm_cpu__emulate_io(cpu,
cpu->kvm_run->io.port,
(u8 *)cpu->kvm_run +
cpu->kvm_run->io.data_offset,
diff --git a/pci.c b/pci.c
index 5d605854..fdff49c1 100644
--- a/pci.c
+++ b/pci.c
@@ -54,7 +54,7 @@ static void *pci_config_address_ptr(u16 port)
return base + offset;
}
-static bool pci_config_address_out(struct ioport *ioport, struct kvm *kvm, u16 port, void *data, int size)
+static bool pci_config_address_out(struct ioport *ioport, struct kvm_cpu *vcpu, u16 port, void *data, int size)
{
void *p = pci_config_address_ptr(port);
@@ -63,7 +63,7 @@ static bool pci_config_address_out(struct ioport *ioport, struct kvm *kvm, u16 p
return true;
}
-static bool pci_config_address_in(struct ioport *ioport, struct kvm *kvm, u16 port, void *data, int size)
+static bool pci_config_address_in(struct ioport *ioport, struct kvm_cpu *vcpu, u16 port, void *data, int size)
{
void *p = pci_config_address_ptr(port);
@@ -88,7 +88,7 @@ static bool pci_device_exists(u8 bus_number, u8 device_number, u8 function_numbe
return !IS_ERR_OR_NULL(device__find_dev(DEVICE_BUS_PCI, device_number));
}
-static bool pci_config_data_out(struct ioport *ioport, struct kvm *kvm, u16 port, void *data, int size)
+static bool pci_config_data_out(struct ioport *ioport, struct kvm_cpu *vcpu, u16 port, void *data, int size)
{
/*
* If someone accesses PCI configuration space offsets that are not
@@ -96,12 +96,12 @@ static bool pci_config_data_out(struct ioport *ioport, struct kvm *kvm, u16 port
*/
pci_config_address.reg_offset = port - PCI_CONFIG_DATA;
- pci__config_wr(kvm, pci_config_address, data, size);
+ pci__config_wr(vcpu->kvm, pci_config_address, data, size);
return true;
}
-static bool pci_config_data_in(struct ioport *ioport, struct kvm *kvm, u16 port, void *data, int size)
+static bool pci_config_data_in(struct ioport *ioport, struct kvm_cpu *vcpu, u16 port, void *data, int size)
{
/*
* If someone accesses PCI configuration space offsets that are not
@@ -109,7 +109,7 @@ static bool pci_config_data_in(struct ioport *ioport, struct kvm *kvm, u16 port,
*/
pci_config_address.reg_offset = port - PCI_CONFIG_DATA;
- pci__config_rd(kvm, pci_config_address, data, size);
+ pci__config_rd(vcpu->kvm, pci_config_address, data, size);
return true;
}
diff --git a/powerpc/include/kvm/kvm-cpu-arch.h b/powerpc/include/kvm/kvm-cpu-arch.h
index 82cb5987..e256f5d0 100644
--- a/powerpc/include/kvm/kvm-cpu-arch.h
+++ b/powerpc/include/kvm/kvm-cpu-arch.h
@@ -66,7 +66,7 @@ struct kvm_cpu {
void kvm_cpu__irq(struct kvm_cpu *vcpu, int pin, int level);
/* This is never actually called on PPC. */
-static inline bool kvm_cpu__emulate_io(struct kvm *kvm, u16 port, void *data, int direction, int size, u32 count)
+static inline bool kvm_cpu__emulate_io(struct kvm_cpu *vcpu, u16 port, void *data, int direction, int size, u32 count)
{
return false;
}
diff --git a/powerpc/spapr_pci.h b/powerpc/spapr_pci.h
index f9cb42ff..f659edaf 100644
--- a/powerpc/spapr_pci.h
+++ b/powerpc/spapr_pci.h
@@ -41,7 +41,7 @@ static inline bool spapr_phb_mmio(struct kvm_cpu *vcpu, u64 phys_addr, u8 *data,
if ((phys_addr >= SPAPR_PCI_IO_WIN_ADDR) &&
(phys_addr < SPAPR_PCI_IO_WIN_ADDR +
SPAPR_PCI_IO_WIN_SIZE)) {
- return kvm__emulate_io(vcpu->kvm, phys_addr - SPAPR_PCI_IO_WIN_ADDR,
+ return kvm__emulate_io(vcpu, phys_addr - SPAPR_PCI_IO_WIN_ADDR,
data, is_write ? KVM_EXIT_IO_OUT :
KVM_EXIT_IO_IN,
len, 1);
diff --git a/virtio/pci.c b/virtio/pci.c
index 57ccde64..c14c7fb8 100644
--- a/virtio/pci.c
+++ b/virtio/pci.c
@@ -2,6 +2,7 @@
#include "kvm/ioport.h"
#include "kvm/kvm.h"
+#include "kvm/kvm-cpu.h"
#include "kvm/virtio-pci-dev.h"
#include "kvm/irq.h"
#include "kvm/virtio.h"
@@ -108,14 +109,16 @@ static bool virtio_pci__specific_io_in(struct kvm *kvm, struct virtio_device *vd
return false;
}
-static bool virtio_pci__io_in(struct ioport *ioport, struct kvm *kvm, u16 port, void *data, int size)
+static bool virtio_pci__io_in(struct ioport *ioport, struct kvm_cpu *vcpu, u16 port, void *data, int size)
{
unsigned long offset;
bool ret = true;
struct virtio_device *vdev;
struct virtio_pci *vpci;
+ struct kvm *kvm;
u32 val;
+ kvm = vcpu->kvm;
vdev = ioport->priv;
vpci = vdev->virtio;
offset = port - vpci->port_addr;
@@ -191,14 +194,16 @@ static bool virtio_pci__specific_io_out(struct kvm *kvm, struct virtio_device *v
return false;
}
-static bool virtio_pci__io_out(struct ioport *ioport, struct kvm *kvm, u16 port, void *data, int size)
+static bool virtio_pci__io_out(struct ioport *ioport, struct kvm_cpu *vcpu, u16 port, void *data, int size)
{
unsigned long offset;
bool ret = true;
struct virtio_device *vdev;
struct virtio_pci *vpci;
+ struct kvm *kvm;
u32 val;
+ kvm = vcpu->kvm;
vdev = ioport->priv;
vpci = vdev->virtio;
offset = port - vpci->port_addr;
@@ -224,6 +229,8 @@ static bool virtio_pci__io_out(struct ioport *ioport, struct kvm *kvm, u16 port,
break;
case VIRTIO_PCI_STATUS:
vpci->status = ioport__read8(data);
+ if (!vpci->status) /* Sample endianness on reset */
+ vdev->endian = kvm_cpu__get_endianness(vcpu);
if (vdev->ops->notify_status)
vdev->ops->notify_status(kvm, vpci->dev, vpci->status);
break;
@@ -330,7 +337,7 @@ static void virtio_pci__io_mmio_callback(struct kvm_cpu *vcpu,
int direction = is_write ? KVM_EXIT_IO_OUT : KVM_EXIT_IO_IN;
u16 port = vpci->port_addr + (addr & (IOPORT_SIZE - 1));
- kvm__emulate_io(vpci->kvm, port, data, direction, len, 1);
+ kvm__emulate_io(vcpu, port, data, direction, len, 1);
}
int virtio_pci__init(struct kvm *kvm, void *dev, struct virtio_device *vdev,
diff --git a/x86/include/kvm/kvm-cpu-arch.h b/x86/include/kvm/kvm-cpu-arch.h
index fd86b4d0..89c80595 100644
--- a/x86/include/kvm/kvm-cpu-arch.h
+++ b/x86/include/kvm/kvm-cpu-arch.h
@@ -36,9 +36,9 @@ struct kvm_cpu {
* As these are such simple wrappers, let's have them in the header so they'll
* be cheaper to call:
*/
-static inline bool kvm_cpu__emulate_io(struct kvm *kvm, u16 port, void *data, int direction, int size, u32 count)
+static inline bool kvm_cpu__emulate_io(struct kvm_cpu *vcpu, u16 port, void *data, int direction, int size, u32 count)
{
- return kvm__emulate_io(kvm, port, data, direction, size, count);
+ return kvm__emulate_io(vcpu, port, data, direction, size, count);
}
static inline bool kvm_cpu__emulate_mmio(struct kvm_cpu *vcpu, u64 phys_addr, u8 *data, u32 len, u8 is_write)
diff --git a/x86/ioport.c b/x86/ioport.c
index 11a15923..8572c758 100644
--- a/x86/ioport.c
+++ b/x86/ioport.c
@@ -3,7 +3,7 @@
#include <stdlib.h>
#include <stdio.h>
-static bool debug_io_out(struct ioport *ioport, struct kvm *kvm, u16 port, void *data, int size)
+static bool debug_io_out(struct ioport *ioport, struct kvm_cpu *vcpu, u16 port, void *data, int size)
{
return 0;
}
@@ -12,7 +12,7 @@ static struct ioport_operations debug_ops = {
.io_out = debug_io_out,
};
-static bool seabios_debug_io_out(struct ioport *ioport, struct kvm *kvm, u16 port, void *data, int size)
+static bool seabios_debug_io_out(struct ioport *ioport, struct kvm_cpu *vcpu, u16 port, void *data, int size)
{
char ch;
@@ -27,12 +27,12 @@ static struct ioport_operations seabios_debug_ops = {
.io_out = seabios_debug_io_out,
};
-static bool dummy_io_in(struct ioport *ioport, struct kvm *kvm, u16 port, void *data, int size)
+static bool dummy_io_in(struct ioport *ioport, struct kvm_cpu *vcpu, u16 port, void *data, int size)
{
return true;
}
-static bool dummy_io_out(struct ioport *ioport, struct kvm *kvm, u16 port, void *data, int size)
+static bool dummy_io_out(struct ioport *ioport, struct kvm_cpu *vcpu, u16 port, void *data, int size)
{
return true;
}
@@ -50,7 +50,7 @@ static struct ioport_operations dummy_write_only_ioport_ops = {
* The "fast A20 gate"
*/
-static bool ps2_control_a_io_in(struct ioport *ioport, struct kvm *kvm, u16 port, void *data, int size)
+static bool ps2_control_a_io_in(struct ioport *ioport, struct kvm_cpu *vcpu, u16 port, void *data, int size)
{
/*
* A20 is always enabled.