Kernel KVM virtualization development
 help / color / mirror / Atom feed
From: Mostafa Saleh <smostafa@google.com>
To: kvm@vger.kernel.org
Cc: will@kernel.org, julien.thierry.kdev@gmail.com, praan@google.com,
	 eric.auger@redhat.com, alex@shazbot.org,
	Mostafa Saleh <smostafa@google.com>
Subject: [PATCH kvmtool 7/9] vfio: Add basic support for vfio-platform
Date: Sat, 24 Oct 2026 16:19:00 +0000	[thread overview]
Message-ID: <20261024161902.2093581-8-smostafa@google.com> (raw)
In-Reply-To: <20261024161902.2093581-1-smostafa@google.com>

A VFIO device can be assigned to a guest with new cmdline
--vfio-platform ${dev} , where ${dev} is the name of the device under
/sys/bus/platform.

The device is expected to be bound to vfio-platform driver before
running the tool.

The MMIO regions of the device are mapped into the guest address
space reserved for VFIO, and described in a device tree node.
The node only carries reg, so no guest driver binds to it yet.
Interrupts and the rest of the node are added in the next patches.

Signed-off-by: Mostafa Saleh <smostafa@google.com>
---
 Makefile           |   1 +
 builtin-run.c      |   3 +
 include/kvm/vfio.h |   3 +
 vfio/core.c        |  22 +++++++
 vfio/platform.c    | 158 +++++++++++++++++++++++++++++++++++++++++++++
 5 files changed, 187 insertions(+)
 create mode 100644 vfio/platform.c

diff --git a/Makefile b/Makefile
index 1c0e7f5..8d1c0d9 100644
--- a/Makefile
+++ b/Makefile
@@ -65,6 +65,7 @@ OBJS	+= pci.o
 OBJS	+= term.o
 OBJS	+= vfio/core.o
 OBJS	+= vfio/pci.o
+OBJS	+= vfio/platform.o
 OBJS	+= virtio/blk.o
 OBJS	+= virtio/scsi.o
 OBJS	+= virtio/console.o
diff --git a/builtin-run.c b/builtin-run.c
index 81f255f..b09fc2e 100644
--- a/builtin-run.c
+++ b/builtin-run.c
@@ -261,6 +261,9 @@ static int loglevel_parser(const struct option *opt, const char *arg, int unset)
 	OPT_GROUP("VFIO options:"),					\
 	OPT_CALLBACK('\0', "vfio-pci", NULL, "[domain:]bus:dev.fn",	\
 		     "Assign a PCI device to the virtual machine",	\
+		     vfio_device_parser, kvm),				\
+	OPT_CALLBACK('\0', "vfio-platform", NULL, "device",		\
+		     "Assign a platform device to the virtual machine",	\
 		     vfio_device_parser, kvm),				\
 									\
 	OPT_GROUP("Debug options:"),					\
diff --git a/include/kvm/vfio.h b/include/kvm/vfio.h
index 0b2b105..f641292 100644
--- a/include/kvm/vfio.h
+++ b/include/kvm/vfio.h
@@ -24,6 +24,7 @@
 
 enum vfio_device_type {
 	VFIO_DEVICE_PCI,
+	VFIO_DEVICE_PLATFORM,
 };
 
 /* MSI/MSI-X capability enabled */
@@ -146,5 +147,7 @@ void vfio_irq_disable(struct kvm *kvm, struct vfio_device *vdev,
 		      unsigned int index, struct vfio_irq *irq);
 int vfio_pci_setup_device(struct kvm *kvm, struct vfio_device *device);
 void vfio_pci_teardown_device(struct kvm *kvm, struct vfio_device *vdev);
+int vfio_platform_setup_device(struct kvm *kvm, struct vfio_device *device);
+void vfio_platform_teardown_device(struct kvm *kvm, struct vfio_device *vdev);
 
 #endif /* KVM__VFIO_H */
diff --git a/vfio/core.c b/vfio/core.c
index aa124d2..6823a95 100644
--- a/vfio/core.c
+++ b/vfio/core.c
@@ -41,6 +41,19 @@ static int vfio_device_pci_parser(const struct option *opt, char *arg,
 	return 0;
 }
 
