clear-pkgs-linux-iot-lts2018/0477-VBS-K-virtqueue-initia...

505 lines
17 KiB
Diff

From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Hao Li <hao.l.li@intel.com>
Date: Fri, 31 Aug 2018 10:58:56 +0800
Subject: [PATCH] VBS-K: virtqueue initialization API.
This patch added the following to the VBS-K framework:
- virtqueue data structures shared between VBS-K and its
counterpart in userspace, which is VBS-U;
- virtqueue initialization API;
Change-Id: Ib928ea94cb4f33cf30abd17921089afc14518365
Tracked-On:218445
Signed-off-by: Hao Li <hao.l.li@intel.com>
Reviewed-on:
Reviewed-by: Chi, Mingqiang <mingqiang.chi@intel.com>
Reviewed-by: Dong, Eddie <eddie.dong@intel.com>
Tested-by: Dong, Eddie <eddie.dong@intel.com>
---
drivers/vbs/Makefile | 1 +
drivers/vbs/vbs.c | 75 ++++++++++++++++++
drivers/vbs/vq.c | 125 ++++++++++++++++++++++++++++++
include/linux/vbs/vbs.h | 57 ++++++++++++++
include/linux/vbs/vbs_common_if.h | 18 +++++
include/linux/vbs/vq.h | 99 +++++++++++++++++++++++
6 files changed, 375 insertions(+)
create mode 100644 drivers/vbs/vq.c
create mode 100644 include/linux/vbs/vq.h
diff --git a/drivers/vbs/Makefile b/drivers/vbs/Makefile
index b52b65b6bd13..cbd5076e2313 100644
--- a/drivers/vbs/Makefile
+++ b/drivers/vbs/Makefile
@@ -1,3 +1,4 @@
ccflags-$(CONFIG_VBS_DEBUG) := -DDEBUG
obj-$(CONFIG_VBS) += vbs.o
+obj-$(CONFIG_VBS) += vq.o
diff --git a/drivers/vbs/vbs.c b/drivers/vbs/vbs.c
index 591d43dbe536..1e7a9645a353 100644
--- a/drivers/vbs/vbs.c
+++ b/drivers/vbs/vbs.c
@@ -65,6 +65,66 @@
#include <linux/module.h>
#include <linux/uaccess.h>
#include <linux/vbs/vbs.h>
+#include <linux/vbs/vq.h>
+
+static long virtio_vqs_info_set(struct virtio_dev_info *dev,
+ struct vbs_vqs_info __user *i)
+{
+ struct vbs_vqs_info info;
+ struct virtio_vq_info *vq;
+ int j;
+
+ vq = dev->vqs;
+
+ if (copy_from_user(&info, i, sizeof(struct vbs_vqs_info)))
+ return -EFAULT;
+
+ /* setup struct virtio_vq_info based on info in struct vbs_vq_info */
+ if (dev->nvq && dev->nvq != info.nvq) {
+ pr_err("Oops! dev's nvq != vqs's nvq. Not the same device?\n");
+ return -EFAULT;
+ }
+
+ for (j = 0; j < info.nvq; j++) {
+ vq->qsize = info.vqs[j].qsize;
+ vq->pfn = info.vqs[j].pfn;
+ vq->msix_idx = info.vqs[j].msix_idx;
+ vq->msix_addr = info.vqs[j].msix_addr;
+ vq->msix_data = info.vqs[j].msix_data;
+
+ pr_debug("msix id %x, addr %llx, data %x\n", vq->msix_idx,
+ vq->msix_addr, vq->msix_data);
+
+ virtio_vq_init(vq, vq->pfn);
+
+ vq++;
+ }
+
+ return 0;
+}
+
+/* invoked by VBS-K device's ioctl routine */
+long virtio_vqs_ioctl(struct virtio_dev_info *dev, unsigned int ioctl,
+ void __user *argp)
+{
+ long ret;
+
+ /*
+ * Currently we don't conduct ownership checking,
+ * but assuming caller would have device mutex.
+ */
+
+ switch (ioctl) {
+ case VBS_SET_VQ:
+ ret = virtio_vqs_info_set(dev, argp);
+ break;
+ default:
+ ret = -ENOIOCTLCMD;
+ break;
+ }
+ return ret;
+}
+EXPORT_SYMBOL_GPL(virtio_vqs_ioctl);
static long virtio_dev_info_set(struct virtio_dev_info *dev,
struct vbs_dev_info __user *i)
@@ -77,6 +137,7 @@ static long virtio_dev_info_set(struct virtio_dev_info *dev,
/* setup struct virtio_dev_info based on info in vbs_dev_info */
strncpy(dev->name, info.name, VBS_NAME_LEN);
dev->_ctx.vmid = info.vmid;
+ dev->nvq = info.nvq;
dev->negotiated_features = info.negotiated_features;
dev->io_range_start = info.pio_range_start;
dev->io_range_len = info.pio_range_len;
@@ -85,6 +146,7 @@ static long virtio_dev_info_set(struct virtio_dev_info *dev,
return 0;
}
+/* invoked by VBS-K device's ioctl routine */
long virtio_dev_ioctl(struct virtio_dev_info *dev, unsigned int ioctl,
void __user *argp)
{
@@ -107,6 +169,19 @@ long virtio_dev_ioctl(struct virtio_dev_info *dev, unsigned int ioctl,
}
EXPORT_SYMBOL_GPL(virtio_dev_ioctl);
+/* called in VBS-K device's .open() */
+long virtio_dev_init(struct virtio_dev_info *dev,
+ struct virtio_vq_info *vqs, int nvq)
+{
+ int i;
+
+ for (i = 0; i < nvq; i++)
+ virtio_vq_reset(&vqs[i]);
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(virtio_dev_init);
+
static int __init vbs_init(void)
{
return 0;
diff --git a/drivers/vbs/vq.c b/drivers/vbs/vq.c
new file mode 100644
index 000000000000..95a6757a1c85
--- /dev/null
+++ b/drivers/vbs/vq.c
@@ -0,0 +1,125 @@
+/*
+ * ACRN Project
+ * Virtio Backend Service (VBS) for ACRN hypervisor
+ *
+ * This file is provided under a dual BSD/GPLv2 license. When using or
+ * redistributing this file, you may do so under either license.
+ *
+ * GPL LICENSE SUMMARY
+ *
+ * Copyright (c) 2017 Intel Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * Contact Information: Hao Li <hao.l.li@intel.com>
+ *
+ * BSD LICENSE
+ *
+ * Copyright (c) 2017 Intel Corporation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Intel Corporation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Chris Torek <torek @ torek net>
+ * Hao Li <hao.l.li@intel.com>
+ * Created Virtqueue APIs for ACRN VBS framework:
+ * - VBS-K is a kernel-level virtio framework that can be used for
+ * virtio backend driver development for ACRN hypervisor.
+ * - Virtqueue APIs abstract away the details of the internal data
+ * structures of virtqueue, so that callers could easily access
+ * the data from guest through virtqueues.
+ */
+
+#include <linux/module.h>
+#include <linux/vbs/vq.h>
+#include <linux/vbs/vbs.h>
+#include <linux/vhm/acrn_vhm_mm.h>
+
+/* helper function for remote memory map */
+void * paddr_guest2host(struct ctx *ctx, uintptr_t gaddr, size_t len)
+{
+ return map_guest_phys(ctx->vmid, gaddr, len);
+}
+
+/*
+ * Initialize the currently-selected virtqueue.
+ * The guest just gave us a page frame number, from which we can
+ * calculate the addresses of the queue.
+ */
+void virtio_vq_init(struct virtio_vq_info *vq, uint32_t pfn)
+{
+ uint64_t phys;
+ size_t size;
+ char *base;
+ struct ctx *ctx;
+
+ ctx = &vq->dev->_ctx;
+
+ phys = (uint64_t)pfn << VRING_PAGE_BITS;
+ size = virtio_vq_ring_size(vq->qsize);
+ base = paddr_guest2host(ctx, phys, size);
+
+ /* First page(s) are descriptors... */
+ vq->desc = (struct virtio_desc *)base;
+ base += vq->qsize * sizeof(struct virtio_desc);
+
+ /* ... immediately followed by "avail" ring (entirely uint16_t's) */
+ vq->avail = (struct vring_avail *)base;
+ base += (2 + vq->qsize + 1) * sizeof(uint16_t);
+
+ /* Then it's rounded up to the next page... */
+ base = (char *)roundup2((uintptr_t)base, VRING_ALIGN);
+
+ /* ... and the last page(s) are the used ring. */
+ vq->used = (struct vring_used *)base;
+
+ /* Mark queue as allocated, and start at 0 when we use it. */
+ vq->flags = VQ_ALLOC;
+ vq->last_avail = 0;
+ vq->save_used = 0;
+}
+
+/* reset one virtqueue, make it invalid */
+void virtio_vq_reset(struct virtio_vq_info *vq)
+{
+ if (!vq) {
+ pr_info("%s: vq is NULL!\n", __func__);
+ return;
+ }
+
+ vq->pfn = 0;
+ vq->msix_idx = VIRTIO_MSI_NO_VECTOR;
+ vq->flags = 0;
+ vq->last_avail = 0;
+ vq->save_used = 0;
+}
diff --git a/include/linux/vbs/vbs.h b/include/linux/vbs/vbs.h
index 7b876782fe41..715c49156a1a 100644
--- a/include/linux/vbs/vbs.h
+++ b/include/linux/vbs/vbs.h
@@ -80,19 +80,76 @@ struct ctx {
int vmid;
};
+struct virtio_desc { /* AKA vring_desc */
+ uint64_t addr; /* guest physical address */
+ uint32_t len; /* length of scatter/gather seg */
+ uint16_t flags; /* desc flags */
+ uint16_t next; /* next desc if F_NEXT */
+} __attribute__((packed));
+
+struct virtio_used { /* AKA vring_used_elem */
+ uint32_t idx; /* head of used descriptor chain */
+ uint32_t len; /* length written-to */
+} __attribute__((packed));
+
+struct vring_avail {
+ uint16_t flags; /* vring_avail flags */
+ uint16_t idx; /* counts to 65535, then cycles */
+ uint16_t ring[]; /* size N, reported in QNUM value */
+} __attribute__((packed));
+
+struct vring_used {
+ uint16_t flags; /* vring_used flags */
+ uint16_t idx; /* counts to 65535, then cycles */
+ struct virtio_used ring[]; /* size N */
+} __attribute__((packed));
+
+/* struct used to maintain virtqueue info from userspace VBS */
+struct virtio_vq_info {
+ /* virtqueue info from VBS-U */
+ uint16_t qsize; /* size of this queue (a power of 2) */
+ uint32_t pfn; /* PFN of virt queue (not shifted!) */
+ uint16_t msix_idx; /* MSI-X index/VIRTIO_MSI_NO_VECTOR */
+ uint64_t msix_addr; /* MSI-X address specified by index */
+ uint32_t msix_data; /* MSI-X data specified by index */
+
+ /* members created in kernel space VBS */
+ int (*vq_notify)(int); /* vq-wide notification */
+ struct virtio_dev_info *dev; /* backpointer to virtio_dev_info */
+ uint16_t num; /* we're the num'th virtqueue */
+ uint16_t flags; /* virtqueue flags */
+ uint16_t last_avail; /* a recent value of vq_avail->va_idx */
+ uint16_t save_used; /* saved vq_used->vu_idx */
+
+ volatile struct virtio_desc *desc; /* descriptor array */
+ volatile struct vring_avail *avail; /* the "avail" ring */
+ volatile struct vring_used *used; /* the "used" ring */
+};
+
/* struct used to maintain virtio device info from userspace VBS */
struct virtio_dev_info {
/* dev info from VBS */
char name[VBS_NAME_LEN]; /* VBS device name */
struct ctx _ctx; /* device context */
+ int nvq; /* number of virtqueues */
uint32_t negotiated_features; /* features after guest loads driver */
uint64_t io_range_start; /* IO range start of VBS device */
uint64_t io_range_len; /* IO range len of VBS device */
enum IORangeType io_range_type; /* IO range type, PIO or MMIO */
+
+ /* members created in kernel space VBS */
+ void (*dev_notify)(void *, struct virtio_vq_info *);
+ /* device-wide notification */
+ struct virtio_vq_info *vqs; /* virtqueue(s) */
+ int curq; /* current virtqueue index */
};
/* VBS Runtime Control APIs */
+long virtio_dev_init(struct virtio_dev_info *dev, struct virtio_vq_info *vqs,
+ int nvq);
long virtio_dev_ioctl(struct virtio_dev_info *dev, unsigned int ioctl,
void __user *argp);
+long virtio_vqs_ioctl(struct virtio_dev_info *dev, unsigned int ioctl,
+ void __user *argp);
#endif
diff --git a/include/linux/vbs/vbs_common_if.h b/include/linux/vbs/vbs_common_if.h
index 78b36a6c58c8..91eb4e01d95c 100644
--- a/include/linux/vbs/vbs_common_if.h
+++ b/include/linux/vbs/vbs_common_if.h
@@ -59,11 +59,28 @@
#ifndef _VBS_COMMON_IF_H_
#define _VBS_COMMON_IF_H_
+#define VBS_MAX_VQ_CNT 10
#define VBS_NAME_LEN 32
+#define VIRTIO_MSI_NO_VECTOR 0xFFFF
+
+struct vbs_vq_info {
+ uint16_t qsize; /* size of this virtqueue (a power of 2) */
+ uint32_t pfn; /* PFN of virtqueue (not shifted!) */
+ uint16_t msix_idx; /* MSI-X index, or VIRTIO_MSI_NO_VECTOR */
+ uint64_t msix_addr; /* MSI-X address specified by index */
+ uint32_t msix_data; /* MSI-X data specified by index */
+};
+
+struct vbs_vqs_info {
+ uint32_t nvq; /* number of virtqueues */
+ struct vbs_vq_info vqs[VBS_MAX_VQ_CNT];
+ /* array of struct vbs_vq_info */
+};
struct vbs_dev_info {
char name[VBS_NAME_LEN];/* VBS name */
int vmid; /* id of VM this device belongs to */
+ int nvq; /* number of virtqueues */
uint32_t negotiated_features;
/* features after VIRTIO_CONFIG_S_DRIVER_OK */
uint64_t pio_range_start;
@@ -74,5 +91,6 @@ struct vbs_dev_info {
#define VBS_IOCTL 0xAF
#define VBS_SET_DEV _IOW(VBS_IOCTL, 0x00, struct vbs_dev_info)
+#define VBS_SET_VQ _IOW(VBS_IOCTL, 0x01, struct vbs_vqs_info)
#endif
diff --git a/include/linux/vbs/vq.h b/include/linux/vbs/vq.h
new file mode 100644
index 000000000000..55ff810fa094
--- /dev/null
+++ b/include/linux/vbs/vq.h
@@ -0,0 +1,99 @@
+/*
+ * ACRN Project
+ * Virtio Backend Service (VBS) for ACRN hypervisor
+ *
+ * This file is provided under a dual BSD/GPLv2 license. When using or
+ * redistributing this file, you may do so under either license.
+ *
+ * GPL LICENSE SUMMARY
+ *
+ * Copyright (c) 2017 Intel Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * Contact Information: Hao Li <hao.l.li@intel.com>
+ *
+ * BSD LICENSE
+ *
+ * Copyright (c) 2017 Intel Corporation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Intel Corporation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Chris Torek <torek @ torek net>
+ * Hao Li <hao.l.li@intel.com>
+ * Define virtqueue data structures and APIs for VBS framework.
+ * - VBS-K is a kernel-level virtio framework that can be used for
+ * virtio backend driver development for ACRN hypervisor.
+ * - VBS-K should be working with VBS-U (Virtio Backend Service in
+ * User) together, in order to connect with virtio frontend driver.
+ */
+
+#ifndef _VQ_H_
+#define _VQ_H_
+
+#include <linux/uio.h>
+#include <linux/vbs/vbs.h>
+
+/* virtqueue alignment */
+#define VRING_ALIGN 4096
+#define roundup2(x, y) (((x)+((y)-1))&(~((y)-1)))
+
+/* PFN register shift amount */
+#define VRING_PAGE_BITS 12
+
+/* virtqueue flags */
+#define VQ_ALLOC 0x01
+#define VQ_BROKED 0x02
+
+/* get virtqueue size according to virtio specification */
+static inline size_t virtio_vq_ring_size(unsigned int qsz)
+{
+ size_t size;
+
+ /* constant 3 below = va_flags, va_idx, va_used_event */
+ size = sizeof(struct virtio_desc) * qsz + sizeof(uint16_t) * (3 + qsz);
+ size = roundup2(size, VRING_ALIGN);
+
+ /* constant 3 below = vu_flags, vu_idx, vu_avail_event */
+ size += sizeof(uint16_t) * 3 + sizeof(struct virtio_used) * qsz;
+ size = roundup2(size, VRING_ALIGN);
+
+ return size;
+}
+
+/* virtqueue initialization APIs */
+void virtio_vq_init(struct virtio_vq_info *vq, uint32_t pfn);
+void virtio_vq_reset(struct virtio_vq_info *vq);
+
+#endif
--
https://clearlinux.org