diff options
-rw-r--r-- | Makefile | 2 | ||||
-rw-r--r-- | adapter.c | 16 | ||||
-rw-r--r-- | vhost_loopback.c | 2 | ||||
-rw-r--r-- | vhost_user_console.c | 293 | ||||
-rw-r--r-- | vhost_user_console.h | 70 | ||||
-rw-r--r-- | vhost_user_sound.c | 3 | ||||
-rw-r--r-- | virtio_loopback.h | 2 |
7 files changed, 380 insertions, 8 deletions
@@ -33,7 +33,7 @@ endif INCL += -I . 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_loopback.c adapter.c +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 OBJS = $(SRC_C:.c=.o) BINS = adapter @@ -50,6 +50,7 @@ #include "vhost_user_gpio.h" #include "vhost_user_sound.h" #include "vhost_user_can.h" +#include "vhost_user_console.h" #ifdef DEBUG @@ -141,7 +142,7 @@ static void help_args(void) "\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\n"); + "\tvrng, vhurng, vhublk, vhuinput, vhusnd, vhugpio, vhucan, vhuconsole\n"); } int find_arg(int argc, char **argv, char *str) @@ -159,10 +160,10 @@ int find_arg(int argc, char **argv, char *str) int val_device_arg(char *str) { char *adapter_devices[] = {"vrng", "vhurng", "vhublk", "vhuinput", - "vhusnd", "vhugpio", "vhucan"}; + "vhusnd", "vhugpio", "vhucan", "vhuconsole"}; char *vhu_devices[] = {"vhurng", "vhublk", "vhuinput", "vhusnd", - "vhugpio", "vhucan"}; - int adapter_devices_num = 7, i; + "vhugpio", "vhucan", "vhuconsole"}; + int adapter_devices_num = 8, i; for (i = 0; i < adapter_devices_num; i++) { if (!strcmp(adapter_devices[i], str)) { @@ -176,8 +177,8 @@ int val_device_arg(char *str) bool check_vhu_device(char *str) { char *vhu_devices[] = {"vhurng", "vhublk", "vhuinput", "vhusnd", - "vhugpio", "vhucan"}; - int vhu_devices_num = 6, i; + "vhugpio", "vhucan", "vhuconsole"}; + int vhu_devices_num = 7, i; for (i = 0; i < vhu_devices_num; i++) { if (!strcmp(vhu_devices[i], str)) { @@ -303,6 +304,9 @@ int main(int argc, char **argv) case 7: vhost_user_can_realize(); break; + case 8: + vhost_user_console_realize(); + break; default: exit(1); } diff --git a/vhost_loopback.c b/vhost_loopback.c index 1855ee8..e29707e 100644 --- a/vhost_loopback.c +++ b/vhost_loopback.c @@ -240,7 +240,7 @@ static int vhost_virtqueue_start(struct vhost_dev *dev, a = virtio_queue_get_desc_addr(vdev, idx); if (a == 0) { /* Queue might not be ready for start */ - DBG("Error: Queue might not be ready for start\n"); + DBG("Error: Queue (%d) might not be ready for start\n", idx); return 0; } diff --git a/vhost_user_console.c b/vhost_user_console.c new file mode 100644 index 0000000..8552b91 --- /dev/null +++ b/vhost_user_console.c @@ -0,0 +1,293 @@ +/* + * 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; + int ret; + int i; + + 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); + } + + /* Wait a bit for the vrings to be set in vhost-user-device */ + sleep(1); + + 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"); +} + +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"); +} + +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() +{ + VirtIODevice *vdev = global_vdev; + int ret; + + DBG("vhost_user_console_device_realize\n"); + + /* 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"); +} + +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; + + 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 = &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_console.h b/vhost_user_console.h new file mode 100644 index 0000000..93646c8 --- /dev/null +++ b/vhost_user_console.h @@ -0,0 +1,70 @@ +/* + * + * 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. + * + */ + +#ifndef VHOST_USER_CONSOLE +#define VHOST_USER_CONSOLE + +#include "virtio_loopback.h" +#include "vhost_loopback.h" +#include "vhost_user_loopback.h" + +/* Feature bits */ +#define VIRTIO_CONSOLE_F_SIZE 0 /* Does host provide console size? */ +#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; + /* rows of the screens */ + __virtio16 rows; + /* max. number of ports this device can hold */ + __virtio32 max_nr_ports; + /* emergency write register */ + __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; + VirtQueue **virtqs; + uint16_t num_queues; + 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(void); + +#endif /* VHOST_USER_CONSOLE */ diff --git a/vhost_user_sound.c b/vhost_user_sound.c index 1e4c5cf..c444feb 100644 --- a/vhost_user_sound.c +++ b/vhost_user_sound.c @@ -91,6 +91,9 @@ static void vus_start(VirtIODevice *vdev) goto err_guest_notifiers; } + /* Wait a bit before the vrings be set in vhost-user-device */ + sleep(1); + /* * guest_notifier_mask/pending not used yet, so just unmask * everything here. virtio-pci will do the right thing by diff --git a/virtio_loopback.h b/virtio_loopback.h index cd59a5a..2ece0f9 100644 --- a/virtio_loopback.h +++ b/virtio_loopback.h @@ -365,6 +365,7 @@ typedef struct VhostUserInput VhostUserInput; typedef struct VHostUserGPIO VHostUserGPIO; typedef struct VHostUserSound VHostUserSound; typedef struct VHostUserCan VHostUserCan; +typedef struct VHostUserConsole VHostUserConsole; typedef struct VirtioBus VirtioBus; typedef struct VirtIODevice { @@ -407,6 +408,7 @@ typedef struct VirtIODevice { VHostUserSound *vhusnd; VHostUserGPIO *vhugpio; VHostUserCan *vhucan; + VHostUserConsole *vhuconsole; } VirtIODevice; typedef struct efd_data { |