um: drivers: Add virtio vhost-user driver

This module allows virtio devices to be used over a vhost-user socket.

Signed-off-by: Erel Geron <erelx.geron@intel.com>
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
Signed-off-by: Richard Weinberger <richard@nod.at>
This commit is contained in:
Erel Geron 2019-09-11 14:51:20 +02:00 committed by Richard Weinberger
parent 851b6cb17c
commit 5d38f32499
11 changed files with 1169 additions and 2 deletions

View File

@ -335,3 +335,10 @@ config UML_NET_SLIRP
Startup example: "eth0=slirp,FE:FD:01:02:03:04,/usr/local/bin/slirp"
endmenu
config VIRTIO_UML
tristate "UML driver for virtio devices"
select VIRTIO
help
This driver provides support for virtio based paravirtual device
drivers over vhost-user sockets.

View File

@ -61,6 +61,7 @@ obj-$(CONFIG_XTERM_CHAN) += xterm.o xterm_kern.o
obj-$(CONFIG_UML_WATCHDOG) += harddog.o
obj-$(CONFIG_BLK_DEV_COW_COMMON) += cow_user.o
obj-$(CONFIG_UML_RANDOM) += random.o
obj-$(CONFIG_VIRTIO_UML) += virtio_uml.o
# pcap_user.o must be added explicitly.
USER_OBJS := fd.o null.o pty.o tty.o xterm.o slip_common.o pcap_user.o vde_user.o vector_user.o

View File

@ -0,0 +1,102 @@
// SPDX-License-Identifier: GPL-2.0-or-later
/* Vhost-user protocol */
#ifndef __VHOST_USER_H__
#define __VHOST_USER_H__
/* Message flags */
#define VHOST_USER_FLAG_REPLY BIT(2)
/* Feature bits */
#define VHOST_USER_F_PROTOCOL_FEATURES 30
/* Protocol feature bits */
#define VHOST_USER_PROTOCOL_F_CONFIG 9
/* Vring state index masks */
#define VHOST_USER_VRING_INDEX_MASK 0xff
#define VHOST_USER_VRING_POLL_MASK BIT(8)
/* Supported version */
#define VHOST_USER_VERSION 1
/* Supported transport features */
#define VHOST_USER_SUPPORTED_F BIT_ULL(VHOST_USER_F_PROTOCOL_FEATURES)
/* Supported protocol features */
#define VHOST_USER_SUPPORTED_PROTOCOL_F BIT_ULL(VHOST_USER_PROTOCOL_F_CONFIG)
enum vhost_user_request {
VHOST_USER_GET_FEATURES = 1,
VHOST_USER_SET_FEATURES = 2,
VHOST_USER_SET_OWNER = 3,
VHOST_USER_RESET_OWNER = 4,
VHOST_USER_SET_MEM_TABLE = 5,
VHOST_USER_SET_LOG_BASE = 6,
VHOST_USER_SET_LOG_FD = 7,
VHOST_USER_SET_VRING_NUM = 8,
VHOST_USER_SET_VRING_ADDR = 9,
VHOST_USER_SET_VRING_BASE = 10,
VHOST_USER_GET_VRING_BASE = 11,
VHOST_USER_SET_VRING_KICK = 12,
VHOST_USER_SET_VRING_CALL = 13,
VHOST_USER_SET_VRING_ERR = 14,
VHOST_USER_GET_PROTOCOL_FEATURES = 15,
VHOST_USER_SET_PROTOCOL_FEATURES = 16,
VHOST_USER_GET_QUEUE_NUM = 17,
VHOST_USER_SET_VRING_ENABLE = 18,
VHOST_USER_SEND_RARP = 19,
VHOST_USER_NET_SEND_MTU = 20,
VHOST_USER_SET_SLAVE_REQ_FD = 21,
VHOST_USER_IOTLB_MSG = 22,
VHOST_USER_SET_VRING_ENDIAN = 23,
VHOST_USER_GET_CONFIG = 24,
VHOST_USER_SET_CONFIG = 25,
};
struct vhost_user_header {
u32 request; /* Use enum vhost_user_request */
u32 flags;
u32 size;
} __packed;
struct vhost_user_config {
u32 offset;
u32 size;
u32 flags;
u8 payload[0]; /* Variable length */
} __packed;
struct vhost_user_vring_state {
u32 index;
u32 num;
} __packed;
struct vhost_user_vring_addr {
u32 index;
u32 flags;
u64 desc, used, avail, log;
} __packed;
struct vhost_user_mem_region {
u64 guest_addr;
u64 size;
u64 user_addr;
u64 mmap_offset;
} __packed;
struct vhost_user_mem_regions {
u32 num;
u32 padding;
struct vhost_user_mem_region regions[2]; /* Currently supporting 2 */
} __packed;
union vhost_user_payload {
u64 integer;
struct vhost_user_config config;
struct vhost_user_vring_state vring_state;
struct vhost_user_vring_addr vring_addr;
struct vhost_user_mem_regions mem_regions;
};
struct vhost_user_msg {
struct vhost_user_header header;
union vhost_user_payload payload;
} __packed;
#endif