+/* @arg is the name of the device under /sys/bus/platform/devices */
+static int vfio_device_platform_parser(const struct option *opt, char *arg,
+				       struct vfio_device_params *dev)
+{
+	dev->type = VFIO_DEVICE_PLATFORM;
+	dev->bus = "platform";
+	dev->name = strdup(arg);
+	if (!dev->name)
+		return -ENOMEM;
+
+	return 0;
+}
+
 int vfio_device_parser(const struct option *opt, const char *arg, int unset)
 {
 	int ret = -EINVAL;
@@ -72,6 +85,8 @@ int vfio_device_parser(const struct option *opt, const char *arg, int unset)
 
 	if (!strcmp(opt->long_name, "vfio-pci"))
 		ret = vfio_device_pci_parser(opt, cur, dev);
+	else if (!strcmp(opt->long_name, "vfio-platform"))
+		ret = vfio_device_platform_parser(opt, cur, dev);
 	else
 		ret = -EINVAL;
 
@@ -433,6 +448,10 @@ static int vfio_configure_device(struct kvm *kvm, struct vfio_device *vdev)
 		BUG_ON(!(vdev->info.flags & VFIO_DEVICE_FLAGS_PCI));
 		ret = vfio_pci_setup_device(kvm, vdev);
 		break;
+	case VFIO_DEVICE_PLATFORM:
+		BUG_ON(!(vdev->info.flags & VFIO_DEVICE_FLAGS_PLATFORM));
+		ret = vfio_platform_setup_device(kvm, vdev);
+		break;
 	default:
 		BUG_ON(1);
 		ret = -EINVAL;
@@ -703,6 +722,9 @@ static void vfio_device_exit(struct kvm *kvm, struct vfio_device *vdev)
 	case VFIO_DEVICE_PCI:
 		vfio_pci_teardown_device(kvm, vdev);
 		break;
+	case VFIO_DEVICE_PLATFORM:
+		vfio_platform_teardown_device(kvm, vdev);
+		break;
 	default:
 		vfio_dev_warn(vdev, "no teardown function for device");
 	}
diff --git a/vfio/platform.c b/vfio/platform.c
new file mode 100644
index 0000000..c5b447f
--- /dev/null
+++ b/vfio/platform.c
@@ -0,0 +1,158 @@
+#include "linux/sizes.h"
+
+#include "kvm/kvm.h"
+#include "kvm/vfio.h"
+
+#include <errno.h>
+
+#include <sys/ioctl.h>
+#include <stdlib.h>
+#include "kvm/fdt.h"
+
+static u64 vfio_mmio_io_space_next = KVM_VFIO_MMIO_AREA;
+
+static int vfio_mmio_alloc_io_space(u64 size, u64 *addr)
+{
+	u64 align = max_t(u64, PAGE_SIZE, MAX_PAGE_SIZE);
+	u64 end = KVM_VFIO_MMIO_AREA + KVM_VFIO_MMIO_SIZE;
+
+	vfio_mmio_io_space_next = ALIGN(vfio_mmio_io_space_next, align);
+	size = ALIGN(size, align);
+	if (size > end - vfio_mmio_io_space_next)
+		return -ENOSPC;
+
+	*addr = vfio_mmio_io_space_next;
+	vfio_mmio_io_space_next += size;
+
+	return 0;
+}
+
+#ifdef CONFIG_HAS_LIBFDT
+static void generate_mmio_fdt_node(void *fdt,
+				   struct device_header *dev_hdr,
+				   fdt_irq_fn generate_irq_prop)
+{
+	struct vfio_device *vdev = container_of(dev_hdr,
+						struct vfio_device, dev_hdr);
+	unsigned int i, num_regions = vdev->info.num_regions;
+	char node_name[PATH_MAX];
+	u64 *reg_prop;
+
+	reg_prop = calloc(num_regions, 2 * sizeof(*reg_prop));
+	if (!reg_prop)
+		die("Failed to allocate the reg property");
+
+	for (i = 0; i < num_regions; i++) {
+		reg_prop[2 * i] = cpu_to_fdt64(vdev->regions[i].guest_phys_addr);
+		reg_prop[2 * i + 1] = cpu_to_fdt64(vdev->regions[i].info.size);
+	}
+
+	snprintf(node_name, sizeof(node_name), "%s@%llx",
+		 vdev->params->name, vdev->regions[0].guest_phys_addr);
+
+	_FDT(fdt_begin_node(fdt, node_name));
+	_FDT(fdt_property(fdt, "reg", reg_prop,
+			  2 * sizeof(*reg_prop) * num_regions));
+	_FDT(fdt_end_node(fdt));
+
+	free(reg_prop);
+}
+#endif /* CONFIG_HAS_LIBFDT */
+
+static void vfio_platform_unmap_regions(struct kvm *kvm,
+					struct vfio_device *vdev,
+					unsigned int nr_regions)
+{
+	unsigned int i;
+
+	for (i = 0; i < nr_regions; i++)
+		vfio_unmap_region(kvm, &vdev->regions[i]);
+}
+
+static int vfio_platform_configure_regs(struct kvm *kvm,
+					struct vfio_device *vdev)
+{
+	int ret = 0;
+	unsigned int i = 0;
+	struct vfio_region *region;
+	struct vfio_region_info *info;
+
+	if (!vdev->info.num_regions)
+		return -ENODEV;
+
+	for (i = 0; i < vdev->info.num_regions; i++) {
+		info = &vdev->regions[i].info;
+		*info = (struct vfio_region_info) {
+			.argsz = sizeof(*info),
+			.index = i,
+		};
+
+		if (ioctl(vdev->fd, VFIO_DEVICE_GET_REGION_INFO, info)) {
+			ret = -errno;
+			vfio_dev_err(vdev, "failed to get info for region[%u]", i);
+			goto err_unmap;
+		}
+
+		if (!info->size) {
+			ret = -EINVAL;
+			goto err_unmap;
+		}
+
+		region = &vdev->regions[i];
+		region->vdev = vdev;
+		region->is_ioport = false;
+		ret = vfio_mmio_alloc_io_space(region->info.size,
+					       &region->guest_phys_addr);
+		if (ret) {
+			vfio_dev_err(vdev, "no guest address space left for region[%u] (0x%llx bytes)",
+				     i, info->size);
+			goto err_unmap;
+		}
+
+		ret = vfio_map_region(kvm, vdev, region);
+		if (ret) {
+			vfio_dev_err(vdev, "failed to map region[%u] at 0x%llx", i, info->offset);
+			goto err_unmap;
+		}
+	}
+
+	return 0;
+
+err_unmap:
+	vfio_platform_unmap_regions(kvm, vdev, i);
+	return ret;
+}
+
+int vfio_platform_setup_device(struct kvm *kvm, struct vfio_device *vdev)
+{
+	int ret;
+
+	ret = vfio_platform_configure_regs(kvm, vdev);
+	if (ret) {
+		vfio_dev_err(vdev, "failed to configure regs");
+		return ret;
+	}
+
+	vdev->dev_hdr = (struct device_header) {
+		.bus_type	= DEVICE_BUS_MMIO,
+#ifdef CONFIG_HAS_LIBFDT
+		.data		= generate_mmio_fdt_node,
+#endif
+	};
+
+	ret = device__register(&vdev->dev_hdr);
+	if (ret) {
+		vfio_dev_err(vdev, "failed to register VFIO device");
+		vfio_platform_unmap_regions(kvm, vdev, vdev->info.num_regions);
+		return ret;
+	}
+
+	return 0;
+}
+
+void vfio_platform_teardown_device(struct kvm *kvm, struct vfio_device *vdev)
+{
+	vfio_platform_unmap_regions(kvm, vdev, vdev->info.num_regions);
+
+	device__unregister(&vdev->dev_hdr);
+}
-- 
2.56.0.307.g5fe7bd680c-goog


  parent reply	other threads:[~2026-10-24 16:20 UTC|newest]

