From: Timos Ampelikiotis <[email protected]>

Add vhost-user-console support enabling console device emulation via
the vhost-user protocol. This allows console handling to be performed
by separate userspace processes such as the rust-vmm
vhost-device-console daemon.

The device is based on vhost-user-base: set the console virtio id,
four queues, the console config layout, and add a PCI wrapper.
Migration is disabled for now.

Tested with rust-vmm vhost-device-console:
- https://github.com/rust-vmm/vhost-device/tree/main/vhost-device-console

Signed-off-by: Timos Ampelikiotis <[email protected]>

---

Invocation of rust-vmm device:

    RUST_LOG=trace cargo run --bin vhost-device-console \
                                --socket-path /tmp/console.sock \
                                --console-path <PATH_TO_CONSOLE_FILE>

Invocation of QEMU:

    qemu-system-x86_64  \
        -m 4096 \
        -numa node,memdev=mem \
        -object memory-backend-file,id=mem,size=4G,mem-path=/dev/shm,share=on \
        -chardev socket,id=char1,path=/tmp/console.sock \
        -device vhost-user-console-pci,chardev=char1,id=console \
        ...


Acknowledgements:
- This device was developed in the context of AGL (Automotive Grade Linux)
  SDV-EG (Software Defined Vehicles - Expert Group).
- The development was based on the vhost-user-snd QEMU device introduced by the
  following repository:
  https://github.com/epilys/qemu-virtio-snd/tree/vhost-sound

---
 hw/virtio/Kconfig                      |  5 ++
 hw/virtio/meson.build                  |  2 +
 hw/virtio/vhost-user-console-pci.c     | 72 ++++++++++++++++++++++++++
 hw/virtio/vhost-user-console.c         | 65 +++++++++++++++++++++++
 include/hw/virtio/vhost-user-console.h | 24 +++++++++
 5 files changed, 168 insertions(+)
 create mode 100644 hw/virtio/vhost-user-console-pci.c
 create mode 100644 hw/virtio/vhost-user-console.c
 create mode 100644 include/hw/virtio/vhost-user-console.h

diff --git a/hw/virtio/Kconfig b/hw/virtio/Kconfig
index 10f5c53ac0..9c9dd8d7e3 100644
--- a/hw/virtio/Kconfig
+++ b/hw/virtio/Kconfig
@@ -112,6 +112,11 @@ config VHOST_USER_GPIO
     default y
     depends on VIRTIO && VHOST_USER

+config VHOST_USER_CONSOLE
+    bool
+    default y
+    depends on VIRTIO && VHOST_USER
+
 config VHOST_VDPA_DEV
     bool
     default y
