From: Jean-Philippe Brucker <jean-philippe.brucker@arm.com>
To: will@kernel.org
Cc: andre.przywara@arm.com, alexandru.elisei@arm.com,
kvm@vger.kernel.org, suzuki.poulose@arm.com, sashal@kernel.org,
jean-philippe@linaro.org
Subject: [PATCH kvmtool v2 10/12] virtio: Add support for modern virtio-mmio
Date: Fri, 1 Jul 2022 15:24:32 +0100 [thread overview]
Message-ID: <20220701142434.75170-11-jean-philippe.brucker@arm.com> (raw)
In-Reply-To: <20220701142434.75170-1-jean-philippe.brucker@arm.com>
Add modern MMIO transport to virtio, make it the default. Legacy transport
can be enabled with --virtio-legacy. The main change for MMIO is the queue
addresses. They are now 64-bit addresses instead of 32-bit PFNs. Apart
from that all changes for supporting modern devices are already
implemented.
Signed-off-by: Jean-Philippe Brucker <jean-philippe.brucker@arm.com>
---
Makefile | 1 +
arm/include/arm-common/kvm-arch.h | 2 +-
include/kvm/virtio-mmio.h | 20 +++-
include/kvm/virtio.h | 1 +
riscv/include/kvm/kvm-arch.h | 3 +-
virtio/core.c | 6 +-
virtio/mmio-modern.c | 161 ++++++++++++++++++++++++++++++
virtio/mmio.c | 12 ++-
8 files changed, 195 insertions(+), 11 deletions(-)
create mode 100644 virtio/mmio-modern.c
diff --git a/Makefile b/Makefile
index 4063d185..349468f3 100644
--- a/Makefile
+++ b/Makefile
@@ -107,6 +107,7 @@ OBJS += kvm-ipc.o
OBJS += builtin-sandbox.o
OBJS += virtio/mmio.o
OBJS += virtio/mmio-legacy.o
+OBJS += virtio/mmio-modern.o
# Translate uname -m into ARCH string
ARCH ?= $(shell uname -m | sed -e s/i.86/i386/ -e s/ppc.*/powerpc/ \
diff --git a/arm/include/arm-common/kvm-arch.h b/arm/include/arm-common/kvm-arch.h
index 0a960f4f..a4c7604a 100644
--- a/arm/include/arm-common/kvm-arch.h
+++ b/arm/include/arm-common/kvm-arch.h
@@ -84,7 +84,7 @@
#define VIRTIO_DEFAULT_TRANS(kvm) \
((kvm)->cfg.arch.virtio_trans_pci ? \
((kvm)->cfg.virtio_legacy ? VIRTIO_PCI_LEGACY : VIRTIO_PCI) : \
- VIRTIO_MMIO)
+ ((kvm)->cfg.virtio_legacy ? VIRTIO_MMIO_LEGACY : VIRTIO_MMIO))
#define VIRTIO_RING_ENDIAN (VIRTIO_ENDIAN_LE | VIRTIO_ENDIAN_BE)
diff --git a/include/kvm/virtio-mmio.h b/include/kvm/virtio-mmio.h
index e7ef8386..b428b8d3 100644
--- a/include/kvm/virtio-mmio.h
+++ b/include/kvm/virtio-mmio.h
@@ -27,20 +27,30 @@ struct virtio_mmio_hdr {
u32 reserved_1[2];
u32 guest_features;
u32 guest_features_sel;
- u32 guest_page_size;
+ u32 guest_page_size; /* legacy */
u32 reserved_2;
u32 queue_sel;
u32 queue_num_max;
u32 queue_num;
- u32 queue_align;
- u32 queue_pfn;
- u32 reserved_3[3];
+ u32 queue_align; /* legacy */
+ u32 queue_pfn; /* legacy */
+ u32 queue_ready; /* modern */
+ u32 reserved_3[2];
u32 queue_notify;
u32 reserved_4[3];
u32 interrupt_state;
u32 interrupt_ack;
u32 reserved_5[2];
u32 status;
+ u32 reserved_7[3];
+ u32 queue_desc_low; /* modern */
+ u32 queue_desc_high;
+ u32 reserved_8[2];
+ u32 queue_avail_low;
+ u32 queue_avail_high;
+ u32 reserved_9[2];
+ u32 queue_used_low;
+ u32 queue_used_high;
} __attribute__((packed));
struct virtio_mmio {
@@ -64,6 +74,8 @@ int virtio_mmio_init_ioeventfd(struct kvm *kvm, struct virtio_device *vdev,
void virtio_mmio_legacy_callback(struct kvm_cpu *vcpu, u64 addr, u8 *data,
u32 len, u8 is_write, void *ptr);
+void virtio_mmio_modern_callback(struct kvm_cpu *vcpu, u64 addr, u8 *data,
+ u32 len, u8 is_write, void *ptr);
int virtio_mmio_init_vq(struct kvm *kvm, struct virtio_device *vdev, int vq);
void virtio_mmio_exit_vq(struct kvm *kvm, struct virtio_device *vdev, int vq);
#endif
diff --git a/include/kvm/virtio.h b/include/kvm/virtio.h
index 869064ba..94bddefe 100644
--- a/include/kvm/virtio.h
+++ b/include/kvm/virtio.h
@@ -196,6 +196,7 @@ enum virtio_trans {
VIRTIO_PCI,
VIRTIO_PCI_LEGACY,
VIRTIO_MMIO,
+ VIRTIO_MMIO_LEGACY,
};
struct virtio_device {
diff --git a/riscv/include/kvm/kvm-arch.h b/riscv/include/kvm/kvm-arch.h
index f090883c..1e130f59 100644
--- a/riscv/include/kvm/kvm-arch.h
+++ b/riscv/include/kvm/kvm-arch.h
@@ -46,7 +46,8 @@
#define KVM_VM_TYPE 0
-#define VIRTIO_DEFAULT_TRANS(kvm) VIRTIO_MMIO
+#define VIRTIO_DEFAULT_TRANS(kvm) \
+ ((kvm)->cfg.virtio_legacy ? VIRTIO_MMIO_LEGACY : VIRTIO_MMIO)
#define VIRTIO_RING_ENDIAN VIRTIO_ENDIAN_LE
diff --git a/virtio/core.c b/virtio/core.c
index 5fc2e789..f432421a 100644
--- a/virtio/core.c
+++ b/virtio/core.c
@@ -16,7 +16,7 @@ const char* virtio_trans_name(enum virtio_trans trans)
{
if (trans == VIRTIO_PCI || trans == VIRTIO_PCI_LEGACY)
return "pci";
- else if (trans == VIRTIO_MMIO)
+ else if (trans == VIRTIO_MMIO || trans == VIRTIO_MMIO_LEGACY)
return "mmio";
return "unknown";
}
@@ -345,8 +345,10 @@ int virtio_init(struct kvm *kvm, void *dev, struct virtio_device *vdev,
vdev->ops->reset = virtio_pci__reset;
r = vdev->ops->init(kvm, dev, vdev, device_id, subsys_id, class);
break;
- case VIRTIO_MMIO:
+ case VIRTIO_MMIO_LEGACY:
vdev->legacy = true;
+ /* fall through */
+ case VIRTIO_MMIO:
virtio = calloc(sizeof(struct virtio_mmio), 1);
if (!virtio)
return -ENOMEM;
diff --git a/virtio/mmio-modern.c b/virtio/mmio-modern.c
new file mode 100644
index 00000000..6c0bb382
--- /dev/null
+++ b/virtio/mmio-modern.c
@@ -0,0 +1,161 @@
+#include "kvm/virtio.h"
+#include "kvm/virtio-mmio.h"
+
+#include <linux/byteorder.h>
+
+#define vmmio_selected_vq(vmmio) \
+ vdev->ops->get_vq((vmmio)->kvm, (vmmio)->dev, (vmmio)->hdr.queue_sel)
+
+static void virtio_mmio_config_in(struct kvm_cpu *vcpu,
+ u64 addr, u32 *data, u32 len,
+ struct virtio_device *vdev)
+{
+ struct virtio_mmio *vmmio = vdev->virtio;
+ u64 features = 1ULL << VIRTIO_F_VERSION_1;
+ u32 val = 0;
+
+ switch (addr) {
+ case VIRTIO_MMIO_MAGIC_VALUE:
+ case VIRTIO_MMIO_VERSION:
+ case VIRTIO_MMIO_DEVICE_ID:
+ case VIRTIO_MMIO_VENDOR_ID:
+ case VIRTIO_MMIO_STATUS:
+ case VIRTIO_MMIO_INTERRUPT_STATUS:
+ val = *(u32 *)(((void *)&vmmio->hdr) + addr);
+ break;
+ case VIRTIO_MMIO_DEVICE_FEATURES:
+ if (vmmio->hdr.host_features_sel > 1)
+ break;
+ features |= vdev->ops->get_host_features(vmmio->kvm, vmmio->dev);
+ val = features >> (32 * vmmio->hdr.host_features_sel);
+ break;
+ case VIRTIO_MMIO_QUEUE_NUM_MAX:
+ val = vdev->ops->get_size_vq(vmmio->kvm, vmmio->dev,
+ vmmio->hdr.queue_sel);
+ break;
+ case VIRTIO_MMIO_QUEUE_READY:
+ val = vmmio_selected_vq(vmmio)->enabled;
+ break;
+ case VIRTIO_MMIO_QUEUE_DESC_LOW:
+ val = vmmio_selected_vq(vmmio)->vring_addr.desc_lo;
+ break;
+ case VIRTIO_MMIO_QUEUE_DESC_HIGH:
+ val = vmmio_selected_vq(vmmio)->vring_addr.desc_hi;
+ break;
+ case VIRTIO_MMIO_QUEUE_USED_LOW:
+ val = vmmio_selected_vq(vmmio)->vring_addr.used_lo;
+ break;
+ case VIRTIO_MMIO_QUEUE_USED_HIGH:
+ val = vmmio_selected_vq(vmmio)->vring_addr.used_hi;
+ break;
+ case VIRTIO_MMIO_QUEUE_AVAIL_LOW:
+ val = vmmio_selected_vq(vmmio)->vring_addr.avail_lo;
+ break;
+ case VIRTIO_MMIO_QUEUE_AVAIL_HIGH:
+ val = vmmio_selected_vq(vmmio)->vring_addr.avail_hi;
+ break;
+ case VIRTIO_MMIO_CONFIG_GENERATION:
+ /*
+ * The config generation changes when the device updates a
+ * config field larger than 32 bits, that the driver reads using
+ * multiple accesses. Since kvmtool doesn't use any mutable
+ * config field larger than 32 bits, the generation is constant.
+ */
+ break;
+ default:
+ return;
+ }
+
+ *data = cpu_to_le32(val);
+}
+
+static void virtio_mmio_config_out(struct kvm_cpu *vcpu,
+ u64 addr, u32 *data, u32 len,
+ struct virtio_device *vdev)
+{
+ struct virtio_mmio *vmmio = vdev->virtio;
+ struct kvm *kvm = vmmio->kvm;
+ u32 val = le32_to_cpu(*data);
+ u64 features;
+
+ switch (addr) {
+ case VIRTIO_MMIO_DEVICE_FEATURES_SEL:
+ case VIRTIO_MMIO_DRIVER_FEATURES_SEL:
+ case VIRTIO_MMIO_QUEUE_SEL:
+ *(u32 *)(((void *)&vmmio->hdr) + addr) = val;
+ break;
+ case VIRTIO_MMIO_STATUS:
+ vmmio->hdr.status = val;
+ virtio_notify_status(kvm, vdev, vmmio->dev, val);
+ break;
+ case VIRTIO_MMIO_DRIVER_FEATURES:
+ if (vmmio->hdr.guest_features_sel > 1)
+ break;
+
+ features = (u64)val << (32 * vmmio->hdr.guest_features_sel);
+ virtio_set_guest_features(vmmio->kvm, vdev, vmmio->dev,
+ features);
+ break;
+ case VIRTIO_MMIO_QUEUE_NUM:
+ vmmio->hdr.queue_num = val;
+ vdev->ops->set_size_vq(vmmio->kvm, vmmio->dev,
+ vmmio->hdr.queue_sel, val);
+ break;
+ case VIRTIO_MMIO_QUEUE_READY:
+ if (val)
+ virtio_mmio_init_vq(kvm, vdev, vmmio->hdr.queue_sel);
+ else
+ virtio_mmio_exit_vq(kvm, vdev, vmmio->hdr.queue_sel);
+ break;
+ case VIRTIO_MMIO_QUEUE_NOTIFY:
+ vdev->ops->notify_vq(vmmio->kvm, vmmio->dev, val);
+ break;
+ case VIRTIO_MMIO_INTERRUPT_ACK:
+ vmmio->hdr.interrupt_state &= ~val;
+ break;
+ case VIRTIO_MMIO_QUEUE_DESC_LOW:
+ vmmio_selected_vq(vmmio)->vring_addr.desc_lo = val;
+ break;
+ case VIRTIO_MMIO_QUEUE_DESC_HIGH:
+ vmmio_selected_vq(vmmio)->vring_addr.desc_hi = val;
+ break;
+ case VIRTIO_MMIO_QUEUE_USED_LOW:
+ vmmio_selected_vq(vmmio)->vring_addr.used_lo = val;
+ break;
+ case VIRTIO_MMIO_QUEUE_USED_HIGH:
+ vmmio_selected_vq(vmmio)->vring_addr.used_hi = val;
+ break;
+ case VIRTIO_MMIO_QUEUE_AVAIL_LOW:
+ vmmio_selected_vq(vmmio)->vring_addr.avail_lo = val;
+ break;
+ case VIRTIO_MMIO_QUEUE_AVAIL_HIGH:
+ vmmio_selected_vq(vmmio)->vring_addr.avail_hi = val;
+ break;
+ };
+}
+
+void virtio_mmio_modern_callback(struct kvm_cpu *vcpu, u64 addr, u8 *data,
+ u32 len, u8 is_write, void *ptr)
+{
+ struct virtio_device *vdev = ptr;
+ struct virtio_mmio *vmmio = vdev->virtio;
+ u32 offset = addr - vmmio->addr;
+
+ if (offset >= VIRTIO_MMIO_CONFIG) {
+ offset -= VIRTIO_MMIO_CONFIG;
+ virtio_access_config(vmmio->kvm, vdev, vmmio->dev, offset, data,
+ len, is_write);
+ return;
+ }
+
+ if (len != 4) {
+ pr_debug("Invalid %s size %d at 0x%llx", is_write ? "write" :
+ "read", len, addr);
+ return;
+ }
+
+ if (is_write)
+ virtio_mmio_config_out(vcpu, offset, (void *)data, len, ptr);
+ else
+ virtio_mmio_config_in(vcpu, offset, (void *)data, len, ptr);
+}
diff --git a/virtio/mmio.c b/virtio/mmio.c
index fab45733..fae73b52 100644
--- a/virtio/mmio.c
+++ b/virtio/mmio.c
@@ -149,6 +149,7 @@ static void generate_virtio_mmio_fdt_node(void *fdt,
int virtio_mmio_init(struct kvm *kvm, void *dev, struct virtio_device *vdev,
int device_id, int subsys_id, int class)
{
+ bool legacy = vdev->legacy;
struct virtio_mmio *vmmio = vdev->virtio;
int r;
@@ -156,14 +157,19 @@ int virtio_mmio_init(struct kvm *kvm, void *dev, struct virtio_device *vdev,
vmmio->kvm = kvm;
vmmio->dev = dev;
- r = kvm__register_mmio(kvm, vmmio->addr, VIRTIO_MMIO_IO_SIZE,
- false, virtio_mmio_legacy_callback, vdev);
+ if (!legacy)
+ vdev->endian = VIRTIO_ENDIAN_LE;
+
+ r = kvm__register_mmio(kvm, vmmio->addr, VIRTIO_MMIO_IO_SIZE, false,
+ legacy ? virtio_mmio_legacy_callback :
+ virtio_mmio_modern_callback,
+ vdev);
if (r < 0)
return r;
vmmio->hdr = (struct virtio_mmio_hdr) {
.magic = {'v', 'i', 'r', 't'},
- .version = 1,
+ .version = legacy ? 1 : 2,
.device_id = subsys_id,
.vendor_id = 0x4d564b4c , /* 'LKVM' */
.queue_num_max = 256,
--
2.36.1
next prev parent reply other threads:[~2022-07-01 14:31 UTC|newest]
Thread overview: 14+ messages / expand[flat|nested] mbox.gz Atom feed top
2022-07-01 14:24 [PATCH kvmtool v2 00/12] Virtio v1 support Jean-Philippe Brucker
2022-07-01 14:24 ` [PATCH kvmtool v2 01/12] virtio/pci: Delete MSI routes Jean-Philippe Brucker
2022-07-01 14:24 ` [PATCH kvmtool v2 02/12] virtio: Extract init_vq() for PCI and MMIO Jean-Philippe Brucker
2022-07-01 14:24 ` [PATCH kvmtool v2 03/12] virtio/pci: Make doorbell offset dynamic Jean-Philippe Brucker
2022-07-01 14:24 ` [PATCH kvmtool v2 04/12] virtio/pci: Use the correct eventfd for vhost notification Jean-Philippe Brucker
2022-07-01 14:24 ` [PATCH kvmtool v2 05/12] virtio/net: Set vhost backend after queue address Jean-Philippe Brucker
2022-07-01 14:24 ` [PATCH kvmtool v2 06/12] virtio: Prepare for more feature bits Jean-Philippe Brucker
2022-07-01 14:24 ` [PATCH kvmtool v2 07/12] virtio: Move PCI transport to pci-legacy Jean-Philippe Brucker
2022-07-01 14:24 ` [PATCH kvmtool v2 08/12] virtio: Add support for modern virtio-pci Jean-Philippe Brucker
2022-07-01 14:24 ` [PATCH kvmtool v2 09/12] virtio: Move MMIO transport to mmio-legacy Jean-Philippe Brucker
2022-07-01 14:24 ` Jean-Philippe Brucker [this message]
2022-07-01 14:24 ` [PATCH kvmtool v2 11/12] virtio/pci: Initialize all vectors to VIRTIO_MSI_NO_VECTOR Jean-Philippe Brucker
2022-07-01 14:24 ` [PATCH kvmtool v2 12/12] virtio/pci: Remove VIRTIO_PCI_F_SIGNAL_MSI Jean-Philippe Brucker
2022-07-01 15:41 ` [PATCH kvmtool v2 00/12] Virtio v1 support Will Deacon
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20220701142434.75170-11-jean-philippe.brucker@arm.com \
--to=jean-philippe.brucker@arm.com \
--cc=alexandru.elisei@arm.com \
--cc=andre.przywara@arm.com \
--cc=jean-philippe@linaro.org \
--cc=kvm@vger.kernel.org \
--cc=sashal@kernel.org \
--cc=suzuki.poulose@arm.com \
--cc=will@kernel.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.