From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 From: Hao Li 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 Reviewed-on: Reviewed-by: Chi, Mingqiang Reviewed-by: Dong, Eddie Tested-by: Dong, Eddie --- 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 #include #include +#include + +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 + * + * 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 + * Hao Li + * 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 +#include +#include +#include + +/* 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 + * + * 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 + * Hao Li + * 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 +#include + +/* 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