[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-Id: <97ae7b7bea8a22108aaebdfd9330de93ecc91333.1753865268.git.viresh.kumar@linaro.org>
Date: Wed, 30 Jul 2025 14:59:33 +0530
From: Viresh Kumar <viresh.kumar@...aro.org>
To: linux-kernel@...r.kernel.org,
"Michael S. Tsirkin" <mst@...hat.com>,
Jason Wang <jasowang@...hat.com>,
Xuan Zhuo <xuanzhuo@...ux.alibaba.com>,
Eugenio Pérez <eperezma@...hat.com>,
Viresh Kumar <viresh.kumar@...aro.org>
Cc: Arnd Bergmann <arnd@...nel.org>,
Vincent Guittot <vincent.guittot@...aro.org>,
Alex Bennée <alex.bennee@...aro.org>,
Bill Mills <bill.mills@...aro.org>,
Rob Herring <robh@...nel.org>,
Saravana Kannan <saravanak@...gle.com>,
devicetree@...r.kernel.org,
virtualization@...ts.linux.dev,
Sudeep Holla <sudeep.holla@....com>,
Bertrand Marquis <bertrand.marquis@....com>,
"Edgar E . Iglesias" <edgar.iglesias@....com>,
Arnaud Pouliquen <arnaud.pouliquen@...s.st.com>,
Krzysztof Kozlowski <krzk+dt@...nel.org>,
Conor Dooley <conor+dt@...nel.org>
Subject: [RFC PATCH 4/6] virtio-msg: Add optional userspace interface for message I/O
Add support for an optional userspace interface to the virtio-msg
transport via a per-bus miscdevice. When enabled by a bus
implementation, this interface allows userspace to send and receive
virtio messages through a character device node.
A separate device node is created for each bus that registers for
userspace access, e.g., /dev/virtio-msg-N. This enables backend-side
components or test tools to interact with the transport layer directly
from userspace.
Bus implementations that do not require userspace interaction can omit
this interface entirely.
Signed-off-by: Viresh Kumar <viresh.kumar@...aro.org>
---
drivers/virtio/Kconfig | 8 ++
drivers/virtio/Makefile | 4 +-
drivers/virtio/virtio_msg_internal.h | 32 ++++++
drivers/virtio/virtio_msg_user.c | 140 +++++++++++++++++++++++++++
4 files changed, 183 insertions(+), 1 deletion(-)
create mode 100644 drivers/virtio/virtio_msg_user.c
diff --git a/drivers/virtio/Kconfig b/drivers/virtio/Kconfig
index 690ac98850b6..a86025c9e008 100644
--- a/drivers/virtio/Kconfig
+++ b/drivers/virtio/Kconfig
@@ -178,6 +178,14 @@ config VIRTIO_MSG
This enables support for Virtio message transport. This option is
selected by any driver which implements the virtio message bus.
+config VIRTIO_MSG_USER
+ tristate "Userspace interface for virtio message transport"
+ depends on VIRTIO_MSG
+ help
+ This enables userspace interface for Virtio message transport. This
+ can be used to read / write messages over virtio-msg transport from
+ userspace.
+
config VIRTIO_DMA_SHARED_BUFFER
tristate
depends on DMA_SHARED_BUFFER
diff --git a/drivers/virtio/Makefile b/drivers/virtio/Makefile
index 3eff8ca72446..5b664c5f5f25 100644
--- a/drivers/virtio/Makefile
+++ b/drivers/virtio/Makefile
@@ -4,7 +4,9 @@ obj-$(CONFIG_VIRTIO_ANCHOR) += virtio_anchor.o
obj-$(CONFIG_VIRTIO_PCI_LIB) += virtio_pci_modern_dev.o
obj-$(CONFIG_VIRTIO_PCI_LIB_LEGACY) += virtio_pci_legacy_dev.o
obj-$(CONFIG_VIRTIO_MMIO) += virtio_mmio.o
-obj-$(CONFIG_VIRTIO_MSG) += virtio_msg.o
+virtio_msg_transport-y := virtio_msg.o
+virtio_msg_transport-$(CONFIG_VIRTIO_MSG_USER) += virtio_msg_user.o
+obj-$(CONFIG_VIRTIO_MSG) += virtio_msg_transport.o
obj-$(CONFIG_VIRTIO_PCI) += virtio_pci.o
virtio_pci-y := virtio_pci_modern.o virtio_pci_common.o
virtio_pci-$(CONFIG_VIRTIO_PCI_LEGACY) += virtio_pci_legacy.o
diff --git a/drivers/virtio/virtio_msg_internal.h b/drivers/virtio/virtio_msg_internal.h
index b7c2cb44b67b..0d13d73507eb 100644
--- a/drivers/virtio/virtio_msg_internal.h
+++ b/drivers/virtio/virtio_msg_internal.h
@@ -9,6 +9,8 @@
#ifndef _DRIVERS_VIRTIO_MSG_INTERNAL_H
#define _DRIVERS_VIRTIO_MSG_INTERNAL_H
+#include <linux/completion.h>
+#include <linux/miscdevice.h>
#include <linux/virtio.h>
#include <uapi/linux/virtio_msg.h>
@@ -53,4 +55,34 @@ void virtio_msg_unregister(struct virtio_msg_device *vmdev);
void virtio_msg_prepare(struct virtio_msg *vmsg, u8 msg_id, u16 payload_size);
int virtio_msg_event(struct virtio_msg_device *vmdev, struct virtio_msg *vmsg);
+/* Virtio msg userspace interface */
+struct virtio_msg_user_device;
+
+struct virtio_msg_user_ops {
+ int (*handle)(struct virtio_msg_user_device *vmudev, struct virtio_msg *vmsg);
+};
+
+/* Host side device using virtio message */
+struct virtio_msg_user_device {
+ struct virtio_msg_user_ops *ops;
+ struct miscdevice misc;
+ struct completion r_completion;
+ struct completion w_completion;
+ struct virtio_msg *vmsg;
+ struct device *parent;
+ char name[15];
+};
+
+#if IS_REACHABLE(CONFIG_VIRTIO_MSG_USER)
+int virtio_msg_user_register(struct virtio_msg_user_device *vmudev);
+void virtio_msg_user_unregister(struct virtio_msg_user_device *vmudev);
+#else
+static inline int virtio_msg_user_register(struct virtio_msg_user_device *vmudev)
+{
+ return -EOPNOTSUPP;
+}
+
+static inline void virtio_msg_user_unregister(struct virtio_msg_user_device *vmudev) {}
+#endif /* CONFIG_VIRTIO_MSG_USER */
+
#endif /* _DRIVERS_VIRTIO_MSG_INTERNAL_H */
diff --git a/drivers/virtio/virtio_msg_user.c b/drivers/virtio/virtio_msg_user.c
new file mode 100644
index 000000000000..cf7286b3a311
--- /dev/null
+++ b/drivers/virtio/virtio_msg_user.c
@@ -0,0 +1,140 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Virtio message transport user API.
+ *
+ * Copyright (C) 2025 Google LLC and Linaro.
+ * Viresh Kumar <viresh.kumar@...aro.org>
+ */
+
+#define pr_fmt(fmt) "virtio-msg: " fmt
+
+#include <linux/err.h>
+#include <linux/fs.h>
+#include <linux/miscdevice.h>
+#include <linux/slab.h>
+#include <linux/uaccess.h>
+
+#include "virtio_msg_internal.h"
+
+#define to_virtio_msg_user_device(_misc) \
+ container_of(_misc, struct virtio_msg_user_device, misc)
+
+static ssize_t vmsg_miscdev_read(struct file *file, char __user *buf,
+ size_t count, loff_t *pos)
+{
+ struct miscdevice *misc = file->private_data;
+ struct virtio_msg_user_device *vmudev = to_virtio_msg_user_device(misc);
+ struct device *dev = vmudev->parent;
+ int ret;
+
+ if (count < VIRTIO_MSG_MIN_SIZE) {
+ dev_err(dev, "Trying to read message of incorrect size: %zu\n",
+ count);
+ return 0;
+ }
+
+ /* Wait for the message */
+ ret = wait_for_completion_interruptible(&vmudev->r_completion);
+ if (ret < 0) {
+ dev_err(dev, "Interrupted while waiting for response: %d\n", ret);
+ return 0;
+ }
+
+ WARN_ON(!vmudev->vmsg);
+
+ /* The "vmsg" pointer is filled by the bus driver before waking up */
+ if (copy_to_user(buf, vmudev->vmsg, count) != 0)
+ return 0;
+
+ vmudev->vmsg = NULL;
+
+ return count;
+}
+
+static ssize_t vmsg_miscdev_write(struct file *file, const char __user *buf,
+ size_t count, loff_t *pos)
+{
+ struct miscdevice *misc = file->private_data;
+ struct virtio_msg_user_device *vmudev = to_virtio_msg_user_device(misc);
+ struct virtio_msg *vmsg __free(kfree) = NULL;
+
+ if (count < VIRTIO_MSG_MIN_SIZE) {
+ dev_err(vmudev->parent, "Trying to write message of incorrect size: %zu\n",
+ count);
+ return 0;
+ }
+
+ vmsg = kzalloc(count, GFP_KERNEL);
+ if (!vmsg)
+ return 0;
+
+ if (copy_from_user(vmsg, buf, count) != 0)
+ return 0;
+
+ vmudev->ops->handle(vmudev, vmsg);
+
+ /* Wake up the handler only for responses */
+ if (vmsg->type & VIRTIO_MSG_TYPE_RESPONSE)
+ complete(&vmudev->w_completion);
+
+ return count;
+}
+
+static const struct file_operations vmsg_miscdev_fops = {
+ .owner = THIS_MODULE,
+ .read = vmsg_miscdev_read,
+ .write = vmsg_miscdev_write,
+};
+
+/**
+ * virtio_msg_user_register - Register a user-space accessible virtio message device
+ * @vmudev: Pointer to the virtio message user device
+ *
+ * Initializes and registers a user-accessible virtio message device as a `misc`
+ * character device. Upon successful registration, the device appears in
+ * userspace as `/dev/virtio-msg-N` where `N` is a unique identifier assigned at
+ * runtime.
+ *
+ * The resulting device node allows user-space interaction with the virtio
+ * message transport.
+ *
+ * Return: 0 on success, or a negative error code on failure.
+ */
+int virtio_msg_user_register(struct virtio_msg_user_device *vmudev)
+{
+ static u8 vmsg_user_device_count;
+ int ret;
+
+ if (!vmudev || !vmudev->ops)
+ return -EINVAL;
+
+ init_completion(&vmudev->r_completion);
+ init_completion(&vmudev->w_completion);
+
+ vmudev->misc.parent = vmudev->parent;
+ vmudev->misc.minor = MISC_DYNAMIC_MINOR;
+ vmudev->misc.fops = &vmsg_miscdev_fops;
+ vmudev->misc.name = vmudev->name;
+ sprintf(vmudev->name, "virtio-msg-%d", vmsg_user_device_count);
+
+ ret = misc_register(&vmudev->misc);
+ if (ret)
+ return ret;
+
+ vmsg_user_device_count++;
+ return 0;
+}
+EXPORT_SYMBOL_GPL(virtio_msg_user_register);
+
+/**
+ * virtio_msg_user_unregister - Unregister a user-space virtio message device
+ * @vmudev: Pointer to the virtio message user device
+ *
+ * Unregisters a previously registered virtio message device from the misc
+ * subsystem. This removes its user-space interface (e.g., /dev/virtio-msg-N).
+ */
+void virtio_msg_user_unregister(struct virtio_msg_user_device *vmudev)
+{
+ misc_deregister(&vmudev->misc);
+}
+EXPORT_SYMBOL_GPL(virtio_msg_user_unregister);
--
2.31.1.272.g89b43f80a514
Powered by blists - more mailing lists