summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Makefile2
-rw-r--r--adapter.c16
-rw-r--r--vhost_loopback.c2
-rw-r--r--vhost_user_console.c293
-rw-r--r--vhost_user_console.h70
-rw-r--r--vhost_user_sound.c3
-rw-r--r--virtio_loopback.h2
7 files changed, 380 insertions, 8 deletions
diff --git a/Makefile b/Makefile
index 45d6725..ae3cf79 100644
--- a/Makefile
+++ b/Makefile
@@ -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
diff --git a/adapter.c b/adapter.c
index 68effcd..ebf3171 100644
--- a/adapter.c
+++ b/adapter.c
@@ -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 {