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,
+ ®ion->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
next prev 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