Thread overview: 10+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-10-24 16:18 [PATCH kvmtool 0/9] vfio: Add support for platform devices Mostafa Saleh
2026-10-24 16:18 ` [PATCH kvmtool 1/9] vfio: Fix fd leak in vfio_group_get_for_dev() Mostafa Saleh
2026-10-24 16:18 ` [PATCH kvmtool 2/9] vfio: Factor out wired IRQ setup and teardown Mostafa Saleh
2026-10-24 16:18 ` [PATCH kvmtool 3/9] vfio: Support edge-triggered wired IRQs Mostafa Saleh
2026-10-24 16:18 ` [PATCH kvmtool 4/9] fdt: Allow fdt_irq_fn to generate multiple interrupts Mostafa Saleh
2026-10-24 16:18 ` [PATCH kvmtool 5/9] fdt: Add helper to copy an FDT node Mostafa Saleh
2026-10-24 16:18 ` [PATCH kvmtool 6/9] vfio: Reserve guest address space for VFIO platform Mostafa Saleh
2026-10-24 16:19 ` Mostafa Saleh [this message]
2026-10-24 16:19 ` [PATCH kvmtool 8/9] vfio: platform: Add interrupts support Mostafa Saleh
2026-10-24 16:19 ` [PATCH kvmtool 9/9] vfio: platform: Take the guest node from a device tree template Mostafa Saleh

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20261024161902.2093581-8-smostafa@google.com \
    --to=smostafa@google.com \
    --cc=alex@shazbot.org \
    --cc=eric.auger@redhat.com \
    --cc=julien.thierry.kdev@gmail.com \
    --cc=kvm@vger.kernel.org \
    --cc=praan@google.com \
    --cc=will@kernel.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox