mirror of
https://github.com/projectacrn/acrn-hypervisor.git
synced 2025-05-22 07:03:16 +00:00
dm: virtio: add vhost support
This patch adds the vhost support to the device model virtio. A vhost proxy is implemented based on the virtio framework and vhost char dev. Key data structures and external interfaces are implemented in this patch. Tracked-On: #1329 Signed-off-by: Jian Jun Chen <jian.jun.chen@intel.com> Acked-by: Yu Wang <yu1.wang@intel.com>
This commit is contained in:
parent
781e7dfb29
commit
bb34ffe672
@ -62,6 +62,7 @@ SRCS += hw/usb_core.c
|
|||||||
SRCS += hw/uart_core.c
|
SRCS += hw/uart_core.c
|
||||||
SRCS += hw/pci/virtio/virtio.c
|
SRCS += hw/pci/virtio/virtio.c
|
||||||
SRCS += hw/pci/virtio/virtio_kernel.c
|
SRCS += hw/pci/virtio/virtio_kernel.c
|
||||||
|
SRCS += hw/pci/virtio/vhost.c
|
||||||
SRCS += hw/platform/usb_mouse.c
|
SRCS += hw/platform/usb_mouse.c
|
||||||
SRCS += hw/platform/usb_pmapper.c
|
SRCS += hw/platform/usb_pmapper.c
|
||||||
SRCS += hw/platform/atkbdc.c
|
SRCS += hw/platform/atkbdc.c
|
||||||
|
328
devicemodel/hw/pci/virtio/vhost.c
Normal file
328
devicemodel/hw/pci/virtio/vhost.c
Normal file
@ -0,0 +1,328 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2018 Intel Corporation. All rights reserved.
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: BSD-3-Clause
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <sys/cdefs.h>
|
||||||
|
#include <sys/param.h>
|
||||||
|
#include <sys/uio.h>
|
||||||
|
#include <sys/ioctl.h>
|
||||||
|
#include <sys/eventfd.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#include <stdarg.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <pthread.h>
|
||||||
|
#include <linux/vhost.h>
|
||||||
|
|
||||||
|
#include "dm.h"
|
||||||
|
#include "pci_core.h"
|
||||||
|
#include "irq.h"
|
||||||
|
#include "vmmapi.h"
|
||||||
|
#include "vhost.h"
|
||||||
|
|
||||||
|
static int vhost_debug;
|
||||||
|
#define LOG_TAG "vhost: "
|
||||||
|
#define DPRINTF(fmt, args...) \
|
||||||
|
do { if (vhost_debug) printf(LOG_TAG fmt, ##args); } while (0)
|
||||||
|
#define WPRINTF(fmt, args...) printf(LOG_TAG fmt, ##args)
|
||||||
|
|
||||||
|
static void
|
||||||
|
vhost_kernel_init(struct vhost_dev *vdev, struct virtio_base *base,
|
||||||
|
int fd, int vq_idx, uint32_t busyloop_timeout)
|
||||||
|
{
|
||||||
|
/* to be implemented */
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
vhost_kernel_deinit(struct vhost_dev *vdev)
|
||||||
|
{
|
||||||
|
/* to be implemented */
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
vhost_kernel_set_vring_busyloop_timeout(struct vhost_dev *vdev,
|
||||||
|
struct vhost_vring_state *s)
|
||||||
|
{
|
||||||
|
/* to be implemented */
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
vhost_kernel_set_features(struct vhost_dev *vdev,
|
||||||
|
uint64_t features)
|
||||||
|
{
|
||||||
|
/* to be implemented */
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
vhost_kernel_get_features(struct vhost_dev *vdev,
|
||||||
|
uint64_t *features)
|
||||||
|
{
|
||||||
|
/* to be implemented */
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
vhost_kernel_set_owner(struct vhost_dev *vdev)
|
||||||
|
{
|
||||||
|
/* to be implemented */
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
vhost_kernel_reset_device(struct vhost_dev *vdev)
|
||||||
|
{
|
||||||
|
/* to be implemented */
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
vhost_kernel_net_set_backend(struct vhost_dev *vdev,
|
||||||
|
struct vhost_vring_file *file)
|
||||||
|
{
|
||||||
|
/* to be implemented */
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
vhost_vq_init(struct vhost_dev *vdev, int idx)
|
||||||
|
{
|
||||||
|
/* to be implemented */
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
vhost_vq_deinit(struct vhost_vq *vq)
|
||||||
|
{
|
||||||
|
/* to be implemented */
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
vhost_vq_start(struct vhost_dev *vdev, int idx)
|
||||||
|
{
|
||||||
|
/* to be implemented */
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
vhost_vq_stop(struct vhost_dev *vdev, int idx)
|
||||||
|
{
|
||||||
|
/* to be implemented */
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
vhost_set_mem_table(struct vhost_dev *vdev)
|
||||||
|
{
|
||||||
|
/* to be implemented */
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
vhost_dev_init(struct vhost_dev *vdev,
|
||||||
|
struct virtio_base *base,
|
||||||
|
int fd,
|
||||||
|
int vq_idx,
|
||||||
|
uint64_t vhost_features,
|
||||||
|
uint64_t vhost_ext_features,
|
||||||
|
uint32_t busyloop_timeout)
|
||||||
|
{
|
||||||
|
uint64_t features;
|
||||||
|
int i, rc;
|
||||||
|
|
||||||
|
/* sanity check */
|
||||||
|
if (!base || !base->queues || !base->vops) {
|
||||||
|
WPRINTF("virtio_base is not initialized\n");
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!vdev->vqs || vdev->nvqs == 0) {
|
||||||
|
WPRINTF("virtqueue is not initialized\n");
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (vq_idx + vdev->nvqs > base->vops->nvq) {
|
||||||
|
WPRINTF("invalid vq_idx: %d\n", vq_idx);
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
|
||||||
|
vhost_kernel_init(vdev, base, fd, vq_idx, busyloop_timeout);
|
||||||
|
|
||||||
|
rc = vhost_kernel_get_features(vdev, &features);
|
||||||
|
if (rc < 0) {
|
||||||
|
WPRINTF("vhost_get_features failed\n");
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i = 0; i < vdev->nvqs; i++) {
|
||||||
|
rc = vhost_vq_init(vdev, i);
|
||||||
|
if (rc < 0)
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* specific backend features to vhost */
|
||||||
|
vdev->vhost_ext_features = vhost_ext_features & features;
|
||||||
|
|
||||||
|
/* features supported by vhost */
|
||||||
|
vdev->vhost_features = vhost_features & features;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* If the features bits are not supported by either vhost kernel
|
||||||
|
* mediator or configuration of device model(specified by
|
||||||
|
* vhost_features), they should be disabled in device_caps,
|
||||||
|
* which expose as virtio host_features for virtio FE driver.
|
||||||
|
*/
|
||||||
|
vdev->base->device_caps &= ~(vhost_features ^ features);
|
||||||
|
vdev->started = false;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
fail:
|
||||||
|
vhost_dev_deinit(vdev);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
vhost_dev_deinit(struct vhost_dev *vdev)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
|
||||||
|
if (!vdev->base || !vdev->base->queues || !vdev->base->vops)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
for (i = 0; i < vdev->nvqs; i++)
|
||||||
|
vhost_vq_deinit(&vdev->vqs[i]);
|
||||||
|
|
||||||
|
vhost_kernel_deinit(vdev);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
vhost_dev_start(struct vhost_dev *vdev)
|
||||||
|
{
|
||||||
|
struct vhost_vring_state state;
|
||||||
|
uint64_t features;
|
||||||
|
int i, rc;
|
||||||
|
|
||||||
|
if (vdev->started)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
/* sanity check */
|
||||||
|
if (!vdev->base || !vdev->base->queues || !vdev->base->vops) {
|
||||||
|
WPRINTF("virtio_base is not initialized\n");
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((vdev->base->status & VIRTIO_CR_STATUS_DRIVER_OK) == 0) {
|
||||||
|
WPRINTF("status error 0x%x\n", vdev->base->status);
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
|
||||||
|
rc = vhost_kernel_set_owner(vdev);
|
||||||
|
if (rc < 0) {
|
||||||
|
WPRINTF("vhost_set_owner failed\n");
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* set vhost internal features */
|
||||||
|
features = (vdev->base->negotiated_caps & vdev->vhost_features) |
|
||||||
|
vdev->vhost_ext_features;
|
||||||
|
rc = vhost_kernel_set_features(vdev, features);
|
||||||
|
if (rc < 0) {
|
||||||
|
WPRINTF("set_features failed\n");
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
DPRINTF("set_features: 0x%lx\n", features);
|
||||||
|
|
||||||
|
/* set memory table */
|
||||||
|
rc = vhost_set_mem_table(vdev);
|
||||||
|
if (rc < 0) {
|
||||||
|
WPRINTF("set_mem_table failed\n");
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* config busyloop timeout */
|
||||||
|
if (vdev->busyloop_timeout) {
|
||||||
|
state.num = vdev->busyloop_timeout;
|
||||||
|
for (i = 0; i < vdev->nvqs; i++) {
|
||||||
|
state.index = i;
|
||||||
|
rc = vhost_kernel_set_vring_busyloop_timeout(vdev,
|
||||||
|
&state);
|
||||||
|
if (rc < 0) {
|
||||||
|
WPRINTF("set_busyloop_timeout failed\n");
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* start vhost virtqueue */
|
||||||
|
for (i = 0; i < vdev->nvqs; i++) {
|
||||||
|
rc = vhost_vq_start(vdev, i);
|
||||||
|
if (rc < 0)
|
||||||
|
goto fail_vq;
|
||||||
|
}
|
||||||
|
|
||||||
|
vdev->started = true;
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
fail_vq:
|
||||||
|
while (--i >= 0)
|
||||||
|
vhost_vq_stop(vdev, i);
|
||||||
|
fail:
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
vhost_dev_stop(struct vhost_dev *vdev)
|
||||||
|
{
|
||||||
|
int i, rc = 0;
|
||||||
|
|
||||||
|
for (i = 0; i < vdev->nvqs; i++)
|
||||||
|
vhost_vq_stop(vdev, i);
|
||||||
|
|
||||||
|
/* the following are done by this ioctl:
|
||||||
|
* 1) resources of the vhost dev are freed
|
||||||
|
* 2) vhost virtqueues are reset
|
||||||
|
*/
|
||||||
|
rc = vhost_kernel_reset_device(vdev);
|
||||||
|
if (rc < 0) {
|
||||||
|
WPRINTF("vhost_reset_device failed\n");
|
||||||
|
rc = -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
vdev->started = false;
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
vhost_net_set_backend(struct vhost_dev *vdev, int backend_fd)
|
||||||
|
{
|
||||||
|
struct vhost_vring_file file;
|
||||||
|
int rc, i;
|
||||||
|
|
||||||
|
file.fd = backend_fd;
|
||||||
|
for (i = 0; i < vdev->nvqs; i++) {
|
||||||
|
file.index = i;
|
||||||
|
rc = vhost_kernel_net_set_backend(vdev, &file);
|
||||||
|
if (rc < 0)
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
fail:
|
||||||
|
file.fd = -1;
|
||||||
|
while (--i >= 0) {
|
||||||
|
file.index = i;
|
||||||
|
vhost_kernel_net_set_backend(vdev, &file);
|
||||||
|
}
|
||||||
|
|
||||||
|
return -1;
|
||||||
|
}
|
136
devicemodel/include/vhost.h
Normal file
136
devicemodel/include/vhost.h
Normal file
@ -0,0 +1,136 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2018 Intel Corporation. All rights reserved.
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: BSD-3-Clause
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __VHOST_H__
|
||||||
|
#define __VHOST_H__
|
||||||
|
|
||||||
|
#include "virtio.h"
|
||||||
|
#include "mevent.h"
|
||||||
|
|
||||||
|
struct vhost_vq {
|
||||||
|
int kick_fd; /**< fd of kick eventfd */
|
||||||
|
int call_fd; /**< fd of call eventfd */
|
||||||
|
int idx; /**< index of this vq in vhost dev */
|
||||||
|
struct mevent *mevp; /**< mevent for call eventfd */
|
||||||
|
struct vhost_dev *dev; /**< pointer to vhost_dev */
|
||||||
|
};
|
||||||
|
|
||||||
|
struct vhost_dev {
|
||||||
|
/**
|
||||||
|
* backpointer to virtio_base
|
||||||
|
*/
|
||||||
|
struct virtio_base *base;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* pointer to vhost_vq array
|
||||||
|
*/
|
||||||
|
struct vhost_vq *vqs;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* number of virtqueues
|
||||||
|
*/
|
||||||
|
int nvqs;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* vhost chardev fd
|
||||||
|
*/
|
||||||
|
int fd;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* first vq's index in virtio_vq_info
|
||||||
|
*/
|
||||||
|
int vq_idx;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* supported virtio defined features
|
||||||
|
*/
|
||||||
|
uint64_t vhost_features;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* vhost self-defined internal features bits used for
|
||||||
|
* communicate between vhost user-space and kernel-space modules
|
||||||
|
*/
|
||||||
|
uint64_t vhost_ext_features;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* vq busyloop timeout in us
|
||||||
|
*/
|
||||||
|
uint32_t busyloop_timeout;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* whether vhost is started
|
||||||
|
*/
|
||||||
|
bool started;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief vhost_dev initialization.
|
||||||
|
*
|
||||||
|
* This interface is called to initialize the vhost_dev. It must be called
|
||||||
|
* before the actual feature negoitiation with the guest OS starts.
|
||||||
|
*
|
||||||
|
* @param vdev Pointer to struct vhost_dev.
|
||||||
|
* @param base Pointer to struct virtio_base.
|
||||||
|
* @param fd fd of the vhost chardev.
|
||||||
|
* @param vq_idx The first virtqueue which would be used by this vhost dev.
|
||||||
|
* @param vhost_features Subset of vhost features which would be enabled.
|
||||||
|
* @param vhost_ext_features Specific vhost internal features to be enabled.
|
||||||
|
* @param busyloop_timeout Busy loop timeout in us.
|
||||||
|
*
|
||||||
|
* @return 0 on success and -1 on failure.
|
||||||
|
*/
|
||||||
|
int vhost_dev_init(struct vhost_dev *vdev, struct virtio_base *base, int fd,
|
||||||
|
int vq_idx, uint64_t vhost_features,
|
||||||
|
uint64_t vhost_ext_features, uint32_t busyloop_timeout);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief vhost_dev cleanup.
|
||||||
|
*
|
||||||
|
* This interface is called to cleanup the vhost_dev.
|
||||||
|
*
|
||||||
|
* @param vdev Pointer to struct vhost_dev.
|
||||||
|
*
|
||||||
|
* @return 0 on success and -1 on failure.
|
||||||
|
*/
|
||||||
|
int vhost_dev_deinit(struct vhost_dev *vdev);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief start vhost data plane.
|
||||||
|
*
|
||||||
|
* This interface is called to start the data plane in vhost.
|
||||||
|
*
|
||||||
|
* @param vdev Pointer to struct vhost_dev.
|
||||||
|
*
|
||||||
|
* @return 0 on success and -1 on failure.
|
||||||
|
*/
|
||||||
|
int vhost_dev_start(struct vhost_dev *vdev);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief stop vhost data plane.
|
||||||
|
*
|
||||||
|
* This interface is called to stop the data plane in vhost.
|
||||||
|
*
|
||||||
|
* @param vdev Pointer to struct vhost_dev.
|
||||||
|
*
|
||||||
|
* @return 0 on success and -1 on failure.
|
||||||
|
*/
|
||||||
|
int vhost_dev_stop(struct vhost_dev *vdev);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief set backend fd of vhost net.
|
||||||
|
*
|
||||||
|
* This interface is called to set the backend fd (for example tap fd)
|
||||||
|
* to vhost.
|
||||||
|
*
|
||||||
|
* @param vdev Pointer to struct vhost_dev.
|
||||||
|
* @param backend_fd fd of backend (for example tap fd).
|
||||||
|
*
|
||||||
|
* @return 0 on success and -1 on failure.
|
||||||
|
*/
|
||||||
|
int vhost_net_set_backend(struct vhost_dev *vdev, int backend_fd);
|
||||||
|
|
||||||
|
#endif
|
Loading…
Reference in New Issue
Block a user