diff --git a/hw/virtio/meson.build b/hw/virtio/meson.build
index affd66887d..232178e217 100644
--- a/hw/virtio/meson.build
+++ b/hw/virtio/meson.build
@@ -61,6 +61,7 @@ system_virtio_ss.add(when: 'CONFIG_VIRTIO_MEM', if_true: 
files('virtio-mem.c'))
 system_virtio_ss.add(when: 'CONFIG_VIRTIO_NSM', if_true: files('virtio-nsm.c'))
 system_virtio_ss.add(when: 'CONFIG_VIRTIO_NSM', if_true: 
[files('cbor-helpers.c'), libcbor])
 system_virtio_ss.add(when: 'CONFIG_VHOST_USER_SCMI', if_true: 
files('vhost-user-scmi.c'))
+system_virtio_ss.add(when: 'CONFIG_VHOST_USER_CONSOLE', if_true: 
files('vhost-user-console.c'))

 virtio_pci_ss = ss.source_set()
 virtio_pci_ss.add(when: 'CONFIG_VHOST_VSOCK', if_true: 
files('vhost-vsock-pci.c'))
@@ -82,6 +83,7 @@ virtio_pci_ss.add(when: 'CONFIG_VIRTIO_SCSI', if_true: 
files('virtio-scsi-pci.c'
 virtio_pci_ss.add(when: 'CONFIG_VIRTIO_BLK', if_true: 
files('virtio-blk-pci.c'))
 virtio_pci_ss.add(when: 'CONFIG_VIRTIO_NET', if_true: 
files('virtio-net-pci.c'))
 virtio_pci_ss.add(when: 'CONFIG_VIRTIO_SERIAL', if_true: 
files('virtio-serial-pci.c'))
+virtio_pci_ss.add(when: ['CONFIG_VIRTIO_PCI', 'CONFIG_VHOST_USER_CONSOLE'], 
if_true: files('vhost-user-console-pci.c'))
 virtio_pci_ss.add(when: 'CONFIG_VIRTIO_PMEM', if_true: 
files('virtio-pmem-pci.c'))
 virtio_pci_ss.add(when: 'CONFIG_VIRTIO_IOMMU', if_true: 
files('virtio-iommu-pci.c'))
 virtio_pci_ss.add(when: 'CONFIG_VIRTIO_MEM', if_true: 
files('virtio-mem-pci.c'))
diff --git a/hw/virtio/vhost-user-console-pci.c 
b/hw/virtio/vhost-user-console-pci.c
new file mode 100644
index 0000000000..6c856a3424
--- /dev/null
+++ b/hw/virtio/vhost-user-console-pci.c
@@ -0,0 +1,72 @@
+/*
+ * Vhost-user console virtio device PCI glue
+ *
+ * Copyright (c) 2024-2025 Timos Ampelikiotis 
<[email protected]>
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+
+#include "qemu/osdep.h"
+#include "hw/qdev-properties.h"
+#include "hw/virtio/vhost-user-console.h"
+#include "hw/virtio/virtio-pci.h"
+
+struct VHostUserConsolePCI {
+    VirtIOPCIProxy parent_obj;
+    VHostUserConsole vdev;
+};
+
+typedef struct VHostUserConsolePCI VHostUserConsolePCI;
+
+#define TYPE_VHOST_USER_CONSOLE_PCI "vhost-user-console-pci-base"
+
+DECLARE_INSTANCE_CHECKER(VHostUserConsolePCI, VHOST_USER_CONSOLE_PCI,
+                         TYPE_VHOST_USER_CONSOLE_PCI)
+
+static void vhost_user_console_pci_realize(VirtIOPCIProxy *vpci_dev,
+                                           Error **errp)
+{
+    VHostUserConsolePCI *dev = VHOST_USER_CONSOLE_PCI(vpci_dev);
+    DeviceState *vdev = DEVICE(&dev->vdev);
+
+    vpci_dev->nvectors = 1;
+
+    qdev_realize(vdev, BUS(&vpci_dev->bus), errp);
+}
+
+static void vhost_user_console_pci_class_init(ObjectClass *klass,
+                                              const void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    VirtioPCIClass *k = VIRTIO_PCI_CLASS(klass);
+    PCIDeviceClass *pcidev_k = PCI_DEVICE_CLASS(klass);
+    k->realize = vhost_user_console_pci_realize;
+    set_bit(DEVICE_CATEGORY_INPUT, dc->categories);
+    pcidev_k->vendor_id = PCI_VENDOR_ID_REDHAT_QUMRANET;
+    pcidev_k->device_id = 0; /* Set by virtio-pci based on virtio id */
+    pcidev_k->revision = 0x00;
+    pcidev_k->class_id = PCI_CLASS_COMMUNICATION_OTHER;
+}
+
+static void vhost_user_console_pci_instance_init(Object *obj)
+{
+    VHostUserConsolePCI *dev = VHOST_USER_CONSOLE_PCI(obj);
+
+    virtio_instance_init_common(obj, &dev->vdev, sizeof(dev->vdev),
+                                TYPE_VHOST_USER_CONSOLE);
+}
+
+static const VirtioPCIDeviceTypeInfo vhost_user_console_pci_info = {
+    .base_name = TYPE_VHOST_USER_CONSOLE_PCI,
+    .non_transitional_name = "vhost-user-console-pci",
+    .instance_size = sizeof(VHostUserConsolePCI),
+    .instance_init = vhost_user_console_pci_instance_init,
+    .class_init = vhost_user_console_pci_class_init,
+};
+
+static void vhost_user_console_pci_register(void)
+{
+    virtio_pci_types_register(&vhost_user_console_pci_info);
+}
+
+type_init(vhost_user_console_pci_register);
diff --git a/hw/virtio/vhost-user-console.c b/hw/virtio/vhost-user-console.c
new file mode 100644
index 0000000000..d1eba5bc34
--- /dev/null
+++ b/hw/virtio/vhost-user-console.c
@@ -0,0 +1,65 @@
+/*
+ * Vhost-user console virtio device
+ *
+ * Copyright (c) 2024-2025 Timos Ampelikiotis 
<[email protected]>
+ *
+ * Simple wrapper of the generic vhost-user-device.
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+
+#include "qemu/osdep.h"
+#include "qapi/error.h"
+#include "hw/qdev-properties.h"
+#include "hw/virtio/virtio-bus.h"
+#include "hw/virtio/vhost-user-console.h"
+#include "standard-headers/linux/virtio_ids.h"
+#include "standard-headers/linux/virtio_console.h"
+
+static const VMStateDescription vu_console_vmstate = {
+    .name = "vhost-user-console",
+    .unmigratable = 1,
+};
+
+static const Property vconsole_properties[] = {
+    DEFINE_PROP_CHR("chardev", VHostUserBase, chardev),
+};
+
+static void vu_console_base_realize(DeviceState *dev, Error **errp)
+{
+    VHostUserBase *vub = VHOST_USER_BASE(dev);
+    VHostUserBaseClass *vubs = VHOST_USER_BASE_GET_CLASS(dev);
+
+    vub->virtio_id = VIRTIO_ID_CONSOLE;
+    vub->num_vqs = 4;
+    vub->config_size = sizeof(struct virtio_console_config);
+
+    vubs->parent_realize(dev, errp);
+}
+
+static void vu_console_class_init(ObjectClass *klass, const void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    VHostUserBaseClass *vubc = VHOST_USER_BASE_CLASS(klass);
+
+    dc->vmsd = &vu_console_vmstate;
+    device_class_set_props(dc, vconsole_properties);
+    device_class_set_parent_realize(dc, vu_console_base_realize,
+                                    &vubc->parent_realize);
+
+    set_bit(DEVICE_CATEGORY_INPUT, dc->categories);
+}
+
+static const TypeInfo vu_console_info = {
+    .name = TYPE_VHOST_USER_CONSOLE,
+    .parent = TYPE_VHOST_USER_BASE,
+    .instance_size = sizeof(VHostUserConsole),
+    .class_init = vu_console_class_init,
+};
+
+static void vu_console_register_types(void)
+{
+    type_register_static(&vu_console_info);
+}
+
+type_init(vu_console_register_types)
diff --git a/include/hw/virtio/vhost-user-console.h 
b/include/hw/virtio/vhost-user-console.h
new file mode 100644
index 0000000000..261d62b756
--- /dev/null
+++ b/include/hw/virtio/vhost-user-console.h
@@ -0,0 +1,24 @@
+/*
+ * Vhost-user console virtio device
+ *
+ * Copyright (c) 2024-2025 Timos Ampelikiotis 
<[email protected]>
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+
+#ifndef QEMU_VHOST_USER_CONSOLE_H
+#define QEMU_VHOST_USER_CONSOLE_H
+
+#include "hw/virtio/virtio.h"
+#include "hw/virtio/vhost.h"
+#include "hw/virtio/vhost-user.h"
+#include "hw/virtio/vhost-user-base.h"
+
+#define TYPE_VHOST_USER_CONSOLE "vhost-user-console"
+OBJECT_DECLARE_SIMPLE_TYPE(VHostUserConsole, VHOST_USER_CONSOLE)
+
+struct VHostUserConsole {
+    VHostUserBase parent;
+};
+
+#endif /* QEMU_VHOST_USER_CONSOLE_H */
--
2.43.0


Reply via email to