summaryrefslogtreecommitdiffstats
path: root/vhost_user_input.c
diff options
context:
space:
mode:
Diffstat (limited to 'vhost_user_input.c')
-rw-r--r--vhost_user_input.c235
1 files changed, 235 insertions, 0 deletions
diff --git a/vhost_user_input.c b/vhost_user_input.c
new file mode 100644
index 0000000..9cb2164
--- /dev/null
+++ b/vhost_user_input.c
@@ -0,0 +1,235 @@
+/*
+ * 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");
+ 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");
+
+ VhostUserInput *vhuinput = global_vdev->vhuinput;
+
+ 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) {
+ 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");
+}
+
+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 = &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 nvqs = 2; /* qemu choice: 2 */
+
+ DBG("vhost_user_input_realize()\n");
+
+ 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;
+ int ret, i;
+
+ 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");
+}