diff options
-rw-r--r-- | Makefile | 26 | ||||
-rw-r--r-- | adapter.c | 301 | ||||
-rw-r--r-- | include/adapter.h (renamed from adapter.h) | 17 | ||||
-rw-r--r-- | include/event_notifier.h (renamed from event_notifier.h) | 0 | ||||
-rw-r--r-- | include/parser.h | 42 | ||||
-rw-r--r-- | include/queue.h (renamed from queue.h) | 0 | ||||
-rw-r--r-- | include/vhost_loopback.h (renamed from vhost_loopback.h) | 0 | ||||
-rw-r--r-- | include/vhost_user_blk.h (renamed from vhost_user_blk.h) | 2 | ||||
-rw-r--r-- | include/vhost_user_can.h (renamed from vhost_user_can.h) | 5 | ||||
-rw-r--r-- | include/vhost_user_console.h (renamed from vhost_user_console.h) | 26 | ||||
-rw-r--r-- | include/vhost_user_gpio.h (renamed from vhost_user_gpio.h) | 20 | ||||
-rw-r--r-- | include/vhost_user_input.h | 30 | ||||
-rw-r--r-- | include/vhost_user_loopback.h (renamed from vhost_user_loopback.h) | 87 | ||||
-rw-r--r-- | include/vhost_user_rng.h (renamed from vhost_user_rng.h) | 3 | ||||
-rw-r--r-- | include/vhost_user_sound.h (renamed from vhost_user_sound.h) | 22 | ||||
-rw-r--r-- | include/virtio_loopback.h (renamed from virtio_loopback.h) | 61 | ||||
-rw-r--r-- | include/virtio_rng.h (renamed from virtio_rng.h) | 5 | ||||
-rw-r--r-- | linux/.fuse_hidden001086ab000006da | bin | 0 -> 16384 bytes | |||
-rw-r--r-- | linux/virtio_gpio.h | 72 | ||||
-rw-r--r-- | linux/virtio_snd.h | 334 | ||||
-rw-r--r-- | src/common/event_notifier.c (renamed from event_notifier.c) | 3 | ||||
-rw-r--r-- | src/devices/vhost_user_blk.c (renamed from vhost_user_blk.c) | 432 | ||||
-rw-r--r-- | src/devices/vhost_user_can.c | 179 | ||||
-rw-r--r-- | src/devices/vhost_user_console.c | 175 | ||||
-rw-r--r-- | src/devices/vhost_user_gpio.c | 204 | ||||
-rw-r--r-- | src/devices/vhost_user_input.c | 154 | ||||
-rw-r--r-- | src/devices/vhost_user_rng.c | 112 | ||||
-rw-r--r-- | src/devices/vhost_user_sound.c | 178 | ||||
-rw-r--r-- | src/devices/virtio_rng.c (renamed from virtio_rng.c) | 27 | ||||
-rw-r--r-- | src/lib/vhost_loopback.c (renamed from vhost_loopback.c) | 18 | ||||
-rw-r--r-- | src/lib/vhost_user_loopback.c (renamed from vhost_user_loopback.c) | 389 | ||||
-rw-r--r-- | src/lib/virtio_loopback.c (renamed from virtio_loopback.c) | 307 | ||||
-rw-r--r-- | vhost_user_can.c | 329 | ||||
-rw-r--r-- | vhost_user_console.c | 302 | ||||
-rw-r--r-- | vhost_user_gpio.c | 393 | ||||
-rw-r--r-- | vhost_user_input.c | 241 | ||||
-rw-r--r-- | vhost_user_input.h | 158 | ||||
-rw-r--r-- | vhost_user_rng.c | 219 | ||||
-rw-r--r-- | vhost_user_sound.c | 322 | ||||
-rw-r--r-- | virtio_blk.h | 95 | ||||
-rw-r--r-- | virtio_input.c | 331 |
41 files changed, 1779 insertions, 3842 deletions
@@ -18,8 +18,7 @@ # Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. -#CFLAGS := -Wno-unused-variable -Wno-unused-function -D_GNU_SOURCE -CFLAGS = -D_GNU_SOURCE -O2 -Wall -Wextra -Werror +CFLAGS := -D_GNU_SOURCE -O2 -Wall -Wextra -Werror -Wno-unused-variable -Wno-unused-function CC ?= @@ -27,14 +26,29 @@ ifeq ($(ARCH), arm64) # arm64 CC ?= aarch64-linux-gnu-gcc else - CC ?= gcc + ifeq ($(ARCH), riscv64) + # arm64 + CC ?= riscv64-linux-gnu-gcc + else + CC ?= gcc + endif endif INCL += -I . +INCL += -I ./include/ + DEPS = adapter.h vhost_user_loopback.h event_notifier.h virtio_loopback.h -SRC_C = event_notifier.c vhost_user_loopback.c virtio_loopback.c virtio_rng.c virtio_input.c vhost_user_input.c vhost_user_blk.c vhost_user_rng.c vhost_user_sound.c vhost_user_gpio.c vhost_user_can.c vhost_user_console.c vhost_loopback.c adapter.c +# Source directories +SRC_DIRS = src/adapter src/lib src/common src/lib src/devices + +# Source files +SRC_C = $(foreach dir, $(SRC_DIRS), $(wildcard $(dir)/*.c)) + +# Object files OBJS = $(SRC_C:.c=.o) + +# Binary output BINS = adapter ifeq ($(DEBUG), 1) @@ -43,15 +57,17 @@ endif all: $(BINS) +# Linking $(BINS): $(OBJS) @echo -e "CC\t$@" $(CC) $(CFLAGS) $(INCL) $^ -o $@ -lpthread +# Compilation %.o: %.c @echo -e "CC\t$@" $(CC) $(CFLAGS) $(INCL) -c $< -o $@ clean: - rm -f *.o *~ $(BINS) + rm -f $(OBJS) *~ $(BINS) .PHONY: all diff --git a/adapter.c b/adapter.c deleted file mode 100644 index 1dbde9b..0000000 --- a/adapter.c +++ /dev/null @@ -1,301 +0,0 @@ -/* - * Copyright 2022-2023 Virtual Open Systems SAS - * - * Authors: - * Timos Ampelikiotis <t.ampelikiotis@virtualopensystems.com> - * Stefanos Gerangelos <s.gerangelos@virtualopensystems.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * 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. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ - -#include <unistd.h> -#include <stdlib.h> -#include <stdio.h> -#include <stdint.h> -#include <string.h> -#include <sys/eventfd.h> -#include <fcntl.h> -#include <sys/ioctl.h> -#include <sys/mman.h> -#include <pthread.h> -#include <stdbool.h> -#include <sys/param.h> -#include <assert.h> - -/* For socket */ -#include <errno.h> -#include <sys/types.h> -#include <sys/socket.h> -#include <sys/un.h> - -/* Project header files */ -#include "adapter.h" - -/* Global variables */ -int client_sock; -struct vhost_dev *dev; -struct adapter_dev *adev; -struct vhost_user *vudev; - -void vhost_user_adapter_init(void) -{ - - DBG("Setup adapter data structures\n"); - - /* Init vhost-user device */ - vudev = (struct vhost_user *)malloc(sizeof(struct vhost_user)); - - /* Init vhost device */ - dev = (struct vhost_dev *)malloc(sizeof(struct vhost_dev)); - - /* Init virtio device */ - global_vdev = (VirtIODevice *)malloc(sizeof(VirtIODevice)); - - /* Init virtio bus */ - global_vbus = (VirtioBus *)malloc(sizeof(VirtioBus)); - global_vbus->vdev = global_vdev; - global_vdev->vbus = global_vbus; - global_vdev->vhdev = dev; - - - /* Store virtio_dev reference into vhost_dev struct*/ - dev->vdev = global_vdev; - - /* Init adapter device */ - adev = (struct adapter_dev *)malloc(sizeof(struct adapter_dev)); - adev->vdev = dev; - adev->vudev = vudev; - adev->virtio_dev = global_vdev; - adev->vbus = global_vbus; -} - -void client(char *sock_path) -{ - int rc, len; - struct sockaddr_un client_sockaddr; - - DBG("Create shared socket with vhost-user-device\n"); - - /* Initialize the struct to zero */ - memset(&client_sockaddr, 0, sizeof(struct sockaddr_un)); - - /* - * Create a UNIX socket - */ - client_sock = socket(AF_UNIX, SOCK_STREAM, 0); - if (client_sock == -1) { - DBG("SOCKET ERROR\n"); - exit(1); - } - - /* - * Set up the UNIX sockaddr structure - * by using AF_UNIX for the family and - * giving it a filepath to connect. - */ - client_sockaddr.sun_family = AF_UNIX; - strcpy(client_sockaddr.sun_path, sock_path); - len = sizeof(client_sockaddr); - rc = connect(client_sock, (struct sockaddr *) &client_sockaddr, len); - if (rc == -1) { - printf("CONNECT ERROR: Check the \"-s\" parameter\n"); - close(client_sock); - exit(1); - } -} - -static void help_args(void) -{ - printf("Run example:\n\t./adapter -s /path_to_socket/rng.sock\n" - "\t\t -d device_name\n" - "\t\t [ -qn number of queues ]\n" - "\t\t [ -qs size of queues ]\n" - "The 'device_name' can be one of the following:\n" - "\tvrng, vhurng, vhublk, vhuinput, vhusnd, vhugpio, vhucan, vhuconsole\n"); -} - -int find_arg(int argc, char **argv, char *str) -{ - int i; - - for (i = 0; i < argc; i++) { - if (!strcmp(argv[i], str)) { - return i + 1; - } - } - return -1; -} - -int val_device_arg(char *str) -{ - int adapter_devices_num = ADAPTER_DEVS, i; - - for (i = 0; i < adapter_devices_num; i++) { - if (!strcmp(adapter_devices[i], str)) { - return i + 1; - } - } - - return 0; -} - -bool check_vhu_device(char *str) -{ - int vhu_devices_num = VHU_DEVS, i; - - for (i = 0; i < vhu_devices_num; i++) { - if (!strcmp(vhu_devices[i], str)) { - return true; - } - } - - return false; -} - -void get_queue_num_size_args(int argc, char **argv, - int *eval_queue_num, int *eval_queue_size) -{ - int queue_num, queue_size, queue_num_id, queue_size_id; - - if (argc < 9) { - return; - } - - queue_num_id = find_arg(argc, argv, "-qn"); - queue_size_id = find_arg(argc, argv, "-qs"); - - /* Check if both qs ans qn exist */ - if (queue_num_id < 0 || queue_size_id < 0) { - return; - } - - queue_num = atoi(argv[queue_num_id]); - queue_size = atoi(argv[queue_size_id]); - - /* Evaluate number of queues */ - if (queue_num <= 0 || queue_num > 16) { - return; - } - - /* Evaluate queues' size */ - if (queue_size <= 0 || queue_size > 1024) { - return; - } - - *eval_queue_num = queue_num; - *eval_queue_size = queue_size; -} - - -int main(int argc, char **argv) -{ - int socket_idx, device_idx, device_id; - bool vhost_user_enabled; - /* Assign default queue num and size */ - int queue_num = 1, queue_size = 64; - - /* - * Check if the user has provided all the required arguments. - * If not, print the help messages. - */ - - if (argc < 3) { - goto error_args; - } - - device_idx = find_arg(argc, argv, "-d"); - - if (device_idx < 0) { - printf("You have not specified parameter \"-d\"\n"); - goto error_args; - } - - /* Validate the argumetns */ - device_id = val_device_arg(argv[device_idx]); - - if (device_id == 0) { - goto error_args; - } - - /* Check if this is a vhost-user device */ - vhost_user_enabled = check_vhu_device(argv[device_idx]); - - /* Check if a socket is needed and provided */ - socket_idx = find_arg(argc, argv, "-s"); - - if ((socket_idx < 0) && (vhost_user_enabled)) { - printf("You have not specified parameter \"-s\"\n"); - goto error_args; - } - - /* - * Create the socket and connect to the backend. - * Enabled on vhost-user case - */ - if (vhost_user_enabled) { - client(argv[socket_idx]); - } - - /* Initialize the adapter data structures */ - vhost_user_adapter_init(); - - /* Get queue number and size from arguments */ - get_queue_num_size_args(argc, argv, &queue_num, &queue_size); - - /* Initialize the virtio/vhost-user device */ - /* TODO: Switch numbers with name defs */ - switch (device_id) { - case 1: - virtio_rng_realize(queue_num, queue_size); - break; - case 2: - vhost_user_rng_realize(queue_num, queue_size); - break; - case 3: - printf("Running vhublk with num %d and size %d\n", - queue_num, queue_size); - vhost_user_blk_realize(queue_num, queue_size); - break; - case 4: - vhost_user_input_init(global_vdev); - virtio_input_device_realize(queue_num, queue_size); - break; - case 5: - vus_device_realize(queue_num, queue_size); - break; - case 6: - vu_gpio_device_realize(queue_num, queue_size); - break; - case 7: - vhost_user_can_realize(queue_num, queue_size); - break; - case 8: - vhost_user_console_realize(queue_num, queue_size); - break; - default: - exit(1); - } - - /* - * Start loopback trasnport layer and communiation with the loopback driver - */ - virtio_loopback_start(); - - return 0; - -error_args: - help_args(); - return 1; -} diff --git a/adapter.h b/include/adapter.h index 99a5856..601ed23 100644 --- a/adapter.h +++ b/include/adapter.h @@ -35,19 +35,10 @@ #include "vhost_user_can.h" #include "vhost_user_console.h" -#ifdef DEBUG -#define DBG(...) printf("adapter: " __VA_ARGS__) -#else -#define DBG(...) -#endif /* DEBUG */ +extern Device devices[MAX_DEVICES]; -#define VHU_DEVS 8 -#define ADAPTER_DEVS (VHU_DEVS + 1) - -const char *adapter_devices[] = {"vrng", "vhurng", "vhublk", "vhuinput", - "vhusnd", "vhugpio", "vhucan", - "vhuconsole" }; -const char *vhu_devices[] = {"vhurng", "vhublk", "vhuinput", "vhusnd", - "vhugpio", "vhucan", "vhuconsole"}; +/* Global functions */ +int parse_args(int argc, char *argv[]); +void help_args(void); #endif /* ADAPTER */ diff --git a/event_notifier.h b/include/event_notifier.h index 718f784..718f784 100644 --- a/event_notifier.h +++ b/include/event_notifier.h diff --git a/include/parser.h b/include/parser.h new file mode 100644 index 0000000..f37e41d --- /dev/null +++ b/include/parser.h @@ -0,0 +1,42 @@ +/* + * Copyright (c) 2022-2024 Virtual Open Systems SAS. + * + * Author: + * Timos Ampelikiotis <t.ampelikiotis@virtualopensystems.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * 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. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef PARSER_H +#define PARSER_H + +/* Project header files */ +#include "adapter.h" + +// Default values for queue_num and queue_size +#define DEFAULT_QUEUE_NUM 1 +#define DEFAULT_QUEUE_SIZE 1024 + +/* Global variables */ +const char *adapter_devices[] = {"vrng", "vhurng", "vhublk", + "vhuinput", "vhusnd", "vhugpio", + "vhucan", "vhuconsole"}; +const char *vhu_devices[] = {"vhurng", "vhublk", "vhuinput", + "vhusnd", "vhugpio", "vhucan", + "vhuconsole"}; +const unsigned int num_adapter_devices = sizeof(adapter_devices) / sizeof(adapter_devices[0]); +const unsigned int num_vhu_devices = num_adapter_devices - 1; + +#endif /* PARSER_H */ diff --git a/queue.h b/include/queue.h index e029e7b..e029e7b 100644 --- a/queue.h +++ b/include/queue.h diff --git a/vhost_loopback.h b/include/vhost_loopback.h index 198a5af..198a5af 100644 --- a/vhost_loopback.h +++ b/include/vhost_loopback.h diff --git a/vhost_user_blk.h b/include/vhost_user_blk.h index d5857c8..3b25dfe 100644 --- a/vhost_user_blk.h +++ b/include/vhost_user_blk.h @@ -54,6 +54,6 @@ struct VHostUserBlk { bool started_vu; }; -void vhost_user_blk_realize(int queue_num, int queue_size); +void vhost_user_blk_realize(struct adapter_dev *adev); #endif /* VHOST_USER_BLK */ diff --git a/vhost_user_can.h b/include/vhost_user_can.h index a4615be..4768499 100644 --- a/vhost_user_can.h +++ b/include/vhost_user_can.h @@ -43,15 +43,12 @@ typedef struct VHostUserCan { uint32_t queue_size; struct virtio_can_config config; struct vhost_dev *vhost_dev; - VirtQueue *ctrl_vq; - VirtQueue *tx_vq; - VirtQueue *rx_vq; /* Support classic CAN */ bool support_can_classic; /* Support CAN FD */ bool support_can_fd; } VHostUserCan; -void vhost_user_can_realize(int queue_num, int queue_size); +void vhost_user_can_realize(struct adapter_dev *adev); #endif /* VHOST_USER_CAN */ diff --git a/vhost_user_console.h b/include/vhost_user_console.h index f1a03eb..9f0eed8 100644 --- a/vhost_user_console.h +++ b/include/vhost_user_console.h @@ -20,16 +20,6 @@ #define VIRTIO_CONSOLE_F_MULTIPORT 1 /* Does host provide multiple ports? */ #define VIRTIO_CONSOLE_F_EMERG_WRITE 2 /* Does host support emergency write? */ -/* Some events for control messages */ -#define VIRTIO_CONSOLE_DEVICE_READY 0 -#define VIRTIO_CONSOLE_PORT_ADD 1 -#define VIRTIO_CONSOLE_PORT_REMOVE 2 -#define VIRTIO_CONSOLE_PORT_READY 3 -#define VIRTIO_CONSOLE_CONSOLE_PORT 4 -#define VIRTIO_CONSOLE_RESIZE 5 -#define VIRTIO_CONSOLE_PORT_OPEN 6 -#define VIRTIO_CONSOLE_PORT_NAME 7 - struct virtio_console_config { /* colums of the screens */ __virtio16 cols; @@ -41,16 +31,6 @@ struct virtio_console_config { __virtio32 emerg_wr; }; -/* - * A message that's passed between the Host and the Guest for a - * particular port. - */ -struct virtio_console_control { - __virtio32 id; /* Port number */ - __virtio16 event; /* The kind of control event (see below) */ - __virtio16 value; /* Extra information for the key */ -}; - typedef struct VHostUserConsole { VirtIODevice *parent; struct vhost_virtqueue *vhost_vqs; @@ -59,12 +39,8 @@ typedef struct VHostUserConsole { uint32_t queue_size; struct virtio_console_config config; struct vhost_dev *vhost_dev; - VirtQueue *rx_vq; - VirtQueue *tx_vq; - VirtQueue *ctrl_rx_vq; - VirtQueue *ctrl_tx_vq; } VHostUserConsole; -void vhost_user_console_realize(int queue_num, int queue_size); +void vhost_user_console_realize(struct adapter_dev *adev); #endif /* VHOST_USER_CONSOLE */ diff --git a/vhost_user_gpio.h b/include/vhost_user_gpio.h index 7bf8ac8..4d77e0a 100644 --- a/vhost_user_gpio.h +++ b/include/vhost_user_gpio.h @@ -1,7 +1,7 @@ /* * Based on virtio-gpio.h of QEMU project * - * Copyright (c) 2023 Virtual Open Systems SAS. + * Copyright (c) 2023-2024 Virtual Open Systems SAS. * * This work is licensed under the terms of the GNU GPL, version 2 or * (at your option) any later version. See the COPYING file in the @@ -14,24 +14,24 @@ #include "vhost_loopback.h" #include "vhost_user_loopback.h" #include "virtio_loopback.h" -#include <linux/virtio_gpio.h> -#include "queue.h" -#include <sys/mman.h> -#define TYPE_VHOST_USER_GPIO "vhost-user-gpio-device" #define VIRTIO_GPIO_F_IRQ 0 +struct virtio_gpio_config { + uint16_t ngpio; + uint8_t padding[2]; + uint32_t gpio_names_size; +}; + struct VHostUserGPIO { VirtIODevice *parent; struct virtio_gpio_config config; struct vhost_virtqueue *vhost_vqs; struct vhost_dev *vhost_dev; - VirtQueue *command_vq; - VirtQueue *interrupt_vq; - bool connected; - bool started_vu; + uint16_t num_queues; + uint32_t queue_size; }; -void vu_gpio_device_realize(int queue_num, int queue_size); +void vu_gpio_device_realize(struct adapter_dev *adev); #endif /* VHOST_USER_GPIO */ diff --git a/include/vhost_user_input.h b/include/vhost_user_input.h new file mode 100644 index 0000000..8137694 --- /dev/null +++ b/include/vhost_user_input.h @@ -0,0 +1,30 @@ +/* + * Based on virtio-input.h of QEMU project + * + * Copyright (c) 2022-2024 Virtual Open Systems SAS. + * + * This work is licensed under the terms of the GNU GPL, version 2 or + * (at your option) any later version. See the COPYING file in the + * top-level directory. + */ + +#ifndef VHOST_USER_INPUT +#define VHOST_USER_INPUT + +#include "vhost_loopback.h" +#include "vhost_user_loopback.h" +#include "virtio_loopback.h" +#include <linux/virtio_input.h> + +typedef struct VhostUserInput { + VirtIODevice *parent; + struct vhost_dev *vhost_dev; + struct virtio_input_config config; + VirtQueue *evt, *sts; + bool started; + bool completed; +} VhostUserInput; + +void virtio_input_device_realize(struct adapter_dev *adev); + +#endif /* VHOST_USER_INPUT */ diff --git a/vhost_user_loopback.h b/include/vhost_user_loopback.h index 14919e1..3aa8e8c 100644 --- a/vhost_user_loopback.h +++ b/include/vhost_user_loopback.h @@ -36,16 +36,6 @@ #include "virtio_loopback.h" #include "queue.h" -typedef struct adapter_dev { - struct vhost_dev *vdev; - struct vhost_user *vudev; - VirtIODevice *virtio_dev; - VirtioBus *vbus; -} AdapterDev; - - - - struct scrub_regions { struct vhost_memory_region *region; int reg_idx; @@ -89,6 +79,7 @@ typedef struct MemoryRegionSection { struct vhost_dev { VirtIODevice *vdev; + struct vhost_user *vhudev; struct vhost_memory *mem; int n_mem_sections; MemoryRegionSection *mem_sections; @@ -120,7 +111,7 @@ struct vhost_dev { }; -#define VHOST_USER_MAX_RAM_SLOTS 32 +#define VHOST_USER_MAX_RAM_SLOTS 16 typedef uint64_t ram_addr_t; typedef struct RAMBlock RAMBlock; @@ -236,11 +227,47 @@ struct vhost_user { struct vhost_memory_region shadow_regions[VHOST_USER_MAX_RAM_SLOTS]; }; -/* Global variables */ -extern int client_sock; -extern struct vhost_dev *dev; -extern struct adapter_dev *adev; -extern struct vhost_user *vudev; +#define MAX_DEVICES 100 +#define MAX_NAME_LENGTH 256 +#define MAX_SOCKET_LENGTH 256 + +typedef struct Device { + char device_name[MAX_NAME_LENGTH]; + char socket[MAX_SOCKET_LENGTH]; + int queue_num; + int queue_size; + int device_index; + int requires_socket; + int client_socket; +} Device; + +typedef struct adapter_dev { + struct vhost_dev vdev; + struct vhost_user vudev; + VirtIODevice virtio_dev; + VirtioBus vbus; + Device *device_params; + /* More variables */ + int loopback_fd; + int efd; /* Eventfd file descriptor */ + virtio_neg_t *address; + virtio_device_info_struct_t device_info; + VirtIOMMIOProxy proxy; +} AdapterDev; + +#define container_of_a(ptr, type, member) \ + ((type *)((char *)(ptr) - offsetof(type, member))) + +/* +#define to_vhost_user_device(ptr, field) \ + container_of_a(ptr, struct vhost_user, field) + +#define virtio_to_vhost_dev(ptr, field) \ + container_of_a(ptr, struct vhost_dev, field) + +*/ +#define to_adapter_device(ptr, field) \ + container_of(ptr, struct adapter_dev, field) /* Based on qemu/hw/virtio/vhost-user.c */ #define VHOST_USER_F_PROTOCOL_FEATURES 30 @@ -912,20 +939,21 @@ bool vu_queue_avail_bytes(VuDev *dev, VuVirtq *vq, unsigned int in_bytes, bool vhost_user_one_time_request(VhostUserRequest request); void vmsg_close_fds(VhostUserMsg *vmsg); -int vhost_user_set_owner(void); -int process_message_reply(const VhostUserMsg *msg); -int vhost_user_get_u64(int request, uint64_t *u64); -int vhost_user_get_features(uint64_t *features); -int enforce_reply(const VhostUserMsg *msg); -int vhost_user_set_u64(int request, uint64_t u64, bool wait_for_reply); -int vhost_user_set_protocol_features(uint64_t features); -int vhost_user_get_max_memslots(uint64_t *max_memslots); +int vhost_user_set_owner(struct vhost_dev *dev); +int process_message_reply(struct vhost_dev *dev, const VhostUserMsg *msg); +int vhost_user_get_u64(struct vhost_dev *dev, int request, uint64_t *u64); +int vhost_user_get_features(struct vhost_dev *dev, uint64_t *features); +int enforce_reply(struct vhost_dev *dev, const VhostUserMsg *msg); +int vhost_user_set_u64(struct vhost_dev *dev, int request, uint64_t u64, bool wait_for_reply); +int vhost_user_set_protocol_features(struct vhost_dev *dev, uint64_t features); +int vhost_user_get_max_memslots(struct vhost_dev *dev, uint64_t *max_memslots); int vhost_setup_slave_channel(struct vhost_dev *dev); int vhost_user_get_vq_index(struct vhost_dev *dev, int idx); -int vhost_set_vring_file(VhostUserRequest request, - struct vhost_vring_file *file); -int vhost_user_set_vring_kick(struct vhost_vring_file *file); -int vhost_user_set_vring_call(struct vhost_vring_file *file); +int vhost_set_vring_file(struct vhost_dev *dev, + VhostUserRequest request, + struct vhost_vring_file *file); +int vhost_user_set_vring_kick(struct vhost_dev *dev, struct vhost_vring_file *file); +int vhost_user_set_vring_call(struct vhost_dev *dev, struct vhost_vring_file *file); int vhost_virtqueue_init(struct vhost_dev *dev, struct vhost_virtqueue *vq, int n); void vhost_dev_init(struct vhost_dev *vhdev); @@ -953,7 +981,7 @@ void vhost_commit_vqs(struct vhost_dev *dev); void find_add_new_reg(struct vhost_dev *dev); void print_mem_table(struct vhost_dev *dev); void print_vhost_user_messages(int request); - +void vhost_user_dev_class_init(VirtIODevice *vdev); /* FIXME: This need to move in a better place */ struct vhost_inflight; @@ -963,5 +991,4 @@ int vhost_user_get_inflight_fd(struct vhost_dev *dev, int vhost_user_set_inflight_fd(struct vhost_dev *dev, struct vhost_inflight *inflight); - #endif /* LIBVHOST_USER_H */ diff --git a/vhost_user_rng.h b/include/vhost_user_rng.h index 4627c50..b6f58da 100644 --- a/vhost_user_rng.h +++ b/include/vhost_user_rng.h @@ -39,6 +39,5 @@ typedef struct VHostUserRNG { bool connected; } VHostUserRNG; -void vhost_user_rng_realize(int queue_num, int queue_size); - +void vhost_user_rng_realize(struct adapter_dev *adev); #endif /* VHOST_USER_RNG */ diff --git a/vhost_user_sound.h b/include/vhost_user_sound.h index d802bc0..e63e9d3 100644 --- a/vhost_user_sound.h +++ b/include/vhost_user_sound.h @@ -3,7 +3,7 @@ * * Copyright 2020 Red Hat, Inc. * - * Copyright (c) 2023 Virtual Open Systems SAS. + * Copyright (c) 2023-2024 Virtual Open Systems SAS. * * This work is licensed under the terms of the GNU GPL, version 2 or * (at your option) any later version. See the COPYING file in the @@ -17,10 +17,17 @@ #include "virtio_loopback.h" #include "vhost_loopback.h" #include "vhost_user_loopback.h" -#include <linux/virtio_snd.h> + +struct virtio_snd_config { + /* # of available physical jacks */ + uint32_t jacks; + /* # of available PCM streams */ + uint32_t streams; + /* # of available channel maps */ + uint32_t chmaps; +}; typedef struct VHostUserSound { - /*< private >*/ VirtIODevice *parent; struct vhost_virtqueue *vhost_vqs; VirtQueue **virtqs; @@ -28,13 +35,8 @@ typedef struct VHostUserSound { uint32_t queue_size; struct virtio_snd_config config; struct vhost_dev *vhost_dev; - VirtQueue *ctrl_vq; - VirtQueue *event_vq; - VirtQueue *tx_vq; - VirtQueue *rx_vq; - /*< public >*/ } VHostUserSound; -void vus_device_realize(int queue_num, int queue_size); +void vus_device_realize(struct adapter_dev *adev); -#endif /* VHOST_USER_BLK */ +#endif /* VHOST_USER_SOUND */ diff --git a/virtio_loopback.h b/include/virtio_loopback.h index 62e404c..d8e68f1 100644 --- a/virtio_loopback.h +++ b/include/virtio_loopback.h @@ -165,7 +165,7 @@ sizeof(virtio_device_info_struct_t)) #define IRQ _IOC(_IOC_WRITE, 'k', 4, sizeof(int)) #define SHARE_VQS _IOC(_IOC_WRITE, 'k', 5, sizeof(uint32_t)) -#define SHARE_COM_STRUCT _IOC(_IOC_WRITE, 'k', 7, 0) +#define SHARE_COM_STRUCT _IOC(_IOC_WRITE, 'k', 6, 0) #define VIRTIO_PCI_VRING_ALIGN 4096 @@ -254,14 +254,10 @@ typedef struct VirtIOMMIOProxy { #define VRING_DESC_ALIGN_SIZE 16 /******************/ - #define container_of(ptr, type, member) ({ \ const typeof(((type *) 0)->member) *__mptr = (ptr); \ (type *) ((char *) __mptr - offsetof(type, member));}) -extern uint64_t vring_phys_addrs[10]; -extern uint32_t vring_phys_addrs_idx; - typedef struct VRing { unsigned int num; unsigned int num_default; @@ -356,7 +352,6 @@ typedef struct VirtQueue { } VirtQueue; typedef struct VirtIORNG VirtIORNG; -typedef struct VirtIOInput VirtIOInput; typedef struct VHostUserRNG VHostUserRNG; typedef struct VirtioDeviceClass VirtioDeviceClass; typedef struct VHostUserBlk VHostUserBlk; @@ -382,10 +377,20 @@ typedef struct VirtIODevice { void *config; uint16_t config_vector; uint32_t generation; + int last_avail; + int prev_level; + int int_count; + int eventfd_count; + int notify_cnt; + bool enable_virtio_interrupt; + pthread_mutex_t interrupt_lock; int nvectors; VirtQueue *vq; VirtQueue **vqs; int *nvqs; + /* TODO: Put a defined value for vq num */ + uint64_t vring_phys_addrs[12]; + uint32_t vring_phys_addrs_idx; uint16_t device_id; bool vm_running; bool broken; /* device in invalid state, needs reset */ @@ -398,16 +403,17 @@ typedef struct VirtIODevice { char *bus_name; uint8_t device_endian; bool use_guest_notifier_mask; - /* TODO: Switch to union? */ - VirtIORNG *vrng; - VirtIOInput *vinput; - VHostUserRNG *vhrng; - VHostUserBlk *vhublk; - VhostUserInput *vhuinput; - VHostUserSound *vhusnd; - VHostUserGPIO *vhugpio; - VHostUserCan *vhucan; - VHostUserConsole *vhuconsole; + union { + VirtIORNG *vrng; + VHostUserRNG *vhrng; + VHostUserBlk *vhublk; + VhostUserInput *vhuinput; + VHostUserSound *vhusnd; + VHostUserGPIO *vhugpio; + VHostUserCan *vhucan; + VHostUserConsole *vhuconsole; + }; + const int *user_feature_bits; } VirtIODevice; typedef struct efd_data { @@ -520,6 +526,7 @@ typedef struct VirtioBus { int ioeventfd_grabbed; } VirtioBus; +struct adapter_dev; typedef struct VirtioDeviceClass { /*< private >*/ @@ -535,8 +542,10 @@ typedef struct VirtioDeviceClass { void (*set_config)(VirtIODevice *vdev, const uint8_t *config); void (*reset)(VirtIODevice *vdev); void (*set_status)(VirtIODevice *vdev, uint8_t val); - void (*realize)(int queue_num, int queue_size); + void (*realize)(struct adapter_dev *adev); void (*unrealize)(VirtIODevice *vdev); + void (*start)(VirtIODevice *vdev); + void (*stop)(VirtIODevice *vdev); /* * For transitional devices, this is a bitmap of features * that are only exposed on the legacy interface but not @@ -578,19 +587,15 @@ typedef struct VirtioDeviceClass { struct vhost_dev *(*get_vhost)(VirtIODevice *vdev); } VirtioDeviceClass; -/* Global variables */ -extern int fd; -extern int loopback_fd; - void handle_input(VirtIODevice *vdev, VirtQueue *vq); void *my_select(void *data); void *wait_read_write(void *data); void virtio_notify_config(VirtIODevice *vdev); -void create_rng_struct(void); void print_neg_flag(uint64_t neg_flag, bool read); -void adapter_read_write_cb(void); -int virtio_loopback_start(void); +void adapter_read_write_cb(struct adapter_dev *adev); +int virtio_loopback_start(struct adapter_dev *adev, pthread_t *thread_id); +void virtio_loopback_stop(struct adapter_dev *adev); int virtio_queue_ready(VirtQueue *vq); void virtqueue_get_avail_bytes(VirtQueue *vq, unsigned int *in_bytes, unsigned int *out_bytes, @@ -657,6 +662,8 @@ uint32_t get_vqs_max_size(VirtIODevice *vdev); #define VIRTIO_CONFIG_S_DRIVER_OK 4 #define VIRTIO_F_VERSION_1 32 #define VIRTIO_F_ACCESS_PLATFORM 33 +#define VIRTIO_F_IN_ORDER 35 +#define VIRTIO_F_NOTIFICATION_DATA 38 /* * Legacy name for VIRTIO_F_ACCESS_PLATFORM @@ -705,10 +712,4 @@ uint32_t get_vqs_max_size(VirtIODevice *vdev); */ #define INIT_PA 0 - -extern VirtIODevice *global_vdev; -extern VirtIOMMIOProxy *proxy; -extern VirtioBus *global_vbus; - #endif /* VIRTIO_LOOPBACK */ - diff --git a/virtio_rng.h b/include/virtio_rng.h index 4264b45..6e97294 100644 --- a/virtio_rng.h +++ b/include/virtio_rng.h @@ -20,6 +20,7 @@ #define VIRTIO_RNG_DEV #include "virtio_loopback.h" +#include "vhost_user_loopback.h" extern const char test_str[64]; @@ -48,8 +49,8 @@ bool is_guest_ready(VirtIORNG *vrng); size_t get_request_size(VirtQueue *vq, unsigned quota); void virtio_rng_set_status(VirtIODevice *vdev, uint8_t status); void virtio_rng_process(VirtIORNG *vrng); -void chr_read(VirtIORNG *vrng, const void *buf, size_t size); -void virtio_rng_realize(int queue_num, int queue_size); +void chr_read(VirtIORNG *vrng, const char *buf, size_t size); +void virtio_rng_realize(struct adapter_dev *adev); void virtio_rng_init(VirtIODevice *vdev); #endif /* VIRTIO_RNG */ diff --git a/linux/.fuse_hidden001086ab000006da b/linux/.fuse_hidden001086ab000006da Binary files differnew file mode 100644 index 0000000..ce99873 --- /dev/null +++ b/linux/.fuse_hidden001086ab000006da diff --git a/linux/virtio_gpio.h b/linux/virtio_gpio.h deleted file mode 100644 index d4b29d9..0000000 --- a/linux/virtio_gpio.h +++ /dev/null @@ -1,72 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */ - -#ifndef _LINUX_VIRTIO_GPIO_H -#define _LINUX_VIRTIO_GPIO_H - -#include <linux/types.h> - -/* Virtio GPIO Feature bits */ -#define VIRTIO_GPIO_F_IRQ 0 - -/* Virtio GPIO request types */ -#define VIRTIO_GPIO_MSG_GET_NAMES 0x0001 -#define VIRTIO_GPIO_MSG_GET_DIRECTION 0x0002 -#define VIRTIO_GPIO_MSG_SET_DIRECTION 0x0003 -#define VIRTIO_GPIO_MSG_GET_VALUE 0x0004 -#define VIRTIO_GPIO_MSG_SET_VALUE 0x0005 -#define VIRTIO_GPIO_MSG_IRQ_TYPE 0x0006 - -/* Possible values of the status field */ -#define VIRTIO_GPIO_STATUS_OK 0x0 -#define VIRTIO_GPIO_STATUS_ERR 0x1 - -/* Direction types */ -#define VIRTIO_GPIO_DIRECTION_NONE 0x00 -#define VIRTIO_GPIO_DIRECTION_OUT 0x01 -#define VIRTIO_GPIO_DIRECTION_IN 0x02 - -/* Virtio GPIO IRQ types */ -#define VIRTIO_GPIO_IRQ_TYPE_NONE 0x00 -#define VIRTIO_GPIO_IRQ_TYPE_EDGE_RISING 0x01 -#define VIRTIO_GPIO_IRQ_TYPE_EDGE_FALLING 0x02 -#define VIRTIO_GPIO_IRQ_TYPE_EDGE_BOTH 0x03 -#define VIRTIO_GPIO_IRQ_TYPE_LEVEL_HIGH 0x04 -#define VIRTIO_GPIO_IRQ_TYPE_LEVEL_LOW 0x08 - -struct virtio_gpio_config { - __le16 ngpio; - __u8 padding[2]; - __le32 gpio_names_size; -}; - -/* Virtio GPIO Request / Response */ -struct virtio_gpio_request { - __le16 type; - __le16 gpio; - __le32 value; -}; - -struct virtio_gpio_response { - __u8 status; - __u8 value; -}; - -struct virtio_gpio_response_get_names { - __u8 status; - __u8 value[]; -}; - -/* Virtio GPIO IRQ Request / Response */ -struct virtio_gpio_irq_request { - __le16 gpio; -}; - -struct virtio_gpio_irq_response { - __u8 status; -}; - -/* Possible values of the interrupt status field */ -#define VIRTIO_GPIO_IRQ_STATUS_INVALID 0x0 -#define VIRTIO_GPIO_IRQ_STATUS_VALID 0x1 - -#endif /* _LINUX_VIRTIO_GPIO_H */ diff --git a/linux/virtio_snd.h b/linux/virtio_snd.h deleted file mode 100644 index dfe4954..0000000 --- a/linux/virtio_snd.h +++ /dev/null @@ -1,334 +0,0 @@ -/* SPDX-License-Identifier: BSD-3-Clause */ -/* - * Copyright (C) 2021 OpenSynergy GmbH - */ -#ifndef VIRTIO_SND_IF_H -#define VIRTIO_SND_IF_H - -#include <linux/virtio_types.h> - -/******************************************************************************* - * CONFIGURATION SPACE - */ -struct virtio_snd_config { - /* # of available physical jacks */ - __le32 jacks; - /* # of available PCM streams */ - __le32 streams; - /* # of available channel maps */ - __le32 chmaps; -}; - -enum { - /* device virtqueue indexes */ - VIRTIO_SND_VQ_CONTROL = 0, - VIRTIO_SND_VQ_EVENT, - VIRTIO_SND_VQ_TX, - VIRTIO_SND_VQ_RX, - /* # of device virtqueues */ - VIRTIO_SND_VQ_MAX -}; - -/******************************************************************************* - * COMMON DEFINITIONS - */ - -/* supported dataflow directions */ -enum { - VIRTIO_SND_D_OUTPUT = 0, - VIRTIO_SND_D_INPUT -}; - -enum { - /* jack control request types */ - VIRTIO_SND_R_JACK_INFO = 1, - VIRTIO_SND_R_JACK_REMAP, - - /* PCM control request types */ - VIRTIO_SND_R_PCM_INFO = 0x0100, - VIRTIO_SND_R_PCM_SET_PARAMS, - VIRTIO_SND_R_PCM_PREPARE, - VIRTIO_SND_R_PCM_RELEASE, - VIRTIO_SND_R_PCM_START, - VIRTIO_SND_R_PCM_STOP, - - /* channel map control request types */ - VIRTIO_SND_R_CHMAP_INFO = 0x0200, - - /* jack event types */ - VIRTIO_SND_EVT_JACK_CONNECTED = 0x1000, - VIRTIO_SND_EVT_JACK_DISCONNECTED, - - /* PCM event types */ - VIRTIO_SND_EVT_PCM_PERIOD_ELAPSED = 0x1100, - VIRTIO_SND_EVT_PCM_XRUN, - - /* common status codes */ - VIRTIO_SND_S_OK = 0x8000, - VIRTIO_SND_S_BAD_MSG, - VIRTIO_SND_S_NOT_SUPP, - VIRTIO_SND_S_IO_ERR -}; - -/* common header */ -struct virtio_snd_hdr { - __le32 code; -}; - -/* event notification */ -struct virtio_snd_event { - /* VIRTIO_SND_EVT_XXX */ - struct virtio_snd_hdr hdr; - /* optional event data */ - __le32 data; -}; - -/* common control request to query an item information */ -struct virtio_snd_query_info { - /* VIRTIO_SND_R_XXX_INFO */ - struct virtio_snd_hdr hdr; - /* item start identifier */ - __le32 start_id; - /* item count to query */ - __le32 count; - /* item information size in bytes */ - __le32 size; -}; - -/* common item information header */ -struct virtio_snd_info { - /* function group node id (High Definition Audio Specification 7.1.2) */ - __le32 hda_fn_nid; -}; - -/******************************************************************************* - * JACK CONTROL MESSAGES - */ -struct virtio_snd_jack_hdr { - /* VIRTIO_SND_R_JACK_XXX */ - struct virtio_snd_hdr hdr; - /* 0 ... virtio_snd_config::jacks - 1 */ - __le32 jack_id; -}; - -/* supported jack features */ -enum { - VIRTIO_SND_JACK_F_REMAP = 0 -}; - -struct virtio_snd_jack_info { - /* common header */ - struct virtio_snd_info hdr; - /* supported feature bit map (1 << VIRTIO_SND_JACK_F_XXX) */ - __le32 features; - /* pin configuration (High Definition Audio Specification 7.3.3.31) */ - __le32 hda_reg_defconf; - /* pin capabilities (High Definition Audio Specification 7.3.4.9) */ - __le32 hda_reg_caps; - /* current jack connection status (0: disconnected, 1: connected) */ - __u8 connected; - - __u8 padding[7]; -}; - -/* jack remapping control request */ -struct virtio_snd_jack_remap { - /* .code = VIRTIO_SND_R_JACK_REMAP */ - struct virtio_snd_jack_hdr hdr; - /* selected association number */ - __le32 association; - /* selected sequence number */ - __le32 sequence; -}; - -/******************************************************************************* - * PCM CONTROL MESSAGES - */ -struct virtio_snd_pcm_hdr { - /* VIRTIO_SND_R_PCM_XXX */ - struct virtio_snd_hdr hdr; - /* 0 ... virtio_snd_config::streams - 1 */ - __le32 stream_id; -}; - -/* supported PCM stream features */ -enum { - VIRTIO_SND_PCM_F_SHMEM_HOST = 0, - VIRTIO_SND_PCM_F_SHMEM_GUEST, - VIRTIO_SND_PCM_F_MSG_POLLING, - VIRTIO_SND_PCM_F_EVT_SHMEM_PERIODS, - VIRTIO_SND_PCM_F_EVT_XRUNS -}; - -/* supported PCM sample formats */ -enum { - /* analog formats (width / physical width) */ - VIRTIO_SND_PCM_FMT_IMA_ADPCM = 0, /* 4 / 4 bits */ - VIRTIO_SND_PCM_FMT_MU_LAW, /* 8 / 8 bits */ - VIRTIO_SND_PCM_FMT_A_LAW, /* 8 / 8 bits */ - VIRTIO_SND_PCM_FMT_S8, /* 8 / 8 bits */ - VIRTIO_SND_PCM_FMT_U8, /* 8 / 8 bits */ - VIRTIO_SND_PCM_FMT_S16, /* 16 / 16 bits */ - VIRTIO_SND_PCM_FMT_U16, /* 16 / 16 bits */ - VIRTIO_SND_PCM_FMT_S18_3, /* 18 / 24 bits */ - VIRTIO_SND_PCM_FMT_U18_3, /* 18 / 24 bits */ - VIRTIO_SND_PCM_FMT_S20_3, /* 20 / 24 bits */ - VIRTIO_SND_PCM_FMT_U20_3, /* 20 / 24 bits */ - VIRTIO_SND_PCM_FMT_S24_3, /* 24 / 24 bits */ - VIRTIO_SND_PCM_FMT_U24_3, /* 24 / 24 bits */ - VIRTIO_SND_PCM_FMT_S20, /* 20 / 32 bits */ - VIRTIO_SND_PCM_FMT_U20, /* 20 / 32 bits */ - VIRTIO_SND_PCM_FMT_S24, /* 24 / 32 bits */ - VIRTIO_SND_PCM_FMT_U24, /* 24 / 32 bits */ - VIRTIO_SND_PCM_FMT_S32, /* 32 / 32 bits */ - VIRTIO_SND_PCM_FMT_U32, /* 32 / 32 bits */ - VIRTIO_SND_PCM_FMT_FLOAT, /* 32 / 32 bits */ - VIRTIO_SND_PCM_FMT_FLOAT64, /* 64 / 64 bits */ - /* digital formats (width / physical width) */ - VIRTIO_SND_PCM_FMT_DSD_U8, /* 8 / 8 bits */ - VIRTIO_SND_PCM_FMT_DSD_U16, /* 16 / 16 bits */ - VIRTIO_SND_PCM_FMT_DSD_U32, /* 32 / 32 bits */ - VIRTIO_SND_PCM_FMT_IEC958_SUBFRAME /* 32 / 32 bits */ -}; - -/* supported PCM frame rates */ -enum { - VIRTIO_SND_PCM_RATE_5512 = 0, - VIRTIO_SND_PCM_RATE_8000, - VIRTIO_SND_PCM_RATE_11025, - VIRTIO_SND_PCM_RATE_16000, - VIRTIO_SND_PCM_RATE_22050, - VIRTIO_SND_PCM_RATE_32000, - VIRTIO_SND_PCM_RATE_44100, - VIRTIO_SND_PCM_RATE_48000, - VIRTIO_SND_PCM_RATE_64000, - VIRTIO_SND_PCM_RATE_88200, - VIRTIO_SND_PCM_RATE_96000, - VIRTIO_SND_PCM_RATE_176400, - VIRTIO_SND_PCM_RATE_192000, - VIRTIO_SND_PCM_RATE_384000 -}; - -struct virtio_snd_pcm_info { - /* common header */ - struct virtio_snd_info hdr; - /* supported feature bit map (1 << VIRTIO_SND_PCM_F_XXX) */ - __le32 features; - /* supported sample format bit map (1 << VIRTIO_SND_PCM_FMT_XXX) */ - __le64 formats; - /* supported frame rate bit map (1 << VIRTIO_SND_PCM_RATE_XXX) */ - __le64 rates; - /* dataflow direction (VIRTIO_SND_D_XXX) */ - __u8 direction; - /* minimum # of supported channels */ - __u8 channels_min; - /* maximum # of supported channels */ - __u8 channels_max; - - __u8 padding[5]; -}; - -/* set PCM stream format */ -struct virtio_snd_pcm_set_params { - /* .code = VIRTIO_SND_R_PCM_SET_PARAMS */ - struct virtio_snd_pcm_hdr hdr; - /* size of the hardware buffer */ - __le32 buffer_bytes; - /* size of the hardware period */ - __le32 period_bytes; - /* selected feature bit map (1 << VIRTIO_SND_PCM_F_XXX) */ - __le32 features; - /* selected # of channels */ - __u8 channels; - /* selected sample format (VIRTIO_SND_PCM_FMT_XXX) */ - __u8 format; - /* selected frame rate (VIRTIO_SND_PCM_RATE_XXX) */ - __u8 rate; - - __u8 padding; -}; - -/******************************************************************************* - * PCM I/O MESSAGES - */ - -/* I/O request header */ -struct virtio_snd_pcm_xfer { - /* 0 ... virtio_snd_config::streams - 1 */ - __le32 stream_id; -}; - -/* I/O request status */ -struct virtio_snd_pcm_status { - /* VIRTIO_SND_S_XXX */ - __le32 status; - /* current device latency */ - __le32 latency_bytes; -}; - -/******************************************************************************* - * CHANNEL MAP CONTROL MESSAGES - */ -struct virtio_snd_chmap_hdr { - /* VIRTIO_SND_R_CHMAP_XXX */ - struct virtio_snd_hdr hdr; - /* 0 ... virtio_snd_config::chmaps - 1 */ - __le32 chmap_id; -}; - -/* standard channel position definition */ -enum { - VIRTIO_SND_CHMAP_NONE = 0, /* undefined */ - VIRTIO_SND_CHMAP_NA, /* silent */ - VIRTIO_SND_CHMAP_MONO, /* mono stream */ - VIRTIO_SND_CHMAP_FL, /* front left */ - VIRTIO_SND_CHMAP_FR, /* front right */ - VIRTIO_SND_CHMAP_RL, /* rear left */ - VIRTIO_SND_CHMAP_RR, /* rear right */ - VIRTIO_SND_CHMAP_FC, /* front center */ - VIRTIO_SND_CHMAP_LFE, /* low frequency (LFE) */ - VIRTIO_SND_CHMAP_SL, /* side left */ - VIRTIO_SND_CHMAP_SR, /* side right */ - VIRTIO_SND_CHMAP_RC, /* rear center */ - VIRTIO_SND_CHMAP_FLC, /* front left center */ - VIRTIO_SND_CHMAP_FRC, /* front right center */ - VIRTIO_SND_CHMAP_RLC, /* rear left center */ - VIRTIO_SND_CHMAP_RRC, /* rear right center */ - VIRTIO_SND_CHMAP_FLW, /* front left wide */ - VIRTIO_SND_CHMAP_FRW, /* front right wide */ - VIRTIO_SND_CHMAP_FLH, /* front left high */ - VIRTIO_SND_CHMAP_FCH, /* front center high */ - VIRTIO_SND_CHMAP_FRH, /* front right high */ - VIRTIO_SND_CHMAP_TC, /* top center */ - VIRTIO_SND_CHMAP_TFL, /* top front left */ - VIRTIO_SND_CHMAP_TFR, /* top front right */ - VIRTIO_SND_CHMAP_TFC, /* top front center */ - VIRTIO_SND_CHMAP_TRL, /* top rear left */ - VIRTIO_SND_CHMAP_TRR, /* top rear right */ - VIRTIO_SND_CHMAP_TRC, /* top rear center */ - VIRTIO_SND_CHMAP_TFLC, /* top front left center */ - VIRTIO_SND_CHMAP_TFRC, /* top front right center */ - VIRTIO_SND_CHMAP_TSL, /* top side left */ - VIRTIO_SND_CHMAP_TSR, /* top side right */ - VIRTIO_SND_CHMAP_LLFE, /* left LFE */ - VIRTIO_SND_CHMAP_RLFE, /* right LFE */ - VIRTIO_SND_CHMAP_BC, /* bottom center */ - VIRTIO_SND_CHMAP_BLC, /* bottom left center */ - VIRTIO_SND_CHMAP_BRC /* bottom right center */ -}; - -/* maximum possible number of channels */ -#define VIRTIO_SND_CHMAP_MAX_SIZE 18 - -struct virtio_snd_chmap_info { - /* common header */ - struct virtio_snd_info hdr; - /* dataflow direction (VIRTIO_SND_D_XXX) */ - __u8 direction; - /* # of valid channel position values */ - __u8 channels; - /* channel position values (VIRTIO_SND_CHMAP_XXX) */ - __u8 positions[VIRTIO_SND_CHMAP_MAX_SIZE]; -}; - -#endif /* VIRTIO_SND_IF_H */ diff --git a/event_notifier.c b/src/common/event_notifier.c index 5b7c1cd..d4b08f7 100644 --- a/event_notifier.c +++ b/src/common/event_notifier.c @@ -80,6 +80,9 @@ void qemu_set_cloexec(int fd) int f; f = fcntl(fd, F_GETFD); f = fcntl(fd, F_SETFD, f | FD_CLOEXEC); + + /* TODO: Check the f value */ + (void)f; } /* diff --git a/vhost_user_blk.c b/src/devices/vhost_user_blk.c index f0ae3d4..bba954b 100644 --- a/vhost_user_blk.c +++ b/src/devices/vhost_user_blk.c @@ -45,12 +45,26 @@ #define DBG(...) #endif /* DEBUG */ +static const int user_feature_bits[] = { + VIRTIO_F_VERSION_1, + VIRTIO_RING_F_INDIRECT_DESC, + VIRTIO_RING_F_EVENT_IDX, + VIRTIO_F_RING_RESET, + VIRTIO_F_NOTIFY_ON_EMPTY, + VHOST_INVALID_FEATURE_BIT, + VIRTIO_BLK_F_SEG_MAX, + VIRTIO_BLK_F_GEOMETRY, + VIRTIO_BLK_F_TOPOLOGY, + VIRTIO_BLK_F_FLUSH, + VIRTIO_BLK_F_DISCARD, + VIRTIO_BLK_F_WRITE_ZEROES, + VIRTIO_BLK_F_BLK_SIZE, + VIRTIO_BLK_F_RO, + VIRTIO_BLK_F_CONFIG_WCE, + VIRTIO_BLK_F_MQ, +}; -#define REALIZE_CONNECTION_RETRIES 3 -static uint64_t vhost_user_blk_get_features(VirtIODevice *vdev, - uint64_t features); - -static int vhost_user_blk_start(VirtIODevice *vdev) +static void vhost_user_blk_start(VirtIODevice *vdev) { VHostUserBlk *s = vdev->vhublk; VirtioBus *k = vdev->vbus; @@ -61,19 +75,19 @@ static int vhost_user_blk_start(VirtIODevice *vdev) if (!k->set_guest_notifiers) { DBG("binding does not support guest notifiers\n"); - return -1; + goto error; } ret = vhost_dev_enable_notifiers(s->vhost_dev, vdev); if (ret < 0) { DBG("Error enabling host notifiers\n"); - return ret; + goto error; } ret = k->set_guest_notifiers(k->vdev, s->vhost_dev->nvqs, true); if (ret < 0) { DBG("Error enabling host notifier\n"); - return ret; + goto error; } s->vhost_dev->acked_features = vdev->guest_features; @@ -83,36 +97,31 @@ static int vhost_user_blk_start(VirtIODevice *vdev) ret = vhost_dev_prepare_inflight(s->vhost_dev, vdev); if (ret < 0) { DBG("Error setting inflight format\n"); - return ret; + goto error; } if (!s->inflight->addr) { ret = vhost_dev_get_inflight(s->vhost_dev, s->queue_size, s->inflight); if (ret < 0) { DBG("Error getting inflight\n"); - return ret; + goto error; } } ret = vhost_dev_set_inflight(s->vhost_dev, s->inflight); if (ret < 0) { DBG("Error setting inflight\n"); - return ret; + goto error; } - DBG("After vhost_dev_set_inflight\n"); - - ret = vhost_dev_start(s->vhost_dev, vdev, true); if (ret < 0) { DBG("Error starting vhost\n"); - return ret; + goto error; } s->started_vu = true; - - DBG("vhost_virtqueue_mask\n"); /* * guest_notifier_mask/pending not used yet, so just unmask * everything here. virtio-pci will do the right thing by @@ -122,8 +131,10 @@ static int vhost_user_blk_start(VirtIODevice *vdev) vhost_virtqueue_mask(s->vhost_dev, vdev, i, false); } - DBG("vhost_user_blk_start return successfully: %d\n", ret); - return ret; + DBG("vhost_user_blk_start returns successfully\n"); + return; + +error: } @@ -146,7 +157,6 @@ static int vhost_user_blk_handle_config_change(struct vhost_dev *dev) DBG("blkcfg.capacity != s->blkcfg.capacity\n"); s->blkcfg.capacity = blkcfg.capacity; memcpy(dev->vdev->config, &s->blkcfg, sizeof(struct virtio_blk_config)); - DBG("To virtio_notify_config\n"); virtio_notify_config(dev->vdev); } @@ -157,166 +167,17 @@ const VhostDevConfigOps blk_ops = { .vhost_dev_config_notifier = vhost_user_blk_handle_config_change, }; -static uint64_t vhost_user_blk_get_features(VirtIODevice *vdev, - uint64_t features) -{ - VHostUserBlk *s = vdev->vhublk; - - DBG("vhost_user_blk_get_features()\n"); - - /* Turn on pre-defined features */ - virtio_add_feature(&features, VIRTIO_BLK_F_SEG_MAX); - virtio_add_feature(&features, VIRTIO_BLK_F_GEOMETRY); - virtio_add_feature(&features, VIRTIO_BLK_F_TOPOLOGY); - virtio_add_feature(&features, VIRTIO_BLK_F_FLUSH); - virtio_add_feature(&features, VIRTIO_BLK_F_DISCARD); - virtio_add_feature(&features, VIRTIO_BLK_F_WRITE_ZEROES); - virtio_add_feature(&features, VIRTIO_BLK_F_BLK_SIZE); - virtio_add_feature(&features, VIRTIO_BLK_F_RO); - /* - * TODO: Delete if not needed - * virtio_add_feature(&features, VIRTIO_BLK_F_BLK_SIZE); - */ - - /* - * The next line makes the blk read only - * - * virtio_add_feature(&features, VIRTIO_BLK_F_RO); - * - */ - - if (s->config_wce) { - DBG("Add config feature\n"); - virtio_add_feature(&features, VIRTIO_BLK_F_CONFIG_WCE); - } - - if (s->num_queues > 1) { - virtio_add_feature(&features, VIRTIO_BLK_F_MQ); - } - - return vhost_user_get_features(&features); -} - -static int vhost_user_blk_connect(VirtIODevice *vdev) -{ - VHostUserBlk *s = vdev->vhublk; - - DBG("vhost_user_blk_connect(...)\n"); - - if (s->connected) { - DBG("s->connected\n"); - return 0; - } - - s->connected = true; - s->vhost_dev->num_queues = s->num_queues; - s->vhost_dev->nvqs = s->num_queues; - s->vhost_dev->vqs = s->vhost_vqs; - s->vhost_dev->vq_index = 0; - s->vhost_dev->backend_features = 0; - - DBG("s->vhost_dev->nvqs: %d\n", s->vhost_dev->nvqs); - - vhost_dev_set_config_notifier(s->vhost_dev, &blk_ops); - - vhost_dev_init(s->vhost_dev); - - /* Pass the new obtained features */ - global_vdev->host_features = s->vhost_dev->features; - - /* - * The next line disables VIRTIO_RING_F_INDIRECT_DESC: - * global_vdev->host_features &= ~(1ULL << VIRTIO_RING_F_INDIRECT_DESC); - */ - - DBG("After init global_vdev->host_features: 0x%lx\n", - global_vdev->host_features); - - DBG("vhost_user_blk_connect return successfully!\n"); - - return 0; -} - /* * These functions will be used in the future: * - * static void vhost_user_blk_stop(VirtIODevice *vdev) - * { - * DBG("Not yet implemented\n"); - * (void)vdev; - * } - * * static void vhost_user_blk_disconnect(VirtIODevice *dev) * { * DBG("vhost_user_blk_disconnect not yet implemented\n"); * (void)dev; * } * - * static void vhost_user_blk_chr_closed_bh(void *opaque) - * { - * DBG("vhost_user_blk_chr_closed_bh not yet implemented\n"); - * (void)opaque; - * } - * - * static void vhost_user_blk_event(void *opaque) - * { - * DBG("vhost_user_blk_event not yet implemented"); - * (void)opaque; - * } - * */ -static int vhost_user_blk_realize_connect(VHostUserBlk *s) -{ - int ret; - - DBG("vhost_user_blk_realize_connect(...)\n"); - s->connected = false; - - DBG("s->vdev: 0x%lx\n", (uint64_t)s->parent); - DBG("global_vdev: 0x%lx\n", (uint64_t)global_vdev); - ret = vhost_user_blk_connect(s->parent); - if (ret < 0) { - DBG("vhost_user_blk_connect failed\n"); - return ret; - } - DBG("s->connected: %d\n", s->connected); - - ret = vhost_dev_get_config(s->vhost_dev, (uint8_t *)&s->blkcfg, - sizeof(struct virtio_blk_config)); - if (ret < 0) { - DBG("vhost_dev_get_config failed\n"); - return ret; - } - - if (global_vdev->vhublk->config_wce != s->blkcfg.wce) { - s->blkcfg.wce = global_vdev->vhublk->config_wce; - - ret = vhost_dev_set_config(s->vhost_dev, (uint8_t *)&s->blkcfg.wce, - offsetof(struct virtio_blk_config, wce), - sizeof(s->blkcfg.wce), - VHOST_SET_CONFIG_TYPE_MASTER); - if (ret < 0) { - DBG("set device config space failed\n"); - return ret; - } - } - - return 0; -} - -static void vhost_user_blk_device_unrealize(VirtIODevice *vdev) -{ - DBG("vhost_user_blk_device_unrealize not yet implemented\n"); - (void)vdev; -} - -static void vhost_user_blk_reset(VirtIODevice *vdev) -{ - DBG("vhost_user_blk_reset not yet implemented\n"); - (void)vdev; -} - static void vhost_user_blk_update_config(VirtIODevice *vdev, uint8_t *config) { VHostUserBlk *s = vdev->vhublk; @@ -354,39 +215,131 @@ static void vhost_user_blk_set_config(VirtIODevice *vdev, const uint8_t *config) s->blkcfg.wce = blkcfg->wce; } +static void vhost_user_blk_handle_output(VirtIODevice *vdev, VirtQueue *vq) +{ + /* + * Not normally called; it's the daemon that handles the queue; + * however virtio's cleanup path can call this. + */ + DBG("vhost_user_blk_handle_output not yet implemented\n"); + (void)vdev; + (void)vq; +} + +void vhost_user_blk_init(VirtIODevice *vdev); +static void print_config_blk(uint8_t *config_data); -static void vhost_user_blk_set_status(VirtIODevice *vdev, uint8_t status) +void vhost_user_blk_realize(struct adapter_dev *adev) { - VHostUserBlk *s = vdev->vhublk; - /* Just for testing: bool should_start = true; */ - bool should_start = virtio_device_started(vdev, status); - int ret; + struct VirtIODevice *vdev = &adev->virtio_dev; + unsigned int queue_size = adev->device_params->queue_size; + unsigned int queue_num = adev->device_params->queue_num; + VirtIOMMIOProxy *proxy = &adev->proxy; + int ret, i; - DBG("vhost_user_blk_set_status (...)\n"); + DBG("vhost_user_blk_realize\n"); - /* TODO: Remove if not needed */ - if (!s->connected) { - DBG("Not connected!\n"); - return; + /* Initialize proxy */ + proxy->legacy = 1; + + /* VIRTIO_ID_BLOCK is 2, check virtio_ids.h in linux */ + virtio_dev_init(vdev, "virtio-blk", 2, + sizeof(struct virtio_blk_config)); + vdev->user_feature_bits = user_feature_bits; + + vhost_user_blk_init(vdev); + + vdev->vhublk->config_wce = 1; + + vdev->vhublk->vhost_dev->nvqs = queue_num; + vdev->vhublk->num_queues = queue_num; + vdev->vhublk->queue_size = queue_size; + + /* NOTE: vdev->vqs == vhublk->virtqs */ + vdev->vqs = (VirtQueue **)malloc(sizeof(VirtQueue *) + * vdev->vhublk->num_queues); + for (i = 0; i < vdev->vhublk->num_queues; i++) { + vdev->vqs[i] = virtio_add_queue(vdev, + vdev->vhublk->queue_size, + vhost_user_blk_handle_output); } - DBG("should_start == %d\n", should_start); - if (s->vhost_dev->started == should_start) { - DBG("s->dev->started == should_start\n"); + vdev->vhublk->inflight = (struct vhost_inflight *)malloc( + sizeof(struct vhost_inflight)); + vdev->vhublk->vhost_vqs = (struct vhost_virtqueue *)malloc( + sizeof(struct vhost_virtqueue) * + vdev->vhublk->num_queues); + + vdev->vhublk->vhost_dev->num_queues = vdev->vhublk->num_queues; + vdev->vhublk->vhost_dev->nvqs = vdev->vhublk->num_queues; + vdev->vhublk->vhost_dev->vqs = vdev->vhublk->vhost_vqs; + vdev->vhublk->vhost_dev->vq_index = 0; + vdev->vhublk->vhost_dev->backend_features = 0; + + vhost_dev_set_config_notifier(vdev->vhublk->vhost_dev, &blk_ops); + + vhost_dev_init(vdev->vhublk->vhost_dev); + + /* Pass the new obtained features */ + vdev->host_features = vdev->vhublk->vhost_dev->features; + + /* + * The next line disables VIRTIO_RING_F_INDIRECT_DESC: + * vdev->host_features &= ~(1ULL << VIRTIO_RING_F_INDIRECT_DESC); + */ + + ret = vhost_dev_get_config(vdev->vhublk->vhost_dev, (uint8_t *)&vdev->vhublk->blkcfg, + sizeof(struct virtio_blk_config)); + if (ret < 0) { + DBG("vhost_dev_get_config failed\n"); return; } - if (should_start) { - ret = vhost_user_blk_start(vdev); + if (vdev->vhublk->config_wce != vdev->vhublk->blkcfg.wce) { + vdev->vhublk->blkcfg.wce = vdev->vhublk->config_wce; + + ret = vhost_dev_set_config(vdev->vhublk->vhost_dev, (uint8_t *)&vdev->vhublk->blkcfg.wce, + offsetof(struct virtio_blk_config, wce), + sizeof(vdev->vhublk->blkcfg.wce), + VHOST_SET_CONFIG_TYPE_MASTER); if (ret < 0) { - DBG("vhost_user_blk_start returned error\n"); + DBG("set device config space failed\n"); + return; } - } else { - DBG("Call vhost_user_blk_stop (not yet in place)\n"); - /* TODO: vhost_user_blk_stop(vdev); */ } - DBG("vhost_user_blk_set_status return successfully\n"); + DBG("final vdev->host_features: 0x%lx\n", + vdev->host_features); + + print_config_blk((uint8_t *)(&vdev->vhublk->blkcfg)); +} + +static void vhost_user_dev_class_init_extra(VirtIODevice *vdev) +{ + DBG("virtio_dev_class_init\n"); + + vdev->vdev_class->realize = vhost_user_blk_realize; + vdev->vdev_class->start = vhost_user_blk_start; + vdev->vdev_class->get_config = vhost_user_blk_update_config; + vdev->vdev_class->set_config = vhost_user_blk_set_config; + vdev->vdev_class->print_config = print_config_blk; +} + +void vhost_user_blk_init(VirtIODevice *vdev) +{ + struct vhost_dev *vhdev = vdev->vhdev; + DBG("vhost_user_blk_init\n"); + + VHostUserBlk *vhublk = (VHostUserBlk *)malloc(sizeof(VHostUserBlk)); + vdev->vhublk = vhublk; + vdev->nvqs = (int *)&vhdev->nvqs; + vhublk->parent = vdev; + vhublk->virtqs = vdev->vqs; + vhublk->vhost_dev = vhdev; + + vhost_user_dev_class_init(vdev); + vhost_user_dev_class_init_extra(vdev); + virtio_loopback_bus_init(vdev->vbus); } static void print_config_blk(uint8_t *config_data) @@ -432,104 +385,3 @@ static void print_config_blk(uint8_t *config_data) DBG("uint8_t unused1[3]: %u\n", config_strct->unused1[1]); DBG("uint8_t unused1[3]: %u\n", config_strct->unused1[2]); } - -static void virtio_dev_class_init(VirtIODevice *vdev) -{ - DBG("virtio_dev_class_init\n"); - - vdev->vdev_class = (VirtioDeviceClass *)malloc(sizeof(VirtioDeviceClass)); - vdev->vdev_class->parent = vdev; - vdev->vdev_class->realize = vhost_user_blk_realize; - vdev->vdev_class->unrealize = vhost_user_blk_device_unrealize; - vdev->vdev_class->get_config = vhost_user_blk_update_config; - vdev->vdev_class->set_config = vhost_user_blk_set_config; - vdev->vdev_class->get_features = vhost_user_blk_get_features; - vdev->vdev_class->set_status = vhost_user_blk_set_status; - vdev->vdev_class->reset = vhost_user_blk_reset; - vdev->vdev_class->update_mem_table = update_mem_table; - vdev->vdev_class->print_config = print_config_blk; -} - -void vhost_user_blk_init(VirtIODevice *vdev) -{ - - DBG("vhost_user_blk_init\n"); - - VHostUserBlk *vhublk = (VHostUserBlk *)malloc(sizeof(VHostUserBlk)); - vdev->vhublk = vhublk; - vdev->nvqs = (int *)&dev->nvqs; - vhublk->parent = vdev; - vhublk->virtqs = vdev->vqs; - vhublk->vhost_dev = dev; - - virtio_dev_class_init(vdev); - virtio_loopback_bus_init(vdev->vbus); -} - -static void vhost_user_blk_handle_output(VirtIODevice *vdev, VirtQueue *vq) -{ - /* - * Not normally called; it's the daemon that handles the queue; - * however virtio's cleanup path can call this. - */ - DBG("vhost_user_blk_handle_output not yet implemented\n"); - (void)vdev; - (void)vq; -} - -void vhost_user_blk_realize(int queue_num, int queue_size) -{ - int retries; - int i, ret; - - DBG("vhost_user_blk_realize\n"); - - /* This needs to be added */ - proxy = (VirtIOMMIOProxy *)malloc(sizeof(VirtIOMMIOProxy)); - *proxy = (VirtIOMMIOProxy) { - .legacy = 1, - }; - - /* VIRTIO_ID_BLOCK is 2, check virtio_ids.h in linux */ - virtio_dev_init(global_vdev, "virtio-blk", 2, - sizeof(struct virtio_blk_config)); - - vhost_user_blk_init(global_vdev); - - global_vdev->vhublk->config_wce = 1; - - global_vdev->vhublk->vhost_dev->nvqs = queue_num; - global_vdev->vhublk->num_queues = queue_num; - global_vdev->vhublk->queue_size = queue_size; - - /* NOTE: global_vdev->vqs == vhublk->virtqs */ - global_vdev->vqs = (VirtQueue **)malloc(sizeof(VirtQueue *) - * global_vdev->vhublk->num_queues); - for (i = 0; i < global_vdev->vhublk->num_queues; i++) { - global_vdev->vqs[i] = virtio_add_queue(global_vdev, - global_vdev->vhublk->queue_size, - vhost_user_blk_handle_output); - } - - global_vdev->vhublk->inflight = (struct vhost_inflight *)malloc( - sizeof(struct vhost_inflight)); - global_vdev->vhublk->vhost_vqs = (struct vhost_virtqueue *)malloc( - sizeof(struct vhost_virtqueue) * - global_vdev->vhublk->num_queues); - - retries = REALIZE_CONNECTION_RETRIES; - - do { - ret = vhost_user_blk_realize_connect(global_vdev->vhublk); - } while (ret < 0 && retries--); - - if (ret < 0) { - DBG("vhost_user_blk_realize_connect: -EPROTO\n"); - } - - DBG("final global_vdev->host_features: 0x%lx\n", - global_vdev->host_features); - - print_config_blk((uint8_t *)(&global_vdev->vhublk->blkcfg)); -} - diff --git a/src/devices/vhost_user_can.c b/src/devices/vhost_user_can.c new file mode 100644 index 0000000..091637c --- /dev/null +++ b/src/devices/vhost_user_can.c @@ -0,0 +1,179 @@ +/* + * Virtio CAN Device + * + * Based on virtio_can.h of OpenSynergy's virtio-can RFC + * https://github.com/OpenSynergy/qemu/tree/virtio-can-spec-rfc-v3 + * + * Copyright (C) 2021-2023 OpenSynergy GmbH + * Copyright (c) 2023 Virtual Open Systems SAS. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2. + * + * 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. + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the + * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#include <unistd.h> +#include <stdlib.h> +#include <stdio.h> +#include <stdint.h> +#include <string.h> +#include <stdbool.h> +#include <sys/param.h> + +/* Project header files */ +#include "vhost_user_can.h" + +#ifdef DEBUG +#define DBG(...) printf("vhost-user-can: " __VA_ARGS__) +#else +#define DBG(...) +#endif /* DEBUG */ + +/***************************** vhost-user-can ******************************/ + +static const int user_feature_bits[] = { + VIRTIO_F_VERSION_1, + VIRTIO_RING_F_INDIRECT_DESC, + VIRTIO_RING_F_EVENT_IDX, + VIRTIO_F_RING_RESET, + VIRTIO_F_NOTIFY_ON_EMPTY, + VHOST_INVALID_FEATURE_BIT +}; + +static void vhost_user_can_can_handle_output(VirtIODevice *vdev, VirtQueue *vq) +{ + /* + * Not normally called; it's the daemon that handles the queue; + * however virtio's cleanup path can call this. + */ + DBG("vhost_user_can_can_handle_output: Not yet implemented!\n"); + (void)vdev; + (void)vq; +} + +static int vhost_user_can_can_config_change(struct vhost_dev *dev) +{ + DBG("vhost_user_can_can_config_change\n"); + + int ret = vhost_dev_get_config(dev, (uint8_t *)dev->vdev->config, + sizeof(struct virtio_can_config)); + if (ret < 0) { + DBG("vhost_user_can_sound_config_change error\n"); + return -1; + } + + virtio_notify_config(dev->vdev); + + return 0; +} + +const VhostDevConfigOps can_config_ops = { + .vhost_dev_config_notifier = vhost_user_can_can_config_change, +}; + +static void vhost_user_can_init(VirtIODevice *vdev); + +void vhost_user_can_realize(struct adapter_dev *adev) +{ + VirtIODevice *vdev = &adev->virtio_dev; + VirtIOMMIOProxy *proxy = &adev->proxy; + int ret; + + /* Initialize proxy */ + proxy->legacy = 1; + + /* VIRTIO_ID_CAN is 36, check virtio_ids.h in linux*/ + virtio_dev_init(vdev, "virtio-can", 36, sizeof(struct virtio_can_config)); + vdev->user_feature_bits = user_feature_bits; + vhost_user_can_init(vdev); + + /* add queues */ + vdev->vhucan->vhost_dev->nvqs = 3; + vdev->vhucan->num_queues = 3; + vdev->vhucan->queue_size = 64; + + /* NOTE: vdev->vqs == vhucan->virtqs */ + vdev->vqs = (VirtQueue **)malloc(sizeof(VirtQueue *) + * vdev->vhucan->num_queues); + vdev->vqs[0] = virtio_add_queue(vdev, 64, vhost_user_can_can_handle_output); + vdev->vqs[1] = virtio_add_queue(vdev, 64, vhost_user_can_can_handle_output); + vdev->vqs[2] = virtio_add_queue(vdev, 64, vhost_user_can_can_handle_output); + + vdev->vhucan->vhost_vqs = (struct vhost_virtqueue *)malloc( + sizeof(struct vhost_virtqueue) * + vdev->vhucan->num_queues); + + /* Set up vhost device */ + vdev->vhucan->vhost_dev->num_queues = vdev->vhucan->num_queues; + vdev->vhucan->vhost_dev->nvqs = vdev->vhucan->num_queues; + vdev->vhucan->vhost_dev->vqs = vdev->vhucan->vhost_vqs; + vdev->vhucan->vhost_dev->vq_index = 0; + vdev->vhucan->vhost_dev->backend_features = 0; + + vhost_dev_set_config_notifier(vdev->vhucan->vhost_dev, &can_config_ops); + + /* TODO: Add error handling */ + vhost_dev_init(vdev->vhucan->vhost_dev); + + /* Pass the new obtained features */ + vdev->host_features = vdev->vhucan->vhost_dev->features; + + ret = vhost_dev_get_config(vdev->vhucan->vhost_dev, + (uint8_t *)vdev->config, + sizeof(struct virtio_can_config)); + if (ret < 0) { + goto vhost_dev_init_failed; + } + + vdev->vdev_class->print_config((uint8_t *)&vdev->config); + + return; + +vhost_dev_init_failed: + DBG("vhost_dev_init_failed\n"); + return; +} + +static void print_config_can(uint8_t *config_data) +{ + struct virtio_can_config *config_strct = + (struct virtio_can_config *)config_data; + + (void)config_strct; + DBG("print_config_can:\n"); + + DBG("\tuint16_t status: %u\n", config_strct->status); +} + +static void vhost_user_dev_class_init_extra(VirtIODevice *vdev) +{ + DBG("virtio_dev_class_init\n"); + + vdev->vdev_class->realize = vhost_user_can_realize; + vdev->vdev_class->print_config = print_config_can; +} + +static void vhost_user_can_init(VirtIODevice *vdev) +{ + DBG("vhost_user_can_init\n"); + + VHostUserCan *vhucan = (VHostUserCan *)malloc(sizeof(VHostUserCan)); + vdev->vhucan = vhucan; + vdev->nvqs = (int *)&vdev->vhdev->nvqs; + vhucan->parent = vdev; + vhucan->virtqs = vdev->vqs; + vhucan->vhost_dev = vdev->vhdev; + + vhost_user_dev_class_init(vdev); + vhost_user_dev_class_init_extra(vdev); + virtio_loopback_bus_init(vdev->vbus); +} diff --git a/src/devices/vhost_user_console.c b/src/devices/vhost_user_console.c new file mode 100644 index 0000000..d640b22 --- /dev/null +++ b/src/devices/vhost_user_console.c @@ -0,0 +1,175 @@ +/* + * Copyright (c) 2023 Virtual Open Systems SAS. + * + * This work is licensed under the terms of the GNU GPL, version 2 or + * (at your option) any later version. See the COPYING file in the + * top-level directory. + * + */ + + +#include <unistd.h> +#include <stdlib.h> +#include <stdio.h> +#include <stdint.h> +#include <string.h> +#include <stdbool.h> +#include <sys/param.h> + +/* Project header files */ +#include "vhost_user_console.h" + +#ifdef DEBUG +#define DBG(...) printf("vhost-user-console: " __VA_ARGS__) +#else +#define DBG(...) +#endif /* DEBUG */ + +static const int user_feature_bits[] = { + VIRTIO_F_VERSION_1, + VIRTIO_RING_F_INDIRECT_DESC, + VIRTIO_RING_F_EVENT_IDX, + VIRTIO_F_RING_RESET, + VIRTIO_F_NOTIFY_ON_EMPTY, + VHOST_INVALID_FEATURE_BIT, + VIRTIO_CONSOLE_F_SIZE, + VIRTIO_CONSOLE_F_MULTIPORT, + VIRTIO_CONSOLE_F_EMERG_WRITE +}; + +static void vhost_user_console_handle_output(VirtIODevice *vdev, VirtQueue *vq) +{ + /* + * Not normally called; it's the daemon that handles the queue; + * however virtio's cleanup path console call this. + */ + DBG("vhost_user_console_handle_output: Not yet implemented!\n"); + (void)vdev; + (void)vq; +} + +static int vhost_user_console_config_change(struct vhost_dev *dev) +{ + DBG("vhost_user_console_console_config_change\n"); + + int ret = vhost_dev_get_config(dev, (uint8_t *)dev->vdev->config, + sizeof(struct virtio_console_config)); + if (ret < 0) { + DBG("vhost_user_console_sound_config_change error\n"); + return -1; + } + + virtio_notify_config(dev->vdev); + + return 0; +} + +const VhostDevConfigOps console_config_ops = { + .vhost_dev_config_notifier = vhost_user_console_config_change, +}; + +static void vhost_user_console_init(VirtIODevice *vdev); + +void vhost_user_console_realize(struct adapter_dev *adev) +{ + VirtIODevice *vdev = &adev->virtio_dev; + VirtIOMMIOProxy *proxy = &adev->proxy; + int ret; + + DBG("vhost_user_console_device_realize\n"); + + /* Initialize proxy */ + proxy->legacy = 1; + + /* VIRTIO_ID_CONSOLE is 3, check virtio_ids.h in linux*/ + virtio_dev_init(vdev, "virtio-console", 3, sizeof(struct virtio_console_config)); + vdev->user_feature_bits = user_feature_bits; + vhost_user_console_init(vdev); + + /* add queues */ + vdev->vhuconsole->vhost_dev->nvqs = 4; + vdev->vhuconsole->num_queues = 4; + vdev->vhuconsole->queue_size = 128; + + /* NOTE: vdev->vqs == vhuconsole->virtqs */ + vdev->vqs = (VirtQueue **)malloc(sizeof(VirtQueue *) + * vdev->vhuconsole->num_queues); + vdev->vqs[0] = virtio_add_queue(vdev, 128, vhost_user_console_handle_output); + vdev->vqs[1] = virtio_add_queue(vdev, 128, vhost_user_console_handle_output); + vdev->vqs[2] = virtio_add_queue(vdev, 128, vhost_user_console_handle_output); + vdev->vqs[3] = virtio_add_queue(vdev, 128, vhost_user_console_handle_output); + + vdev->vhuconsole->vhost_vqs = (struct vhost_virtqueue *)malloc( + sizeof(struct vhost_virtqueue) * + vdev->vhuconsole->num_queues); + + /* Set up vhost device */ + vdev->vhuconsole->vhost_dev->num_queues = vdev->vhuconsole->num_queues; + vdev->vhuconsole->vhost_dev->nvqs = vdev->vhuconsole->num_queues; + vdev->vhuconsole->vhost_dev->vqs = vdev->vhuconsole->vhost_vqs; + vdev->vhuconsole->vhost_dev->vq_index = 0; + vdev->vhuconsole->vhost_dev->backend_features = 0; + + vhost_dev_set_config_notifier(vdev->vhuconsole->vhost_dev, + &console_config_ops); + + /* TODO: Add error handling */ + vhost_dev_init(vdev->vhuconsole->vhost_dev); + + /* Pass the new obtained features */ + vdev->host_features = vdev->vhuconsole->vhost_dev->features; + + ret = vhost_dev_get_config(vdev->vhdev, + (uint8_t *)vdev->config, + sizeof(struct virtio_console_config)); + if (ret < 0) { + goto vhost_dev_init_failed; + } + + vdev->vdev_class->print_config((uint8_t *)&vdev->config); + + return; + +vhost_dev_init_failed: + DBG("vhost_dev_init_failed\n"); + return; +} + +static void print_config_console(uint8_t *config_data) +{ + struct virtio_console_config *config_strct = + (struct virtio_console_config *)config_data; + + (void)config_strct; + DBG("print_config_console:\n"); + DBG("\tuint16_t cols: %u\n", config_strct->cols); + DBG("\tuint16_t rows: %u\n", config_strct->rows); + DBG("\tuint16_t max_nr_ports: %u\n", config_strct->max_nr_ports); + DBG("\tuint16_t emerg_wr: %u\n", config_strct->emerg_wr); +} + +static void vhost_user_dev_class_init_extra(VirtIODevice *vdev) +{ + DBG("virtio_dev_class_init\n"); + + vdev->vdev_class->realize = vhost_user_console_realize; + vdev->vdev_class->print_config = print_config_console; +} + +static void vhost_user_console_init(VirtIODevice *vdev) +{ + + DBG("vhost_user_console_init\n"); + + VHostUserConsole *vhuconsole = + (VHostUserConsole *)malloc(sizeof(VHostUserConsole)); + vdev->vhuconsole = vhuconsole; + vdev->nvqs = (int *)&vdev->vhdev->nvqs; + vhuconsole->parent = vdev; + vhuconsole->virtqs = vdev->vqs; + vhuconsole->vhost_dev = vdev->vhdev; + + vhost_user_dev_class_init(vdev); + vhost_user_dev_class_init_extra(vdev); + virtio_loopback_bus_init(vdev->vbus); +} diff --git a/src/devices/vhost_user_gpio.c b/src/devices/vhost_user_gpio.c new file mode 100644 index 0000000..0858020 --- /dev/null +++ b/src/devices/vhost_user_gpio.c @@ -0,0 +1,204 @@ +/* + * Based on vhost-user-gpio.c of QEMU project + * + * Copyright (c) 2022 Viresh Kumar <viresh.kumar@linaro.org> + * + * Copyright (c) 2023 Virtual Open Systems SAS. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * 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. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#include <unistd.h> +#include <stdlib.h> +#include <stdio.h> +#include <stdint.h> +#include <string.h> +#include <stdbool.h> +#include <sys/param.h> +#include <errno.h> + +/* Project header files */ +#include "vhost_user_gpio.h" + +#ifdef DEBUG +#define DBG(...) printf("vhost-user-gpio: " __VA_ARGS__) +#else +#define DBG(...) +#endif /* DEBUG */ + +static const int user_feature_bits[] = { + VIRTIO_F_VERSION_1, + VIRTIO_F_NOTIFY_ON_EMPTY, + VIRTIO_RING_F_INDIRECT_DESC, + VIRTIO_RING_F_EVENT_IDX, + VIRTIO_GPIO_F_IRQ, + VIRTIO_F_RING_RESET, + VHOST_INVALID_FEATURE_BIT +}; + +static int vu_gpio_config_notifier(struct vhost_dev *dev) +{ + DBG("vu_gpio_config_notifier\n"); + + /* TODO: Investigate if we need that */ + //memcpy(dev->vdev->config, &dev->vdev->vhugpio->config, sizeof(gpio->config)); + + virtio_notify_config(dev->vdev); + + return 0; +} + +const VhostDevConfigOps gpio_ops = { + .vhost_dev_config_notifier = vu_gpio_config_notifier, +}; + +static void vu_gpio_handle_output(VirtIODevice *vdev, VirtQueue *vq) +{ + /* + * Not normally called; it's the daemon that handles the queue; + * however virtio's cleanup path can call this. + */ + DBG("vu_gpio_handle_output not yet implemented\n"); + (void)vdev; + (void)vq; +} + +static void do_vhost_user_cleanup(VirtIODevice *vdev, VHostUserGPIO *gpio) +{ + DBG("do_vhost_user_cleanup not yet implemented\n"); + (void)vdev; + (void)gpio; +} + +static void print_config_gpio(uint8_t *config_data) +{ + struct virtio_gpio_config *config = + (struct virtio_gpio_config *)config_data; + + (void)config; + DBG("ngpio: %hu\n", config->ngpio); + DBG("gpio_names_size: %u\n", config->gpio_names_size); +} + +void vhost_user_gpio_init(VirtIODevice *vdev); + +void vu_gpio_device_realize(struct adapter_dev *adev) +{ + VirtIODevice *vdev = &adev->virtio_dev; + VirtIOMMIOProxy *proxy = &adev->proxy; + int ret; + + DBG("vu_gpio_device_realize()\n"); + + /* Initialize proxy */ + proxy->legacy = 1; + + /* VIRTIO_ID_GPIO is 41, check virtio_ids.h in linux */ + virtio_dev_init(vdev, "virtio-gpio", 41, + sizeof(struct virtio_gpio_config)); + vdev->user_feature_bits = user_feature_bits; + + vhost_user_gpio_init(vdev); + if (!vdev->vhugpio) { + DBG("vhugpio memory allocation failed\n"); + goto out_with_error; + } + + /* add queues */ + vdev->vhugpio->num_queues = 2; + vdev->vhugpio->queue_size = 64; + + vdev->vqs = (VirtQueue **)malloc(sizeof(VirtQueue *) + * vdev->vhugpio->num_queues); + vdev->vqs[0] = virtio_add_queue(vdev, 64, vu_gpio_handle_output); + vdev->vqs[1] = virtio_add_queue(vdev, 64, vu_gpio_handle_output); + + + vdev->vhugpio->vhost_vqs = (struct vhost_virtqueue *) + malloc(sizeof(struct vhost_virtqueue *)); + if (!vdev->vhugpio->vhost_vqs) { + DBG("vhost_vqs memory allocation failed\n"); + goto out_with_dev; + } + + /* Set up vhost device */ + vdev->vhdev->num_queues = vdev->vhugpio->num_queues; + vdev->vhdev->nvqs = vdev->vhugpio->num_queues; + vdev->vhdev->vqs = vdev->vhugpio->vhost_vqs; + vdev->vhdev->vq_index = 0; + vdev->vhdev->backend_features = 0; + + vhost_dev_set_config_notifier(vdev->vhdev, &gpio_ops); + + /* TODO: Add error handling */ + vhost_dev_init(vdev->vhdev); + + /* Pass the new obtained features */ + vdev->host_features = vdev->vhdev->features; + + ret = vhost_dev_get_config(vdev->vhdev, (uint8_t *)vdev->config, + vdev->config_len); + if (ret < 0) { + DBG("vu_gpio_realize_connect(): -EPROTO\n"); + do_vhost_user_cleanup(vdev, vdev->vhugpio); + } + + print_config_gpio((uint8_t *)(vdev->config)); + DBG("(realize completed)\n"); + + return; + + /* + * TODO: Fix the following considering also do_vhost_user_cleanup() + * + * out_with_cmd_vq: + * free(vdev->vhugpio->command_vq); + */ +out_with_dev: + free(vdev->vhugpio); +out_with_error: + DBG("Realize funciton return error\n"); + return; +} + +static void vhost_user_dev_class_init_extra(VirtIODevice *vdev) +{ + DBG("vu_gpio_class_init()\n"); + + vdev->vdev_class->realize = vu_gpio_device_realize; +} + +void vhost_user_gpio_init(VirtIODevice *vdev) +{ + DBG("vhost_user_gpio_init(...)\n"); + + VHostUserGPIO *vhugpio = (VHostUserGPIO *)malloc(sizeof(VHostUserGPIO)); + if (!vhugpio) { + DBG("proxy memory allocation failed\n"); + goto out; + } + + vdev->vhugpio = vhugpio; + vdev->nvqs = (int *)&vdev->vhdev->nvqs; + vhugpio->parent = vdev; + vhugpio->vhost_dev = vdev->vhdev; + + vhost_user_dev_class_init(vdev); + vhost_user_dev_class_init_extra(vdev); + virtio_loopback_bus_init(vdev->vbus); + +out: + return; +} diff --git a/src/devices/vhost_user_input.c b/src/devices/vhost_user_input.c new file mode 100644 index 0000000..1ea18a9 --- /dev/null +++ b/src/devices/vhost_user_input.c @@ -0,0 +1,154 @@ +/* + * Based on vhost-user-input.c of QEMU project + * + * Copyright (c) 2022-2024 Virtual Open Systems SAS. + * + * This work is licensed under the terms of the GNU GPL, version 2 or + * (at your option) any later version. See the COPYING file in the + * top-level directory. + */ + +#include <unistd.h> +#include <stdlib.h> +#include <stdio.h> +#include <stdint.h> +#include <string.h> +#include <stdbool.h> +#include <sys/param.h> + +/* Project header files */ +#include "vhost_user_input.h" + +#ifdef DEBUG +#define DBG(...) printf("vhost-user-input: " __VA_ARGS__) +#else +#define DBG(...) +#endif /* DEBUG */ + +static int vhost_input_config_change(struct vhost_dev *dev) +{ + DBG("vhost-user-input: unhandled backend config change\n"); + (void)dev; + + return -1; +} + +const VhostDevConfigOps config_ops = { + .vhost_dev_config_notifier = vhost_input_config_change, +}; + +static void vhost_input_set_config(VirtIODevice *vdev, const uint8_t *config_data) +{ + int ret; + + DBG("vhost_input_set_config(...)\n"); + + ret = vhost_dev_set_config(vdev->vhdev, config_data, + 0, sizeof(struct virtio_input_config), + VHOST_SET_CONFIG_TYPE_MASTER); + if (ret < 0) { + DBG("vhost_input_set_config failed\n"); + return; + } + + virtio_notify_config(vdev); +} + +static void print_config_input(uint8_t *config_data) +{ + struct virtio_input_config *config_strct = + (struct virtio_input_config *)config_data; + + DBG("print_config_input: Not yet implemented\n"); + (void)config_strct; +} + +static void virtio_input_handle(VirtIODevice *vdev, VirtQueue *vq) +{ + DBG("virtio_input_handle_evt(...) not yet implemeted\n"); + (void)vdev; + (void)vq; +} + +static const int user_feature_bits[] = { + VIRTIO_F_VERSION_1, + VIRTIO_RING_F_INDIRECT_DESC, + VIRTIO_RING_F_EVENT_IDX, + VIRTIO_F_RING_RESET, + VIRTIO_F_NOTIFY_ON_EMPTY, + VHOST_INVALID_FEATURE_BIT +}; + +static void vhost_user_input_init(VirtIODevice *vdev); + +void virtio_input_device_realize(struct adapter_dev *adev) +{ + VirtIODevice *vdev = &adev->virtio_dev; + VirtIOMMIOProxy *proxy = &adev->proxy; + + int nvqs = 2; /* qemu choice: 2 */ + + DBG("virtio_input_device_realize(...)\n"); + + /* Initialize proxy */ + proxy->legacy = 1; + + virtio_dev_init(vdev, "virtio-input", 18, sizeof(struct virtio_input_config)); + vdev->user_feature_bits = user_feature_bits; + vhost_user_input_init(vdev); + + vdev->vqs = (struct VirtQueue **)malloc( + sizeof(struct VirtQueue *) * nvqs); + + vdev->vqs[0] = virtio_add_queue(vdev, 64, virtio_input_handle); + vdev->vqs[1] = virtio_add_queue(vdev, 64, virtio_input_handle); + + vhost_dev_set_config_notifier(vdev->vhdev, + &config_ops); + + vdev->vhdev->nvqs = nvqs; + vdev->vhdev->num_queues = nvqs; + vdev->vhdev->vq_index = 0; + vdev->vhdev->backend_features = 0; + vdev->vhdev->vqs = (struct vhost_virtqueue *)malloc( + sizeof(struct vhost_virtqueue) * nvqs); + + vhost_dev_init(vdev->vhdev); + + /* Pass the new obtained features */ + vdev->host_features = vdev->vhuinput->vhost_dev->features; + + DBG("final features: 0x%lx\n", vdev->host_features); +} + +static void vhost_user_dev_class_init_extra(VirtIODevice *vdev) +{ + + DBG("vhost_user_dev_class_init_extra(...)\n"); + + vdev->vdev_class->realize = virtio_input_device_realize; + vdev->vdev_class->set_config = vhost_input_set_config; + vdev->vdev_class->print_config = print_config_input; +} + +static void vhost_user_input_init(VirtIODevice *vdev) +{ + DBG("vhost_user_input_init(...)\n"); + + VhostUserInput *vhuinput = (VhostUserInput *)malloc(sizeof(VhostUserInput)); + vdev->vhuinput = vhuinput; + vdev->nvqs = (int*)&vdev->vhdev->nvqs; + vhuinput->parent = vdev; + vhuinput->vhost_dev = vdev->vhdev; + + /* + * Call first the virtio_input class init to set up + * the basic functionality. + */ + vhost_user_dev_class_init(vdev); + vhost_user_dev_class_init_extra(vdev); + + /* finally initialize the bus */ + virtio_loopback_bus_init(vdev->vbus); +} + diff --git a/src/devices/vhost_user_rng.c b/src/devices/vhost_user_rng.c new file mode 100644 index 0000000..b58fa59 --- /dev/null +++ b/src/devices/vhost_user_rng.c @@ -0,0 +1,112 @@ +/* + * Based on vhost-user-rng of QEMU project + * + * Copyright (c) 2021 Mathieu Poirier <mathieu.poirier@linaro.org> + * + * Copyright (c) 2022-2023 Virtual Open Systems SAS. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * 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. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#include <unistd.h> +#include <stdlib.h> +#include <stdio.h> +#include <stdint.h> +#include <string.h> +#include <stdbool.h> +#include <sys/param.h> + +/* Project header files */ +#include "vhost_loopback.h" +#include "vhost_user_rng.h" + +#ifdef DEBUG +#define DBG(...) printf("vhost-user-rng: " __VA_ARGS__) +#else +#define DBG(...) +#endif /* DEBUG */ + +static const int user_feature_bits[] = { + VIRTIO_F_VERSION_1, + VIRTIO_F_NOTIFY_ON_EMPTY, + VIRTIO_RING_F_INDIRECT_DESC, + VIRTIO_RING_F_EVENT_IDX, + VIRTIO_F_RING_RESET, + VHOST_INVALID_FEATURE_BIT +}; + +static void vu_rng_handle_output(VirtIODevice *vdev, VirtQueue *vq) +{ + (void)vdev; + (void)vq; + /* + * Not normally called; it's the daemon that handles the queue; + * however virtio's cleanup path can call this. + */ + DBG("vu_rng_handle_output\n"); +} + +void vhost_user_rng_init(VirtIODevice *vdev); + +void vhost_user_rng_realize(struct adapter_dev *adev) +{ + VirtIODevice *vdev = &adev->virtio_dev; + struct vhost_dev *vhdev = &adev->vdev; + VirtIOMMIOProxy *proxy = &adev->proxy; + + /* Initialize proxy */ + proxy->legacy = 1; + + /* Initiliaze virtio_dev data structures */ + virtio_dev_init(vdev, "virtio-rng", 4, 0); + vdev->user_feature_bits = user_feature_bits; + + /* This needs to be change to vhost-user-rng init */ + vhost_user_rng_init(vdev); + + vdev->vq = virtio_add_queue(vdev, 4, vu_rng_handle_output); + vdev->host_features = 0x39000000; + + /* Virtqueues conf */ + vhdev->nvqs = 1; + vhdev->vqs = (struct vhost_virtqueue *)malloc(vhdev->nvqs * + sizeof(struct vhost_virtqueue)); + + /* Initiale vhost-user communication */ + vhost_dev_init(vhdev); + + /* Write the final features */ + vdev->host_features = vhdev->features; + DBG("final features: 0x%lx\n", vhdev->features); +} + +static void vhost_user_dev_class_init_extra(VirtIODevice *vdev) +{ + vdev->vdev_class->realize = vhost_user_rng_realize; +} + +void vhost_user_rng_init(VirtIODevice *vdev) +{ + VHostUserRNG *vhrng = (VHostUserRNG *)malloc(sizeof(VHostUserRNG)); + vdev->vhrng = vhrng; + vdev->nvqs = (int *)&vdev->vhdev->nvqs; + vhrng->parent = vdev; + vhrng->req_vq = vdev->vq; + vhrng->vhost_dev = vdev->vhdev; + + vhost_user_dev_class_init(vdev); + vhost_user_dev_class_init_extra(vdev); + virtio_loopback_bus_init(vdev->vbus); +} diff --git a/src/devices/vhost_user_sound.c b/src/devices/vhost_user_sound.c new file mode 100644 index 0000000..cd3881f --- /dev/null +++ b/src/devices/vhost_user_sound.c @@ -0,0 +1,178 @@ +/* + * Based on vhost-user-sound.c of QEMU project + * + * Copyright 2020 Red Hat, Inc. + * + * Copyright (c) 2023 Virtual Open Systems SAS. + * + * This work is licensed under the terms of the GNU GPL, version 2 or + * (at your option) any later version. See the COPYING file in the + * top-level directory. + * + */ + + +#include <unistd.h> +#include <stdlib.h> +#include <stdio.h> +#include <stdint.h> +#include <string.h> +#include <stdbool.h> +#include <sys/param.h> + +/* Project header files */ +#include "vhost_user_sound.h" + +#ifdef DEBUG +#define DBG(...) printf("vhost-user-sound: " __VA_ARGS__) +#else +#define DBG(...) +#endif /* DEBUG */ + +/***************************** vhost-user-sound ******************************/ + +static const int user_feature_bits[] = { + VIRTIO_F_VERSION_1, + VIRTIO_RING_F_INDIRECT_DESC, + VIRTIO_RING_F_EVENT_IDX, + VIRTIO_F_RING_RESET, + VIRTIO_F_NOTIFY_ON_EMPTY, + VHOST_INVALID_FEATURE_BIT +}; + +static void vus_snd_handle_output(VirtIODevice *vdev, VirtQueue *vq) +{ + /* + * Not normally called; it's the daemon that handles the queue; + * however virtio's cleanup path can call this. + */ + (void)vdev; + (void)vq; +} + +static int vus_sound_config_change(struct vhost_dev *dev) +{ + DBG("vus_sound_config_change\n"); + + int ret = vhost_dev_get_config(dev, (uint8_t *)dev->vdev->config, + sizeof(struct virtio_snd_config)); + if (ret < 0) { + DBG("vus_sound_config_change error\n"); + return -1; + } + + virtio_notify_config(dev->vdev); + + return 0; +} + +const VhostDevConfigOps snd_config_ops = { + .vhost_dev_config_notifier = vus_sound_config_change, +}; + +static void vhost_user_snd_init(VirtIODevice *vdev); + +void vus_device_realize(struct adapter_dev *adev) +{ + VirtIODevice *vdev = &adev->virtio_dev; + VirtIOMMIOProxy *proxy = &adev->proxy; + int ret; + + DBG("vus_device_realize\n"); + + /* Initialize proxy */ + proxy->legacy = 1; + + /* VIRTIO_ID_SOUND is 25, check virtio_ids.h in linux*/ + virtio_dev_init(vdev, "virtio-sound", 25, sizeof(struct virtio_snd_config)); + vdev->user_feature_bits = user_feature_bits; + vhost_user_snd_init(vdev); + + /* add queues */ + vdev->vhusnd->vhost_dev->nvqs = 4; + vdev->vhusnd->num_queues = 4; + vdev->vhusnd->queue_size = 64; + + /* NOTE: vdev->vqs == vhublk->virtqs */ + vdev->vqs = (VirtQueue **)malloc(sizeof(VirtQueue *) + * vdev->vhusnd->num_queues); + vdev->vqs[0] = virtio_add_queue(vdev, 64, vus_snd_handle_output); + vdev->vqs[1] = virtio_add_queue(vdev, 64, vus_snd_handle_output); + vdev->vqs[2] = virtio_add_queue(vdev, 64, vus_snd_handle_output); + vdev->vqs[3] = virtio_add_queue(vdev, 64, vus_snd_handle_output); + + vdev->vhusnd->vhost_vqs = (struct vhost_virtqueue *)malloc( + sizeof(struct vhost_virtqueue) * + vdev->vhusnd->num_queues); + + /* Set up vhost device */ + vdev->vhusnd->vhost_dev->num_queues = vdev->vhusnd->num_queues; + vdev->vhusnd->vhost_dev->nvqs = vdev->vhusnd->num_queues; + vdev->vhusnd->vhost_dev->vqs = vdev->vhusnd->vhost_vqs; + vdev->vhusnd->vhost_dev->vq_index = 0; + vdev->vhusnd->vhost_dev->backend_features = 0; + + vhost_dev_set_config_notifier(vdev->vhusnd->vhost_dev, &snd_config_ops); + + /* TODO: Add error handling */ + vhost_dev_init(vdev->vhusnd->vhost_dev); + + /* Pass the new obtained features */ + vdev->host_features = vdev->vhusnd->vhost_dev->features; + + ret = vhost_dev_get_config(vdev->vhusnd->vhost_dev, + (uint8_t *)vdev->config, + sizeof(struct virtio_snd_config)); + if (ret < 0) { + goto vhost_dev_init_failed; + } + + vdev->vdev_class->print_config((uint8_t *)&vdev->config); + + return; + +vhost_dev_init_failed: + DBG("vhost_dev_init_failed\n"); + return; +} + +static void print_config_snd(uint8_t *config_data) +{ + struct virtio_snd_config *config_strct = + (struct virtio_snd_config *)config_data; + + (void)config_strct; + + DBG("print_config_snd:\n"); + /* # of available physical jacks */ + DBG("\tuint32_t jacks: %u\n", config_strct->jacks); + /* # of available PCM streams */ + DBG("\tuint32_t streams: %u\n", config_strct->streams); + /* # of available channel maps */ + DBG("\tuint32_t chmaps: %u\n", config_strct->chmaps); +} + +static void vhost_user_dev_class_init_extra(VirtIODevice *vdev) +{ + DBG("vhost_user_dev_class_init_extra\n"); + + vdev->vdev_class->realize = vus_device_realize; + vdev->vdev_class->print_config = print_config_snd; +} + +static void vhost_user_snd_init(VirtIODevice *vdev) +{ + + DBG("vhost_user_blk_init\n"); + + VHostUserSound *vhusnd = (VHostUserSound *)malloc(sizeof(VHostUserSound)); + vdev->vhusnd = vhusnd; + vdev->nvqs = (int *)&vdev->vhdev->nvqs; + vhusnd->parent = vdev; + vhusnd->virtqs = vdev->vqs; + vhusnd->vhost_dev = vdev->vhdev; + + vhost_user_dev_class_init(vdev); + vhost_user_dev_class_init_extra(vdev); + virtio_loopback_bus_init(vdev->vbus); +} diff --git a/virtio_rng.c b/src/devices/virtio_rng.c index f230b23..cfb95d2 100644 --- a/virtio_rng.c +++ b/src/devices/virtio_rng.c @@ -60,7 +60,7 @@ void virtio_rng_set_status(VirtIODevice *vdev, uint8_t status) } /* Send data from a char device over to the guest */ -void chr_read(VirtIORNG *vrng, const void *buf, size_t size) +void chr_read(VirtIORNG *vrng, const char *buf, size_t size) { VirtIODevice *vdev = vrng->parent_obj; VirtQueueElement *elem; @@ -129,7 +129,7 @@ void virtio_rng_process(VirtIORNG *vrng) size = MIN(vrng->quota_remaining, size); if (size) { - chr_read(vrng, &test_str, size); + chr_read(vrng, (const char *)&test_str, size); } } @@ -158,25 +158,22 @@ void virtio_rng_init(VirtIODevice *vdev) virtio_dev_class_init(vdev); } - -void virtio_rng_realize(int queue_num, int queue_size) +void virtio_rng_realize(struct adapter_dev *adev) { - (void)queue_num; - (void)queue_size; + VirtIODevice *vdev = &adev->virtio_dev; + VirtIOMMIOProxy *proxy = &adev->proxy; - /* prepare procy and virtio dev*/ - proxy = (VirtIOMMIOProxy *)malloc(sizeof(VirtIOMMIOProxy)); + DBG("virtio_rng_realize(...)\n"); - virtio_dev_init(global_vdev, "virtio-rng", 4, 0); + /* Initialize proxy */ + proxy->legacy = 1; - virtio_rng_init(global_vdev); + virtio_dev_init(vdev, "virtio-rng", 4, 0); - global_vdev->vq = virtio_add_queue(global_vdev, 8, handle_input); + virtio_rng_init(vdev); - global_vdev->host_features = 0x39000000; + vdev->vq = virtio_add_queue(vdev, 8, handle_input); - *proxy = (VirtIOMMIOProxy) { - .legacy = 1, - }; + vdev->host_features = 0x39000000; } diff --git a/vhost_loopback.c b/src/lib/vhost_loopback.c index 5fd3b05..3ea18b7 100644 --- a/vhost_loopback.c +++ b/src/lib/vhost_loopback.c @@ -196,8 +196,6 @@ void vhost_ack_features(struct vhost_dev *hdev, const int *feature_bits, } } - - /* Mask/unmask events from this vq. */ void vhost_virtqueue_mask(struct vhost_dev *hdev, VirtIODevice *vdev, int n, bool mask) @@ -214,7 +212,7 @@ void vhost_virtqueue_mask(struct vhost_dev *hdev, VirtIODevice *vdev, int n, file.index = vhost_user_get_vq_index(hdev, n); - r = vhost_user_set_vring_call(&file); + r = vhost_user_set_vring_call(hdev, &file); if (r < 0) { DBG("vhost_set_vring_call failed\n"); } @@ -260,10 +258,10 @@ static int vhost_virtqueue_start(struct vhost_dev *dev, } vq->desc_size = s = l = virtio_queue_get_desc_size(vdev, idx); - vq->desc_phys = vring_phys_addrs[idx] << 12; + vq->desc_phys = vdev->vring_phys_addrs[idx] << 12; vq->desc = (void *)virtio_queue_get_desc_addr(vdev, idx); if (!vq->desc || l != s) { - DBG("Error : vq->desc = a\n"); + DBG("Error : vq->desc\n"); r = -ENOMEM; return r; } @@ -273,7 +271,7 @@ static int vhost_virtqueue_start(struct vhost_dev *dev, - virtio_queue_get_desc_addr(vdev, idx); vq->avail = (void *)virtio_queue_get_avail_addr(vdev, idx); if (!vq->avail || l != s) { - DBG("Error : vq->avail = a\n"); + DBG("Error : vq->avail\n"); r = -ENOMEM; return r; } @@ -283,14 +281,14 @@ static int vhost_virtqueue_start(struct vhost_dev *dev, - virtio_queue_get_avail_addr(vdev, idx); vq->used = (void *)virtio_queue_get_used_addr(vdev, idx); if (!vq->used || l != s) { - DBG("Error : vq->used = a\n"); + DBG("Error : vq->used\n"); r = -ENOMEM; return r; } r = vhost_virtqueue_set_addr(dev, vq, vhost_vq_index, dev->log_enabled); if (r < 0) { - DBG("Fail vhost_virtqueue_set_addr\n"); + DBG("vhost_virtqueue_set_addr failed\n"); return r; } @@ -299,7 +297,7 @@ static int vhost_virtqueue_start(struct vhost_dev *dev, event_notifier_test_and_clear(virtio_queue_get_host_notifier(vvq)); file.fd = event_notifier_get_fd(virtio_queue_get_host_notifier(vvq)); - r = vhost_user_set_vring_kick(&file); + r = vhost_user_set_vring_kick(dev, &file); if (r < 0) { DBG("vhost_set_vring_kick failed\n"); return r; @@ -396,7 +394,6 @@ int vhost_dev_start(struct vhost_dev *hdev, VirtIODevice *vdev, bool vrings) return 0; } - int vhost_dev_get_config(struct vhost_dev *hdev, uint8_t *config, uint32_t config_len) { @@ -467,4 +464,3 @@ int vhost_dev_get_inflight(struct vhost_dev *dev, uint16_t queue_size, return 0; } - diff --git a/vhost_user_loopback.c b/src/lib/vhost_user_loopback.c index 1d52f05..3181cb9 100644 --- a/vhost_user_loopback.c +++ b/src/lib/vhost_user_loopback.c @@ -9,7 +9,7 @@ * Marc-André Lureau <mlureau@redhat.com> * Victor Kaplansky <victork@redhat.com> * - * Copyright 2022-2023 Virtual Open Systems SAS. + * Copyright 2022-2024 Virtual Open Systems SAS. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -58,7 +58,6 @@ #define DBG(...) #endif /* DEBUG */ - bool vhost_user_one_time_request(VhostUserRequest request) { switch (request) { @@ -73,7 +72,6 @@ bool vhost_user_one_time_request(VhostUserRequest request) } } - void vmsg_close_fds(VhostUserMsg *vmsg) { int i; @@ -83,8 +81,7 @@ void vmsg_close_fds(VhostUserMsg *vmsg) } } - -static int vu_message_write(int conn_fd, VhostUserMsg *vmsg) +static int vu_message_write(struct vhost_dev *dev, VhostUserMsg *vmsg) { int rc; uint8_t *p = (uint8_t *)vmsg; @@ -94,6 +91,11 @@ static int vu_message_write(int conn_fd, VhostUserMsg *vmsg) .iov_base = (char *)vmsg, .iov_len = VHOST_USER_HDR_SIZE, }; + struct adapter_dev *adev = to_adapter_device(dev, vdev); + Device *dev_par = adev->device_params; + int conn_fd = adev->device_params->client_socket; + + (void)dev_par; struct msghdr msg = { .msg_iov = &iov, @@ -137,7 +139,7 @@ static int vu_message_write(int conn_fd, VhostUserMsg *vmsg) return rc; } -static int vu_message_read(int conn_fd, VhostUserMsg *vmsg) +static int vu_message_read(struct vhost_dev *dev, VhostUserMsg *vmsg) { char control[CMSG_SPACE(VHOST_MEMORY_BASELINE_NREGIONS * sizeof(int))] = {}; struct iovec iov = { @@ -153,6 +155,8 @@ static int vu_message_read(int conn_fd, VhostUserMsg *vmsg) size_t fd_size; struct cmsghdr *cmsg; int rc; + struct adapter_dev *adev = to_adapter_device(dev, vdev); + int conn_fd = adev->device_params->client_socket; do { rc = recvmsg(conn_fd, &msg, 0); @@ -200,17 +204,17 @@ fail: return rc; } -int vhost_user_set_owner(void) +int vhost_user_set_owner(struct vhost_dev *dev) { VhostUserMsg msg = { .request = VHOST_USER_SET_OWNER, .flags = VHOST_USER_VERSION, }; - return vu_message_write(client_sock, &msg); + return vu_message_write(dev, &msg); } -int process_message_reply(const VhostUserMsg *msg) +int process_message_reply(struct vhost_dev *dev, const VhostUserMsg *msg) { int ret; VhostUserMsg msg_reply; @@ -220,7 +224,7 @@ int process_message_reply(const VhostUserMsg *msg) return 0; } - ret = vu_message_read(client_sock, &msg_reply); + ret = vu_message_read(dev, &msg_reply); if (ret < 0) { return ret; } @@ -235,7 +239,7 @@ int process_message_reply(const VhostUserMsg *msg) return msg_reply.payload.u64 ? -EIO : 0; } -int vhost_user_get_u64(int request, uint64_t *u64) +int vhost_user_get_u64(struct vhost_dev *dev, int request, uint64_t *u64) { int ret; VhostUserMsg msg = { @@ -249,12 +253,12 @@ int vhost_user_get_u64(int request, uint64_t *u64) return 0; } - ret = vu_message_write(client_sock, &msg); + ret = vu_message_write(dev, &msg); if (ret < 0) { return ret; } - ret = vu_message_read(client_sock, &msg); + ret = vu_message_read(dev, &msg); if (ret < 0) { return ret; } @@ -271,27 +275,25 @@ int vhost_user_get_u64(int request, uint64_t *u64) } *u64 = msg.payload.u64; - DBG("\tGet value: 0x%lx\n", msg.payload.u64); return 0; } - -int vhost_user_get_features(uint64_t *features) +int vhost_user_get_features(struct vhost_dev *dev, uint64_t *features) { - if (vhost_user_get_u64(VHOST_USER_GET_FEATURES, features) < 0) { + if (vhost_user_get_u64(dev, VHOST_USER_GET_FEATURES, features) < 0) { return -EPROTO; } return 0; } -int enforce_reply(const VhostUserMsg *msg) +int enforce_reply(struct vhost_dev *dev, const VhostUserMsg *msg) { uint64_t dummy; if (msg->flags & VHOST_USER_NEED_REPLY_MASK) { - return process_message_reply(msg); + return process_message_reply(dev, msg); } /* @@ -300,10 +302,10 @@ int enforce_reply(const VhostUserMsg *msg) * Send VHOST_USER_GET_FEATURES which makes all backends * send a reply. */ - return vhost_user_get_features(&dummy); + return vhost_user_get_features(dev, &dummy); } -int vhost_user_set_u64(int request, uint64_t u64, bool wait_for_reply) +int vhost_user_set_u64(struct vhost_dev *dev, int request, uint64_t u64, bool wait_for_reply) { int ret = 0; @@ -315,7 +317,6 @@ int vhost_user_set_u64(int request, uint64_t u64, bool wait_for_reply) }; print_vhost_user_messages(request); - DBG("\tSet value: 0x%lx\n", u64); if (wait_for_reply) { bool reply_supported = virtio_has_feature(dev->protocol_features, @@ -326,13 +327,13 @@ int vhost_user_set_u64(int request, uint64_t u64, bool wait_for_reply) } } - ret = vu_message_write(client_sock, &msg); + ret = vu_message_write(dev, &msg); if (ret < 0) { return ret; } if (wait_for_reply) { - return enforce_reply(&msg); + return enforce_reply(dev, &msg); } return ret; @@ -351,22 +352,23 @@ int vhost_user_set_features(struct vhost_dev *dev, /* Pass hdev as parameter! */ DBG("vhost_user_set_features: 0x%lx\n", features | dev->backend_features); - return vhost_user_set_u64(VHOST_USER_SET_FEATURES, + return vhost_user_set_u64(dev, VHOST_USER_SET_FEATURES, features | dev->backend_features, log_enabled); } -int vhost_user_set_protocol_features(uint64_t features) +int vhost_user_set_protocol_features(struct vhost_dev *dev, uint64_t features) { - return vhost_user_set_u64(VHOST_USER_SET_PROTOCOL_FEATURES, features, + return vhost_user_set_u64(dev, VHOST_USER_SET_PROTOCOL_FEATURES, features, false); } -int vhost_user_get_max_memslots(uint64_t *max_memslots) +int vhost_user_get_max_memslots(struct vhost_dev *dev, uint64_t *max_memslots) { uint64_t backend_max_memslots; int err; - err = vhost_user_get_u64(VHOST_USER_GET_MAX_MEM_SLOTS, + err = vhost_user_get_u64(dev, + VHOST_USER_GET_MAX_MEM_SLOTS, &backend_max_memslots); if (err < 0) { return err; @@ -377,8 +379,6 @@ int vhost_user_get_max_memslots(uint64_t *max_memslots) return 0; } - - int vhost_setup_slave_channel(struct vhost_dev *dev) { VhostUserMsg msg = { @@ -406,18 +406,17 @@ int vhost_setup_slave_channel(struct vhost_dev *dev) /* FIXME: something missing here */ - if (reply_supported) { msg.flags |= VHOST_USER_NEED_REPLY_MASK; } - ret = vu_message_write(client_sock, &msg); + ret = vu_message_write(dev, &msg); if (ret < 0) { goto out; } if (reply_supported) { - ret = process_message_reply(&msg); + ret = process_message_reply(dev, &msg); DBG("Reply is done!\n"); } @@ -445,7 +444,8 @@ int vhost_user_get_vq_index(struct vhost_dev *dev, int idx) return idx; } -static int vhost_user_write_sync(VhostUserMsg *msg, +static int vhost_user_write_sync(struct vhost_dev *dev, + VhostUserMsg *msg, bool wait_for_reply) { int ret; @@ -458,7 +458,7 @@ static int vhost_user_write_sync(VhostUserMsg *msg, } } - ret = vu_message_write(client_sock, msg); + ret = vu_message_write(dev, msg); if (ret < 0) { return ret; } @@ -468,7 +468,7 @@ static int vhost_user_write_sync(VhostUserMsg *msg, DBG("Wait for reply\n"); if (msg->flags & VHOST_USER_NEED_REPLY_MASK) { - return process_message_reply(msg); + return process_message_reply(dev, msg); } /* @@ -477,14 +477,15 @@ static int vhost_user_write_sync(VhostUserMsg *msg, * Send VHOST_USER_GET_FEATURES which makes all backends * send a reply. */ - return vhost_user_get_features(&dummy); + return vhost_user_get_features(dev, &dummy); } return 0; } -int vhost_set_vring_file(VhostUserRequest request, - struct vhost_vring_file *file) +int vhost_set_vring_file(struct vhost_dev *dev, + VhostUserRequest request, + struct vhost_vring_file *file) { int fds[VHOST_USER_MAX_RAM_SLOTS]; size_t fd_num = 0; @@ -514,19 +515,17 @@ int vhost_set_vring_file(VhostUserRequest request, msg.fd_num = fd_num; memcpy(msg.fds, &fds, fd_num * sizeof(int)); - return vu_message_write(client_sock, &msg); + return vu_message_write(dev, &msg); } -int vhost_user_set_vring_kick(struct vhost_vring_file *file) +int vhost_user_set_vring_kick(struct vhost_dev *dev, struct vhost_vring_file *file) { - DBG("Call vhost_user_set_vring_kick()\n"); - return vhost_set_vring_file(VHOST_USER_SET_VRING_KICK, file); + return vhost_set_vring_file(dev, VHOST_USER_SET_VRING_KICK, file); } -int vhost_user_set_vring_call(struct vhost_vring_file *file) +int vhost_user_set_vring_call(struct vhost_dev *dev, struct vhost_vring_file *file) { - DBG("Call vhost_user_set_vring_call()\n"); - return vhost_set_vring_file(VHOST_USER_SET_VRING_CALL, file); + return vhost_set_vring_file(dev, VHOST_USER_SET_VRING_CALL, file); } static int vhost_set_vring(struct vhost_dev *dev, @@ -542,7 +541,7 @@ static int vhost_set_vring(struct vhost_dev *dev, }; (void)dev; - return vhost_user_write_sync(&msg, wait_for_reply); + return vhost_user_write_sync(dev, &msg, wait_for_reply); } int vhost_user_set_vring_num(struct vhost_dev *dev, @@ -557,7 +556,6 @@ int vhost_user_set_vring_base(struct vhost_dev *dev, return vhost_set_vring(dev, VHOST_USER_SET_VRING_BASE, ring, false); } - int vhost_user_set_vring_addr(struct vhost_dev *dev, struct vhost_vring_addr *addr) { @@ -569,10 +567,9 @@ int vhost_user_set_vring_addr(struct vhost_dev *dev, }; (void)dev; - return vhost_user_write_sync(&msg, true); + return vhost_user_write_sync(dev, &msg, true); } - int vhost_virtqueue_init(struct vhost_dev *dev, struct vhost_virtqueue *vq, int n) { @@ -589,7 +586,7 @@ int vhost_virtqueue_init(struct vhost_dev *dev, file.fd = event_notifier_get_wfd(&vq->masked_notifier); - r = vhost_user_set_vring_call(&file); + r = vhost_user_set_vring_call(dev, &file); if (r < 0) { DBG("vhost_set_vring_call failed\n"); return r; @@ -621,14 +618,14 @@ int vhost_user_get_config(struct vhost_dev *dev, uint8_t *config, msg.payload.config.offset = 0; msg.payload.config.size = config_len; - ret = vu_message_write(client_sock, &msg); + ret = vu_message_write(dev, &msg); DBG("vu_message_write return: %d\n", ret); if (ret < 0) { DBG("vhost_get_config failed\n"); return ret; } - ret = vu_message_read(client_sock, &msg); + ret = vu_message_read(dev, &msg); if (ret < 0) { DBG("vhost_get_config failed\n"); return ret; @@ -649,8 +646,6 @@ int vhost_user_get_config(struct vhost_dev *dev, uint8_t *config, DBG("Received config: %u, config_len: %u\n", *config, config_len); - DBG("vhost_user_get_config return successfully\n"); - return 0; } @@ -662,6 +657,8 @@ int vhost_user_set_config(struct vhost_dev *dev, const uint8_t *data, bool reply_supported = virtio_has_feature(dev->protocol_features, VHOST_USER_PROTOCOL_F_REPLY_ACK); + DBG("vhost_user_set_config(...)\n"); + VhostUserMsg msg = { .request = VHOST_USER_SET_CONFIG, .flags = VHOST_USER_VERSION, @@ -688,14 +685,13 @@ int vhost_user_set_config(struct vhost_dev *dev, const uint8_t *data, p = msg.payload.config.region; memcpy(p, data, size); - ret = vu_message_write(client_sock, &msg); - DBG("vu_message_write return: %d\n", ret); + ret = vu_message_write(dev, &msg); if (ret < 0) { return ret; } if (reply_supported) { - return process_message_reply(&msg); + return process_message_reply(dev, &msg); DBG("Reply is done!\n"); } @@ -718,7 +714,7 @@ int vhost_user_get_inflight_fd(struct vhost_dev *dev, .size = sizeof(msg.payload.inflight), }; - DBG("vhost_user_get_inflight_fd\n"); + DBG("vhost_user_get_inflight_fd()\n"); if (!virtio_has_feature(dev->protocol_features, VHOST_USER_PROTOCOL_F_INFLIGHT_SHMFD)) { @@ -726,14 +722,14 @@ int vhost_user_get_inflight_fd(struct vhost_dev *dev, } /* NOTE: This stays here as a reference */ - ret = vu_message_write(client_sock, &msg); + ret = vu_message_write(dev, &msg); if (ret < 0) { DBG("vhost_user_get_inflight_fd\n\t->write error\n"); return ret; } /* NOTE: This stays here as a reference */ - ret = vu_message_read(client_sock, &msg); + ret = vu_message_read(dev, &msg); if (ret < 0) { DBG("vhost_user_get_inflight_fd\n\t->read error\n"); return ret; @@ -781,7 +777,6 @@ int vhost_user_get_inflight_fd(struct vhost_dev *dev, return 0; } - int vhost_user_set_inflight_fd(struct vhost_dev *dev, struct vhost_inflight *inflight) { @@ -805,17 +800,18 @@ int vhost_user_set_inflight_fd(struct vhost_dev *dev, msg.fd_num = 1; memcpy(msg.fds, &inflight->fd, msg.fd_num * sizeof(int)); - return vu_message_write(client_sock, &msg); + return vu_message_write(dev, &msg); } - /* -------------------- Mem regions functions -------------------- */ - -static MemoryRegion *vhost_user_get_mr_data(struct vhost_memory_region *reg, +static MemoryRegion *vhost_user_get_mr_data(struct vhost_dev *dev, + struct vhost_memory_region *reg, ram_addr_t *offset, int *fd) { MemoryRegion *mr; + struct adapter_dev *adev = to_adapter_device(dev, vdev); + int loopback_fd = adev->loopback_fd; (void)reg; mr = (MemoryRegion *)malloc(sizeof(MemoryRegion)); @@ -855,7 +851,7 @@ static int vhost_user_fill_set_mem_table_msg(struct vhost_user *u, for (i = 0; i < dev->mem->nregions; ++i) { reg = dev->mem->regions + i; - mr = vhost_user_get_mr_data(reg, &offset, &fd); + mr = vhost_user_get_mr_data(dev, reg, &offset, &fd); if (fd > 0) { if (track_ramblocks) { u->region_rb_offset[i] = offset; @@ -896,7 +892,6 @@ static inline bool reg_equal(struct vhost_memory_region *shadow_reg, shadow_reg->memory_size == vdev_reg->memory_size; } - /* Sync the two region lists (device / adapter) */ static void scrub_shadow_regions(struct vhost_dev *dev, struct scrub_regions *add_reg, @@ -905,7 +900,7 @@ static void scrub_shadow_regions(struct vhost_dev *dev, int *nr_rem_reg, uint64_t *shadow_pcb, bool track_ramblocks) { - struct vhost_user *u = adev->vudev; + struct vhost_user *u = dev->vhudev; bool found[VHOST_USER_MAX_RAM_SLOTS] = {}; struct vhost_memory_region *reg, *shadow_reg; int fd, add_idx = 0, rm_idx = 0, fd_num = 0; @@ -930,7 +925,7 @@ static void scrub_shadow_regions(struct vhost_dev *dev, for (j = 0; j < dev->mem->nregions; j++) { reg = &dev->mem->regions[j]; - mr = vhost_user_get_mr_data(reg, &offset, &fd); + mr = vhost_user_get_mr_data(dev, reg, &offset, &fd); if (reg_equal(shadow_reg, reg)) { matching = true; @@ -963,7 +958,7 @@ static void scrub_shadow_regions(struct vhost_dev *dev, reg = &dev->mem->regions[i]; - mr = vhost_user_get_mr_data(reg, &offset, &fd); + mr = vhost_user_get_mr_data(dev, reg, &offset, &fd); /* * If the region was in both the shadow and device state we don't @@ -984,7 +979,6 @@ static void scrub_shadow_regions(struct vhost_dev *dev, return; } - static int send_remove_regions(struct vhost_dev *dev, struct scrub_regions *remove_reg, int nr_rem_reg, VhostUserMsg *msg, @@ -994,6 +988,8 @@ static int send_remove_regions(struct vhost_dev *dev, int i, fd, shadow_reg_idx, ret = 0; ram_addr_t offset; VhostUserMemoryRegion region_buffer; + struct adapter_dev *adev = to_adapter_device(dev, vdev); + int loopback_fd = adev->loopback_fd; (void)ret; (void)dev; @@ -1009,7 +1005,7 @@ static int send_remove_regions(struct vhost_dev *dev, DBG("Try to remove: 0x%llx\n", remove_reg[i].region->guest_phys_addr); - (void)vhost_user_get_mr_data(shadow_reg, &offset, &fd); + (void)vhost_user_get_mr_data(dev, shadow_reg, &offset, &fd); if (fd > 0) { msg->request = VHOST_USER_REM_MEM_REG; @@ -1019,14 +1015,14 @@ static int send_remove_regions(struct vhost_dev *dev, msg->fd_num = 1; memcpy(msg->fds, &loopback_fd, sizeof(int)); - ret = vu_message_write(client_sock, msg); + ret = vu_message_write(dev, msg); if (ret < 0) { return ret; } if (reply_supported) { msg->flags |= VHOST_USER_NEED_REPLY_MASK; - ret = process_message_reply(msg); + ret = process_message_reply(dev, msg); /* * TODO: For this release do not process the message: @@ -1047,12 +1043,14 @@ static int send_add_regions(struct vhost_dev *dev, VhostUserMsg *msg, uint64_t *shadow_pcb, bool reply_supported, bool track_ramblocks) { - struct vhost_user *u = adev->vudev; + struct vhost_user *u = dev->vhudev; int i, fd, ret = 0, reg_idx, reg_fd_idx; struct vhost_memory_region *reg; MemoryRegion *mr; ram_addr_t offset; VhostUserMemoryRegion region_buffer; + struct adapter_dev *adev = to_adapter_device(dev, vdev); + int loopback_fd = adev->loopback_fd; (void)dev; (void)shadow_pcb; @@ -1067,7 +1065,7 @@ static int send_add_regions(struct vhost_dev *dev, DBG("Try to add: 0x%llx\n", add_reg[i].region->guest_phys_addr); - mr = vhost_user_get_mr_data(reg, &offset, &fd); + mr = vhost_user_get_mr_data(dev, reg, &offset, &fd); if (fd > 0) { @@ -1078,7 +1076,7 @@ static int send_add_regions(struct vhost_dev *dev, msg->fd_num = 1; memcpy(msg->fds, &loopback_fd, sizeof(int)); - ret = vu_message_write(client_sock, msg); + ret = vu_message_write(dev, msg); if (ret < 0) { DBG("send_add_regions -> write failed\n"); return ret; @@ -1086,7 +1084,7 @@ static int send_add_regions(struct vhost_dev *dev, if (reply_supported) { msg->flags |= VHOST_USER_NEED_REPLY_MASK; - ret = process_message_reply(msg); + ret = process_message_reply(dev, msg); /* * TODO: For this release do not process the message: @@ -1109,7 +1107,7 @@ static int vhost_user_add_remove_regions(struct vhost_dev *dev, bool reply_supported, bool track_ramblocks) { - struct vhost_user *u = adev->vudev; + struct vhost_user *u = dev->vhudev; struct scrub_regions add_reg[VHOST_USER_MAX_RAM_SLOTS]; struct scrub_regions rem_reg[VHOST_USER_MAX_RAM_SLOTS]; uint64_t shadow_pcb[VHOST_USER_MAX_RAM_SLOTS] = {}; @@ -1135,7 +1133,6 @@ static int vhost_user_add_remove_regions(struct vhost_dev *dev, goto err; } - /* TODO: At this point we need to update the shadow list */ u->num_shadow_regions = dev->mem->nregions; memcpy(u->shadow_regions, dev->mem->regions, @@ -1148,7 +1145,6 @@ err: return -1; } - /* TODO: This funciton might be implemented in a later release */ static int vhost_user_set_mem_table_postcopy(struct vhost_dev *dev, bool reply_supported, @@ -1161,7 +1157,6 @@ static int vhost_user_set_mem_table_postcopy(struct vhost_dev *dev, return 0; } - /* * TODO: This function is not yet fully optimized because in the current release * it is not used. t will be implemented or deleted in a later release. @@ -1176,7 +1171,8 @@ int vhost_user_set_mem_table(struct vhost_dev *dev) bool config_mem_slots = virtio_has_feature(dev->protocol_features, VHOST_USER_PROTOCOL_F_CONFIGURE_MEM_SLOTS); - struct vhost_user *u = adev->vudev; + //struct vhost_user *u = to_vhost_user_device(dev, dev); + struct vhost_user *u = dev->vhudev; bool do_postcopy = false; if (do_postcopy) { @@ -1215,22 +1211,20 @@ int vhost_user_set_mem_table(struct vhost_dev *dev) msg.fd_num = fd_num; memcpy(msg.fds, fds, fd_num * sizeof(int)); - ret = vu_message_write(client_sock, &msg); + ret = vu_message_write(dev, &msg); if (ret < 0) { DBG("vhost_user_set_mem_table failed write msg\n"); return ret; } if (reply_supported) { - ret = process_message_reply(&msg); + ret = process_message_reply(dev, &msg); } } return ret; } - - void print_mem_table(struct vhost_dev *dev) { struct vhost_memory_region *cur_vmr; @@ -1313,41 +1307,33 @@ static bool find_reg(struct vhost_dev *dev, uint64_t hpa, uint64_t len) return false; } -int last_avail = -1; - void find_add_new_reg(struct vhost_dev *dev) { - int sglist_elem_num; uint64_t i, j; + VirtIODevice *vdev = dev->vdev; - (void)sglist_elem_num; DBG("Total nvqs: %d\n", dev->nvqs); for (i = 0; (unsigned int)i < dev->nvqs; i++) { - VRing *vring = &dev->vdev->vq[i].vring; + VRing *vring = &vdev->vq[i].vring; uint64_t vring_num = vring->num; DBG("For vq[%lu]:\n", i); - DBG("vqs[%lu] hpa 0x%lx\n", i, vring_phys_addrs[i]); + DBG("vqs[%lu] hpa 0x%lx\n", i, vdev->vring_phys_addrs[i]); DBG("vq[%lu].vring.num: %ld\n", i, vring_num); DBG("We got avail buf: %d\n", - ((VRingAvail *)(dev->vdev->vq[i].vring.avail))->idx); - - int avail_diff = ((VRingAvail *)(dev->vdev->vq[i].vring.avail))->idx - - last_avail; + ((VRingAvail *)(vdev->vq[i].vring.avail))->idx); for (j = 0; j < vring_num; j++) { - uint64_t desc_addr = dev->vdev->vq[i].vring.desc; + uint64_t desc_addr = vdev->vq[i].vring.desc; VRingDesc desc_p = ((VRingDesc *)desc_addr)[j]; uint64_t sg_addr = desc_p.addr; uint64_t sg_len = desc_p.len; if (desc_p.addr == 0) { - sglist_elem_num = j; DBG("We got avail buf: %d\n", - ((VRingAvail *)(dev->vdev->vq[i].vring.avail))->idx); - DBG("We got sglist_ele_num: %d\n", sglist_elem_num); + ((VRingAvail *)(vdev->vq[i].vring.avail))->idx); break; } @@ -1362,10 +1348,7 @@ void find_add_new_reg(struct vhost_dev *dev) } DBG("We got avail buf: %d\n", - ((VRingAvail *)(dev->vdev->vq[i].vring.avail))->idx); - - last_avail = ((VRingAvail *)(dev->vdev->vq[i].vring.avail))->idx; - sglist_elem_num = 3 * avail_diff; + ((VRingAvail *)(vdev->vq[i].vring.avail))->idx); } } @@ -1373,6 +1356,9 @@ void vhost_commit_init_vqs(struct vhost_dev *dev) { size_t regions_size; unsigned int i; + //struct adapter_dev *adev = to_adapter_device(dev, vdev); + //VirtIODevice *vdev = &adev->virtio_dev; + VirtIODevice *vdev = dev->vdev; dev->n_mem_sections = dev->nvqs; @@ -1385,8 +1371,8 @@ void vhost_commit_init_vqs(struct vhost_dev *dev) for (i = 0; i < dev->nvqs; i++) { struct vhost_memory_region *cur_vmr = dev->mem->regions + i; - cur_vmr->guest_phys_addr = vring_phys_addrs[i] << PAGE_SHIFT; - cur_vmr->memory_size = get_vqs_max_size(global_vdev); + cur_vmr->guest_phys_addr = vdev->vring_phys_addrs[i] << PAGE_SHIFT; + cur_vmr->memory_size = get_vqs_max_size(vdev); cur_vmr->userspace_addr = 0; cur_vmr->flags_padding = 0; } @@ -1430,7 +1416,7 @@ int vhost_user_backend_init(struct vhost_dev *vhdev) DBG("vhost_user_backend_init (...)\n"); - err = vhost_user_get_features(&features); + err = vhost_user_get_features(vhdev, &features); if (err < 0) { DBG("vhost_backend_init failed\n"); return err; @@ -1439,7 +1425,7 @@ int vhost_user_backend_init(struct vhost_dev *vhdev) if (virtio_has_feature(features, VHOST_USER_F_PROTOCOL_FEATURES)) { vhdev->backend_features |= 1ULL << VHOST_USER_F_PROTOCOL_FEATURES; - err = vhost_user_get_u64(VHOST_USER_GET_PROTOCOL_FEATURES, + err = vhost_user_get_u64(vhdev, VHOST_USER_GET_PROTOCOL_FEATURES, &protocol_features); if (err < 0) { DBG("vhost_backend_init failed\n"); @@ -1463,7 +1449,7 @@ int vhost_user_backend_init(struct vhost_dev *vhdev) !vhdev->config_ops->vhost_dev_config_notifier) { DBG("There is no config_ops or vhost_dev_config_notifier\n"); /* Don't acknowledge CONFIG feature if device doesn't support it */ - dev->protocol_features &= ~(1ULL << VHOST_USER_PROTOCOL_F_CONFIG); + vhdev->protocol_features &= ~(1ULL << VHOST_USER_PROTOCOL_F_CONFIG); } else if (!(protocol_features & (1ULL << VHOST_USER_PROTOCOL_F_CONFIG))) { DBG("Device expects VHOST_USER_PROTOCOL_F_CONFIG " @@ -1471,7 +1457,7 @@ int vhost_user_backend_init(struct vhost_dev *vhdev) return -EINVAL; } - err = vhost_user_set_protocol_features(vhdev->protocol_features); + err = vhost_user_set_protocol_features(vhdev, vhdev->protocol_features); if (err < 0) { DBG("vhost_backend_init failed\n"); return -EPROTO; @@ -1479,7 +1465,7 @@ int vhost_user_backend_init(struct vhost_dev *vhdev) /* query the max queues we support if backend supports Multiple Queue */ if (vhdev->protocol_features & (1ULL << VHOST_USER_PROTOCOL_F_MQ)) { - err = vhost_user_get_u64(VHOST_USER_GET_QUEUE_NUM, + err = vhost_user_get_u64(vhdev, VHOST_USER_GET_QUEUE_NUM, &vhdev->max_queues); if (err < 0) { DBG("vhost_backend_init failed\n"); @@ -1510,7 +1496,7 @@ int vhost_user_backend_init(struct vhost_dev *vhdev) VHOST_USER_PROTOCOL_F_CONFIGURE_MEM_SLOTS)) { vhdev->memory_slots = VHOST_MEMORY_BASELINE_NREGIONS; } else { - err = vhost_user_get_max_memslots(&ram_slots); + err = vhost_user_get_max_memslots(vhdev, &ram_slots); if (err < 0) { DBG("vhost_backend_init failed\n"); return -EPROTO; @@ -1567,12 +1553,12 @@ void vhost_dev_init(struct vhost_dev *vhdev) (void)vhost_user_backend_init(vhdev); - r = vhost_user_set_owner(); + r = vhost_user_set_owner(vhdev); if (r < 0) { DBG("vhost_set_owner failed\n"); } - r = vhost_user_get_features(&features); + r = vhost_user_get_features(vhdev, &features); if (r < 0) { DBG("vhost_get_features failed\n"); } @@ -1596,7 +1582,6 @@ void vhost_dev_init(struct vhost_dev *vhdev) vhdev->log_enabled = false; vhdev->started = false; - /* * TODO: busyloop == 0 in rng case, but we might need it for new devices: * @@ -1651,7 +1636,7 @@ int vhost_user_set_vring_enable(struct vhost_dev *dev, int enable) static int vhost_user_set_status(struct vhost_dev *dev, uint8_t status) { (void)dev; - return vhost_user_set_u64(VHOST_USER_SET_STATUS, status, false); + return vhost_user_set_u64(dev, VHOST_USER_SET_STATUS, status, false); } static int vhost_user_get_status(struct vhost_dev *dev, uint8_t *status) @@ -1660,7 +1645,7 @@ static int vhost_user_get_status(struct vhost_dev *dev, uint8_t *status) int ret; (void)dev; - ret = vhost_user_get_u64(VHOST_USER_GET_STATUS, &value); + ret = vhost_user_get_u64(dev, VHOST_USER_GET_STATUS, &value); if (ret < 0) { return ret; } @@ -1810,3 +1795,167 @@ void print_vhost_user_messages(int request) DBG("Unhandled request: %d\n", request); } } + +static void vhost_user_device_reset(VirtIODevice *vdev) +{ + DBG("vhost_user_device_reset not yet implemented)\n"); + (void)vdev; + + /* + * TODO: To be added + * + * if (vdev->active) { + * vhost_user_backend_stop(vdev); + * } + */ +} + + +static void vhost_user_device_unrealize(VirtIODevice *vdev) +{ + DBG("vhost_user_device_unrealize not yet implemented\n"); + (void)vdev; +} + +static void vhost_user_device_stop(VirtIODevice *vdev) +{ + DBG("vhost_user_device_stop: not yet implemented\n"); + (void)vdev; +} + +static uint64_t vhost_user_device_get_features(VirtIODevice *vdev, + uint64_t features) +{ + DBG("vhost_user_device_get_features()\n"); + + return vhost_get_features(vdev->vhdev, vdev->user_feature_bits, features); +} + + +static void vhost_user_device_set_status(VirtIODevice *vdev, uint8_t status) +{ + bool should_start = virtio_device_started(vdev, status); + DBG("vhost_user_device_set_status: %d\n", status); + + if (vdev->vhdev->started == should_start) { + DBG("vdev->vhost_dev->started == should_start\n"); + return; + } + + if (should_start) { + vdev->vdev_class->start(vdev); + } else { + vdev->vdev_class->stop(vdev); + } +} + +/* TODO: We need to implement this function in a future release */ +static void vhost_user_device_guest_notifier_mask(VirtIODevice *vdev, int idx, bool mask) +{ + DBG("vhost_user_device_guest_notifier_mask is not yet implemented\n"); + (void)vdev; + (void)idx; + (void)mask; + + /* ADD: vhost_virtqueue_mask(&rng->vhost_dev, vdev, idx, mask); */ + vhost_virtqueue_mask(vdev->vhdev, vdev, idx, mask); +} + +/* TODO: We need to implement this function in a future release */ +static bool vhost_user_device_guest_notifier_pending(VirtIODevice *vdev, int idx) +{ + DBG("vhost_user_device_guest_notifier_pending is not yet implemented\n"); + (void)vdev; + (void)idx; + + /* ADD: return vhost_virtqueue_pending(&rng->vhost_dev, idx); */ + return 1; +} + +static void vhost_user_device_get_config(VirtIODevice *vdev, uint8_t *config) +{ + int ret; + + DBG("vhost_user_device_get_config\n"); + + memset(config, 0, vdev->config_len); + + ret = vhost_dev_get_config(vdev->vhdev, config, vdev->config_len); + if (ret) { + DBG("vhost_input_get_config failed\n"); + return; + } + //memcpy(config, vdev->config, vdev->config_len); +} + +static void vhost_user_device_start(VirtIODevice *vdev) +{ + VirtioBus *k = vdev->vbus; + int ret; + unsigned int i; + + DBG("vhost_user_device_start(...)\n"); + + if (!k->set_guest_notifiers) { + DBG("binding does not support guest notifiers\n"); + return; + } + + ret = vhost_dev_enable_notifiers(vdev->vhdev, vdev); + if (ret < 0) { + DBG("Error enabling host notifiers: %d\n", -ret); + return; + } + + ret = k->set_guest_notifiers(k->vdev, vdev->vhdev->nvqs, true); + if (ret < 0) { + DBG("Error binding guest notifier: %d\n", -ret); + goto err_host_notifiers; + } + + vdev->vhdev->acked_features = vdev->guest_features; + + ret = vhost_dev_start(vdev->vhdev, vdev, true); + if (ret < 0) { + DBG("Error starting vhost: %d\n", -ret); + goto err_guest_notifiers; + } + + /* + * guest_notifier_mask/pending not used yet, so just unmask + * everything here. virtio-pci will do the right thing by + * enabling/disabling irqfd. + */ + for (i = 0; i < vdev->vhdev->nvqs; i++) { + vhost_virtqueue_mask(vdev->vhdev, vdev, i, false); + } + + return; + +err_guest_notifiers: +err_host_notifiers: + DBG("vhu_start error\n"); + return; +} + + +void vhost_user_dev_class_init(VirtIODevice *vdev) +{ + DBG("virtio_loopback_class_init(...)\n"); + vdev->vdev_class = (VirtioDeviceClass *)malloc(sizeof(VirtioDeviceClass)); + vdev->vdev_class->parent = vdev; + + /* Define common functions */ + vdev->vdev_class->realize = NULL; + vdev->vdev_class->start = vhost_user_device_start; + vdev->vdev_class->stop = vhost_user_device_stop; + vdev->vdev_class->unrealize = vhost_user_device_unrealize; + vdev->vdev_class->get_config = vhost_user_device_get_config; + vdev->vdev_class->get_features = vhost_user_device_get_features; + vdev->vdev_class->reset = vhost_user_device_reset; + vdev->vdev_class->set_status = vhost_user_device_set_status; + vdev->vdev_class->update_mem_table = update_mem_table; + vdev->vdev_class->guest_notifier_mask = vhost_user_device_guest_notifier_mask; + vdev->vdev_class->guest_notifier_pending = vhost_user_device_guest_notifier_pending; + +} diff --git a/virtio_loopback.c b/src/lib/virtio_loopback.c index 5457f20..1b57794 100644 --- a/virtio_loopback.c +++ b/src/lib/virtio_loopback.c @@ -54,6 +54,7 @@ /* Project header files */ #include "virtio_loopback.h" +#include "vhost_user_loopback.h" #include "virtio_rng.h" #include <stddef.h> @@ -66,23 +67,6 @@ #define DBG(...) #endif /* DEBUG */ -/* Global variables */ - -int s; /* To be deleted */ -int efd; /* Eventfd file descriptor */ -int efd_notify; /* Eventfd file descriptor */ -fd_set rfds; -int fd; -int loopback_fd; - -virtio_device_info_struct_t device_info; -virtio_neg_t *address; - -VirtIOMMIOProxy *proxy; - -int eventfd_count; -pthread_mutex_t interrupt_lock; - void virtio_add_feature(uint64_t *features, unsigned int fbit) { *features |= (1ULL << fbit); @@ -122,8 +106,6 @@ bool virtio_device_started(VirtIODevice *vdev, uint8_t status) return status & VIRTIO_CONFIG_S_DRIVER_OK; } - - void virtio_set_started(VirtIODevice *vdev, bool started) { if (started) { @@ -160,7 +142,6 @@ int virtio_set_status(VirtIODevice *vdev, uint8_t val) DBG("set vdev->status:%u\n", vdev->status); if (k->set_status) { - DBG("k->set_status\n"); k->set_status(vdev, val); } @@ -194,13 +175,11 @@ uint64_t virtio_queue_get_used_addr(VirtIODevice *vdev, int n) return vdev->vq[n].vring.used; } - int virtio_queue_get_num(VirtIODevice *vdev, int n) { return vdev->vq[n].vring.num; } - uint64_t virtio_queue_get_avail_size(VirtIODevice *vdev, int n) { int s; @@ -242,7 +221,6 @@ static uint16_t virtio_queue_split_get_last_avail_idx(VirtIODevice *vdev, return vdev->vq[n].last_avail_idx; } - unsigned int virtio_queue_get_last_avail_idx(VirtIODevice *vdev, int n) { return virtio_queue_split_get_last_avail_idx(vdev, n); @@ -267,7 +245,6 @@ uint64_t virtio_queue_get_addr(VirtIODevice *vdev, int n) return vdev->vq[n].vring.desc; } - void virtio_queue_set_addr(VirtIODevice *vdev, int n, uint64_t addr) { if (!vdev->vq[n].vring.num) { @@ -282,7 +259,6 @@ int virtio_queue_ready(VirtQueue *vq) return vq->vring.avail != 0; } - uint16_t vring_avail_idx(VirtQueue *vq) { vq->shadow_avail_idx = ((VRingAvail *)vq->vring.avail)->idx; @@ -334,7 +310,6 @@ size_t iov_from_buf_full(const struct iovec *iov, unsigned int iov_cnt, return done; } - size_t qemu_iov_from_buf(const struct iovec *iov, unsigned int iov_cnt, size_t offset, const void *buf, size_t bytes) { @@ -347,7 +322,6 @@ size_t qemu_iov_from_buf(const struct iovec *iov, unsigned int iov_cnt, } } - /* Called within rcu_read_lock(). */ static inline uint16_t vring_avail_flags(VirtQueue *vq) { @@ -366,18 +340,19 @@ static inline uint16_t vring_get_used_event(VirtQueue *vq) * we have just incremented index from old to new_idx, * should we trigger an event? */ -static inline int vring_need_event(uint16_t event_idx, - uint16_t new_idx, uint16_t old) -{ - /* - * Note: Xen has similar logic for notification hold-off - * in include/xen/interface/io/ring.h with req_event and req_prod - * corresponding to event_idx + 1 and new_idx respectively. - * Note also that req_event and req_prod in Xen start at 1, - * event indexes in virtio start at 0. - */ - return (uint16_t)(new_idx - event_idx - 1) < (uint16_t)(new_idx - old); -} +//static inline int vring_need_event(uint16_t event_idx, +//static int vring_need_event(uint16_t event_idx, +// uint16_t new_idx, uint16_t old) +//{ +// /* +// * Note: Xen has similar logic for notification hold-off +// * in include/xen/interface/io/ring.h with req_event and req_prod +// * corresponding to event_idx + 1 and new_idx respectively. +// * Note also that req_event and req_prod in Xen start at 1, +// * event indexes in virtio start at 0. +// */ +// return (uint16_t)(new_idx - event_idx - 1) < (uint16_t)(new_idx - old); +//} /* Called within rcu_read_lock(). */ static bool virtio_split_should_notify(VirtIODevice *vdev, VirtQueue *vq) @@ -408,7 +383,6 @@ static bool virtio_should_notify(VirtIODevice *vdev, VirtQueue *vq) return virtio_split_should_notify(vdev, vq); } - void virtio_set_isr(VirtIODevice *vdev, int value) { uint8_t old = vdev->isr; @@ -454,7 +428,6 @@ void virtio_notify(VirtIODevice *vdev, VirtQueue *vq) DBG("Do not notify!\n"); return; } - DBG("Go on and notify!\n"); virtio_irq(vq); } @@ -523,7 +496,6 @@ void virtqueue_push(VirtQueue *vq, const VirtQueueElement *elem, virtqueue_flush(vq, 1); } - void vring_set_avail_event(VirtQueue *vq, uint16_t val) { uint16_t *avail; @@ -769,7 +741,6 @@ int virtqueue_split_read_next_desc(VirtIODevice *vdev, VRingDesc *desc, return VIRTQUEUE_READ_DESC_MORE; } - static void virtqueue_split_get_avail_bytes(VirtQueue *vq, unsigned int *in_bytes, unsigned int *out_bytes, unsigned max_in_bytes, unsigned max_out_bytes) @@ -980,7 +951,7 @@ void print_neg_flag(uint64_t neg_flag, bool read) if (neg_flag >= VIRTIO_MMIO_CONFIG) { DBG("\tVIRTIO_MMIO_CONFIG\n"); } else { - DBG("\tNegotiation flag Unknown: %ld\n", neg_flag); + DBG("\tNegotiation flag Unknown: %lu\n", neg_flag); } return; } @@ -1012,7 +983,6 @@ int virtio_set_features(VirtIODevice *vdev, uint64_t val) return ret; } - /* TODO: MMIO notifiers -- This might not be needed anymore */ static void virtio_queue_guest_notifier_read(EventNotifier *n) { @@ -1029,6 +999,7 @@ void *loopback_event_select(void *_e) EventNotifier *e = (EventNotifier *)_e; int rfd = e->rfd; VirtQueue *vq = container_of(e, VirtQueue, guest_notifier); + VirtIODevice *vdev = vq->vdev; DBG("\nWaiting event from vhost-user-device\n"); @@ -1043,24 +1014,23 @@ void *loopback_event_select(void *_e) } if (retval > 0) { - if (pthread_mutex_lock(&interrupt_lock) != 0) { + if (pthread_mutex_lock(&vdev->interrupt_lock) != 0) { printf("[ERROR] Locking failed\n"); exit(1); } DBG("\n\nEvent has come from the vhost-user-device " "(eventfd: %d) -> event_count: %d (select value: %d)\n\n", - rfd, eventfd_count, retval); + rfd, vdev->eventfd_count, retval); if (event_notifier_test_and_clear(e)) { - eventfd_count++; + vdev->eventfd_count++; virtio_irq(vq); } - pthread_mutex_unlock(&interrupt_lock); + pthread_mutex_unlock(&vdev->interrupt_lock); } } } - void event_notifier_set_handler(EventNotifier *e, void *handler) { @@ -1077,7 +1047,6 @@ void event_notifier_set_handler(EventNotifier *e, } } - void virtio_queue_set_guest_notifier_fd_handler(VirtQueue *vq, bool assign, bool with_irqfd) { @@ -1159,12 +1128,12 @@ void virtio_queue_set_host_notifier_enabled(VirtQueue *vq, bool enabled) int virtio_bus_set_host_notifier(VirtioBus *vbus, int n, bool assign) { VirtIODevice *vdev = vbus->vdev; + struct adapter_dev *adev = to_adapter_device(vdev, virtio_dev); VirtQueue *vq = virtio_get_queue(vdev, n); EventNotifier *notifier = virtio_queue_get_host_notifier(vq); int r = 0; - if (!vbus->ioeventfd_assign) { return -ENOSYS; } @@ -1175,12 +1144,12 @@ int virtio_bus_set_host_notifier(VirtioBus *vbus, int n, bool assign) DBG("unable to init event notifier: %d", r); return r; } - r = vbus->ioeventfd_assign(proxy, notifier, n, true); + r = vbus->ioeventfd_assign(&adev->proxy, notifier, n, true); if (r < 0) { DBG("unable to assign ioeventfd: %d", r); } } else { - vbus->ioeventfd_assign(proxy, notifier, n, false); + vbus->ioeventfd_assign(&adev->proxy, notifier, n, false); } if (r == 0) { @@ -1190,8 +1159,6 @@ int virtio_bus_set_host_notifier(VirtioBus *vbus, int n, bool assign) return r; } - - /* On success, ioeventfd ownership belongs to the caller. */ int virtio_bus_grab_ioeventfd(VirtioBus *bus) { @@ -1224,12 +1191,10 @@ bool virtio_device_disabled(VirtIODevice *vdev) return vdev->disabled || vdev->broken; } -static int prev_level; -static int int_count; - void virtio_loopback_update_irq(VirtIODevice *vdev) { int level, irq_num = 44; + struct adapter_dev *adev = to_adapter_device(vdev, virtio_dev); if (!vdev) { return; @@ -1237,24 +1202,19 @@ void virtio_loopback_update_irq(VirtIODevice *vdev) level = (vdev->isr != 0); - DBG("level: %d\n", level); - DBG("prev_level: %d\n", prev_level); - - if (!((level == 1) && (prev_level == 0))) { + if (!((level == 1) && (vdev->prev_level == 0))) { DBG("No interrupt\n"); - prev_level = level; + vdev->prev_level = level; return; } - prev_level = level; + vdev->prev_level = level; DBG("Trigger interrupt (ioctl)\n"); - DBG("Interrupt counter: %d\n", int_count++); + DBG("Interrupt counter: %d\n", vdev->int_count++); - (void) ioctl(fd, IRQ, &irq_num); + (void) ioctl(adev->loopback_fd, IRQ, &irq_num); } -bool enable_virtio_interrupt; - /* virtio device */ void virtio_notify_vector(VirtIODevice *vdev) { @@ -1296,7 +1256,6 @@ void virtio_queue_notify(VirtIODevice *vdev, int n) if (vq->host_notifier_enabled) { event_notifier_set(&vq->host_notifier); } else if (vq->handle_output) { - DBG("vq->handle_output\n"); vq->handle_output(vdev, vq); if (vdev->start_on_kick) { @@ -1402,13 +1361,12 @@ void virtio_config_writel(VirtIODevice *vdev, uint32_t addr, uint32_t data) } } - - static uint64_t virtio_loopback_read(VirtIODevice *vdev, uint64_t offset, unsigned size) { uint64_t ret; + struct adapter_dev *adev = to_adapter_device(vdev, virtio_dev); if (!vdev) { /* @@ -1424,7 +1382,7 @@ static uint64_t virtio_loopback_read(VirtIODevice *vdev, uint64_t offset, case VIRTIO_MMIO_MAGIC_VALUE: return VIRT_MAGIC; case VIRTIO_MMIO_VERSION: - if (proxy->legacy) { + if (adev->proxy.legacy) { return VIRT_VERSION_LEGACY; } else { return VIRT_VERSION; @@ -1439,7 +1397,7 @@ static uint64_t virtio_loopback_read(VirtIODevice *vdev, uint64_t offset, if (offset >= VIRTIO_MMIO_CONFIG) { offset -= VIRTIO_MMIO_CONFIG; - if (proxy->legacy) { + if (adev->proxy.legacy) { switch (size) { case 1: ret = virtio_config_readb(vdev, offset); @@ -1451,9 +1409,9 @@ static uint64_t virtio_loopback_read(VirtIODevice *vdev, uint64_t offset, ret = virtio_config_readl(vdev, offset); break; default: + DBG("VIRTIO_MMIO_CONFIG abort\n"); abort(); } - DBG("ret: %lu\n", ret); return ret; } @@ -1469,7 +1427,7 @@ static uint64_t virtio_loopback_read(VirtIODevice *vdev, uint64_t offset, case VIRTIO_MMIO_MAGIC_VALUE: return VIRT_MAGIC; case VIRTIO_MMIO_VERSION: - if (proxy->legacy) { + if (adev->proxy.legacy) { DBG("VIRTIO_MMIO_VERSION -> legacy\n"); return VIRT_VERSION_LEGACY; } else { @@ -1479,11 +1437,10 @@ static uint64_t virtio_loopback_read(VirtIODevice *vdev, uint64_t offset, case VIRTIO_MMIO_DEVICE_ID: return vdev->device_id; case VIRTIO_MMIO_VENDOR_ID: - DBG("READ\n"); return VIRT_VENDOR; case VIRTIO_MMIO_DEVICE_FEATURES: - if (proxy->legacy) { - if (proxy->host_features_sel) { + if (adev->proxy.legacy) { + if (adev->proxy.host_features_sel) { return vdev->host_features >> 32; } else { return vdev->host_features & (uint64_t)(((1ULL << 32) - 1)); @@ -1496,16 +1453,16 @@ static uint64_t virtio_loopback_read(VirtIODevice *vdev, uint64_t offset, DBG("Return queue_size = %d\n", vdev->vq[vdev->queue_sel].vring.num); return vdev->vq[vdev->queue_sel].vring.num; case VIRTIO_MMIO_QUEUE_PFN: - if (!proxy->legacy) { + if (!adev->proxy.legacy) { DBG("VIRTIO_MMIO_QUEUE_PFN: read from legacy register (0x%lx) " "in non-legacy mode\n", offset); return 0; } return virtio_queue_get_addr(vdev, vdev->queue_sel) >> - proxy->guest_page_shift; + adev->proxy.guest_page_shift; case VIRTIO_MMIO_QUEUE_READY: - if (proxy->legacy) { + if (adev->proxy.legacy) { DBG("VIRTIO_MMIO_QUEUE_READY: read from legacy register (0x%lx) " "in non-legacy mode\n", offset); return 0; @@ -1519,7 +1476,7 @@ static uint64_t virtio_loopback_read(VirtIODevice *vdev, uint64_t offset, DBG("Read VIRTIO_MMIO_STATUS: %d\n", vdev->status); return vdev->status; case VIRTIO_MMIO_CONFIG_GENERATION: - if (proxy->legacy) { + if (adev->proxy.legacy) { DBG("VIRTIO_MMIO_CONFIG_GENERATION: read from legacy " "register (0x%lx) in non-legacy mode\n", offset); return 0; @@ -1558,13 +1515,11 @@ static uint64_t virtio_loopback_read(VirtIODevice *vdev, uint64_t offset, return 0; } -uint64_t vring_phys_addrs[10] = {0}; -uint32_t vring_phys_addrs_idx; -static int notify_cnt; - void virtio_loopback_write(VirtIODevice *vdev, uint64_t offset, uint64_t value, unsigned size) { + struct adapter_dev *adev = to_adapter_device(vdev, virtio_dev); + if (!vdev) { /* * If no backend is present, we just make all registers @@ -1577,7 +1532,7 @@ void virtio_loopback_write(VirtIODevice *vdev, uint64_t offset, if (offset >= VIRTIO_MMIO_CONFIG) { offset -= VIRTIO_MMIO_CONFIG; - if (proxy->legacy) { + if (adev->proxy.legacy) { switch (size) { case 1: virtio_config_writeb(vdev, offset, value); @@ -1605,14 +1560,14 @@ void virtio_loopback_write(VirtIODevice *vdev, uint64_t offset, case VIRTIO_MMIO_DEVICE_FEATURES_SEL: DBG("VIRTIO_MMIO_DEVICE_FEATURES_SEL: 0x%lx\n", value); if (value) { - proxy->host_features_sel = 1; + adev->proxy.host_features_sel = 1; } else { - proxy->host_features_sel = 0; + adev->proxy.host_features_sel = 0; } break; case VIRTIO_MMIO_DRIVER_FEATURES: - if (proxy->legacy) { - if (proxy->guest_features_sel) { + if (adev->proxy.legacy) { + if (adev->proxy.guest_features_sel) { DBG("Set driver features: 0x%lx\n", value << 32); virtio_set_features(vdev, value << 32); } else { @@ -1625,19 +1580,19 @@ void virtio_loopback_write(VirtIODevice *vdev, uint64_t offset, break; case VIRTIO_MMIO_DRIVER_FEATURES_SEL: if (value) { - proxy->guest_features_sel = 1; + adev->proxy.guest_features_sel = 1; } else { - proxy->guest_features_sel = 0; + adev->proxy.guest_features_sel = 0; } break; case VIRTIO_MMIO_GUEST_PAGE_SIZE: - if (!proxy->legacy) { + if (!adev->proxy.legacy) { DBG("write to legacy register (0x%lx" ") in non-legacy mode\n", offset); return; } - if (proxy->guest_page_shift > 31) { - proxy->guest_page_shift = 0; + if (adev->proxy.guest_page_shift > 31) { + adev->proxy.guest_page_shift = 0; } break; case VIRTIO_MMIO_QUEUE_SEL: @@ -1650,7 +1605,7 @@ void virtio_loopback_write(VirtIODevice *vdev, uint64_t offset, virtio_queue_set_num(vdev, vdev->queue_sel, value); - if (proxy->legacy) { + if (adev->proxy.legacy) { virtio_queue_update_rings(vdev, vdev->queue_sel); } else { /* TODO: To be implemented */ @@ -1658,7 +1613,7 @@ void virtio_loopback_write(VirtIODevice *vdev, uint64_t offset, } break; case VIRTIO_MMIO_QUEUE_ALIGN: - if (!proxy->legacy) { + if (!adev->proxy.legacy) { DBG("write to legacy register (0x%lx) in " "non-legacy mode\n", offset); return; @@ -1666,33 +1621,34 @@ void virtio_loopback_write(VirtIODevice *vdev, uint64_t offset, /* TODO: To be implemented */ break; case VIRTIO_MMIO_QUEUE_PFN: - if (!proxy->legacy) { + if (!adev->proxy.legacy) { DBG("write to legacy register (0x%lx) in " "non-legacy mode\n", offset); return; } if (value == 0) { /* TODO: To be implemented */ + DBG("Not implemented\n"); } else { DBG("desc_addr: 0x%lx\n", value); - vring_phys_addrs[vring_phys_addrs_idx++] = value; + vdev->vring_phys_addrs[vdev->vring_phys_addrs_idx++] = value; uint64_t desc_addr; - uint32_t vqs_size = get_vqs_max_size(global_vdev); + uint32_t vqs_size = get_vqs_max_size(vdev); - ioctl(fd, SHARE_VQS, &vdev->queue_sel); + ioctl(adev->loopback_fd, SHARE_VQS, &vdev->queue_sel); desc_addr = (uint64_t)mmap(NULL, vqs_size, PROT_READ | PROT_WRITE, - MAP_SHARED, fd, 0); + MAP_SHARED, adev->loopback_fd, 0); virtio_queue_set_addr(vdev, vdev->queue_sel, desc_addr); } break; case VIRTIO_MMIO_QUEUE_READY: - if (proxy->legacy) { + if (adev->proxy.legacy) { DBG("write to non-legacy register (0x%lx) in " "legacy mode\n", offset); return; @@ -1701,7 +1657,7 @@ void virtio_loopback_write(VirtIODevice *vdev, uint64_t offset, break; case VIRTIO_MMIO_QUEUE_NOTIFY: DBG("VIRTIO_MMIO_QUEUE_NOTIFY: vq_index -> %lu, notify_cnt: %d\n", - value, notify_cnt++); + value, vdev->notify_cnt++); if (value < VIRTIO_QUEUE_MAX) { virtio_queue_notify(vdev, value); } @@ -1716,32 +1672,32 @@ void virtio_loopback_write(VirtIODevice *vdev, uint64_t offset, * TODO: Add it in a future release later * * if (!(value & VIRTIO_CONFIG_S_DRIVER_OK)) { - * virtio_loopback_stop_ioeventfd(proxy); + * virtio_loopback_stop_ioeventfd(adev->proxy); * } */ - if (!proxy->legacy && (value & VIRTIO_CONFIG_S_FEATURES_OK)) { + if (!adev->proxy.legacy && (value & VIRTIO_CONFIG_S_FEATURES_OK)) { virtio_set_features(vdev, - ((uint64_t)proxy->guest_features[1]) << 32 | - proxy->guest_features[0]); + ((uint64_t)adev->proxy.guest_features[1]) << 32 | + adev->proxy.guest_features[0]); } virtio_set_status(vdev, value & 0xff); - DBG("STATUS -> %ld\n", value); + DBG("STATUS -> %lu\n", value); /* * TODO: Check if this is still needed * * if (vdev->status == 0) { * virtio_reset(vdev); - * virtio_loopback_soft_reset(proxy); + * virtio_loopback_soft_reset(adev->proxy); * } */ break; case VIRTIO_MMIO_QUEUE_DESC_LOW: - if (proxy->legacy) { + if (adev->proxy.legacy) { DBG("write to non-legacy register (0x%lx) in " "legacy mode\n", offset); return; @@ -1749,7 +1705,7 @@ void virtio_loopback_write(VirtIODevice *vdev, uint64_t offset, /* TODO: To be implemented */ break; case VIRTIO_MMIO_QUEUE_DESC_HIGH: - if (proxy->legacy) { + if (adev->proxy.legacy) { DBG("write to non-legacy register (0x%lx) in " "legacy mode\n", offset); return; @@ -1757,7 +1713,7 @@ void virtio_loopback_write(VirtIODevice *vdev, uint64_t offset, /* TODO: To be implemented */ break; case VIRTIO_MMIO_QUEUE_AVAIL_LOW: - if (proxy->legacy) { + if (adev->proxy.legacy) { DBG("write to non-legacy register (0x%lx) in " "legacy mode\n", offset); return; @@ -1765,7 +1721,7 @@ void virtio_loopback_write(VirtIODevice *vdev, uint64_t offset, /* TODO: To be implemented */ break; case VIRTIO_MMIO_QUEUE_AVAIL_HIGH: - if (proxy->legacy) { + if (adev->proxy.legacy) { DBG("write to non-legacy register (0x%lx) in " "legacy mode\n", offset); return; @@ -1773,7 +1729,7 @@ void virtio_loopback_write(VirtIODevice *vdev, uint64_t offset, /* TODO: To be implemented */ break; case VIRTIO_MMIO_QUEUE_USED_LOW: - if (proxy->legacy) { + if (adev->proxy.legacy) { DBG("write to non-legacy register (0x%lx) in " "legacy mode\n", offset); return; @@ -1781,7 +1737,7 @@ void virtio_loopback_write(VirtIODevice *vdev, uint64_t offset, /* TODO: To be implemented */ break; case VIRTIO_MMIO_QUEUE_USED_HIGH: - if (proxy->legacy) { + if (adev->proxy.legacy) { DBG("write to non-legacy register (0x%lx) in " "legacy mode\n", offset); return; @@ -1803,44 +1759,43 @@ void virtio_loopback_write(VirtIODevice *vdev, uint64_t offset, } } -VirtIODevice *global_vdev; -VirtioBus *global_vbus; - -void adapter_read_write_cb(void) +void adapter_read_write_cb(struct adapter_dev *adev) { /* * Enabling the next line, all the incoming * read/write events will be printed: * - * print_neg_flag (address->notification, address->read); + * print_neg_flag (adev->address->notification, adev->address->read); */ - print_neg_flag(address->notification, address->read); + print_neg_flag(adev->address->notification, adev->address->read); - if (address->read) { - address->data = virtio_loopback_read(global_vdev, - address->notification, address->size); + if (adev->address->read) { + adev->address->data = virtio_loopback_read(&adev->virtio_dev, + adev->address->notification, adev->address->size); } else { - virtio_loopback_write(global_vdev, address->notification, - address->data, address->size); + virtio_loopback_write(&adev->virtio_dev, adev->address->notification, + adev->address->data, adev->address->size); } DBG("Return to the driver\n"); /* * Note the driver that we have done - * All the required actions. + * all the required actions. */ - (void)ioctl(fd, WAKEUP); + (void)ioctl(adev->loopback_fd, WAKEUP); } void *driver_event_select(void *data) { - int retval; + int retval, s; uint64_t eftd_ctr; - int efd = *(int *)data; + fd_set rfds; + struct adapter_dev *adev = (struct adapter_dev *)data; + int efd = adev->efd; - DBG("\nWaiting for loopback read/write events\n"); + DBG("\nWaiting for loopback read/write events (efd :%d)\n", efd); FD_ZERO(&rfds); FD_SET(efd, &rfds); @@ -1859,7 +1814,7 @@ void *driver_event_select(void *data) DBG("\neventfd read error. Exiting..."); exit(1); } else { - adapter_read_write_cb(); + adapter_read_write_cb(adev); } } else if (retval == 0) { @@ -1868,14 +1823,6 @@ void *driver_event_select(void *data) } } -void create_rng_struct(void) -{ - device_info.magic = 0x74726976; - device_info.version = 0x1; - device_info.device_id = 0x4; - device_info.vendor = 0x554d4551; -} - VirtQueue *virtio_get_queue(VirtIODevice *vdev, int n) { return vdev->vq + n; @@ -1910,20 +1857,21 @@ VirtQueue *virtio_add_queue(VirtIODevice *vdev, int queue_size, void virtio_dev_init(VirtIODevice *vdev, const char *name, uint16_t device_id, size_t config_size) { + struct adapter_dev *adev = to_adapter_device(vdev, virtio_dev); int i; DBG("virtio_dev_init\n"); /* Initialize global variables */ - prev_level = 0; - int_count = 0; - eventfd_count = 0; - enable_virtio_interrupt = false; - vring_phys_addrs_idx = 0; - notify_cnt = 0; + vdev->prev_level = 0; + vdev->int_count = 0; + vdev->enable_virtio_interrupt = false; + vdev->vring_phys_addrs_idx = 0; + vdev->eventfd_count = 0; + vdev->notify_cnt = 0; /* Initialize interrupt mutex */ - if (pthread_mutex_init(&interrupt_lock, NULL) != 0) { + if (pthread_mutex_init(&vdev->interrupt_lock, NULL) != 0) { printf("[ERROR] mutex init has failed\n"); exit(1); } @@ -1932,6 +1880,7 @@ void virtio_dev_init(VirtIODevice *vdev, const char *name, vdev->started = false; vdev->device_id = device_id; vdev->status = 0; + vdev->last_avail = -1; vdev->queue_sel = 0; vdev->config_vector = VIRTIO_NO_VECTOR; /* TODO: check malloc return value */ @@ -1953,14 +1902,20 @@ void virtio_dev_init(VirtIODevice *vdev, const char *name, vdev->config = NULL; } + /* Initialize device_info */ + adev->device_info.magic = 0x74726976; + adev->device_info.version = 0x1; + adev->device_info.device_id = device_id; + adev->device_info.vendor = 0x554d4551; + vdev->use_guest_notifier_mask = true; - DBG("virtio_dev_init return\n"); } static bool virtio_loopback_ioeventfd_enabled(VirtIODevice *d) { - (void)d; - return (proxy->flags & VIRTIO_IOMMIO_FLAG_USE_IOEVENTFD) != 0; + struct adapter_dev *adev = to_adapter_device(d, virtio_dev); + + return (adev->proxy.flags & VIRTIO_IOMMIO_FLAG_USE_IOEVENTFD) != 0; } /* TODO: This function might not be needed anymore */ @@ -1992,63 +1947,61 @@ void virtio_loopback_bus_init(VirtioBus *k) k->set_guest_notifiers = virtio_loopback_set_guest_notifiers; k->ioeventfd_enabled = virtio_loopback_ioeventfd_enabled; k->ioeventfd_assign = virtio_loopback_ioeventfd_assign; - DBG("virtio_loopback_bus_init(...) return\n"); } - -int virtio_loopback_start(void) +int virtio_loopback_start(struct adapter_dev *adev, pthread_t *thread_id) { efd_data_t info; - pthread_t thread_id; int ret = -1; - fd = open("/dev/loopback", O_RDWR); - if (fd < 0) { + adev->loopback_fd = open("/dev/loopback", O_RDWR); + if (adev->loopback_fd < 0) { perror("Open call failed"); return -1; } - loopback_fd = fd; /* Create eventfd */ - efd = eventfd(0, 0); - if (efd == -1) { + adev->efd = eventfd(0, 0); + if (adev->efd == -1) { DBG("\nUnable to create eventfd! Exiting...\n"); exit(EXIT_FAILURE); } info.pid = getpid(); - info.efd[0] = efd; + info.efd[0] = adev->efd; /* * Send the appropriate information to the driver * so to be able to trigger an eventfd */ - (void)ioctl(fd, EFD_INIT, &info); + (void)ioctl(adev->loopback_fd, EFD_INIT, &info); /* Map communication mechanism */ - (void)ioctl(fd, SHARE_COM_STRUCT); - address = mmap(NULL, PAGE_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); - if (address == MAP_FAILED) { + (void)ioctl(adev->loopback_fd, SHARE_COM_STRUCT); + adev->address = mmap(NULL, PAGE_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED, adev->loopback_fd, 0); + if (adev->address == MAP_FAILED) { perror("mmap operation failed"); return -1; } /* Wait the eventfd */ - ret = pthread_create(&thread_id, NULL, driver_event_select, (void *)&efd); + ret = pthread_create(thread_id, NULL, driver_event_select, (void *)adev); if (ret != 0) { - exit(1); + goto error_start; } /* Start loopback transport */ - (void)ioctl(fd, START_LOOPBACK, &device_info); + (void)ioctl(adev->loopback_fd, START_LOOPBACK, &adev->device_info); - ret = pthread_join(thread_id, NULL); - if (ret != 0) { - exit(1); - } +error_start: + return ret; +} - DBG("\nClosing eventfd. Exiting...\n"); - close(efd); +void virtio_loopback_stop(struct adapter_dev *adev) +{ + DBG("\nClosing eventfd\n"); + close(adev->efd); - exit(EXIT_SUCCESS); + DBG("\nClosing loopback fd. Exiting...\n"); + close(adev->loopback_fd); } diff --git a/vhost_user_can.c b/vhost_user_can.c deleted file mode 100644 index c645948..0000000 --- a/vhost_user_can.c +++ /dev/null @@ -1,329 +0,0 @@ -/* - * Virtio CAN Device - * - * Based on virtio_can.h of OpenSynergy's virtio-can RFC - * https://github.com/OpenSynergy/qemu/tree/virtio-can-spec-rfc-v3 - * - * Copyright (C) 2021-2023 OpenSynergy GmbH - * Copyright (c) 2023 Virtual Open Systems SAS. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2. - * - * 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. - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the - * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - */ - -#include <unistd.h> -#include <stdlib.h> -#include <stdio.h> -#include <stdint.h> -#include <string.h> -#include <stdbool.h> -#include <sys/param.h> - -/* Project header files */ -#include "vhost_user_can.h" - -#ifdef DEBUG -#define DBG(...) printf("vhost-user-can: " __VA_ARGS__) -#else -#define DBG(...) -#endif /* DEBUG */ - -/***************************** vhost-user-can ******************************/ - -static const int user_feature_bits[] = { - VIRTIO_F_VERSION_1, - VIRTIO_RING_F_INDIRECT_DESC, - VIRTIO_RING_F_EVENT_IDX, - VIRTIO_F_RING_RESET, - VIRTIO_F_NOTIFY_ON_EMPTY, - VHOST_INVALID_FEATURE_BIT -}; - -static void vhost_user_can_get_config(VirtIODevice *vdev, uint8_t *config) -{ - VHostUserCan *can = vdev->vhucan; - - DBG("vhost_user_can_get_config: Not yet implemented!\n"); - - /* - * TODO : Add this check depend on 'busoff' value - * if (vcan->busoff) { - * config->status = cpu_to_le32(VIRTIO_CAN_S_CTRL_BUSOFF); - * } else { - * config->status = cpu_to_le32(0); - * } - */ - - memcpy(config, &can->config, sizeof(struct virtio_can_config)); -} - - -static void vhost_user_can_start(VirtIODevice *vdev) -{ - VHostUserCan *vhucan = vdev->vhucan; - VirtioBus *k = vdev->vbus; - int ret; - unsigned int i; - - DBG("vhost_user_can_start(...)\n"); - - if (!k->set_guest_notifiers) { - DBG("binding does not support guest notifiers\n"); - return; - } - - ret = vhost_dev_enable_notifiers(vhucan->vhost_dev, vdev); - if (ret < 0) { - DBG("Error enabling host notifiers: %d\n", -ret); - return; - } - - ret = k->set_guest_notifiers(k->vdev, vhucan->vhost_dev->nvqs, true); - if (ret < 0) { - DBG("Error binding guest notifier: %d\n", -ret); - goto err_host_notifiers; - } - - vhucan->vhost_dev->acked_features = vdev->guest_features; - - ret = vhost_dev_start(vhucan->vhost_dev, vdev, true); - if (ret < 0) { - DBG("Error starting vhost: %d\n", -ret); - goto err_guest_notifiers; - } - - /* - * guest_notifier_mask/pending not used yet, so just unmask - * everything here. virtio-pci will do the right thing by - * enabling/disabling irqfd. - */ - for (i = 0; i < vhucan->vhost_dev->nvqs; i++) { - vhost_virtqueue_mask(vhucan->vhost_dev, vdev, i, false); - } - - return; - -err_guest_notifiers: -err_host_notifiers: - DBG("vhu_start error\n"); - return; -} - -static void vhost_user_can_stop(VirtIODevice *vdev) -{ - DBG("vhost_user_can_stop: not yet implemented\n"); - (void)vdev; -} - -static void vhost_user_can_set_status(VirtIODevice *vdev, uint8_t status) -{ - VHostUserCan *vhucan = vdev->vhucan; - bool should_start = virtio_device_started(vdev, status); - DBG("vhost_user_can_set_status: %d\n", status); - - if (vhucan->vhost_dev->started == should_start) { - DBG("can->vhost_dev->started == should_start\n"); - return; - } - - if (should_start) { - vhost_user_can_start(vdev); - } else { - vhost_user_can_stop(vdev); - } -} - -static uint64_t vhost_user_can_get_features(VirtIODevice *vdev, - uint64_t features) -{ - VHostUserCan *s = vdev->vhucan; - - DBG("vhost_user_can_get_features()\n"); - - return vhost_get_features(s->vhost_dev, user_feature_bits, features); -} - -static void vhost_user_can_can_handle_output(VirtIODevice *vdev, VirtQueue *vq) -{ - /* - * Not normally called; it's the daemon that handles the queue; - * however virtio's cleanup path can call this. - */ - DBG("vhost_user_can_can_handle_output: Not yet implemented!\n"); - (void)vdev; - (void)vq; -} - -/* - * TODO: Add it later - * static void vhost_sound_guest_notifier_mask(VirtIODevice *vdev, int idx, - * bool mask) - */ - -/* - * TODO: Add it later - * static bool vhost_sound_guest_notifier_pending(VirtIODevice *vdev, - * int idx) - */ - -static int vhost_user_can_can_config_change(struct vhost_dev *dev) -{ - VHostUserCan *vhucan = dev->vdev->vhucan; - DBG("vhost_user_can_can_config_change: Not yet implemented!\n"); - - int ret = vhost_dev_get_config(dev, (uint8_t *)&vhucan->config, - sizeof(struct virtio_can_config)); - if (ret < 0) { - DBG("vhost_user_can_sound_config_change error\n"); - return -1; - } - - virtio_notify_config(dev->vdev); - - return 0; -} - -const VhostDevConfigOps can_config_ops = { - .vhost_dev_config_notifier = vhost_user_can_can_config_change, -}; - -static void vhost_user_can_init(VirtIODevice *vdev); - -void vhost_user_can_realize(int queue_num, int queue_size) -{ - VirtIODevice *vdev = global_vdev; - int ret; - - DBG("vhost_user_can_device_realize\n"); - (void)queue_num; - (void)queue_size; - - /* This needs to be added */ - proxy = (VirtIOMMIOProxy *)malloc(sizeof(VirtIOMMIOProxy)); - *proxy = (VirtIOMMIOProxy) { - .legacy = 1, - }; - - /* VIRTIO_ID_CAN is 36, check virtio_ids.h in linux*/ - virtio_dev_init(vdev, "virtio-can", 36, sizeof(vdev->vhucan->config)); - vhost_user_can_init(global_vdev); - - /* add queues */ - vdev->vhucan->ctrl_vq = virtio_add_queue(vdev, 64, - vhost_user_can_can_handle_output); - vdev->vhucan->tx_vq = virtio_add_queue(vdev, 64, - vhost_user_can_can_handle_output); - vdev->vhucan->rx_vq = virtio_add_queue(vdev, 64, - vhost_user_can_can_handle_output); - vdev->vhucan->vhost_dev->nvqs = 3; - vdev->vhucan->num_queues = 3; - vdev->vhucan->queue_size = 64; - - /* NOTE: global_vdev->vqs == vhucan->virtqs */ - vdev->vqs = (VirtQueue **)malloc(sizeof(VirtQueue *) - * global_vdev->vhucan->num_queues); - vdev->vqs[0] = vdev->vhucan->tx_vq; - vdev->vqs[1] = vdev->vhucan->rx_vq; - vdev->vqs[2] = vdev->vhucan->ctrl_vq; - - vdev->vhucan->vhost_vqs = (struct vhost_virtqueue *)malloc( - sizeof(struct vhost_virtqueue) * - vdev->vhucan->num_queues); - - /* Set up vhost device */ - vdev->vhucan->vhost_dev->num_queues = vdev->vhucan->num_queues; - vdev->vhucan->vhost_dev->nvqs = vdev->vhucan->num_queues; - vdev->vhucan->vhost_dev->vqs = vdev->vhucan->vhost_vqs; - vdev->vhucan->vhost_dev->vq_index = 0; - vdev->vhucan->vhost_dev->backend_features = 0; - - vhost_dev_set_config_notifier(vdev->vhucan->vhost_dev, &can_config_ops); - - /* TODO: Add error handling */ - vhost_dev_init(vdev->vhucan->vhost_dev); - - /* Pass the new obtained features */ - global_vdev->host_features = vdev->vhucan->vhost_dev->features; - - ret = vhost_dev_get_config(vdev->vhucan->vhost_dev, - (uint8_t *)&vdev->vhucan->config, - sizeof(struct virtio_can_config)); - if (ret < 0) { - goto vhost_dev_init_failed; - } - - vdev->vdev_class->print_config((uint8_t *)&vdev->vhucan->config); - - return; - -vhost_dev_init_failed: - DBG("vhost_dev_init_failed\n"); - return; -} - -static void vhost_user_can_device_unrealize(VirtIODevice *vdev) -{ - DBG("vhost_user_blk_device_unrealize not yet implemented\n"); - (void)vdev; -} - -/* This funciton might be useful in the future - * - * static struct vhost_dev *vhost_user_can_get_vhost(VirtIODevice *vdev) - * { - * VHostUserCan *vhucan = vdev->vhucan; - * return vhucan->vhost_dev; - * } - * - */ - -static void print_config_can(uint8_t *config_data) -{ - struct virtio_can_config *config_strct = - (struct virtio_can_config *)config_data; - - (void)config_strct; - DBG("print_config_can:\n"); - - DBG("\tuint16_t status: %u\n", config_strct->status); -} - -static void virtio_dev_class_init(VirtIODevice *vdev) -{ - DBG("virtio_dev_class_init\n"); - - vdev->vdev_class = (VirtioDeviceClass *)malloc(sizeof(VirtioDeviceClass)); - vdev->vdev_class->parent = vdev; - vdev->vdev_class->realize = vhost_user_can_realize; - vdev->vdev_class->unrealize = vhost_user_can_device_unrealize; - vdev->vdev_class->get_config = vhost_user_can_get_config; - vdev->vdev_class->get_features = vhost_user_can_get_features; - vdev->vdev_class->set_status = vhost_user_can_set_status; - vdev->vdev_class->update_mem_table = update_mem_table; - vdev->vdev_class->print_config = print_config_can; -} - -static void vhost_user_can_init(VirtIODevice *vdev) -{ - DBG("vhost_user_can_init\n"); - - VHostUserCan *vhucan = (VHostUserCan *)malloc(sizeof(VHostUserCan)); - vdev->vhucan = vhucan; - vdev->nvqs = (int *)&vdev->vhdev->nvqs; - vhucan->parent = vdev; - vhucan->virtqs = vdev->vqs; - vhucan->vhost_dev = vdev->vhdev; - - virtio_dev_class_init(vdev); - virtio_loopback_bus_init(vdev->vbus); -} diff --git a/vhost_user_console.c b/vhost_user_console.c deleted file mode 100644 index ac453b5..0000000 --- a/vhost_user_console.c +++ /dev/null @@ -1,302 +0,0 @@ -/* - * Copyright (c) 2023 Virtual Open Systems SAS. - * - * This work is licensed under the terms of the GNU GPL, version 2 or - * (at your option) any later version. See the COPYING file in the - * top-level directory. - * - */ - - -#include <unistd.h> -#include <stdlib.h> -#include <stdio.h> -#include <stdint.h> -#include <string.h> -#include <stdbool.h> -#include <sys/param.h> - -/* Project header files */ -#include "vhost_user_console.h" - -#ifdef DEBUG -#define DBG(...) printf("vhost-user-console: " __VA_ARGS__) -#else -#define DBG(...) -#endif /* DEBUG */ - -static const int user_feature_bits[] = { - VIRTIO_F_VERSION_1, - VIRTIO_RING_F_INDIRECT_DESC, - VIRTIO_RING_F_EVENT_IDX, - VIRTIO_F_RING_RESET, - VIRTIO_F_NOTIFY_ON_EMPTY, - VHOST_INVALID_FEATURE_BIT -}; - -static void vhost_user_console_get_config(VirtIODevice *vdev, uint8_t *config) -{ - VHostUserConsole *console = vdev->vhuconsole; - - DBG("vhost_user_console_get_config: Not yet implemented!\n"); - - memcpy(config, &console->config, sizeof(struct virtio_console_config)); -} - -static void vhost_user_console_start(VirtIODevice *vdev) -{ - VHostUserConsole *vhuconsole = vdev->vhuconsole; - VirtioBus *k = vdev->vbus; - unsigned int i; - int ret; - - DBG("vhost_user_console_start(...)\n"); - - if (!k->set_guest_notifiers) { - DBG("binding does not support guest notifiers\n"); - return; - } - - ret = vhost_dev_enable_notifiers(vhuconsole->vhost_dev, vdev); - if (ret < 0) { - DBG("Error enabling host notifiers: %d\n", -ret); - return; - } - - ret = k->set_guest_notifiers(k->vdev, vhuconsole->vhost_dev->nvqs, true); - if (ret < 0) { - DBG("Error binding guest notifier: %d\n", -ret); - goto err_host_notifiers; - } - - vhuconsole->vhost_dev->acked_features = vdev->guest_features; - - ret = vhost_dev_start(vhuconsole->vhost_dev, vdev, true); - if (ret < 0) { - DBG("Error starting vhost: %d\n", -ret); - goto err_guest_notifiers; - } - - /* - * guest_notifier_mask/pending not used yet, so just unmask - * everything here. virtio-pci will do the right thing by - * enabling/disabling irqfd. - */ - for (i = 0; i < vhuconsole->vhost_dev->nvqs; i++) { - vhost_virtqueue_mask(vhuconsole->vhost_dev, vdev, i, false); - } - - return; - -err_guest_notifiers: -err_host_notifiers: - DBG("vhu_start error\n"); - return; -} - -static void vhost_user_console_stop(VirtIODevice *vdev) -{ - DBG("vhost_user_console_stop: not yet implemented\n"); - (void)vdev; -} - -static void vhost_user_console_set_status(VirtIODevice *vdev, uint8_t status) -{ - VHostUserConsole *vhuconsole = vdev->vhuconsole; - bool should_start = virtio_device_started(vdev, status); - DBG("vhost_user_console_set_status: %d\n", status); - - if (vhuconsole->vhost_dev->started == should_start) { - DBG("console->vhost_dev->started == should_start\n"); - return; - } - - if (should_start) { - vhost_user_console_start(vdev); - } else { - vhost_user_console_stop(vdev); - } -} - -static uint64_t vhost_user_console_get_features(VirtIODevice *vdev, - uint64_t features) -{ - VHostUserConsole *s = vdev->vhuconsole; - - DBG("vhost_user_console_get_features()\n"); - - return vhost_get_features(s->vhost_dev, user_feature_bits, features); -} - -static void vhost_user_console_handle_output(VirtIODevice *vdev, VirtQueue *vq) -{ - /* - * Not normally called; it's the daemon that handles the queue; - * however virtio's cleanup path console call this. - */ - DBG("vhost_user_console_handle_output: Not yet implemented!\n"); - (void)vdev; - (void)vq; -} - -static int vhost_user_console_config_change(struct vhost_dev *dev) -{ - VHostUserConsole *vhuconsole = dev->vdev->vhuconsole; - DBG("vhost_user_console_console_config_change: Not yet implemented!\n"); - - int ret = vhost_dev_get_config(dev, (uint8_t *)&vhuconsole->config, - sizeof(struct virtio_console_config)); - if (ret < 0) { - DBG("vhost_user_console_sound_config_change error\n"); - return -1; - } - - virtio_notify_config(dev->vdev); - - return 0; -} - -const VhostDevConfigOps console_config_ops = { - .vhost_dev_config_notifier = vhost_user_console_config_change, -}; - -static void vhost_user_console_init(VirtIODevice *vdev); - -void vhost_user_console_realize(int queue_num, int queue_size) -{ - VirtIODevice *vdev = global_vdev; - int ret; - - DBG("vhost_user_console_device_realize\n"); - (void)queue_num; - (void)queue_size; - - /* This needs to be added */ - proxy = (VirtIOMMIOProxy *)malloc(sizeof(VirtIOMMIOProxy)); - *proxy = (VirtIOMMIOProxy) { - .legacy = 1, - }; - - /* VIRTIO_ID_CAN is 36, check virtio_ids.h in linux*/ - virtio_dev_init(vdev, "virtio-console", 3, - sizeof(vdev->vhuconsole->config)); - vhost_user_console_init(global_vdev); - - /* add queues */ - vdev->vhuconsole->rx_vq = virtio_add_queue(vdev, 64, - vhost_user_console_handle_output); - vdev->vhuconsole->tx_vq = virtio_add_queue(vdev, 64, - vhost_user_console_handle_output); - vdev->vhuconsole->ctrl_rx_vq = virtio_add_queue(vdev, 64, - vhost_user_console_handle_output); - vdev->vhuconsole->ctrl_tx_vq = virtio_add_queue(vdev, 64, - vhost_user_console_handle_output); - vdev->vhuconsole->vhost_dev->nvqs = 4; - vdev->vhuconsole->num_queues = 4; - vdev->vhuconsole->queue_size = 64; - - /* NOTE: global_vdev->vqs == vhuconsole->virtqs */ - vdev->vqs = (VirtQueue **)malloc(sizeof(VirtQueue *) - * global_vdev->vhuconsole->num_queues); - vdev->vqs[0] = vdev->vhuconsole->rx_vq; - vdev->vqs[1] = vdev->vhuconsole->tx_vq; - vdev->vqs[2] = vdev->vhuconsole->ctrl_rx_vq; - vdev->vqs[3] = vdev->vhuconsole->ctrl_tx_vq; - - vdev->vhuconsole->vhost_vqs = (struct vhost_virtqueue *)malloc( - sizeof(struct vhost_virtqueue) * - vdev->vhuconsole->num_queues); - - /* Set up vhost device */ - vdev->vhuconsole->vhost_dev->num_queues = vdev->vhuconsole->num_queues; - vdev->vhuconsole->vhost_dev->nvqs = vdev->vhuconsole->num_queues; - vdev->vhuconsole->vhost_dev->vqs = vdev->vhuconsole->vhost_vqs; - vdev->vhuconsole->vhost_dev->vq_index = 0; - vdev->vhuconsole->vhost_dev->backend_features = 0; - - vhost_dev_set_config_notifier(vdev->vhuconsole->vhost_dev, - &console_config_ops); - - /* TODO: Add error handling */ - vhost_dev_init(vdev->vhuconsole->vhost_dev); - - /* Pass the new obtained features */ - global_vdev->host_features = vdev->vhuconsole->vhost_dev->features; - - ret = vhost_dev_get_config(vdev->vhuconsole->vhost_dev, - (uint8_t *)&vdev->vhuconsole->config, - sizeof(struct virtio_console_config)); - if (ret < 0) { - goto vhost_dev_init_failed; - } - - vdev->vdev_class->print_config((uint8_t *)&vdev->vhuconsole->config); - - return; - -vhost_dev_init_failed: - DBG("vhost_dev_init_failed\n"); - return; -} - -static void vhost_user_console_device_unrealize(VirtIODevice *vdev) -{ - DBG("vhost_user_blk_device_unrealize not yet implemented\n"); - (void)vdev; -} - -/* - * This function might be useful in the future: - * - * static struct vhost_dev *vhost_user_console_get_vhost(VirtIODevice *vdev) - * { - * VHostUserConsole *vhuconsole = vdev->vhuconsole; - * return vhuconsole->vhost_dev; - * } - * - */ - -static void print_config_console(uint8_t *config_data) -{ - struct virtio_console_config *config_strct = - (struct virtio_console_config *)config_data; - - (void)config_strct; - DBG("print_config_console:\n"); - DBG("\tuint16_t cols: %u\n", config_strct->cols); - DBG("\tuint16_t rows: %u\n", config_strct->rows); - DBG("\tuint16_t max_nr_ports: %u\n", config_strct->max_nr_ports); - DBG("\tuint16_t emerg_wr: %u\n", config_strct->emerg_wr); -} - -static void virtio_dev_class_init(VirtIODevice *vdev) -{ - DBG("virtio_dev_class_init\n"); - - vdev->vdev_class = (VirtioDeviceClass *)malloc(sizeof(VirtioDeviceClass)); - vdev->vdev_class->parent = vdev; - vdev->vdev_class->realize = vhost_user_console_realize; - vdev->vdev_class->unrealize = vhost_user_console_device_unrealize; - vdev->vdev_class->get_config = vhost_user_console_get_config; - vdev->vdev_class->get_features = vhost_user_console_get_features; - vdev->vdev_class->set_status = vhost_user_console_set_status; - vdev->vdev_class->update_mem_table = update_mem_table; - vdev->vdev_class->print_config = print_config_console; -} - -static void vhost_user_console_init(VirtIODevice *vdev) -{ - - DBG("vhost_user_console_init\n"); - - VHostUserConsole *vhuconsole = - (VHostUserConsole *)malloc(sizeof(VHostUserConsole)); - vdev->vhuconsole = vhuconsole; - vdev->nvqs = (int *)&vdev->vhdev->nvqs; - vhuconsole->parent = vdev; - vhuconsole->virtqs = vdev->vqs; - vhuconsole->vhost_dev = vdev->vhdev; - - virtio_dev_class_init(vdev); - virtio_loopback_bus_init(vdev->vbus); -} diff --git a/vhost_user_gpio.c b/vhost_user_gpio.c deleted file mode 100644 index fd525fe..0000000 --- a/vhost_user_gpio.c +++ /dev/null @@ -1,393 +0,0 @@ -/* - * Based on vhost-user-gpio.c of QEMU project - * - * Copyright (c) 2022 Viresh Kumar <viresh.kumar@linaro.org> - * - * Copyright (c) 2023 Virtual Open Systems SAS. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * 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. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ - -#include <unistd.h> -#include <stdlib.h> -#include <stdio.h> -#include <stdint.h> -#include <string.h> -#include <stdbool.h> -#include <sys/param.h> -#include <errno.h> - -/* Project header files */ -#include "vhost_user_gpio.h" - -#ifdef DEBUG -#define DBG(...) printf("vhost-user-gpio: " __VA_ARGS__) -#else -#define DBG(...) -#endif /* DEBUG */ - -#define REALIZE_CONNECTION_RETRIES 3 -#define VHOST_NVQS 2 - -static const int feature_bits[] = { - VIRTIO_F_VERSION_1, - VIRTIO_F_NOTIFY_ON_EMPTY, - VIRTIO_RING_F_INDIRECT_DESC, - VIRTIO_RING_F_EVENT_IDX, - VIRTIO_GPIO_F_IRQ, - VIRTIO_F_RING_RESET, - VHOST_INVALID_FEATURE_BIT -}; - -static void vu_gpio_get_config(VirtIODevice *vdev, uint8_t *config) -{ - VHostUserGPIO *gpio = dev->vdev->vhugpio; - - DBG("vu_gpio_get_config()\n"); - (void)vdev; - memcpy(config, &gpio->config, sizeof(gpio->config)); -} - -static int vu_gpio_config_notifier(struct vhost_dev *dev) -{ - VHostUserGPIO *gpio = dev->vdev->vhugpio; - - DBG("vu_gpio_config_notifier\n"); - - memcpy(dev->vdev->config, &gpio->config, sizeof(gpio->config)); - virtio_notify_config(dev->vdev); - - return 0; -} - -const VhostDevConfigOps gpio_ops = { - .vhost_dev_config_notifier = vu_gpio_config_notifier, -}; - -static int vu_gpio_start(VirtIODevice *vdev) -{ - VirtioBus *k = vdev->vbus; - VHostUserGPIO *gpio = vdev->vhugpio; - unsigned int i; - int ret; - - DBG("vu_gpio_start()\n"); - - if (!k->set_guest_notifiers) { - DBG("binding does not support guest notifiers"); - return -ENOSYS; - } - - ret = vhost_dev_enable_notifiers(gpio->vhost_dev, vdev); - if (ret < 0) { - DBG("Error enabling host notifiers: %d", ret); - return ret; - } - - ret = k->set_guest_notifiers(k->vdev, gpio->vhost_dev->nvqs, true); - if (ret < 0) { - DBG("Error binding guest notifier: %d", ret); - goto out_with_err_host_notifiers; - } - - vhost_ack_features(gpio->vhost_dev, feature_bits, vdev->guest_features); - - ret = vhost_dev_start(gpio->vhost_dev, vdev, true); - if (ret < 0) { - DBG("Error starting vhost-user-gpio: %d", ret); - goto out_with_err_guest_notifiers; - } - gpio->started_vu = true; - - for (i = 0; i < gpio->vhost_dev->nvqs; i++) { - vhost_virtqueue_mask(gpio->vhost_dev, vdev, i, false); - } - - /* - * TODO: check if we need the following is needed - * ret = gpio->vhost_dev->vhost_ops->vhost_set_vring_enable(gpio->vhost_dev, - * true); - */ - - return 0; - -out_with_err_guest_notifiers: - k->set_guest_notifiers(k->vdev, gpio->vhost_dev->nvqs, false); -out_with_err_host_notifiers: - /* - * TODO: implement the following functions: - * vhost_dev_disable_notifiers(&gpio->vhost_dev, vdev); - */ - - return ret; -} - -static void vu_gpio_stop(VirtIODevice *vdev) -{ - DBG("vu_gpio_stop() not yet implemented\n"); - (void)vdev; -} - -static void vu_gpio_set_status(VirtIODevice *vdev, uint8_t status) -{ - VHostUserGPIO *gpio = vdev->vhugpio; - bool should_start = virtio_device_started(vdev, status); - - DBG("vu_gpio_set_status()\n"); - - if (!gpio->connected) { - return; - } - -printf("should_start: %d\n", should_start); - if (gpio->vhost_dev->started) { - return; - } - - if (should_start) { - if (vu_gpio_start(vdev)) { - DBG("vu_gpio_start() failed\n"); - } - } else { - vu_gpio_stop(vdev); - } -} - -static uint64_t vu_gpio_get_features(VirtIODevice *vdev, uint64_t features) -{ - VHostUserGPIO *gpio = vdev->vhugpio; - - DBG("vu_gpio_get_features()\n"); - return vhost_get_features(gpio->vhost_dev, feature_bits, features); -} - -static void vu_gpio_handle_output(VirtIODevice *vdev, VirtQueue *vq) -{ - /* - * Not normally called; it's the daemon that handles the queue; - * however virtio's cleanup path can call this. - */ - DBG("vu_gpio_handle_output not yet implemented\n"); - (void)vdev; - (void)vq; -} - -static void vu_gpio_guest_notifier_mask(VirtIODevice *vdev, int idx, bool mask) -{ - VHostUserGPIO *gpio = vdev->vhugpio; - - DBG("vu_gpio_guest_notifier_mask() not yet implemented\n"); - - vhost_virtqueue_mask(gpio->vhost_dev, vdev, idx, mask); -} - -static void do_vhost_user_cleanup(VirtIODevice *vdev, VHostUserGPIO *gpio) -{ - DBG("do_vhost_user_cleanup() not yet implemented\n"); - (void)vdev; - (void)gpio; -} - -static int vu_gpio_connect(VirtIODevice *vdev) -{ - VHostUserGPIO *gpio = vdev->vhugpio; - - DBG("vu_gpio_connect()\n"); - - if (gpio->connected) { - return 0; - } - gpio->connected = true; - - vhost_dev_set_config_notifier(gpio->vhost_dev, &gpio_ops); - /* - * TODO: Investigate if the following is needed - * gpio->vhost_user.supports_config = true; - */ - - gpio->vhost_dev->nvqs = VHOST_NVQS; - gpio->vhost_dev->vqs = gpio->vhost_vqs; - - vhost_dev_init(gpio->vhost_dev); - /* - * TODO: Add error handling - * if (ret < 0) { - * return ret; - * } - */ - - /* restore vhost state */ - if (virtio_device_started(vdev, vdev->status)) { - vu_gpio_start(vdev); - } - - return 0; -} - -static int vu_gpio_realize_connect(VHostUserGPIO *gpio) -{ - int ret; - - DBG("vu_gpio_realize_connect()\n"); - - ret = vu_gpio_connect(gpio->parent); - if (ret < 0) { - return ret; - } - - ret = vhost_dev_get_config(gpio->vhost_dev, (uint8_t *)&gpio->config, - sizeof(gpio->config)); - - if (ret < 0) { - DBG("vhost-user-gpio: get config failed\n"); - /* - * TODO: Add cleanup function - * vhost_dev_cleanup(vhost_dev); - */ - return ret; - } - - return 0; -} - -static void vu_gpio_device_unrealize(VirtIODevice *vdev) -{ - DBG("vu_gpio_device_unrealize() not yet implemented\n"); - (void)vdev; -} - -static void print_config_gpio(uint8_t *config_data) -{ - struct virtio_gpio_config *config = - (struct virtio_gpio_config *)config_data; - - (void)config; - DBG("ngpio: %hu\n", config->ngpio); - DBG("gpio_names_size: %u\n", config->gpio_names_size); -} - -static void vu_gpio_class_init(VirtIODevice *vdev) -{ - DBG("vu_gpio_class_init()\n"); - - vdev->vdev_class = (VirtioDeviceClass *)malloc(sizeof(VirtioDeviceClass)); - if (!vdev->vdev_class) { - DBG("vdev_class memory allocation failed\n"); - return; - } - vdev->vdev_class->realize = vu_gpio_device_realize; - vdev->vdev_class->unrealize = vu_gpio_device_unrealize; - vdev->vdev_class->get_features = vu_gpio_get_features; - vdev->vdev_class->get_config = vu_gpio_get_config; - vdev->vdev_class->set_status = vu_gpio_set_status; - vdev->vdev_class->guest_notifier_mask = vu_gpio_guest_notifier_mask; -} - -void vu_gpio_init(VirtIODevice *vdev) -{ - DBG("vu_gpio_init()\n"); - - VHostUserGPIO *vhugpio = (VHostUserGPIO *)malloc(sizeof(VHostUserGPIO)); - if (!proxy) { - DBG("proxy memory allocation failed\n"); - goto out; - } - - vdev->vhugpio = vhugpio; - vdev->nvqs = (int *)&dev->nvqs; - vhugpio->parent = vdev; - vhugpio->vhost_dev = dev; - - vu_gpio_class_init(vdev); - virtio_loopback_bus_init(vdev->vbus); - -out: - return; -} - -/* TODO: Add queue_num, queue_size as parameters */ -void vu_gpio_device_realize(int queue_num, int queue_size) -{ - int retries, ret; - - DBG("vu_gpio_device_realize()\n"); - (void)queue_num; - (void)queue_size; - - /* This needs to be added */ - proxy = (VirtIOMMIOProxy *)malloc(sizeof(VirtIOMMIOProxy)); - if (!proxy) { - DBG("proxy memory allocation failed\n"); - goto out_with_error; - } - - *proxy = (VirtIOMMIOProxy) { - .legacy = 1, - }; - - /* VIRTIO_ID_GPIO is 41, check virtio_ids.h in linux */ - virtio_dev_init(global_vdev, "virtio-gpio", 41, - sizeof(struct virtio_gpio_config)); - - vu_gpio_init(global_vdev); - if (!global_vdev->vhugpio) { - DBG("vhugpio memory allocation failed\n"); - goto out_with_proxy; - } - - global_vdev->vhugpio->command_vq = virtio_add_queue(global_vdev, 64, - vu_gpio_handle_output); - global_vdev->vhugpio->interrupt_vq = virtio_add_queue(global_vdev, 64, - vu_gpio_handle_output); - - global_vdev->vhugpio->vhost_vqs = (struct vhost_virtqueue *) - malloc(sizeof(struct vhost_virtqueue *)); - if (!global_vdev->vhugpio->vhost_vqs) { - DBG("vhost_vqs memory allocation failed\n"); - goto out_with_dev; - } - - global_vdev->vhugpio->connected = false; - - retries = REALIZE_CONNECTION_RETRIES; - - do { - ret = vu_gpio_realize_connect(global_vdev->vhugpio); - } while (ret < 0 && retries--); - - if (ret < 0) { - DBG("vu_gpio_realize_connect(): -EPROTO\n"); - do_vhost_user_cleanup(global_vdev, global_vdev->vhugpio); - } - - print_config_gpio((uint8_t *)(&global_vdev->vhugpio->config)); - DBG("(realize completed)\n"); - - return; - - /* - * TODO: Fix the following considering also do_vhost_user_cleanup() - * - * out_with_cmd_vq: - * free(global_vdev->vhugpio->command_vq); - */ -out_with_dev: - free(global_vdev->vhugpio); -out_with_proxy: - free(proxy); -out_with_error: - DBG("Realize funciton return error\n"); - return; -} diff --git a/vhost_user_input.c b/vhost_user_input.c deleted file mode 100644 index 5cb4ca6..0000000 --- a/vhost_user_input.c +++ /dev/null @@ -1,241 +0,0 @@ -/* - * Based on vhost-user-input.c of QEMU project - * - * Copyright (c) 2022-2023 Virtual Open Systems SAS. - * - * This work is licensed under the terms of the GNU GPL, version 2 or - * (at your option) any later version. See the COPYING file in the - * top-level directory. - */ - -#include <unistd.h> -#include <stdlib.h> -#include <stdio.h> -#include <stdint.h> -#include <string.h> -#include <stdbool.h> -#include <sys/param.h> - -/* Project header files */ -#include "vhost_user_input.h" - -#ifdef DEBUG -#define DBG(...) printf("vhost-user-input: " __VA_ARGS__) -#else -#define DBG(...) -#endif /* DEBUG */ - - -static int vhost_input_config_change(struct vhost_dev *dev) -{ - DBG("vhost-user-input: unhandled backend config change\n"); - (void)dev; - - return -1; -} - -const VhostDevConfigOps config_ops = { - .vhost_dev_config_notifier = vhost_input_config_change, -}; - -static void vhost_input_change_active(VirtIOInput *vinput) -{ - DBG("vhost_input_change_active(...)\n"); - - if (vinput->active) { - vhost_user_backend_start(global_vdev); - } else { - vhost_user_backend_stop(global_vdev); - } -} - -static void vhost_input_get_config(VirtIODevice *vdev, uint8_t *config_data) -{ - DBG("vhost_input_get_config(...)\n"); - - VirtIOInput *vinput = vdev->vinput; - VhostUserInput *vhi = vdev->vhuinput; - int ret; - - memset(config_data, 0, vinput->cfg_size); - - ret = vhost_dev_get_config(vhi->vhost_dev, config_data, vinput->cfg_size); - if (ret) { - DBG("vhost_input_get_config failed\n"); - return; - } -} - -static void vhost_input_set_config(VirtIODevice *vdev, - const uint8_t *config_data) -{ - DBG("vhost_input_set_config(...)\n"); - - VhostUserInput *vhi = vdev->vhuinput; - int ret; - - ret = vhost_dev_set_config(vhi->vhost_dev, config_data, - 0, sizeof(virtio_input_config), - VHOST_SET_CONFIG_TYPE_MASTER); - if (ret < 0) { - DBG("vhost_input_set_config failed\n"); - return; - } - - virtio_notify_config(vdev); -} - -static struct vhost_dev *vhost_input_get_vhost(VirtIODevice *vdev) -{ - DBG("vhost_input_get_vhost(...)\n"); - - return vdev->vhuinput->vhost_dev; -} - -static void print_config_input(uint8_t *config_data) -{ - struct virtio_input_config *config_strct = - (struct virtio_input_config *)config_data; - - DBG("print_config_input: Not yet implemented\n"); - (void)config_strct; -} - -static void vhost_input_class_init(VirtIODevice *vdev) -{ - DBG("vhost_input_class_init(...)\n"); - - - /* Comment out the following lines to get the local config */ - vdev->vdev_class->get_config = vhost_input_get_config; - vdev->vdev_class->set_config = vhost_input_set_config; - vdev->vdev_class->get_vhost = vhost_input_get_vhost; - vdev->vhuinput->vdev_input->input_class->realize = vhost_user_input_realize; - vdev->vhuinput->vdev_input->input_class->change_active = - vhost_input_change_active; - vdev->vdev_class->update_mem_table = update_mem_table; - vdev->vdev_class->print_config = print_config_input; -} - - -void vhost_user_input_init(VirtIODevice *vdev) -{ - - DBG("vhost_user_input_init(...)\n"); - - struct VirtIOInputClass *input_class = (struct VirtIOInputClass *)malloc( - sizeof(struct VirtIOInputClass)); - VirtIOInput *vinput = (VirtIOInput *)malloc(sizeof(VirtIOInput)); - VhostUserInput *vhuinput = (VhostUserInput *)malloc(sizeof(VhostUserInput)); - - vdev->vinput = vinput; - vdev->vinput->input_class = input_class; - - vdev->vhuinput = vhuinput; - vdev->nvqs = (int*)&dev->nvqs; - vhuinput->vdev = vdev; - vhuinput->vhost_dev = dev; - vhuinput->vdev_input = vinput; - - /* - * Call first the virtio_input class init to set up - * the basic functionality. - */ - virtio_input_class_init(vdev); - - /* Then call the vhost_user class init */ - vhost_input_class_init(vdev); - - /* finally initialize the bus */ - virtio_loopback_bus_init(vdev->vbus); -} - - -void vhost_user_input_realize(int queue_num, int queue_size) -{ - int nvqs = 2; /* qemu choice: 2 */ - - DBG("vhost_user_input_realize()\n"); - (void)queue_num; - (void)queue_size; - - vhost_dev_set_config_notifier(global_vdev->vhuinput->vhost_dev, - &config_ops); - - global_vdev->vhuinput->vdev_input->cfg_size = - sizeof_field(virtio_input_config, u); - - global_vdev->vhuinput->vhost_dev->vq_index = 0; - global_vdev->vhuinput->vhost_dev->backend_features = 0; - global_vdev->vhuinput->vhost_dev->num_queues = nvqs; - - - global_vdev->vq = (struct VirtQueue *)malloc( - sizeof(struct VirtQueue) * nvqs); - - global_vdev->vhuinput->vhost_dev->nvqs = nvqs; - global_vdev->vhuinput->vhost_dev->vqs = (struct vhost_virtqueue *)malloc( - sizeof(struct vhost_virtqueue) * nvqs); - vhost_dev_init(global_vdev->vhuinput->vhost_dev); - - /* Pass the new obtained features */ - global_vdev->host_features = global_vdev->vhuinput->vhost_dev->features; -} - -void vhost_user_backend_start(VirtIODevice *vdev) -{ - VirtioBus *k = vdev->vbus; - unsigned int i; - int ret; - - DBG("vhost_user_backend_start(...)\n"); - - if (vdev->started) { - DBG("Device has already been started!\n"); - return; - } - - if (!k->set_guest_notifiers) { - DBG("binding does not support guest notifiers\n"); - return; - } - - ret = vhost_dev_enable_notifiers(vdev->vhuinput->vhost_dev, vdev); - if (ret < 0) { - DBG("vhost_dev_enable_notifiers failed!\n"); - return; - } - - DBG("k->set_guest_notifiers, nvqs: %d\n", vdev->vhuinput->vhost_dev->nvqs); - ret = k->set_guest_notifiers(vdev, vdev->vhuinput->vhost_dev->nvqs, true); - if (ret < 0) { - DBG("Error binding guest notifier\n"); - } - - vdev->vhuinput->vhost_dev->acked_features = vdev->guest_features; - ret = vhost_dev_start(vdev->vhuinput->vhost_dev, vdev, false); - if (ret < 0) { - DBG("Error start vhost dev\n"); - return; - } - - /* - * guest_notifier_mask/pending not used yet, so just unmask - * everything here. virtio-pci will do the right thing by - * enabling/disabling irqfd. - */ - for (i = 0; i < vdev->vhuinput->vhost_dev->nvqs; i++) { - vhost_virtqueue_mask(vdev->vhuinput->vhost_dev, vdev, - vdev->vhuinput->vhost_dev->vq_index + i, false); - } - - vdev->started = true; - return; - -} - -void vhost_user_backend_stop(VirtIODevice *vdev) -{ - DBG("vhost_user_backend_stop() not yet implemented\n"); - (void)vdev; -} diff --git a/vhost_user_input.h b/vhost_user_input.h deleted file mode 100644 index 23f4ddd..0000000 --- a/vhost_user_input.h +++ /dev/null @@ -1,158 +0,0 @@ -/* - * Based on virtio-input.h of QEMU project - * - * Copyright (c) 2022-2023 Virtual Open Systems SAS. - * - * This work is licensed under the terms of the GNU GPL, version 2 or - * (at your option) any later version. See the COPYING file in the - * top-level directory. - */ - -#ifndef VHOST_USER_INPUT -#define VHOST_USER_INPUT - -#include "vhost_loopback.h" -#include "vhost_user_loopback.h" -#include "virtio_loopback.h" -#include <linux/virtio_input.h> -#include "queue.h" -#include <sys/mman.h> - -/* ----------------------------------------------------------------- */ -/* virtio input protocol */ - -typedef struct virtio_input_absinfo virtio_input_absinfo; -typedef struct virtio_input_config virtio_input_config; -typedef struct virtio_input_event virtio_input_event; - -/* ----------------------------------------------------------------- */ -/* qemu internals */ - -#define TYPE_VIRTIO_INPUT "virtio-input-device" -#define TYPE_VIRTIO_INPUT_HID "virtio-input-hid-device" -#define TYPE_VIRTIO_KEYBOARD "virtio-keyboard-device" -#define TYPE_VIRTIO_MOUSE "virtio-mouse-device" -#define TYPE_VIRTIO_TABLET "virtio-tablet-device" - -#define TYPE_VIRTIO_INPUT_HOST "virtio-input-host-device" - -#define TYPE_VHOST_USER_INPUT "vhost-user-input" - -typedef struct VirtIOInputConfig { - virtio_input_config config; - QTAILQ_ENTRY(VirtIOInputConfig) node; -} VirtIOInputConfig; - -struct VirtIOInputClass; - -typedef struct VirtIOInput { - VirtIODevice *parent_dev; - struct VirtIOInputClass *input_class; - uint8_t cfg_select; - uint8_t cfg_subsel; - uint32_t cfg_size; - QTAILQ_HEAD(, VirtIOInputConfig) cfg_list; - VirtQueue *evt, *sts; - char *serial; - struct { - virtio_input_event event; - VirtQueueElement *elem; - } *queue; - uint32_t qindex, qsize; - bool active; - -} VirtIOInput; - -typedef struct VirtIOInputClass { - VirtioDeviceClass *parent_class; - void (*realize)(); - void (*unrealize)(VirtIODevice *dev); - void (*change_active)(VirtIOInput *vinput); - void (*handle_status)(VirtIOInput *vinput, virtio_input_event *event); -} VirtIOInputClass; - -struct VirtIOInputHID { - VirtIOInput parent_obj; - char *display; - uint32_t head; - int ledstate; - bool wheel_axis; -}; - -struct VirtIOInputHost { - VirtIOInput parent_obj; - char *evdev; - int fd; -}; - -typedef struct VhostUserInput { - VirtIOInput *vdev_input; - struct vhost_dev *vhost_dev; - VirtIODevice *vdev; - bool started; - bool completed; -} VhostUserInput; - -#define VIRTIO_ID_NAME_KEYBOARD "QEMU Virtio Keyboard" -#define BUS_VIRTUAL 0x06 - - -/* - * Event types - */ - -#define EV_SYN 0x00 -#define EV_KEY 0x01 -#define EV_REL 0x02 -#define EV_ABS 0x03 -#define EV_MSC 0x04 -#define EV_SW 0x05 -#define EV_LED 0x11 -#define EV_SND 0x12 -#define EV_REP 0x14 -#define EV_FF 0x15 -#define EV_PWR 0x16 -#define EV_FF_STATUS 0x17 -#define EV_MAX 0x1f -#define EV_CNT (EV_MAX + 1) - -/* - * LEDs - */ - -#define LED_NUML 0x00 -#define LED_CAPSL 0x01 -#define LED_SCROLLL 0x02 -#define LED_COMPOSE 0x03 -#define LED_KANA 0x04 -#define LED_SLEEP 0x05 -#define LED_SUSPEND 0x06 -#define LED_MUTE 0x07 -#define LED_MISC 0x08 -#define LED_MAIL 0x09 -#define LED_CHARGING 0x0a -#define LED_MAX 0x0f -#define LED_CNT (LED_MAX + 1) - -/* - * Keys and buttons - * - * Most of the keys/buttons are modeled after USB HUT 1.12 - * (see http://www.usb.org/developers/hidpage). - * Abbreviations in the comments: - * AC - Application Control - * AL - Application Launch Button - * SC - System Control - */ -#define KEY_G 34 - -void vhost_user_backend_start(VirtIODevice *vdev); -void vhost_user_backend_stop(VirtIODevice *vdev); -void virtio_input_init_config(VirtIOInput *vinput, - virtio_input_config *config); -void virtio_input_class_init(VirtIODevice *vdev); -void virtio_input_device_realize(int queue_num, int queue_size); -void vhost_user_input_init(VirtIODevice *vdev); -void vhost_user_input_realize(); - -#endif /* VHOST_USER_INPUT */ diff --git a/vhost_user_rng.c b/vhost_user_rng.c deleted file mode 100644 index 96eb13e..0000000 --- a/vhost_user_rng.c +++ /dev/null @@ -1,219 +0,0 @@ -/* - * Based on vhost-user-rng of QEMU project - * - * Copyright (c) 2021 Mathieu Poirier <mathieu.poirier@linaro.org> - * - * Copyright (c) 2022-2023 Virtual Open Systems SAS. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * 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. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ - -#include <unistd.h> -#include <stdlib.h> -#include <stdio.h> -#include <stdint.h> -#include <string.h> -#include <stdbool.h> -#include <sys/param.h> - -/* Project header files */ -#include "vhost_loopback.h" -#include "vhost_user_rng.h" - -#ifdef DEBUG -#define DBG(...) printf("vhost-user-rng: " __VA_ARGS__) -#else -#define DBG(...) -#endif /* DEBUG */ - -static void vu_rng_start(VirtIODevice *vdev) -{ - VHostUserRNG *rng = vdev->vhrng; - VirtioBus *k = vdev->vbus; - int ret; - int i; - - /* TODO: This might be deleted in future */ - if (!k->set_guest_notifiers) { - DBG("binding does not support guest notifiers\n"); - return; - } - - ret = vhost_dev_enable_notifiers(rng->vhost_dev, vdev); - if (ret < 0) { - DBG("Error enabling host notifiers: %d\n", ret); - return; - } - - ret = k->set_guest_notifiers(vdev, rng->vhost_dev->nvqs, true); - if (ret < 0) { - DBG("Error binding guest notifier: %d\n", ret); - return; - } - - rng->vhost_dev->acked_features = vdev->guest_features; - DBG("rng->vhost_dev->acked_features: 0x%lx\n", vdev->guest_features); - - ret = vhost_dev_start(rng->vhost_dev, vdev, true); - if (ret < 0) { - DBG("Error starting vhost-user-rng: %d\n", ret); - return; - } - - /* - * guest_notifier_mask/pending not used yet, so just unmask - * everything here. virtio-pci will do the right thing by - * enabling/disabling irqfd. - */ - for (i = 0; i < (int)rng->vhost_dev->nvqs; i++) { - vhost_virtqueue_mask(rng->vhost_dev, vdev, i, false); - } -} - -/* To be used in future release - * - * static void vu_rng_stop(VirtIODevice *vdev) - * { - * DBG("vu_rng_stop is not yet implemented\n"); - * (void)vdev; - * } - * - */ - -static uint64_t vu_rng_get_features(VirtIODevice *vdev, - uint64_t requested_features) -{ - DBG("vu_rng_get_features is not yet implemented\n"); - (void)vdev; - - /* No feature bits used yet */ - return requested_features; -} - -/* TODO: We need to implement this function in a future release */ -static void vu_rng_guest_notifier_mask(VirtIODevice *vdev, int idx, bool mask) -{ - VHostUserRNG *rng = vdev->vhrng; - - DBG("vu_rng_guest_notifier_mask is not yet implemented\n"); - (void)vdev; - (void)idx; - (void)mask; - (void)rng; - - /* ADD: vhost_virtqueue_mask(&rng->vhost_dev, vdev, idx, mask); */ -} - -/* TODO: We need to implement this function in a future release */ -static bool vu_rng_guest_notifier_pending(VirtIODevice *vdev, int idx) -{ - VHostUserRNG *rng = vdev->vhrng; - - DBG("vu_rng_guest_notifier_pending is not yet implemented\n"); - (void)vdev; - (void)idx; - (void)rng; - - /* ADD: return vhost_virtqueue_pending(&rng->vhost_dev, idx); */ - return 1; -} - -static void vu_rng_set_status(VirtIODevice *vdev, uint8_t status) -{ - VHostUserRNG *rng = vdev->vhrng; - bool should_start = status & VIRTIO_CONFIG_S_DRIVER_OK; - - if (rng->vhost_dev->started == should_start) { - DBG("rng->vhost_dev->started != should_start\n"); - return; - } - - if (should_start) { - vu_rng_start(vdev); - } else { - DBG("vu_rng_stop(vdev)\n"); - /* TODO: Add vu_rng_stop(vdev); when this function is implemented */ - } -} - -static void virtio_dev_class_init(VirtIODevice *vdev) -{ - vdev->vdev_class = (VirtioDeviceClass *)malloc(sizeof(VirtioDeviceClass)); - vdev->vdev_class->parent = vdev; - vdev->vdev_class->set_status = vu_rng_set_status; - vdev->vdev_class->get_features = vu_rng_get_features; - vdev->vdev_class->guest_notifier_mask = vu_rng_guest_notifier_mask; - vdev->vdev_class->guest_notifier_pending = vu_rng_guest_notifier_pending; - vdev->vdev_class->update_mem_table = update_mem_table; -} - - -void vhost_user_rng_init(VirtIODevice *vdev) -{ - VHostUserRNG *vhrng = (VHostUserRNG *)malloc(sizeof(VHostUserRNG)); - vdev->vhrng = vhrng; - vdev->nvqs = (int *)&dev->nvqs; - vhrng->parent = vdev; - vhrng->req_vq = vdev->vq; - vhrng->vhost_dev = dev; - - virtio_dev_class_init(vdev); - virtio_loopback_bus_init(vdev->vbus); -} - -static void vu_rng_handle_output(VirtIODevice *vdev, VirtQueue *vq) -{ - (void)vdev; - (void)vq; - /* - * Not normally called; it's the daemon that handles the queue; - * however virtio's cleanup path can call this. - */ - DBG("vu_rng_handle_output\n"); -} - - -void vhost_user_rng_realize(int queue_num, int queue_size) -{ - (void)queue_num; - (void)queue_size; - - /* Initiliaze virtio_dev data structures */ - virtio_dev_init(global_vdev, "virtio-rng", 4, 0); - - /* This needs to be change to vhost-user-rng init */ - vhost_user_rng_init(global_vdev); - - global_vdev->vq = virtio_add_queue(global_vdev, 4, vu_rng_handle_output); - - global_vdev->host_features = 0x39000000; - - proxy = (VirtIOMMIOProxy *)malloc(sizeof(VirtIOMMIOProxy)); - *proxy = (VirtIOMMIOProxy) { - .legacy = 1, - }; - - /* Virtqueues conf */ - dev->nvqs = 1; - dev->vqs = (struct vhost_virtqueue *)malloc(dev->nvqs * - sizeof(struct vhost_virtqueue)); - - /* Initiale vhost-user communication */ - vhost_dev_init(dev); - - /* Write the final features */ - global_vdev->host_features = dev->features; - DBG("dev->host_features: 0x%lx\n", dev->features); -} diff --git a/vhost_user_sound.c b/vhost_user_sound.c deleted file mode 100644 index d9f6a98..0000000 --- a/vhost_user_sound.c +++ /dev/null @@ -1,322 +0,0 @@ -/* - * Based on vhost-user-sound.c of QEMU project - * - * Copyright 2020 Red Hat, Inc. - * - * Copyright (c) 2023 Virtual Open Systems SAS. - * - * This work is licensed under the terms of the GNU GPL, version 2 or - * (at your option) any later version. See the COPYING file in the - * top-level directory. - * - */ - - -#include <unistd.h> -#include <stdlib.h> -#include <stdio.h> -#include <stdint.h> -#include <string.h> -#include <stdbool.h> -#include <sys/param.h> - -/* Project header files */ -#include "vhost_user_sound.h" - -#ifdef DEBUG -#define DBG(...) printf("vhost-user-sound: " __VA_ARGS__) -#else -#define DBG(...) -#endif /* DEBUG */ - -/***************************** vhost-user-sound ******************************/ - -/* - * Features supported by the vhost-user-sound frontend: - * VIRTIO_F_VERSION_1, - * VIRTIO_RING_F_INDIRECT_DESC, - * VIRTIO_RING_F_EVENT_IDX, - * VIRTIO_F_RING_RESET, - * VIRTIO_F_NOTIFY_ON_EMPTY, - * VHOST_INVALID_FEATURE_BIT - */ -static const int user_feature_bits[] = { - VIRTIO_F_VERSION_1, - VIRTIO_RING_F_INDIRECT_DESC, - VIRTIO_RING_F_EVENT_IDX, - VIRTIO_F_RING_RESET, - VIRTIO_F_NOTIFY_ON_EMPTY, - VHOST_INVALID_FEATURE_BIT -}; - -static void vus_get_config(VirtIODevice *vdev, uint8_t *config) -{ - VHostUserSound *snd = vdev->vhusnd; - - memcpy(config, &snd->config, sizeof(struct virtio_snd_config)); -} - - -static void vus_start(VirtIODevice *vdev) -{ - VHostUserSound *vhusnd = vdev->vhusnd; - VirtioBus *k = vdev->vbus; - int ret; - unsigned int i; - - DBG("vus_start(...)\n"); - - if (!k->set_guest_notifiers) { - DBG("binding does not support guest notifiers\n"); - return; - } - - ret = vhost_dev_enable_notifiers(vhusnd->vhost_dev, vdev); - if (ret < 0) { - DBG("Error enabling host notifiers: %d\n", -ret); - return; - } - - ret = k->set_guest_notifiers(k->vdev, vhusnd->vhost_dev->nvqs, true); - if (ret < 0) { - DBG("Error binding guest notifier: %d\n", -ret); - goto err_host_notifiers; - } - - vhusnd->vhost_dev->acked_features = vdev->guest_features; - - ret = vhost_dev_start(vhusnd->vhost_dev, vdev, true); - if (ret < 0) { - DBG("Error starting vhost: %d\n", -ret); - goto err_guest_notifiers; - } - - /* - * guest_notifier_mask/pending not used yet, so just unmask - * everything here. virtio-pci will do the right thing by - * enabling/disabling irqfd. - */ - for (i = 0; i < vhusnd->vhost_dev->nvqs; i++) { - vhost_virtqueue_mask(vhusnd->vhost_dev, vdev, i, false); - } - - return; - -err_guest_notifiers: -err_host_notifiers: - DBG("vhu_start error\n"); - return; -} - -static void vus_stop(VirtIODevice *vdev) -{ - DBG("vus_stop: not yet implemented\n"); - (void)vdev; -} - -static void vus_set_status(VirtIODevice *vdev, uint8_t status) -{ - VHostUserSound *vhusnd = vdev->vhusnd; - bool should_start = virtio_device_started(vdev, status); - DBG("vus_set_status\n"); - - if (vhusnd->vhost_dev->started == should_start) { - DBG("snd->vhost_dev->started == should_start\n"); - return; - } - - if (should_start) { - vus_start(vdev); - } else { - vus_stop(vdev); - } -} - -static uint64_t vus_get_features(VirtIODevice *vdev, uint64_t features) -{ - VHostUserSound *s = vdev->vhusnd; - - DBG("vus_get_features()\n"); - - return vhost_get_features(s->vhost_dev, user_feature_bits, features); -} - -static void vus_snd_handle_output(VirtIODevice *vdev, VirtQueue *vq) -{ - /* - * Not normally called; it's the daemon that handles the queue; - * however virtio's cleanup path can call this. - */ - (void)vdev; - (void)vq; -} - -/* - * TODO: Add it later - * static void vhost_sound_guest_notifier_mask(VirtIODevice *vdev, int idx, - * bool mask) - */ - -/* - * TODO: Add it later - * static bool vhost_sound_guest_notifier_pending(VirtIODevice *vdev, - * int idx) - */ - -static int vus_sound_config_change(struct vhost_dev *dev) -{ - VHostUserSound *vhusnd = dev->vdev->vhusnd; - DBG("vus_sound_config_change\n"); - - int ret = vhost_dev_get_config(dev, (uint8_t *)&vhusnd->config, - sizeof(struct virtio_snd_config)); - if (ret < 0) { - DBG("vus_sound_config_change error\n"); - return -1; - } - - virtio_notify_config(dev->vdev); - - return 0; -} - -const VhostDevConfigOps snd_config_ops = { - .vhost_dev_config_notifier = vus_sound_config_change, -}; - -static void vhost_user_snd_init(VirtIODevice *vdev); - -void vus_device_realize(int queue_num, int queue_size) -{ - VirtIODevice *vdev = global_vdev; - int ret; - - DBG("vus_device_realize\n"); - (void)queue_num; - (void)queue_size; - - /* This needs to be added */ - proxy = (VirtIOMMIOProxy *)malloc(sizeof(VirtIOMMIOProxy)); - *proxy = (VirtIOMMIOProxy) { - .legacy = 1, - }; - - /* VIRTIO_ID_SOUND is 25, check virtio_ids.h in linux*/ - virtio_dev_init(vdev, "virtio-sound", 25, sizeof(vdev->vhusnd->config)); - vhost_user_snd_init(global_vdev); - - /* add queues */ - vdev->vhusnd->ctrl_vq = virtio_add_queue(vdev, 64, vus_snd_handle_output); - vdev->vhusnd->event_vq = virtio_add_queue(vdev, 64, vus_snd_handle_output); - vdev->vhusnd->tx_vq = virtio_add_queue(vdev, 64, vus_snd_handle_output); - vdev->vhusnd->rx_vq = virtio_add_queue(vdev, 64, vus_snd_handle_output); - vdev->vhusnd->vhost_dev->nvqs = 4; - vdev->vhusnd->num_queues = 4; - vdev->vhusnd->queue_size = 64; - - /* NOTE: global_vdev->vqs == vhublk->virtqs */ - vdev->vqs = (VirtQueue **)malloc(sizeof(VirtQueue *) - * global_vdev->vhusnd->num_queues); - vdev->vqs[0] = vdev->vhusnd->ctrl_vq; - vdev->vqs[1] = vdev->vhusnd->event_vq; - vdev->vqs[2] = vdev->vhusnd->tx_vq; - vdev->vqs[3] = vdev->vhusnd->rx_vq; - - vdev->vhusnd->vhost_vqs = (struct vhost_virtqueue *)malloc( - sizeof(struct vhost_virtqueue) * - vdev->vhusnd->num_queues); - - /* Set up vhost device */ - vdev->vhusnd->vhost_dev->num_queues = vdev->vhusnd->num_queues; - vdev->vhusnd->vhost_dev->nvqs = vdev->vhusnd->num_queues; - vdev->vhusnd->vhost_dev->vqs = vdev->vhusnd->vhost_vqs; - vdev->vhusnd->vhost_dev->vq_index = 0; - vdev->vhusnd->vhost_dev->backend_features = 0; - - vhost_dev_set_config_notifier(vdev->vhusnd->vhost_dev, &snd_config_ops); - - /* TODO: Add error handling */ - vhost_dev_init(vdev->vhusnd->vhost_dev); - - /* Pass the new obtained features */ - global_vdev->host_features = vdev->vhusnd->vhost_dev->features; - - ret = vhost_dev_get_config(vdev->vhusnd->vhost_dev, - (uint8_t *)&vdev->vhusnd->config, - sizeof(struct virtio_snd_config)); - if (ret < 0) { - goto vhost_dev_init_failed; - } - - vdev->vdev_class->print_config((uint8_t *)&vdev->vhusnd->config); - - return; - -vhost_dev_init_failed: - DBG("vhost_dev_init_failed\n"); - return; -} - -static void vus_device_unrealize(VirtIODevice *vdev) -{ - DBG("vhost_user_blk_device_unrealize not yet implemented\n"); - (void)vdev; -} - -/* - * This will be might be useful in the future - * - * static struct vhost_dev *vus_get_vhost(VirtIODevice *vdev) - * { - * VHostUserSound *vhusnd = vdev->vhusnd; - * return vhusnd->vhost_dev; - * } - * - */ - -static void print_config_snd(uint8_t *config_data) -{ - struct virtio_snd_config *config_strct = - (struct virtio_snd_config *)config_data; - - (void)config_strct; - - DBG("print_config_snd:\n"); - /* # of available physical jacks */ - DBG("\tuint32_t jacks: %u\n", config_strct->jacks); - /* # of available PCM streams */ - DBG("\tuint32_t streams: %u\n", config_strct->streams); - /* # of available channel maps */ - DBG("\tuint32_t chmaps: %u\n", config_strct->chmaps); -} - -static void virtio_dev_class_init(VirtIODevice *vdev) -{ - DBG("virtio_dev_class_init\n"); - - vdev->vdev_class = (VirtioDeviceClass *)malloc(sizeof(VirtioDeviceClass)); - vdev->vdev_class->parent = vdev; - vdev->vdev_class->realize = vus_device_realize; - vdev->vdev_class->unrealize = vus_device_unrealize; - vdev->vdev_class->get_config = vus_get_config; - vdev->vdev_class->get_features = vus_get_features; - vdev->vdev_class->set_status = vus_set_status; - vdev->vdev_class->update_mem_table = update_mem_table; - vdev->vdev_class->print_config = print_config_snd; -} - -static void vhost_user_snd_init(VirtIODevice *vdev) -{ - - DBG("vhost_user_blk_init\n"); - - VHostUserSound *vhusnd = (VHostUserSound *)malloc(sizeof(VHostUserSound)); - vdev->vhusnd = vhusnd; - vdev->nvqs = (int *)&vdev->vhdev->nvqs; - vhusnd->parent = vdev; - vhusnd->virtqs = vdev->vqs; - vhusnd->vhost_dev = vdev->vhdev; - - virtio_dev_class_init(vdev); - virtio_loopback_bus_init(vdev->vbus); -} diff --git a/virtio_blk.h b/virtio_blk.h deleted file mode 100644 index 75534ed..0000000 --- a/virtio_blk.h +++ /dev/null @@ -1,95 +0,0 @@ -/* - * Virtio Block Device - * - * Copyright IBM, Corp. 2007 - * - * Authors: - * Anthony Liguori <aliguori@us.ibm.com> - * - * This work is licensed under the terms of the GNU GPL, version 2. See - * the COPYING file in the top-level directory. - * - */ - -#ifndef QEMU_VIRTIO_BLK_H -#define QEMU_VIRTIO_BLK_H - -#include "standard-headers/linux/virtio_blk.h" -#include "hw/virtio/virtio.h" -#include "hw/block/block.h" -#include "sysemu/iothread.h" -#include "sysemu/block-backend.h" -#include "qom/object.h" - -#define TYPE_VIRTIO_BLK "virtio-blk-device" -#define VIRTIO_BLK_AUTO_NUM_QUEUES UINT16_MAX -OBJECT_DECLARE_SIMPLE_TYPE(VirtIOBlock, VIRTIO_BLK) - -/* This is the last element of the write scatter-gather list */ -struct virtio_blk_inhdr { - unsigned char status; -}; - - -struct VirtIOBlkConf { - BlockConf conf; - IOThread *iothread; - char *serial; - uint32_t request_merging; - uint16_t num_queues; - uint16_t queue_size; - bool seg_max_adjust; - bool report_discard_granularity; - uint32_t max_discard_sectors; - uint32_t max_write_zeroes_sectors; - bool x_enable_wce_if_config_wce; -}; - - -struct VirtIOBlockDataPlane; - -struct VirtIOBlockReq; -struct VirtIOBlock { - VirtIODevice parent_obj; - BlockBackend *blk; - void *rq; - QEMUBH *bh; - VirtIOBlkConf conf; - unsigned short sector_mask; - bool original_wce; - VMChangeStateEntry *change; - bool dataplane_disabled; - bool dataplane_started; - struct VirtIOBlockDataPlane *dataplane; - uint64_t host_features; - size_t config_size; -}; - -typedef struct VirtIOBlockReq { - VirtQueueElement elem; - int64_t sector_num; - VirtIOBlock *dev; - VirtQueue *vq; - IOVDiscardUndo inhdr_undo; - IOVDiscardUndo outhdr_undo; - struct virtio_blk_inhdr *in; - struct virtio_blk_outhdr out; - QEMUIOVector qiov; - size_t in_len; - struct VirtIOBlockReq *next; - struct VirtIOBlockReq *mr_next; - BlockAcctCookie acct; -} VirtIOBlockReq; - -#define VIRTIO_BLK_MAX_MERGE_REQS 32 - -typedef struct MultiReqBuffer { - VirtIOBlockReq *reqs[VIRTIO_BLK_MAX_MERGE_REQS]; - unsigned int num_reqs; - bool is_write; -} MultiReqBuffer; - -bool virtio_blk_handle_vq(VirtIOBlock *s, VirtQueue *vq); -void virtio_blk_process_queued_requests(VirtIOBlock *s, bool is_bh); - -#endif diff --git a/virtio_input.c b/virtio_input.c deleted file mode 100644 index 668abe6..0000000 --- a/virtio_input.c +++ /dev/null @@ -1,331 +0,0 @@ -/* - * Based on virtio-input.h of QEMU project - * - * Copyright (c) 2022-2023 Virtual Open Systems SAS. - * - * This work is licensed under the terms of the GNU GPL, version 2 or - * (at your option) any later version. See the COPYING file in the - * top-level directory. - */ - -#include <unistd.h> -#include <stdlib.h> -#include <stdio.h> -#include <stdint.h> -#include <string.h> -#include <stdbool.h> -#include <sys/param.h> - -/* Project header files */ -#include "vhost_user_input.h" - -#ifdef DEBUG -#define DBG(...) printf("virtio-input: " __VA_ARGS__) -#else -#define DBG(...) -#endif /* DEBUG */ - -#define VIRTIO_INPUT_VM_VERSION 1 - -/* ----------------------------------------------------------------- */ - -/* - * Example struct for keyboard - */ -static struct virtio_input_config virtio_keyboard_config[] = { - { - .select = VIRTIO_INPUT_CFG_ID_NAME, - .size = sizeof(VIRTIO_ID_NAME_KEYBOARD), - .u.string = VIRTIO_ID_NAME_KEYBOARD, - },{ - .select = VIRTIO_INPUT_CFG_ID_DEVIDS, - .size = sizeof(struct virtio_input_devids), - .u.ids = { - .bustype = (BUS_VIRTUAL), - .vendor = (0x0627), /* same we use for usb hid devices */ - .product = (0x0001), - .version = (0x0001), - }, - },{ - .select = VIRTIO_INPUT_CFG_EV_BITS, - .subsel = EV_KEY, - .size = 1, - .u.bitmap = { - KEY_G, - }, - }, - {}, /* End of list */ -}; - - -void virtio_input_send(VirtIOInput *vinput, virtio_input_event *event) -{ - DBG("virtio_input_send() not yet implemeted\n"); - (void)vinput; - (void)event; -} - -static void virtio_input_handle_evt(VirtIODevice *vdev, VirtQueue *vq) -{ - DBG("virtio_input_handle_evt(...) not yet implemeted\n"); - (void)vdev; - (void)vq; -} - -static void virtio_input_handle_sts(VirtIODevice *vdev, VirtQueue *vq) -{ - VirtIOInputClass *vic = vdev->vinput->input_class; - VirtIOInput *vinput = vdev->vinput; - virtio_input_event event; - VirtQueueElement *elem; - int len; - - DBG("virtio_input_handle_sts(...)\n"); - (void)vq; - - for (;;) { - elem = virtqueue_pop(vinput->sts, sizeof(VirtQueueElement)); - if (!elem) { - break; - } - - memset(&event, 0, sizeof(event)); - /* FIXME: add iov_to_buf func */ - len = 1; - /* - * TODO: Will be added in a next release - * len = iov_to_buf(elem->out_sg, elem->out_num, - * 0, &event, sizeof(event)); - */ - if (vic->handle_status) { - vic->handle_status(vinput, &event); - } - virtqueue_push(vinput->sts, elem, len); - munmap(elem, sizeof(VirtQueueElement)); - } - virtio_notify(vdev, vinput->sts); -} - -virtio_input_config *virtio_input_find_config(VirtIOInput *vinput, - uint8_t select, - uint8_t subsel) -{ - DBG("virtio_input_find_config(...)\n"); - VirtIOInputConfig *cfg; - - QTAILQ_FOREACH(cfg, &vinput->cfg_list, node) { - if (select == cfg->config.select && - subsel == cfg->config.subsel) { - return &cfg->config; - } - } - return NULL; -} - -void virtio_input_add_config(VirtIOInput *vinput, - virtio_input_config *config) -{ - DBG("virtio_input_add_config(...)\n"); - VirtIOInputConfig *cfg; - - if (virtio_input_find_config(vinput, config->select, config->subsel)) { - /* should not happen */ - DBG("Error duplicate config: %d/%d\n", config->select, config->subsel); - exit(1); - } - - cfg = (VirtIOInputConfig *)malloc(sizeof(VirtIOInputConfig)); - cfg->config = *config; - - QTAILQ_INSERT_TAIL(&vinput->cfg_list, cfg, node); -} - -void virtio_input_init_config(VirtIOInput *vinput, - virtio_input_config *config) -{ - DBG("virtio_input_init_config(...)\n"); - int i = 0; - - QTAILQ_INIT(&vinput->cfg_list); - while (config[i].select) { - virtio_input_add_config(vinput, config + i); - i++; - } -} - -void virtio_input_idstr_config(VirtIOInput *vinput, - uint8_t select, const char *string) -{ - DBG("virtio_input_idstr_config(...)\n"); - virtio_input_config id; - - if (!string) { - return; - } - memset(&id, 0, sizeof(id)); - id.select = select; - id.size = snprintf(id.u.string, sizeof(id.u.string), "%s", string); - virtio_input_add_config(vinput, &id); -} - -static void virtio_input_get_config(VirtIODevice *vdev, uint8_t *config_data) -{ - DBG("virtio_input_get_config(...)\n"); - VirtIOInput *vinput = vdev->vinput; - virtio_input_config *config; - - config = virtio_input_find_config(vinput, vinput->cfg_select, - vinput->cfg_subsel); - if (config) { - memcpy(config_data, config, vinput->cfg_size); - } else { - memset(config_data, 0, vinput->cfg_size); - } -} - -static void virtio_input_set_config(VirtIODevice *vdev, - const uint8_t *config_data) -{ - VirtIOInput *vinput = vdev->vinput; - virtio_input_config *config = (virtio_input_config *)config_data; - - DBG("virtio_input_set_config(...)\n"); - - vinput->cfg_select = config->select; - vinput->cfg_subsel = config->subsel; - virtio_notify_config(vdev); -} - -static uint64_t virtio_input_get_features(VirtIODevice *vdev, uint64_t f) -{ - DBG("virtio_input_get_features(...)\n"); - (void)vdev; - (void)f; - - return f; -} - -static void virtio_input_set_status(VirtIODevice *vdev, uint8_t val) -{ - VirtIOInputClass *vic = vdev->vinput->input_class; - VirtIOInput *vinput = vdev->vinput; - bool should_start = virtio_device_started(vdev, val); - - DBG("virtio_input_set_status(...): %u\n", val); - - if (should_start) { - if (!vinput->active) { - vinput->active = true; - if (vic->change_active) { - vic->change_active(vinput); - } - } - } -} - -static void virtio_input_reset(VirtIODevice *vdev) -{ - VirtIOInputClass *vic = vdev->vinput->input_class; - VirtIOInput *vinput = vdev->vinput; - - DBG("virtio_input_reset(...)\n"); - - if (vinput->active) { - vinput->active = false; - if (vic->change_active) { - vic->change_active(vinput); - } - } -} - -/* - * Functions which might be used in the future: - * - * static int virtio_input_post_load(void *opaque, int version_id) - * { - * VirtIOInput *vinput = global_vdev->vinput; - * VirtIOInputClass *vic = global_vdev->vinput->input_class; - * VirtIODevice *vdev = global_vdev; - * - * DBG("virtio_input_post_load(...)\n"); - * (void)opaque; - * (void)version_id; - * - * vinput->active = vdev->status & VIRTIO_CONFIG_S_DRIVER_OK; - * if (vic->change_active) { - * vic->change_active(vinput); - * } - * return 0; - * } - * - * static void virtio_input_finalize(VirtIODevice *vdev) - * { - * DBG("virtio_input_finalize not yet implemented"); - * (void)vdev; - * } - * - * static void virtio_input_device_unrealize(VirtIODevice *vdev) - * { - * DBG("virtio_input_device_unrealize not yet implemented"); - * (void)vdev; - * } - */ - -void virtio_input_device_realize(int queue_num, int queue_size) -{ - VirtIODevice *vdev = global_vdev; - struct VirtIOInputClass *vic = vdev->vinput->input_class; - VirtIOInput *vinput = vdev->vinput; - VirtIOInputConfig *cfg; - - DBG("virtio_input_device_realize(...)\n"); - (void)queue_num; - (void)queue_size; - - /* This needs to be added */ - proxy = (VirtIOMMIOProxy *)malloc(sizeof(VirtIOMMIOProxy)); - *proxy = (VirtIOMMIOProxy) { - .legacy = 1, - }; - - if (vic->realize) { - vic->realize(vdev); - } - - virtio_input_idstr_config(vinput, VIRTIO_INPUT_CFG_ID_SERIAL, - vinput->serial); - - QTAILQ_FOREACH(cfg, &vinput->cfg_list, node) { - if (vinput->cfg_size < cfg->config.size) { - vinput->cfg_size = cfg->config.size; - } - } - vinput->cfg_size += 8; - - virtio_input_init_config(vinput, virtio_keyboard_config); - - virtio_dev_init(vdev, "virtio-input", 18, vinput->cfg_size); - vinput->evt = virtio_add_queue(vdev, 64, virtio_input_handle_evt); - vinput->sts = virtio_add_queue(vdev, 64, virtio_input_handle_sts); - - /* FIXME: do we need that? */ - memcpy(global_vdev->vq, vinput->evt, sizeof(VirtQueue)); - memcpy(&global_vdev->vq[1], vinput->sts, sizeof(VirtQueue)); - - DBG("global_vdev->guest_features: 0x%lx\n", global_vdev->guest_features); -} - -void virtio_input_class_init(VirtIODevice *vdev) -{ - vdev->vdev_class = (VirtioDeviceClass *)malloc(sizeof(VirtioDeviceClass)); - vdev->vdev_class->parent = vdev; - - DBG("virtio_input_class_init(...)\n"); - - vdev->vdev_class->realize = virtio_input_device_realize; - vdev->vdev_class->get_config = virtio_input_get_config; - vdev->vdev_class->set_config = virtio_input_set_config; - vdev->vdev_class->get_features = virtio_input_get_features; - vdev->vdev_class->set_status = virtio_input_set_status; - vdev->vdev_class->reset = virtio_input_reset; -} |