1002
arch/um/drivers/virtio_uml.c Normal file

File diff suppressed because it is too large Load Diff

View File

@ -17,17 +17,18 @@
#define TELNETD_IRQ 12
#define XTERM_IRQ 13
#define RANDOM_IRQ 14
#define VIRTIO_IRQ 15
#ifdef CONFIG_UML_NET_VECTOR
#define VECTOR_BASE_IRQ 15
#define VECTOR_BASE_IRQ (VIRTIO_IRQ + 1)
#define VECTOR_IRQ_SPACE 8
#define LAST_IRQ (VECTOR_IRQ_SPACE + VECTOR_BASE_IRQ - 1)
#else
#define LAST_IRQ RANDOM_IRQ
#define LAST_IRQ VIRTIO_IRQ
#endif

View File

@ -36,6 +36,8 @@
#define OS_LIB_PATH "/usr/lib/"
#endif
#define OS_SENDMSG_MAX_FDS 8
/*
* types taken from stat_file() in hostfs_user.c
* (if they are wrong here, they are wrong there...).
@ -176,6 +178,9 @@ extern unsigned os_major(unsigned long long dev);
extern unsigned os_minor(unsigned long long dev);
extern unsigned long long os_makedev(unsigned major, unsigned minor);
extern int os_falloc_punch(int fd, unsigned long long offset, int count);
extern int os_eventfd(unsigned int initval, int flags);
extern int os_sendmsg_fds(int fd, const void *buf, unsigned int len,
const int *fds, unsigned int fds_num);
/* start_up.c */
extern void os_early_checks(void);

View File

@ -38,6 +38,8 @@ EXPORT_SYMBOL(run_helper);
EXPORT_SYMBOL(os_major);
EXPORT_SYMBOL(os_minor);
EXPORT_SYMBOL(os_makedev);
EXPORT_SYMBOL(os_eventfd);
EXPORT_SYMBOL(os_sendmsg_fds);
EXPORT_SYMBOL(add_sigio_fd);
EXPORT_SYMBOL(ignore_sigio_fd);

View File

@ -31,6 +31,7 @@ pgd_t swapper_pg_dir[PTRS_PER_PGD];
/* Initialized at boot time, and readonly after that */
unsigned long long highmem;
EXPORT_SYMBOL(highmem);
int kmalloc_ok = 0;
/* Used during early boot */

View File

@ -143,6 +143,7 @@ int phys_mapping(unsigned long phys, unsigned long long *offset_out)
return fd;
}
EXPORT_SYMBOL(phys_mapping);
static int __init uml_mem_setup(char *line, int *add)
{

View File

@ -113,6 +113,7 @@ static int have_root __initdata = 0;
/* Set in uml_mem_setup and modified in linux_main */
long long physmem_size = 32 * 1024 * 1024;
EXPORT_SYMBOL(physmem_size);
static const char *usage_string =
"User Mode Linux v%s\n"

View File

@ -15,6 +15,7 @@
#include <sys/sysmacros.h>
#include <sys/un.h>
#include <sys/types.h>
#include <sys/eventfd.h>
#include <os.h>
static void copy_stat(struct uml_stat *dst, const struct stat64 *src)
@ -620,3 +621,46 @@ int os_falloc_punch(int fd, unsigned long long offset, int len)
return n;
}
int os_eventfd(unsigned int initval, int flags)
{
int fd = eventfd(initval, flags);
if (fd < 0)
return -errno;
return fd;
}
int os_sendmsg_fds(int fd, const void *buf, unsigned int len, const int *fds,
unsigned int fds_num)
{
struct iovec iov = {
.iov_base = (void *) buf,
.iov_len = len,
};
union {
char control[CMSG_SPACE(sizeof(*fds) * OS_SENDMSG_MAX_FDS)];
struct cmsghdr align;
} u;
unsigned int fds_size = sizeof(*fds) * fds_num;
struct msghdr msg = {
.msg_iov = &iov,
.msg_iovlen = 1,
.msg_control = u.control,
.msg_controllen = CMSG_SPACE(fds_size),
};
struct cmsghdr *cmsg = CMSG_FIRSTHDR(&msg);
int err;
if (fds_num > OS_SENDMSG_MAX_FDS)
return -EINVAL;
memset(u.control, 0, sizeof(u.control));
cmsg->cmsg_level = SOL_SOCKET;
cmsg->cmsg_type = SCM_RIGHTS;
cmsg->cmsg_len = CMSG_LEN(fds_size);
memcpy(CMSG_DATA(cmsg), fds, fds_size);
err = sendmsg(fd, &msg, 0);
if (err < 0)
return -errno;
return err;
}