Commit 4123ca55 authored by Marc Zyngier's avatar Marc Zyngier Committed by Will Deacon
Browse files

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: default avatarWill Deacon <will.deacon@arm.com>
Signed-off-by: default avatarMarc Zyngier <marc.zyngier@arm.com>
Signed-off-by: default avatarPekka Enberg <penberg@kernel.org>
parent fc9d8ec3
......@@ -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;
......
......@@ -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);
}
......
......@@ -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: {
......
......@@ -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;
......
......@@ -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;
......
......@@ -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);
......
......@@ -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;
}
......
......@@ -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));
};
......
......@@ -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,
......
......@@ -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;
}
......
......@@ -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,
......
......@@ -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;
}
......
......@@ -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;
}
......
......@@ -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);
......
......@@ -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,
......
......@@ -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)
......
......@@ -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.
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment