@@ -74,6 +74,7 @@ OBJS += virtio/rng.o
OBJS += virtio/balloon.o
OBJS += virtio/pci.o
OBJS += virtio/vsock.o
+OBJS += virtio/pci-legacy.o
OBJS += disk/blk.o
OBJS += disk/qcow.o
OBJS += disk/raw.o
@@ -4,12 +4,15 @@
#include "kvm/devices.h"
#include "kvm/pci.h"
+#include <stdbool.h>
+#include <linux/byteorder.h>
#include <linux/types.h>
#define VIRTIO_PCI_MAX_VQ 32
#define VIRTIO_PCI_MAX_CONFIG 1
struct kvm;
+struct kvm_cpu;
struct virtio_pci_ioevent_param {
struct virtio_device *vdev;
@@ -18,6 +21,13 @@ struct virtio_pci_ioevent_param {
#define VIRTIO_PCI_F_SIGNAL_MSI (1 << 0)
+#define ALIGN_UP(x, s) ALIGN((x) + (s) - 1, (s))
+#define VIRTIO_NR_MSIX (VIRTIO_PCI_MAX_VQ + VIRTIO_PCI_MAX_CONFIG)
+#define VIRTIO_MSIX_TABLE_SIZE (VIRTIO_NR_MSIX * 16)
+#define VIRTIO_MSIX_PBA_SIZE (ALIGN_UP(VIRTIO_MSIX_TABLE_SIZE, 64) / 8)
+#define VIRTIO_MSIX_BAR_SIZE (1UL << fls_long(VIRTIO_MSIX_TABLE_SIZE + \
+ VIRTIO_MSIX_PBA_SIZE))
+
struct virtio_pci {
struct pci_device_header pci_hdr;
struct device_header dev_hdr;
@@ -57,4 +67,33 @@ int virtio_pci__reset(struct kvm *kvm, struct virtio_device *vdev);
int virtio_pci__init(struct kvm *kvm, void *dev, struct virtio_device *vdev,
int device_id, int subsys_id, int class);
+static inline bool virtio_pci__msix_enabled(struct virtio_pci *vpci)
+{
+ return vpci->pci_hdr.msix.ctrl & cpu_to_le16(PCI_MSIX_FLAGS_ENABLE);
+}
+
+static inline u16 virtio_pci__port_addr(struct virtio_pci *vpci)
+{
+ return pci__bar_address(&vpci->pci_hdr, 0);
+}
+
+static inline u32 virtio_pci__mmio_addr(struct virtio_pci *vpci)
+{
+ return pci__bar_address(&vpci->pci_hdr, 1);
+}
+
+static inline u32 virtio_pci__msix_io_addr(struct virtio_pci *vpci)
+{
+ return pci__bar_address(&vpci->pci_hdr, 2);
+}
+
+int virtio_pci__add_msix_route(struct virtio_pci *vpci, u32 vec);
+int virtio_pci__init_ioeventfd(struct kvm *kvm, struct virtio_device *vdev,
+ u32 vq);
+int virtio_pci_init_vq(struct kvm *kvm, struct virtio_device *vdev, int vq);
+void virtio_pci_exit_vq(struct kvm *kvm, struct virtio_device *vdev, int vq);
+
+void virtio_pci_legacy__io_mmio_callback(struct kvm_cpu *vcpu, u64 addr, u8 *data,
+ u32 len, u8 is_write, void *ptr);
+
#endif
new file mode 100644
@@ -0,0 +1,205 @@
+#include "kvm/virtio-pci.h"
+
+#include "kvm/ioport.h"
+#include "kvm/virtio.h"
+
+static bool virtio_pci__specific_data_in(struct kvm *kvm, struct virtio_device *vdev,
+ void *data, u32 size, unsigned long offset)
+{
+ u32 config_offset;
+ struct virtio_pci *vpci = vdev->virtio;
+ int type = virtio__get_dev_specific_field(offset - 20,
+ virtio_pci__msix_enabled(vpci),
+ &config_offset);
+ if (type == VIRTIO_PCI_O_MSIX) {
+ switch (offset) {
+ case VIRTIO_MSI_CONFIG_VECTOR:
+ ioport__write16(data, vpci->config_vector);
+ break;
+ case VIRTIO_MSI_QUEUE_VECTOR:
+ ioport__write16(data, vpci->vq_vector[vpci->queue_selector]);
+ break;
+ };
+
+ return true;
+ } else if (type == VIRTIO_PCI_O_CONFIG) {
+ return virtio_access_config(kvm, vdev, vpci->dev, config_offset,
+ data, size, false);
+ }
+
+ return false;
+}
+
+static bool virtio_pci__data_in(struct kvm_cpu *vcpu, struct virtio_device *vdev,
+ unsigned long offset, void *data, u32 size)
+{
+ bool ret = true;
+ struct virtio_pci *vpci;
+ struct virt_queue *vq;
+ struct kvm *kvm;
+ u32 val;
+
+ kvm = vcpu->kvm;
+ vpci = vdev->virtio;
+
+ switch (offset) {
+ case VIRTIO_PCI_HOST_FEATURES:
+ val = vdev->ops->get_host_features(kvm, vpci->dev);
+ ioport__write32(data, val);
+ break;
+ case VIRTIO_PCI_QUEUE_PFN:
+ vq = vdev->ops->get_vq(kvm, vpci->dev, vpci->queue_selector);
+ ioport__write32(data, vq->vring_addr.pfn);
+ break;
+ case VIRTIO_PCI_QUEUE_NUM:
+ val = vdev->ops->get_size_vq(kvm, vpci->dev, vpci->queue_selector);
+ ioport__write16(data, val);
+ break;
+ case VIRTIO_PCI_STATUS:
+ ioport__write8(data, vpci->status);
+ break;
+ case VIRTIO_PCI_ISR:
+ ioport__write8(data, vpci->isr);
+ kvm__irq_line(kvm, vpci->legacy_irq_line, VIRTIO_IRQ_LOW);
+ vpci->isr = VIRTIO_IRQ_LOW;
+ break;
+ default:
+ ret = virtio_pci__specific_data_in(kvm, vdev, data, size, offset);
+ break;
+ };
+
+ return ret;
+}
+
+static bool virtio_pci__specific_data_out(struct kvm *kvm, struct virtio_device *vdev,
+ void *data, u32 size, unsigned long offset)
+{
+ struct virtio_pci *vpci = vdev->virtio;
+ u32 config_offset, vec;
+ int gsi;
+ int type = virtio__get_dev_specific_field(offset - 20, virtio_pci__msix_enabled(vpci),
+ &config_offset);
+ if (type == VIRTIO_PCI_O_MSIX) {
+ switch (offset) {
+ case VIRTIO_MSI_CONFIG_VECTOR:
+ vec = vpci->config_vector = ioport__read16(data);
+
+ gsi = virtio_pci__add_msix_route(vpci, vec);
+ if (gsi < 0)
+ break;
+
+ vpci->config_gsi = gsi;
+ break;
+ case VIRTIO_MSI_QUEUE_VECTOR:
+ vec = ioport__read16(data);
+ vpci->vq_vector[vpci->queue_selector] = vec;
+
+ gsi = virtio_pci__add_msix_route(vpci, vec);
+ if (gsi < 0)
+ break;
+
+ vpci->gsis[vpci->queue_selector] = gsi;
+ if (vdev->ops->notify_vq_gsi)
+ vdev->ops->notify_vq_gsi(kvm, vpci->dev,
+ vpci->queue_selector,
+ gsi);
+ break;
+ };
+
+ return true;
+ } else if (type == VIRTIO_PCI_O_CONFIG) {
+ return virtio_access_config(kvm, vdev, vpci->dev, config_offset,
+ data, size, true);
+ }
+
+ return false;
+}
+
+static bool virtio_pci__data_out(struct kvm_cpu *vcpu, struct virtio_device *vdev,
+ unsigned long offset, void *data, u32 size)
+{
+ bool ret = true;
+ struct virtio_pci *vpci;
+ struct virt_queue *vq;
+ struct kvm *kvm;
+ u32 val;
+ unsigned int vq_count;
+
+ kvm = vcpu->kvm;
+ vpci = vdev->virtio;
+ vq_count = vdev->ops->get_vq_count(kvm, vpci->dev);
+
+ switch (offset) {
+ case VIRTIO_PCI_GUEST_FEATURES:
+ val = ioport__read32(data);
+ virtio_set_guest_features(kvm, vdev, vpci->dev, val);
+ break;
+ case VIRTIO_PCI_QUEUE_PFN:
+ val = ioport__read32(data);
+ if (val) {
+ vq = vdev->ops->get_vq(kvm, vpci->dev,
+ vpci->queue_selector);
+ vq->vring_addr = (struct vring_addr) {
+ .legacy = true,
+ .pfn = val,
+ .align = VIRTIO_PCI_VRING_ALIGN,
+ .pgsize = 1 << VIRTIO_PCI_QUEUE_ADDR_SHIFT,
+ };
+ virtio_pci_init_vq(kvm, vdev, vpci->queue_selector);
+ } else {
+ virtio_pci_exit_vq(kvm, vdev, vpci->queue_selector);
+ }
+ break;
+ case VIRTIO_PCI_QUEUE_SEL:
+ val = ioport__read16(data);
+ if (val >= vq_count) {
+ WARN_ONCE(1, "QUEUE_SEL value (%u) is larger than VQ count (%u)\n",
+ val, vq_count);
+ return false;
+ }
+ vpci->queue_selector = val;
+ break;
+ case VIRTIO_PCI_QUEUE_NOTIFY:
+ val = ioport__read16(data);
+ if (val >= vq_count) {
+ WARN_ONCE(1, "QUEUE_SEL value (%u) is larger than VQ count (%u)\n",
+ val, vq_count);
+ return false;
+ }
+ vdev->ops->notify_vq(kvm, vpci->dev, val);
+ break;
+ case VIRTIO_PCI_STATUS:
+ vpci->status = ioport__read8(data);
+ if (!vpci->status) /* Sample endianness on reset */
+ vdev->endian = kvm_cpu__get_endianness(vcpu);
+ virtio_notify_status(kvm, vdev, vpci->dev, vpci->status);
+ break;
+ default:
+ ret = virtio_pci__specific_data_out(kvm, vdev, data, size, offset);
+ break;
+ };
+
+ return ret;
+}
+
+void virtio_pci_legacy__io_mmio_callback(struct kvm_cpu *vcpu, u64 addr,
+ u8 *data, u32 len, u8 is_write,
+ void *ptr)
+{
+ struct virtio_device *vdev = ptr;
+ struct virtio_pci *vpci = vdev->virtio;
+ u32 ioport_addr = virtio_pci__port_addr(vpci);
+ u32 base_addr;
+
+ if (addr >= ioport_addr &&
+ addr < ioport_addr + pci__bar_size(&vpci->pci_hdr, 0))
+ base_addr = ioport_addr;
+ else
+ base_addr = virtio_pci__mmio_addr(vpci);
+
+ if (!is_write)
+ virtio_pci__data_in(vcpu, vdev, addr - base_addr, data, len);
+ else
+ virtio_pci__data_out(vcpu, vdev, addr - base_addr, data, len);
+}
+
@@ -11,33 +11,10 @@
#include <sys/ioctl.h>
#include <linux/virtio_pci.h>
-#include <linux/byteorder.h>
#include <assert.h>
#include <string.h>
-#define ALIGN_UP(x, s) ALIGN((x) + (s) - 1, (s))
-#define VIRTIO_NR_MSIX (VIRTIO_PCI_MAX_VQ + VIRTIO_PCI_MAX_CONFIG)
-#define VIRTIO_MSIX_TABLE_SIZE (VIRTIO_NR_MSIX * 16)
-#define VIRTIO_MSIX_PBA_SIZE (ALIGN_UP(VIRTIO_MSIX_TABLE_SIZE, 64) / 8)
-#define VIRTIO_MSIX_BAR_SIZE (1UL << fls_long(VIRTIO_MSIX_TABLE_SIZE + \
- VIRTIO_MSIX_PBA_SIZE))
-
-static u16 virtio_pci__port_addr(struct virtio_pci *vpci)
-{
- return pci__bar_address(&vpci->pci_hdr, 0);
-}
-
-static u32 virtio_pci__mmio_addr(struct virtio_pci *vpci)
-{
- return pci__bar_address(&vpci->pci_hdr, 1);
-}
-
-static u32 virtio_pci__msix_io_addr(struct virtio_pci *vpci)
-{
- return pci__bar_address(&vpci->pci_hdr, 2);
-}
-
-static int virtio_pci__add_msix_route(struct virtio_pci *vpci, u32 vec)
+int virtio_pci__add_msix_route(struct virtio_pci *vpci, u32 vec)
{
int gsi;
struct msi_msg *msg;
@@ -75,7 +52,8 @@ static void virtio_pci__ioevent_callback(struct kvm *kvm, void *param)
ioeventfd->vdev->ops->notify_vq(kvm, vpci->dev, ioeventfd->vq);
}
-static int virtio_pci__init_ioeventfd(struct kvm *kvm, struct virtio_device *vdev, u32 vq)
+int virtio_pci__init_ioeventfd(struct kvm *kvm, struct virtio_device *vdev,
+ u32 vq)
{
struct ioevent ioevent;
struct virtio_pci *vpci = vdev->virtio;
@@ -129,8 +107,7 @@ free_ioport_evt:
return r;
}
-static int virtio_pci_init_vq(struct kvm *kvm, struct virtio_device *vdev,
- int vq)
+int virtio_pci_init_vq(struct kvm *kvm, struct virtio_device *vdev, int vq)
{
int ret;
struct virtio_pci *vpci = vdev->virtio;
@@ -143,8 +120,7 @@ static int virtio_pci_init_vq(struct kvm *kvm, struct virtio_device *vdev,
return vdev->ops->init_vq(kvm, vpci->dev, vq);
}
-static void virtio_pci_exit_vq(struct kvm *kvm, struct virtio_device *vdev,
- int vq)
+void virtio_pci_exit_vq(struct kvm *kvm, struct virtio_device *vdev, int vq)
{
struct virtio_pci *vpci = vdev->virtio;
u32 mmio_addr = virtio_pci__mmio_addr(vpci);
@@ -159,79 +135,6 @@ static void virtio_pci_exit_vq(struct kvm *kvm, struct virtio_device *vdev,
virtio_exit_vq(kvm, vdev, vpci->dev, vq);
}
-static inline bool virtio_pci__msix_enabled(struct virtio_pci *vpci)
-{
- return vpci->pci_hdr.msix.ctrl & cpu_to_le16(PCI_MSIX_FLAGS_ENABLE);
-}
-
-static bool virtio_pci__specific_data_in(struct kvm *kvm, struct virtio_device *vdev,
- void *data, u32 size, unsigned long offset)
-{
- u32 config_offset;
- struct virtio_pci *vpci = vdev->virtio;
- int type = virtio__get_dev_specific_field(offset - 20,
- virtio_pci__msix_enabled(vpci),
- &config_offset);
- if (type == VIRTIO_PCI_O_MSIX) {
- switch (offset) {
- case VIRTIO_MSI_CONFIG_VECTOR:
- ioport__write16(data, vpci->config_vector);
- break;
- case VIRTIO_MSI_QUEUE_VECTOR:
- ioport__write16(data, vpci->vq_vector[vpci->queue_selector]);
- break;
- };
-
- return true;
- } else if (type == VIRTIO_PCI_O_CONFIG) {
- return virtio_access_config(kvm, vdev, vpci->dev, config_offset,
- data, size, false);
- }
-
- return false;
-}
-
-static bool virtio_pci__data_in(struct kvm_cpu *vcpu, struct virtio_device *vdev,
- unsigned long offset, void *data, u32 size)
-{
- bool ret = true;
- struct virtio_pci *vpci;
- struct virt_queue *vq;
- struct kvm *kvm;
- u32 val;
-
- kvm = vcpu->kvm;
- vpci = vdev->virtio;
-
- switch (offset) {
- case VIRTIO_PCI_HOST_FEATURES:
- val = vdev->ops->get_host_features(kvm, vpci->dev);
- ioport__write32(data, val);
- break;
- case VIRTIO_PCI_QUEUE_PFN:
- vq = vdev->ops->get_vq(kvm, vpci->dev, vpci->queue_selector);
- ioport__write32(data, vq->vring_addr.pfn);
- break;
- case VIRTIO_PCI_QUEUE_NUM:
- val = vdev->ops->get_size_vq(kvm, vpci->dev, vpci->queue_selector);
- ioport__write16(data, val);
- break;
- case VIRTIO_PCI_STATUS:
- ioport__write8(data, vpci->status);
- break;
- case VIRTIO_PCI_ISR:
- ioport__write8(data, vpci->isr);
- kvm__irq_line(kvm, vpci->legacy_irq_line, VIRTIO_IRQ_LOW);
- vpci->isr = VIRTIO_IRQ_LOW;
- break;
- default:
- ret = virtio_pci__specific_data_in(kvm, vdev, data, size, offset);
- break;
- };
-
- return ret;
-}
-
static void update_msix_map(struct virtio_pci *vpci,
struct msix_table *msix_entry, u32 vecnum)
{
@@ -256,117 +159,6 @@ static void update_msix_map(struct virtio_pci *vpci,
irq__update_msix_route(vpci->kvm, gsi, &msix_entry->msg);
}
-static bool virtio_pci__specific_data_out(struct kvm *kvm, struct virtio_device *vdev,
- void *data, u32 size, unsigned long offset)
-{
- struct virtio_pci *vpci = vdev->virtio;
- u32 config_offset, vec;
- int gsi;
- int type = virtio__get_dev_specific_field(offset - 20, virtio_pci__msix_enabled(vpci),
- &config_offset);
- if (type == VIRTIO_PCI_O_MSIX) {
- switch (offset) {
- case VIRTIO_MSI_CONFIG_VECTOR:
- vec = vpci->config_vector = ioport__read16(data);
-
- gsi = virtio_pci__add_msix_route(vpci, vec);
- if (gsi < 0)
- break;
-
- vpci->config_gsi = gsi;
- break;
- case VIRTIO_MSI_QUEUE_VECTOR:
- vec = ioport__read16(data);
- vpci->vq_vector[vpci->queue_selector] = vec;
-
- gsi = virtio_pci__add_msix_route(vpci, vec);
- if (gsi < 0)
- break;
-
- vpci->gsis[vpci->queue_selector] = gsi;
- if (vdev->ops->notify_vq_gsi)
- vdev->ops->notify_vq_gsi(kvm, vpci->dev,
- vpci->queue_selector,
- gsi);
- break;
- };
-
- return true;
- } else if (type == VIRTIO_PCI_O_CONFIG) {
- return virtio_access_config(kvm, vdev, vpci->dev, config_offset,
- data, size, true);
- }
-
- return false;
-}
-
-static bool virtio_pci__data_out(struct kvm_cpu *vcpu, struct virtio_device *vdev,
- unsigned long offset, void *data, u32 size)
-{
- bool ret = true;
- struct virtio_pci *vpci;
- struct virt_queue *vq;
- struct kvm *kvm;
- u32 val;
- unsigned int vq_count;
-
- kvm = vcpu->kvm;
- vpci = vdev->virtio;
- vq_count = vdev->ops->get_vq_count(kvm, vpci->dev);
-
- switch (offset) {
- case VIRTIO_PCI_GUEST_FEATURES:
- val = ioport__read32(data);
- virtio_set_guest_features(kvm, vdev, vpci->dev, val);
- break;
- case VIRTIO_PCI_QUEUE_PFN:
- val = ioport__read32(data);
- if (val) {
- vq = vdev->ops->get_vq(kvm, vpci->dev,
- vpci->queue_selector);
- vq->vring_addr = (struct vring_addr) {
- .legacy = true,
- .pfn = val,
- .align = VIRTIO_PCI_VRING_ALIGN,
- .pgsize = 1 << VIRTIO_PCI_QUEUE_ADDR_SHIFT,
- };
- virtio_pci_init_vq(kvm, vdev, vpci->queue_selector);
- } else {
- virtio_pci_exit_vq(kvm, vdev, vpci->queue_selector);
- }
- break;
- case VIRTIO_PCI_QUEUE_SEL:
- val = ioport__read16(data);
- if (val >= vq_count) {
- WARN_ONCE(1, "QUEUE_SEL value (%u) is larger than VQ count (%u)\n",
- val, vq_count);
- return false;
- }
- vpci->queue_selector = val;
- break;
- case VIRTIO_PCI_QUEUE_NOTIFY:
- val = ioport__read16(data);
- if (val >= vq_count) {
- WARN_ONCE(1, "QUEUE_SEL value (%u) is larger than VQ count (%u)\n",
- val, vq_count);
- return false;
- }
- vdev->ops->notify_vq(kvm, vpci->dev, val);
- break;
- case VIRTIO_PCI_STATUS:
- vpci->status = ioport__read8(data);
- if (!vpci->status) /* Sample endianness on reset */
- vdev->endian = kvm_cpu__get_endianness(vcpu);
- virtio_notify_status(kvm, vdev, vpci->dev, vpci->status);
- break;
- default:
- ret = virtio_pci__specific_data_out(kvm, vdev, data, size, offset);
- break;
- };
-
- return ret;
-}
-
static void virtio_pci__msix_mmio_callback(struct kvm_cpu *vcpu,
u64 addr, u8 *data, u32 len,
u8 is_write, void *ptr)
@@ -477,27 +269,6 @@ int virtio_pci__signal_config(struct kvm *kvm, struct virtio_device *vdev)
return 0;
}
-static void virtio_pci__io_mmio_callback(struct kvm_cpu *vcpu,
- u64 addr, u8 *data, u32 len,
- u8 is_write, void *ptr)
-{
- struct virtio_device *vdev = ptr;
- struct virtio_pci *vpci = vdev->virtio;
- u32 ioport_addr = virtio_pci__port_addr(vpci);
- u32 base_addr;
-
- if (addr >= ioport_addr &&
- addr < ioport_addr + pci__bar_size(&vpci->pci_hdr, 0))
- base_addr = ioport_addr;
- else
- base_addr = virtio_pci__mmio_addr(vpci);
-
- if (!is_write)
- virtio_pci__data_in(vcpu, vdev, addr - base_addr, data, len);
- else
- virtio_pci__data_out(vcpu, vdev, addr - base_addr, data, len);
-}
-
static int virtio_pci__bar_activate(struct kvm *kvm,
struct pci_device_header *pci_hdr,
int bar_num, void *data)
@@ -514,11 +285,13 @@ static int virtio_pci__bar_activate(struct kvm *kvm,
switch (bar_num) {
case 0:
r = kvm__register_pio(kvm, bar_addr, bar_size,
- virtio_pci__io_mmio_callback, vdev);
+ virtio_pci_legacy__io_mmio_callback,
+ vdev);
break;
case 1:
r = kvm__register_mmio(kvm, bar_addr, bar_size, false,
- virtio_pci__io_mmio_callback, vdev);
+ virtio_pci_legacy__io_mmio_callback,
+ vdev);
break;
case 2:
r = kvm__register_mmio(kvm, bar_addr, bar_size, false,
To make space for the more recent virtio version, move the legacy bits of virtio-pci to a different file. Signed-off-by: Jean-Philippe Brucker <jean-philippe.brucker@arm.com> --- Makefile | 1 + include/kvm/virtio-pci.h | 39 +++++++ virtio/pci-legacy.c | 205 ++++++++++++++++++++++++++++++++ virtio/pci.c | 245 ++------------------------------------- 4 files changed, 254 insertions(+), 236 deletions(-) create mode 100644 virtio/pci-legacy.c