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@xxxxxxx> Signed-off-by: Marc Zyngier <marc.zyngier@xxxxxxx> --- tools/kvm/arm/include/arm-common/kvm-cpu-arch.h | 2 +- tools/kvm/arm/kvm-cpu.c | 2 +- tools/kvm/hw/i8042.c | 6 +++--- tools/kvm/hw/pci-shmem.c | 4 ++-- tools/kvm/hw/rtc.c | 8 ++++---- tools/kvm/hw/serial.c | 10 +++++----- tools/kvm/hw/vesa.c | 4 ++-- tools/kvm/include/kvm/ioport.h | 5 +++-- tools/kvm/include/kvm/kvm.h | 2 +- tools/kvm/ioport.c | 7 ++++--- tools/kvm/kvm-cpu.c | 2 +- tools/kvm/pci.c | 12 ++++++------ tools/kvm/powerpc/include/kvm/kvm-cpu-arch.h | 2 +- tools/kvm/powerpc/spapr_pci.h | 2 +- tools/kvm/virtio/pci.c | 13 ++++++++++--- tools/kvm/x86/include/kvm/kvm-cpu-arch.h | 4 ++-- tools/kvm/x86/ioport.c | 10 +++++----- 17 files changed, 52 insertions(+), 43 deletions(-) diff --git a/tools/kvm/arm/include/arm-common/kvm-cpu-arch.h b/tools/kvm/arm/include/arm-common/kvm-cpu-arch.h index 355a02d..83cd8b8 100644 --- a/tools/kvm/arm/include/arm-common/kvm-cpu-arch.h +++ b/tools/kvm/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/tools/kvm/arm/kvm-cpu.c b/tools/kvm/arm/kvm-cpu.c index 53afa35..aeaa4cf 100644 --- a/tools/kvm/arm/kvm-cpu.c +++ b/tools/kvm/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/tools/kvm/hw/i8042.c b/tools/kvm/hw/i8042.c index 4a12ee7..3801e20 100644 --- a/tools/kvm/hw/i8042.c +++ b/tools/kvm/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/tools/kvm/hw/pci-shmem.c b/tools/kvm/hw/pci-shmem.c index 4b837eb..457e960 100644 --- a/tools/kvm/hw/pci-shmem.c +++ b/tools/kvm/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/tools/kvm/hw/rtc.c b/tools/kvm/hw/rtc.c index 5232bd7..0649b5d 100644 --- a/tools/kvm/hw/rtc.c +++ b/tools/kvm/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/tools/kvm/hw/serial.c b/tools/kvm/hw/serial.c index 3b5540c..60147de 100644 --- a/tools/kvm/hw/serial.c +++ b/tools/kvm/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/tools/kvm/hw/vesa.c b/tools/kvm/hw/vesa.c index a0b15a7..a9a1d3e 100644 --- a/tools/kvm/hw/vesa.c +++ b/tools/kvm/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/tools/kvm/include/kvm/ioport.h b/tools/kvm/include/kvm/ioport.h index f639c2e..18da47c 100644 --- a/tools/kvm/include/kvm/ioport.h +++ b/tools/kvm/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/tools/kvm/include/kvm/kvm.h b/tools/kvm/include/kvm/kvm.h index f1b71a0..058dd91 100644 --- a/tools/kvm/include/kvm/kvm.h +++ b/tools/kvm/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/tools/kvm/ioport.c b/tools/kvm/ioport.c index be95e49..5bfb7e2 100644 --- a/tools/kvm/ioport.c +++ b/tools/kvm/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/tools/kvm/kvm-cpu.c b/tools/kvm/kvm-cpu.c index 9575b32..ee0a8ec 100644 --- a/tools/kvm/kvm-cpu.c +++ b/tools/kvm/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/tools/kvm/pci.c b/tools/kvm/pci.c index e3e07c1..71a7134 100644 --- a/tools/kvm/pci.c +++ b/tools/kvm/pci.c @@ -52,7 +52,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); @@ -61,7 +61,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); @@ -86,7 +86,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 @@ -94,12 +94,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 @@ -107,7 +107,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/tools/kvm/powerpc/include/kvm/kvm-cpu-arch.h b/tools/kvm/powerpc/include/kvm/kvm-cpu-arch.h index 82cb5987..e256f5d 100644 --- a/tools/kvm/powerpc/include/kvm/kvm-cpu-arch.h +++ b/tools/kvm/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/tools/kvm/powerpc/spapr_pci.h b/tools/kvm/powerpc/spapr_pci.h index f9cb42f..f659eda 100644 --- a/tools/kvm/powerpc/spapr_pci.h +++ b/tools/kvm/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/tools/kvm/virtio/pci.c b/tools/kvm/virtio/pci.c index 57ccde6..c14c7fb 100644 --- a/tools/kvm/virtio/pci.c +++ b/tools/kvm/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/tools/kvm/x86/include/kvm/kvm-cpu-arch.h b/tools/kvm/x86/include/kvm/kvm-cpu-arch.h index fd86b4d..89c8059 100644 --- a/tools/kvm/x86/include/kvm/kvm-cpu-arch.h +++ b/tools/kvm/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/tools/kvm/x86/ioport.c b/tools/kvm/x86/ioport.c index 11a1592..8572c758 100644 --- a/tools/kvm/x86/ioport.c +++ b/tools/kvm/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. -- 1.8.3.4 -- To unsubscribe from this list: send the line "unsubscribe kvm" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html