* [PATCH kvmtool 0/9] vfio: Add support for platform devices
@ 2026-10-24 16:18 Mostafa Saleh
2026-10-24 16:18 ` [PATCH kvmtool 1/9] vfio: Fix fd leak in vfio_group_get_for_dev() Mostafa Saleh
` (8 more replies)
0 siblings, 9 replies; 10+ messages in thread
From: Mostafa Saleh @ 2026-10-24 16:18 UTC (permalink / raw)
To: kvm; +Cc: will, julien.thierry.kdev, praan, eric.auger, alex, Mostafa Saleh
This patch series extend VFIO support to platform devices by using
VFIO-platform.
One of the main difference is how the guest discover the device, which
is done through the device tree.
kvmtool can only describe:
- regs
- interrupts
However, the guest still needs a compatible string and other per device
bindings.
To avoid having any hardcoded DT nodes in the source code, kvmtool will
accept a dtb argument with each assigned device that will be copied to
the guest node.
Patches
=======
1-4: Fixes, code refactoring and improving interrupt support.
5: DT common function.
6-8: VFIO-platform support.
9: Custom device tree support.
Patch 2 is better viewed with --color-moved
Testing
=======
Tested on Lenovo Mini-x Gen 10 (Snapdragon-X) by assigning 2 devices,
QCE and BAM as follows:
echo 1dfa000.crypto > /sys/bus/platform/drivers/qcrypto/unbind
echo 1dc4000.dma-controller > /sys/bus/platform/drivers/bam-dma-engine/unbind
echo "vfio-platform" > /sys/bus/platform/devices/1dfa000.crypto/driver_override
echo "vfio-platform" > /sys/bus/platform/devices/1dc4000.dma-controller/driver_override
echo 1dc4000.dma-controller > /sys/bus/platform/drivers/vfio-platform/bind
echo 1dfa000.crypto > /sys/bus/platform/drivers/vfio-platform/bind
./lkvm-static run --irqchip gicv3 -k Image -p "nokaslr" -d rootfs.ext2 --force-pci -c 1 --debug --vfio-
platform 1dc4000.dma-controller,purwa-cryptobam.dtb --vfio-platform 1dfa000.crypto,purwa-qce.dtb
There are some fixes on the list that are needed to be able to unbind
the bam device [1]
Mostafa Saleh (9):
vfio: Fix fd leak in vfio_group_get_for_dev()
vfio: Factor out wired IRQ setup and teardown
vfio: Support edge-triggered wired IRQs
fdt: Allow fdt_irq_fn to generate multiple interrupts
fdt: Add helper to copy an FDT node
vfio: Reserve guest address space for VFIO platform
vfio: Add basic support for vfio-platform
vfio: platform: Add interrupts support
vfio: platform: Take the guest node from a device tree template
Makefile | 1 +
arm64/fdt.c | 36 ++--
arm64/include/kvm/kvm-arch.h | 10 +-
builtin-run.c | 3 +
hw/cfi_flash.c | 4 +-
hw/rtc.c | 4 +-
hw/serial.c | 3 +-
include/kvm/fdt.h | 32 +++-
include/kvm/vfio.h | 41 ++++-
mips/include/kvm/kvm-arch.h | 2 +
powerpc/include/kvm/kvm-arch.h | 2 +
riscv/fdt.c | 2 +-
riscv/include/kvm/kvm-arch.h | 7 +-
riscv/irq.c | 27 ++-
vfio/core.c | 152 +++++++++++++++-
vfio/pci.c | 111 +-----------
vfio/platform.c | 317 +++++++++++++++++++++++++++++++++
virtio/mmio.c | 10 +-
x86/include/kvm/kvm-arch.h | 2 +
19 files changed, 619 insertions(+), 147 deletions(-)
create mode 100644 vfio/platform.c
--
2.56.0.307.g5fe7bd680c-goog
^ permalink raw reply [flat|nested] 10+ messages in thread
* [PATCH kvmtool 1/9] vfio: Fix fd leak in vfio_group_get_for_dev()
2026-10-24 16:18 [PATCH kvmtool 0/9] vfio: Add support for platform devices Mostafa Saleh
@ 2026-10-24 16:18 ` Mostafa Saleh
2026-10-24 16:18 ` [PATCH kvmtool 2/9] vfio: Factor out wired IRQ setup and teardown Mostafa Saleh
` (7 subsequent siblings)
8 siblings, 0 replies; 10+ messages in thread
From: Mostafa Saleh @ 2026-10-24 16:18 UTC (permalink / raw)
To: kvm; +Cc: will, julien.thierry.kdev, praan, eric.auger, alex, Mostafa Saleh
The fd opened to read the iommu_group link of the device is closed
on every path except the one that finds the group already open, so
every device after the first one in a group leaked an fd.
Return through the goto on that path too.
Signed-off-by: Mostafa Saleh <smostafa@google.com>
---
vfio/core.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/vfio/core.c b/vfio/core.c
index fbe0098..e0c56ab 100644
--- a/vfio/core.c
+++ b/vfio/core.c
@@ -544,7 +544,7 @@ vfio_group_get_for_dev(struct kvm *kvm, struct vfio_device *vdev)
list_for_each_entry(group, &vfio_groups, list) {
if (group->id == group_id) {
group->refs++;
- return group;
+ goto out_close;
}
}
--
2.56.0.307.g5fe7bd680c-goog
^ permalink raw reply related [flat|nested] 10+ messages in thread
* [PATCH kvmtool 2/9] vfio: Factor out wired IRQ setup and teardown
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 ` Mostafa Saleh
2026-10-24 16:18 ` [PATCH kvmtool 3/9] vfio: Support edge-triggered wired IRQs Mostafa Saleh
` (6 subsequent siblings)
8 siblings, 0 replies; 10+ messages in thread
From: Mostafa Saleh @ 2026-10-24 16:18 UTC (permalink / raw)
To: kvm; +Cc: will, julien.thierry.kdev, praan, eric.auger, alex, Mostafa Saleh
Factor the wired IRQ eventfd and KVM irqfd setup and teardown out of
vfio_pci_enable_intx() and vfio_pci_disable_intx() into
vfio_irq_enable() and vfio_irq_disable() in vfio/core.c, and move
union vfio_irq_eventfd to vfio.h so both PCI INTx and VFIO platform
devices can share them.
The is a mechanical code move, no functional change.
Signed-off-by: Mostafa Saleh <smostafa@google.com>
---
include/kvm/vfio.h | 27 +++++++++--
vfio/core.c | 107 +++++++++++++++++++++++++++++++++++++++++++
vfio/pci.c | 110 +++------------------------------------------
3 files changed, 137 insertions(+), 107 deletions(-)
diff --git a/include/kvm/vfio.h b/include/kvm/vfio.h
index ac7b622..9a5783e 100644
--- a/include/kvm/vfio.h
+++ b/include/kvm/vfio.h
@@ -6,6 +6,7 @@
#include "kvm/pci.h"
#include <linux/vfio.h>
+#include <string.h>
#define vfio_dev_err(vdev, fmt, ...) \
pr_err("%s: " fmt, (vdev)->params->name, ##__VA_ARGS__)
@@ -70,13 +71,17 @@ struct vfio_pci_msi_common {
#define VFIO_PCI_IRQ_MODE_MSI (1 << 1)
#define VFIO_PCI_IRQ_MODE_MSIX (1 << 2)
+struct vfio_irq {
+ int gsi;
+ int trigger_fd;
+ int unmask_fd;
+};
+
struct vfio_pci_device {
struct pci_device_header hdr;
unsigned long irq_modes;
- int intx_fd;
- int unmask_fd;
- unsigned int intx_gsi;
+ struct vfio_irq intx;
struct vfio_pci_msi_common msi;
struct vfio_pci_msi_common msix;
struct vfio_pci_msix_table msix_table;
@@ -119,10 +124,26 @@ struct vfio_group {
struct list_head list;
};
+/* Wrapper around UAPI vfio_irq_set */
+union vfio_irq_eventfd {
+ struct vfio_irq_set irq;
+ u8 buffer[sizeof(struct vfio_irq_set) + sizeof(int)];
+};
+
+static inline void set_vfio_irq_eventd_payload(union vfio_irq_eventfd *evfd,
+ int fd)
+{
+ memcpy(&evfd->irq.data, &fd, sizeof(fd));
+}
+
int vfio_device_parser(const struct option *opt, const char *arg, int unset);
int vfio_map_region(struct kvm *kvm, struct vfio_device *vdev,
struct vfio_region *region);
void vfio_unmap_region(struct kvm *kvm, struct vfio_region *region);
+int vfio_irq_enable(struct kvm *kvm, struct vfio_device *vdev,
+ unsigned int index, struct vfio_irq *irq);
+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);
diff --git a/vfio/core.c b/vfio/core.c
index e0c56ab..24d3f2d 100644
--- a/vfio/core.c
+++ b/vfio/core.c
@@ -1,8 +1,10 @@
+#include "kvm/irq.h"
#include "kvm/kvm.h"
#include "kvm/vfio.h"
#include "kvm/ioport.h"
#include <linux/list.h>
+#include <sys/eventfd.h>
#include <libgen.h>
#define VFIO_DEV_DIR "/dev/vfio"
@@ -282,6 +284,111 @@ void vfio_unmap_region(struct kvm *kvm, struct vfio_region *region)
}
}
+void vfio_irq_disable(struct kvm *kvm, struct vfio_device *vdev,
+ unsigned int index, struct vfio_irq *irq)
+{
+ int gsi = irq->gsi;
+ struct vfio_irq_set irq_set = {
+ .argsz = sizeof(irq_set),
+ .flags = VFIO_IRQ_SET_DATA_NONE | VFIO_IRQ_SET_ACTION_TRIGGER,
+ .index = index,
+ };
+
+ if (irq->trigger_fd == -1)
+ return;
+
+ ioctl(vdev->fd, VFIO_DEVICE_SET_IRQS, &irq_set);
+ irq__del_irqfd(kvm, gsi, irq->trigger_fd);
+
+ close(irq->trigger_fd);
+ close(irq->unmask_fd);
+ irq->trigger_fd = -1;
+}
+
+int vfio_irq_enable(struct kvm *kvm, struct vfio_device *vdev,
+ unsigned int index, struct vfio_irq *irq)
+{
+ int ret;
+ int trigger_fd, unmask_fd;
+ union vfio_irq_eventfd trigger;
+ union vfio_irq_eventfd unmask;
+ int gsi = irq->gsi;
+
+ if (irq->trigger_fd != -1)
+ return 0;
+
+ /*
+ * PCI IRQ is level-triggered, so we use two eventfds. trigger_fd
+ * signals an interrupt from host to guest, and unmask_fd signals the
+ * deassertion of the line from guest to host.
+ */
+ trigger_fd = eventfd(0, 0);
+ if (trigger_fd < 0) {
+ vfio_dev_err(vdev, "failed to create trigger eventfd");
+ return trigger_fd;
+ }
+
+ unmask_fd = eventfd(0, 0);
+ if (unmask_fd < 0) {
+ vfio_dev_err(vdev, "failed to create unmask eventfd");
+ close(trigger_fd);
+ return unmask_fd;
+ }
+
+ ret = irq__add_irqfd(kvm, gsi, trigger_fd, unmask_fd);
+ if (ret)
+ goto err_close;
+
+ trigger.irq = (struct vfio_irq_set) {
+ .argsz = sizeof(trigger),
+ .flags = VFIO_IRQ_SET_DATA_EVENTFD | VFIO_IRQ_SET_ACTION_TRIGGER,
+ .index = index,
+ .start = 0,
+ .count = 1,
+ };
+ set_vfio_irq_eventd_payload(&trigger, trigger_fd);
+
+ ret = ioctl(vdev->fd, VFIO_DEVICE_SET_IRQS, &trigger);
+ if (ret < 0) {
+ vfio_dev_err(vdev, "failed to setup VFIO IRQ");
+ goto err_delete_line;
+ }
+
+ unmask.irq = (struct vfio_irq_set) {
+ .argsz = sizeof(unmask),
+ .flags = VFIO_IRQ_SET_DATA_EVENTFD | VFIO_IRQ_SET_ACTION_UNMASK,
+ .index = index,
+ .start = 0,
+ .count = 1,
+ };
+ set_vfio_irq_eventd_payload(&unmask, unmask_fd);
+
+ ret = ioctl(vdev->fd, VFIO_DEVICE_SET_IRQS, &unmask);
+ if (ret < 0) {
+ vfio_dev_err(vdev, "failed to setup unmask IRQ");
+ goto err_remove_event;
+ }
+
+ irq->trigger_fd = trigger_fd;
+ irq->unmask_fd = unmask_fd;
+
+ return 0;
+
+err_remove_event:
+ /* Remove trigger event */
+ trigger.irq.flags = VFIO_IRQ_SET_DATA_NONE | VFIO_IRQ_SET_ACTION_TRIGGER;
+ trigger.irq.count = 0;
+ ioctl(vdev->fd, VFIO_DEVICE_SET_IRQS, &trigger);
+
+err_delete_line:
+ irq__del_irqfd(kvm, gsi, trigger_fd);
+
+err_close:
+ close(trigger_fd);
+ close(unmask_fd);
+ return ret;
+}
+
static int vfio_configure_device(struct kvm *kvm, struct vfio_device *vdev)
{
int ret;
diff --git a/vfio/pci.c b/vfio/pci.c
index 0bcd60e..fb98435 100644
--- a/vfio/pci.c
+++ b/vfio/pci.c
@@ -17,17 +17,6 @@
#define PCI_CAP_EXP_RC_ENDPOINT_SIZEOF_V1 12
#endif
-/* Wrapper around UAPI vfio_irq_set */
-union vfio_irq_eventfd {
- struct vfio_irq_set irq;
- u8 buffer[sizeof(struct vfio_irq_set) + sizeof(int)];
-};
-
-static void set_vfio_irq_eventd_payload(union vfio_irq_eventfd *evfd, int fd)
-{
- memcpy(&evfd->irq.data, &fd, sizeof(fd));
-}
-
/*
* To support MSI and MSI-X with common code, track the host and guest states of
* the MSI/MSI-X capability, and of individual vectors.
@@ -1213,108 +1202,21 @@ static int vfio_pci_init_msis(struct kvm *kvm, struct vfio_device *vdev,
static void vfio_pci_disable_intx(struct kvm *kvm, struct vfio_device *vdev)
{
struct vfio_pci_device *pdev = &vdev->pci;
- int gsi = pdev->intx_gsi;
- struct vfio_irq_set irq_set = {
- .argsz = sizeof(irq_set),
- .flags = VFIO_IRQ_SET_DATA_NONE | VFIO_IRQ_SET_ACTION_TRIGGER,
- .index = VFIO_PCI_INTX_IRQ_INDEX,
- };
+ int gsi = pdev->intx.gsi;
- if (pdev->intx_fd == -1)
+ if (pdev->intx.trigger_fd == -1)
return;
pr_debug("user requested MSI, disabling INTx %d", gsi);
- ioctl(vdev->fd, VFIO_DEVICE_SET_IRQS, &irq_set);
- irq__del_irqfd(kvm, gsi, pdev->intx_fd);
-
- close(pdev->intx_fd);
- close(pdev->unmask_fd);
- pdev->intx_fd = -1;
+ vfio_irq_disable(kvm, vdev, VFIO_PCI_INTX_IRQ_INDEX, &pdev->intx);
}
static int vfio_pci_enable_intx(struct kvm *kvm, struct vfio_device *vdev)
{
- int ret;
- int trigger_fd, unmask_fd;
- union vfio_irq_eventfd trigger;
- union vfio_irq_eventfd unmask;
struct vfio_pci_device *pdev = &vdev->pci;
- int gsi = pdev->intx_gsi;
- if (pdev->intx_fd != -1)
- return 0;
-
- /*
- * PCI IRQ is level-triggered, so we use two eventfds. trigger_fd
- * signals an interrupt from host to guest, and unmask_fd signals the
- * deassertion of the line from guest to host.
- */
- trigger_fd = eventfd(0, 0);
- if (trigger_fd < 0) {
- vfio_dev_err(vdev, "failed to create trigger eventfd");
- return trigger_fd;
- }
-
- unmask_fd = eventfd(0, 0);
- if (unmask_fd < 0) {
- vfio_dev_err(vdev, "failed to create unmask eventfd");
- close(trigger_fd);
- return unmask_fd;
- }
-
- ret = irq__add_irqfd(kvm, gsi, trigger_fd, unmask_fd);
- if (ret)
- goto err_close;
-
- trigger.irq = (struct vfio_irq_set) {
- .argsz = sizeof(trigger),
- .flags = VFIO_IRQ_SET_DATA_EVENTFD | VFIO_IRQ_SET_ACTION_TRIGGER,
- .index = VFIO_PCI_INTX_IRQ_INDEX,
- .start = 0,
- .count = 1,
- };
- set_vfio_irq_eventd_payload(&trigger, trigger_fd);
-
- ret = ioctl(vdev->fd, VFIO_DEVICE_SET_IRQS, &trigger);
- if (ret < 0) {
- vfio_dev_err(vdev, "failed to setup VFIO IRQ");
- goto err_delete_line;
- }
-
- unmask.irq = (struct vfio_irq_set) {
- .argsz = sizeof(unmask),
- .flags = VFIO_IRQ_SET_DATA_EVENTFD | VFIO_IRQ_SET_ACTION_UNMASK,
- .index = VFIO_PCI_INTX_IRQ_INDEX,
- .start = 0,
- .count = 1,
- };
- set_vfio_irq_eventd_payload(&unmask, unmask_fd);
-
- ret = ioctl(vdev->fd, VFIO_DEVICE_SET_IRQS, &unmask);
- if (ret < 0) {
- vfio_dev_err(vdev, "failed to setup unmask IRQ");
- goto err_remove_event;
- }
-
- pdev->intx_fd = trigger_fd;
- pdev->unmask_fd = unmask_fd;
-
- return 0;
-
-err_remove_event:
- /* Remove trigger event */
- trigger.irq.flags = VFIO_IRQ_SET_DATA_NONE | VFIO_IRQ_SET_ACTION_TRIGGER;
- trigger.irq.count = 0;
- ioctl(vdev->fd, VFIO_DEVICE_SET_IRQS, &trigger);
-
-err_delete_line:
- irq__del_irqfd(kvm, gsi, trigger_fd);
-
-err_close:
- close(trigger_fd);
- close(unmask_fd);
- return ret;
+ return vfio_irq_enable(kvm, vdev, VFIO_PCI_INTX_IRQ_INDEX, &pdev->intx);
}
static int vfio_pci_init_intx(struct kvm *kvm, struct vfio_device *vdev)
@@ -1345,9 +1247,9 @@ static int vfio_pci_init_intx(struct kvm *kvm, struct vfio_device *vdev)
}
/* Guest is going to ovewrite our irq_line... */
- pdev->intx_gsi = pdev->hdr.irq_line - KVM_IRQ_OFFSET;
+ pdev->intx.gsi = pdev->hdr.irq_line - KVM_IRQ_OFFSET;
- pdev->intx_fd = -1;
+ pdev->intx.trigger_fd = -1;
return 0;
}
--
2.56.0.307.g5fe7bd680c-goog
^ permalink raw reply related [flat|nested] 10+ messages in thread
* [PATCH kvmtool 3/9] vfio: Support edge-triggered wired IRQs
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 ` Mostafa Saleh
2026-10-24 16:18 ` [PATCH kvmtool 4/9] fdt: Allow fdt_irq_fn to generate multiple interrupts Mostafa Saleh
` (5 subsequent siblings)
8 siblings, 0 replies; 10+ messages in thread
From: Mostafa Saleh @ 2026-10-24 16:18 UTC (permalink / raw)
To: kvm; +Cc: will, julien.thierry.kdev, praan, eric.auger, alex, Mostafa Saleh
PCI INTx is are level-triggered and automasked, but platform
device interrupts can also be edge-triggered.
Pass an automasked boolean to vfio_irq_enable() and only create and
register unmask_fd when the interrupt is automasked.
Signed-off-by: Mostafa Saleh <smostafa@google.com>
---
include/kvm/vfio.h | 2 +-
vfio/core.c | 51 ++++++++++++++++++++++++++--------------------
vfio/pci.c | 3 ++-
3 files changed, 32 insertions(+), 24 deletions(-)
diff --git a/include/kvm/vfio.h b/include/kvm/vfio.h
index 9a5783e..0b2b105 100644
--- a/include/kvm/vfio.h
+++ b/include/kvm/vfio.h
@@ -141,7 +141,7 @@ int vfio_map_region(struct kvm *kvm, struct vfio_device *vdev,
struct vfio_region *region);
void vfio_unmap_region(struct kvm *kvm, struct vfio_region *region);
int vfio_irq_enable(struct kvm *kvm, struct vfio_device *vdev,
- unsigned int index, struct vfio_irq *irq);
+ unsigned int index, bool automasked, struct vfio_irq *irq);
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);
diff --git a/vfio/core.c b/vfio/core.c
index 24d3f2d..aa124d2 100644
--- a/vfio/core.c
+++ b/vfio/core.c
@@ -301,15 +301,16 @@ void vfio_irq_disable(struct kvm *kvm, struct vfio_device *vdev,
irq__del_irqfd(kvm, gsi, irq->trigger_fd);
close(irq->trigger_fd);
- close(irq->unmask_fd);
+ if (irq->unmask_fd >= 0)
+ close(irq->unmask_fd);
irq->trigger_fd = -1;
}
int vfio_irq_enable(struct kvm *kvm, struct vfio_device *vdev,
- unsigned int index, struct vfio_irq *irq)
+ unsigned int index, bool automasked, struct vfio_irq *irq)
{
int ret;
- int trigger_fd, unmask_fd;
+ int trigger_fd, unmask_fd = -1;
union vfio_irq_eventfd trigger;
union vfio_irq_eventfd unmask;
int gsi = irq->gsi;
@@ -318,7 +319,7 @@ int vfio_irq_enable(struct kvm *kvm, struct vfio_device *vdev,
return 0;
/*
- * PCI IRQ is level-triggered, so we use two eventfds. trigger_fd
+ * Level-triggered IRQ is automasked, so we use two eventfds. trigger_fd
* signals an interrupt from host to guest, and unmask_fd signals the
* deassertion of the line from guest to host.
*/
@@ -328,11 +329,13 @@ int vfio_irq_enable(struct kvm *kvm, struct vfio_device *vdev,
return trigger_fd;
}
- unmask_fd = eventfd(0, 0);
- if (unmask_fd < 0) {
- vfio_dev_err(vdev, "failed to create unmask eventfd");
- close(trigger_fd);
- return unmask_fd;
+ if (automasked) {
+ unmask_fd = eventfd(0, 0);
+ if (unmask_fd < 0) {
+ vfio_dev_err(vdev, "failed to create unmask eventfd");
+ close(trigger_fd);
+ return unmask_fd;
+ }
}
ret = irq__add_irqfd(kvm, gsi, trigger_fd, unmask_fd);
@@ -354,19 +357,22 @@ int vfio_irq_enable(struct kvm *kvm, struct vfio_device *vdev,
goto err_delete_line;
}
- unmask.irq = (struct vfio_irq_set) {
- .argsz = sizeof(unmask),
- .flags = VFIO_IRQ_SET_DATA_EVENTFD | VFIO_IRQ_SET_ACTION_UNMASK,
- .index = index,
- .start = 0,
- .count = 1,
- };
- set_vfio_irq_eventd_payload(&unmask, unmask_fd);
+ if (unmask_fd >= 0) {
+ unmask.irq = (struct vfio_irq_set) {
+ .argsz = sizeof(unmask),
+ .flags = VFIO_IRQ_SET_DATA_EVENTFD |
+ VFIO_IRQ_SET_ACTION_UNMASK,
+ .index = index,
+ .start = 0,
+ .count = 1,
+ };
+ set_vfio_irq_eventd_payload(&unmask, unmask_fd);
- ret = ioctl(vdev->fd, VFIO_DEVICE_SET_IRQS, &unmask);
- if (ret < 0) {
- vfio_dev_err(vdev, "failed to setup unmask IRQ");
- goto err_remove_event;
+ ret = ioctl(vdev->fd, VFIO_DEVICE_SET_IRQS, &unmask);
+ if (ret < 0) {
+ vfio_dev_err(vdev, "failed to setup unmask IRQ");
+ goto err_remove_event;
+ }
}
irq->trigger_fd = trigger_fd;
@@ -385,7 +391,8 @@ err_delete_line:
err_close:
close(trigger_fd);
- close(unmask_fd);
+ if (unmask_fd >= 0)
+ close(unmask_fd);
return ret;
}
diff --git a/vfio/pci.c b/vfio/pci.c
index fb98435..9bf2f9e 100644
--- a/vfio/pci.c
+++ b/vfio/pci.c
@@ -1216,7 +1216,8 @@ static int vfio_pci_enable_intx(struct kvm *kvm, struct vfio_device *vdev)
{
struct vfio_pci_device *pdev = &vdev->pci;
- return vfio_irq_enable(kvm, vdev, VFIO_PCI_INTX_IRQ_INDEX, &pdev->intx);
+ return vfio_irq_enable(kvm, vdev, VFIO_PCI_INTX_IRQ_INDEX, true,
+ &pdev->intx);
}
static int vfio_pci_init_intx(struct kvm *kvm, struct vfio_device *vdev)
--
2.56.0.307.g5fe7bd680c-goog
^ permalink raw reply related [flat|nested] 10+ messages in thread
* [PATCH kvmtool 4/9] fdt: Allow fdt_irq_fn to generate multiple interrupts
2026-10-24 16:18 [PATCH kvmtool 0/9] vfio: Add support for platform devices Mostafa Saleh
` (2 preceding siblings ...)
2026-10-24 16:18 ` [PATCH kvmtool 3/9] vfio: Support edge-triggered wired IRQs Mostafa Saleh
@ 2026-10-24 16:18 ` Mostafa Saleh
2026-10-24 16:18 ` [PATCH kvmtool 5/9] fdt: Add helper to copy an FDT node Mostafa Saleh
` (4 subsequent siblings)
8 siblings, 0 replies; 10+ messages in thread
From: Mostafa Saleh @ 2026-10-24 16:18 UTC (permalink / raw)
To: kvm; +Cc: will, julien.thierry.kdev, praan, eric.auger, alex, Mostafa Saleh
fdt_irq_fn currently accepts a single interrupt line and trigger type,
which is sufficient for emulated MMIO devices with one interrupt.
Assigned platform devices can expose multiple interrupts that must be
written into a single "interrupts" property.
Update fdt_irq_fn and its arm64 and riscv implementations to accept an
array of interrupt lines and trigger types, and convert existing callers
to use the fdt_irq_fn typedef.
Signed-off-by: Mostafa Saleh <smostafa@google.com>
---
arm64/fdt.c | 36 ++++++++++++++++++++++++++----------
hw/cfi_flash.c | 4 +---
hw/rtc.c | 4 +---
hw/serial.c | 3 ++-
include/kvm/fdt.h | 4 +++-
riscv/fdt.c | 2 +-
riscv/include/kvm/kvm-arch.h | 4 +++-
riscv/irq.c | 27 +++++++++++++++++++--------
virtio/mmio.c | 10 ++++------
9 files changed, 60 insertions(+), 34 deletions(-)
diff --git a/arm64/fdt.c b/arm64/fdt.c
index 3cbd36e..e2c37ad 100644
--- a/arm64/fdt.c
+++ b/arm64/fdt.c
@@ -60,15 +60,29 @@ static void generate_cpu_nodes(void *fdt, struct kvm *kvm)
_FDT(fdt_end_node(fdt));
}
-static void generate_irq_prop(void *fdt, u8 irq, enum irq_type irq_type)
+static void generate_irq_prop(void *fdt, const u8 *irqs,
+ const enum irq_type *irq_types,
+ unsigned int num_irqs)
{
- u32 irq_prop[] = {
- cpu_to_fdt32(GIC_FDT_IRQ_TYPE_SPI),
- cpu_to_fdt32(irq - GIC_SPI_IRQ_BASE),
- cpu_to_fdt32(irq_type)
- };
+ unsigned int i;
+ u32 *irq_prop;
- _FDT(fdt_property(fdt, "interrupts", irq_prop, sizeof(irq_prop)));
+ if (!num_irqs)
+ return;
+
+ irq_prop = calloc(num_irqs, 3 * sizeof(*irq_prop));
+ if (!irq_prop)
+ die("Failed to allocate the interrupts property");
+
+ for (i = 0; i < num_irqs; i++) {
+ irq_prop[3 * i] = cpu_to_fdt32(GIC_FDT_IRQ_TYPE_SPI);
+ irq_prop[3 * i + 1] = cpu_to_fdt32(irqs[i] - GIC_SPI_IRQ_BASE);
+ irq_prop[3 * i + 2] = cpu_to_fdt32(irq_types[i]);
+ }
+
+ _FDT(fdt_property(fdt, "interrupts", irq_prop,
+ 3 * sizeof(*irq_prop) * num_irqs));
+ free(irq_prop);
}
static bool emit_dma_regions;
@@ -78,9 +92,11 @@ void generate_dma_region_prop(void *fdt)
_FDT(fdt_property_cell(fdt, "memory-region", PHANDLE_DMA));
}
-static void generate_aux_props(void *fdt, u8 irq, enum irq_type irq_type)
+static void generate_aux_props(void *fdt, const u8 *irqs,
+ const enum irq_type *irq_types,
+ unsigned int num_irqs)
{
- generate_irq_prop(fdt, irq, irq_type);
+ generate_irq_prop(fdt, irqs, irq_types, num_irqs);
generate_dma_region_prop(fdt);
}
@@ -125,7 +141,7 @@ static int setup_fdt(struct kvm *kvm)
void *fdt_dest = guest_flat_to_host(kvm,
kvm->arch.dtb_guest_start);
void (*generate_mmio_fdt_nodes)(void *, struct device_header *,
- void (*)(void *, u8, enum irq_type));
+ fdt_irq_fn);
void (*generate_cpu_peripheral_fdt_nodes)(void *, struct kvm *)
= kvm->cpus[0]->generate_fdt_nodes;
diff --git a/hw/cfi_flash.c b/hw/cfi_flash.c
index 4413955..5641af6 100644
--- a/hw/cfi_flash.c
+++ b/hw/cfi_flash.c
@@ -518,9 +518,7 @@ static void cfi_flash_mmio(struct kvm_cpu *vcpu,
#ifdef CONFIG_HAS_LIBFDT
static void generate_cfi_flash_fdt_node(void *fdt,
struct device_header *dev_hdr,
- void (*generate_irq_prop)(void *fdt,
- u8 irq,
- enum irq_type))
+ fdt_irq_fn generate_irq_prop)
{
struct cfi_flash_device *sfdev;
u64 reg_prop[2];
diff --git a/hw/rtc.c b/hw/rtc.c
index e3523a1..fc6533a 100644
--- a/hw/rtc.c
+++ b/hw/rtc.c
@@ -136,9 +136,7 @@ static void cmos_ram_io(struct kvm_cpu *vcpu, u64 addr, u8 *data,
#ifdef CONFIG_HAS_LIBFDT
static void generate_rtc_fdt_node(void *fdt,
struct device_header *dev_hdr,
- void (*generate_irq_prop)(void *fdt,
- u8 irq,
- enum irq_type))
+ fdt_irq_fn generate_irq_prop)
{
u64 reg_prop[2] = { cpu_to_fdt64(RTC_BASE_ADDRESS), cpu_to_fdt64(2) };
diff --git a/hw/serial.c b/hw/serial.c
index 68e6186..8e26837 100644
--- a/hw/serial.c
+++ b/hw/serial.c
@@ -434,6 +434,7 @@ void serial8250_generate_fdt_node(void *fdt, struct device_header *dev_hdr,
cpu_to_fdt64(addr),
cpu_to_fdt64(8),
};
+ enum irq_type irq_type = IRQ_TYPE_LEVEL_HIGH;
snprintf(dev_name, DEVICE_NAME_MAX_LEN, "U6_16550A@%llx", addr);
@@ -446,7 +447,7 @@ void serial8250_generate_fdt_node(void *fdt, struct device_header *dev_hdr,
_FDT(fdt_begin_node(fdt, dev_name));
_FDT(fdt_property_string(fdt, "compatible", "ns16550a"));
_FDT(fdt_property(fdt, "reg", reg_prop, sizeof(reg_prop)));
- irq_fn(fdt, dev->irq, IRQ_TYPE_LEVEL_HIGH);
+ irq_fn(fdt, &dev->irq, &irq_type, 1);
_FDT(fdt_property_cell(fdt, "clock-frequency", 1843200));
_FDT(fdt_end_node(fdt));
}
diff --git a/include/kvm/fdt.h b/include/kvm/fdt.h
index 060c37b..e84c5c1 100644
--- a/include/kvm/fdt.h
+++ b/include/kvm/fdt.h
@@ -25,7 +25,9 @@ enum irq_type {
IRQ_TYPE_LEVEL_MASK = (IRQ_TYPE_LEVEL_LOW | IRQ_TYPE_LEVEL_HIGH),
};
-typedef void (*fdt_irq_fn)(void *fdt, u8 irq, enum irq_type irq_type);
+typedef void (*fdt_irq_fn)(void *fdt, const u8 *irqs,
+ const enum irq_type *irq_types,
+ unsigned int num_irqs);
extern char *fdt_stdout_path;
diff --git a/riscv/fdt.c b/riscv/fdt.c
index 1eb45fc..b571724 100644
--- a/riscv/fdt.c
+++ b/riscv/fdt.c
@@ -351,7 +351,7 @@ static int setup_fdt(struct kvm *kvm)
void *fdt_dest = guest_flat_to_host(kvm,
kvm->arch.dtb_guest_start);
void (*generate_mmio_fdt_nodes)(void *, struct device_header *,
- void (*)(void *, u8, enum irq_type));
+ fdt_irq_fn);
/* Create new tree without a reserve map */
_FDT(fdt_create(fdt, FDT_MAX_SIZE));
diff --git a/riscv/include/kvm/kvm-arch.h b/riscv/include/kvm/kvm-arch.h
index 1bb2d32..460b90b 100644
--- a/riscv/include/kvm/kvm-arch.h
+++ b/riscv/include/kvm/kvm-arch.h
@@ -117,7 +117,9 @@ void riscv__del_irqfd(struct kvm *kvm, unsigned int gsi, int trigger_fd);
int riscv__setup_irqfd_lines(struct kvm *kvm);
-void riscv__generate_irq_prop(void *fdt, u8 irq, enum irq_type irq_type);
+void riscv__generate_irq_prop(void *fdt, const u8 *irqs,
+ const enum irq_type *irq_types,
+ unsigned int num_irqs);
void riscv__irqchip_create(struct kvm *kvm);
diff --git a/riscv/irq.c b/riscv/irq.c
index 62dbaa8..2c35f25 100644
--- a/riscv/irq.c
+++ b/riscv/irq.c
@@ -119,18 +119,29 @@ int riscv__setup_irqfd_lines(struct kvm *kvm)
return 0;
}
-void riscv__generate_irq_prop(void *fdt, u8 irq, enum irq_type irq_type)
+void riscv__generate_irq_prop(void *fdt, const u8 *irqs,
+ const enum irq_type *irq_types,
+ unsigned int num_irqs)
{
- u32 prop[2], size;
+ unsigned int i, cells = riscv_irqchip_line_sensing ? 2 : 1;
+ u32 *prop;
- prop[0] = cpu_to_fdt32(irq);
- size = sizeof(u32);
- if (riscv_irqchip_line_sensing) {
- prop[1] = cpu_to_fdt32(irq_type);
- size += sizeof(u32);
+ if (!num_irqs)
+ return;
+
+ prop = calloc(num_irqs, cells * sizeof(*prop));
+ if (!prop)
+ die("Failed to allocate the interrupts property");
+
+ for (i = 0; i < num_irqs; i++) {
+ prop[cells * i] = cpu_to_fdt32(irqs[i]);
+ if (riscv_irqchip_line_sensing)
+ prop[cells * i + 1] = cpu_to_fdt32(irq_types[i]);
}
- _FDT(fdt_property(fdt, "interrupts", prop, size));
+ _FDT(fdt_property(fdt, "interrupts", prop,
+ cells * sizeof(*prop) * num_irqs));
+ free(prop);
}
static void (*riscv__irqchip_create_funcs[])(struct kvm *kvm) = {
diff --git a/virtio/mmio.c b/virtio/mmio.c
index fae73b5..0c66724 100644
--- a/virtio/mmio.c
+++ b/virtio/mmio.c
@@ -113,9 +113,7 @@ int virtio_mmio_signal_config(struct kvm *kvm, struct virtio_device *vdev)
static
void generate_virtio_mmio_fdt_node(void *fdt,
struct device_header *dev_hdr,
- void (*generate_irq_prop)(void *fdt,
- u8 irq,
- enum irq_type))
+ fdt_irq_fn generate_irq_prop)
{
char dev_name[DEVICE_NAME_MAX_LEN];
struct virtio_mmio *vmmio = container_of(dev_hdr,
@@ -126,6 +124,7 @@ void generate_virtio_mmio_fdt_node(void *fdt,
cpu_to_fdt64(addr),
cpu_to_fdt64(VIRTIO_MMIO_IO_SIZE),
};
+ enum irq_type irq_type = IRQ_TYPE_EDGE_RISING;
snprintf(dev_name, DEVICE_NAME_MAX_LEN, "virtio@%llx", addr);
@@ -133,14 +132,13 @@ void generate_virtio_mmio_fdt_node(void *fdt,
_FDT(fdt_property_string(fdt, "compatible", "virtio,mmio"));
_FDT(fdt_property(fdt, "reg", reg_prop, sizeof(reg_prop)));
_FDT(fdt_property(fdt, "dma-coherent", NULL, 0));
- generate_irq_prop(fdt, vmmio->irq, IRQ_TYPE_EDGE_RISING);
+ generate_irq_prop(fdt, &vmmio->irq, &irq_type, 1);
_FDT(fdt_end_node(fdt));
}
#else
static void generate_virtio_mmio_fdt_node(void *fdt,
struct device_header *dev_hdr,
- void (*generate_irq_prop)(void *fdt,
- u8 irq))
+ fdt_irq_fn generate_irq_prop)
{
die("Unable to generate device tree nodes without libfdt\n");
}
--
2.56.0.307.g5fe7bd680c-goog
^ permalink raw reply related [flat|nested] 10+ messages in thread
* [PATCH kvmtool 5/9] fdt: Add helper to copy an FDT node
2026-10-24 16:18 [PATCH kvmtool 0/9] vfio: Add support for platform devices Mostafa Saleh
` (3 preceding siblings ...)
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 ` Mostafa Saleh
2026-10-24 16:18 ` [PATCH kvmtool 6/9] vfio: Reserve guest address space for VFIO platform Mostafa Saleh
` (3 subsequent siblings)
8 siblings, 0 replies; 10+ messages in thread
From: Mostafa Saleh @ 2026-10-24 16:18 UTC (permalink / raw)
To: kvm; +Cc: will, julien.thierry.kdev, praan, eric.auger, alex, Mostafa Saleh
Add fdt__copy_node() to recursively copy all properties and subnodes of
a source FDT node into a destination FDT.
Signed-off-by: Mostafa Saleh <smostafa@google.com>
---
include/kvm/fdt.h | 28 ++++++++++++++++++++++++++++
1 file changed, 28 insertions(+)
diff --git a/include/kvm/fdt.h b/include/kvm/fdt.h
index e84c5c1..e7b65e8 100644
--- a/include/kvm/fdt.h
+++ b/include/kvm/fdt.h
@@ -8,6 +8,7 @@
#include <linux/types.h>
#include "kvm/fdt-arch.h"
+#include "kvm/util.h"
#define FDT_MAX_SIZE 0x10000
@@ -41,4 +42,31 @@ extern char *fdt_stdout_path;
} \
} while (0)
+#ifdef CONFIG_HAS_LIBFDT
+static inline void fdt__copy_node(void *fdt_dest, const void *fdt_src,
+ int offset)
+{
+ int prop_offset, subnode_offset, len;
+ const char *name;
+ const void *prop;
+
+ fdt_for_each_property_offset(prop_offset, fdt_src, offset) {
+ prop = fdt_getprop_by_offset(fdt_src, prop_offset, &name, &len);
+ if (!prop)
+ continue;
+
+ _FDT(fdt_property(fdt_dest, name, prop, len));
+ }
+
+ fdt_for_each_subnode(subnode_offset, fdt_src, offset) {
+ name = fdt_get_name(fdt_src, subnode_offset, NULL);
+ if (!name)
+ continue;
+ _FDT(fdt_begin_node(fdt_dest, name));
+ fdt__copy_node(fdt_dest, fdt_src, subnode_offset);
+ _FDT(fdt_end_node(fdt_dest));
+ }
+}
+#endif
+
#endif /* KVM__FDT_H */
--
2.56.0.307.g5fe7bd680c-goog
^ permalink raw reply related [flat|nested] 10+ messages in thread
* [PATCH kvmtool 6/9] vfio: Reserve guest address space for VFIO platform
2026-10-24 16:18 [PATCH kvmtool 0/9] vfio: Add support for platform devices Mostafa Saleh
` (4 preceding siblings ...)
2026-10-24 16:18 ` [PATCH kvmtool 5/9] fdt: Add helper to copy an FDT node Mostafa Saleh
@ 2026-10-24 16:18 ` Mostafa Saleh
2026-10-24 16:19 ` [PATCH kvmtool 7/9] vfio: Add basic support for vfio-platform Mostafa Saleh
` (2 subsequent siblings)
8 siblings, 0 replies; 10+ messages in thread
From: Mostafa Saleh @ 2026-10-24 16:18 UTC (permalink / raw)
To: kvm; +Cc: will, julien.thierry.kdev, praan, eric.auger, alex, Mostafa Saleh
Assigned platform devices need guest physical addresses for their
MMIO regions.
Reserve an area called KVM_VFIO_MMIO_AREA.
Signed-off-by: Mostafa Saleh <smostafa@google.com>
---
arm64/include/kvm/kvm-arch.h | 10 ++++++----
mips/include/kvm/kvm-arch.h | 2 ++
powerpc/include/kvm/kvm-arch.h | 2 ++
riscv/include/kvm/kvm-arch.h | 3 +++
x86/include/kvm/kvm-arch.h | 2 ++
5 files changed, 15 insertions(+), 4 deletions(-)
diff --git a/arm64/include/kvm/kvm-arch.h b/arm64/include/kvm/kvm-arch.h
index e7dd526..cddb404 100644
--- a/arm64/include/kvm/kvm-arch.h
+++ b/arm64/include/kvm/kvm-arch.h
@@ -19,8 +19,8 @@
* +-------+----+-------+-------+--------+-----+---------+---......
* | PCI |////| plat | | | | |
* | I/O |////| MMIO: | Flash | virtio | GIC | PCI | DRAM
- * | space |////| UART, | | MMIO | | (AXI) |
- * | |////| RTC, | | | | |
+ * | space |////| UART, | | /VFIO | | (AXI) |
+ * | |////| RTC, | | MMIO | | |
* | |////| PVTIME| | | | |
* +-------+----+-------+-------+--------+-----+---------+---......
*/
@@ -47,8 +47,10 @@
#define KVM_FLASH_MAX_SIZE 0x1000000
#define KVM_VIRTIO_MMIO_AREA (KVM_FLASH_MMIO_BASE + KVM_FLASH_MAX_SIZE)
-#define ARM_VIRTIO_MMIO_SIZE (ARM_AXI_AREA - \
- (KVM_VIRTIO_MMIO_AREA + ARM_GIC_SIZE))
+#define ARM_VIRTIO_MMIO_SIZE SZ_128M
+
+#define KVM_VFIO_MMIO_AREA (KVM_VIRTIO_MMIO_AREA + ARM_VIRTIO_MMIO_SIZE)
+#define KVM_VFIO_MMIO_SIZE SZ_32M
#define ARM_GIC_DIST_BASE (ARM_AXI_AREA - ARM_GIC_DIST_SIZE)
#define ARM_GIC_CPUI_BASE (ARM_GIC_DIST_BASE - ARM_GIC_CPUI_SIZE)
diff --git a/mips/include/kvm/kvm-arch.h b/mips/include/kvm/kvm-arch.h
index f5b9044..d9a9a64 100644
--- a/mips/include/kvm/kvm-arch.h
+++ b/mips/include/kvm/kvm-arch.h
@@ -15,6 +15,8 @@
#define KVM_PCI_CFG_AREA KVM_MMIO_START
#define KVM_PCI_MMIO_AREA (KVM_MMIO_START + 0x1000000)
#define KVM_VIRTIO_MMIO_AREA (KVM_MMIO_START + 0x2000000)
+#define KVM_VFIO_MMIO_AREA (KVM_MMIO_START + 0x3000000)
+#define KVM_VFIO_MMIO_SIZE SZ_32M
#define KVM_MMIO_SIZE 0x10000000
/*
diff --git a/powerpc/include/kvm/kvm-arch.h b/powerpc/include/kvm/kvm-arch.h
index ff42c13..cebf73c 100644
--- a/powerpc/include/kvm/kvm-arch.h
+++ b/powerpc/include/kvm/kvm-arch.h
@@ -42,6 +42,8 @@
#define KVM_PCI_CFG_AREA 0x1000000
#define KVM_PCI_MMIO_AREA 0x2000000
#define KVM_VIRTIO_MMIO_AREA 0x3000000
+#define KVM_VFIO_MMIO_AREA 0x4000000
+#define KVM_VFIO_MMIO_SIZE SZ_32M
#define KVM_IRQ_OFFSET 16
diff --git a/riscv/include/kvm/kvm-arch.h b/riscv/include/kvm/kvm-arch.h
index 460b90b..b347216 100644
--- a/riscv/include/kvm/kvm-arch.h
+++ b/riscv/include/kvm/kvm-arch.h
@@ -45,6 +45,9 @@
#define KVM_PCI_CFG_AREA RISCV_PCI
#define KVM_PCI_MMIO_AREA (KVM_PCI_CFG_AREA + RISCV_PCI_CFG_SIZE)
#define KVM_VIRTIO_MMIO_AREA (RISCV_RTC_MMIO_BASE + RISCV_RTC_MMIO_SIZE)
+#define KVM_VIRTIO_MMIO_SIZE SZ_128M
+#define KVM_VFIO_MMIO_AREA (KVM_VIRTIO_MMIO_AREA + KVM_VIRTIO_MMIO_SIZE)
+#define KVM_VFIO_MMIO_SIZE SZ_32M
#define KVM_IOEVENTFD_HAS_PIO 0
diff --git a/x86/include/kvm/kvm-arch.h b/x86/include/kvm/kvm-arch.h
index 73a957b..cc2defa 100644
--- a/x86/include/kvm/kvm-arch.h
+++ b/x86/include/kvm/kvm-arch.h
@@ -24,6 +24,8 @@
#define KVM_PCI_CFG_AREA (KVM_MMIO_START + 0x1000000)
#define KVM_PCI_MMIO_AREA (KVM_MMIO_START + 0x2000000)
#define KVM_VIRTIO_MMIO_AREA (KVM_MMIO_START + 0x3000000)
+#define KVM_VFIO_MMIO_AREA (KVM_MMIO_START + 0x4000000)
+#define KVM_VFIO_MMIO_SIZE SZ_32M
#define KVM_IRQ_OFFSET 5
--
2.56.0.307.g5fe7bd680c-goog
^ permalink raw reply related [flat|nested] 10+ messages in thread
* [PATCH kvmtool 7/9] vfio: Add basic support for vfio-platform
2026-10-24 16:18 [PATCH kvmtool 0/9] vfio: Add support for platform devices Mostafa Saleh
` (5 preceding siblings ...)
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
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
8 siblings, 0 replies; 10+ messages in thread
From: Mostafa Saleh @ 2026-10-24 16:19 UTC (permalink / raw)
To: kvm; +Cc: will, julien.thierry.kdev, praan, eric.auger, alex, Mostafa Saleh
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
^ permalink raw reply related [flat|nested] 10+ messages in thread
* [PATCH kvmtool 8/9] vfio: platform: Add interrupts support
2026-10-24 16:18 [PATCH kvmtool 0/9] vfio: Add support for platform devices Mostafa Saleh
` (6 preceding siblings ...)
2026-10-24 16:19 ` [PATCH kvmtool 7/9] vfio: Add basic support for vfio-platform Mostafa Saleh
@ 2026-10-24 16:19 ` Mostafa Saleh
2026-10-24 16:19 ` [PATCH kvmtool 9/9] vfio: platform: Take the guest node from a device tree template Mostafa Saleh
8 siblings, 0 replies; 10+ messages in thread
From: Mostafa Saleh @ 2026-10-24 16:19 UTC (permalink / raw)
To: kvm; +Cc: will, julien.thierry.kdev, praan, eric.auger, alex, Mostafa Saleh
Configures interrupts of the device, relying on the new common
VFIO interrupt code.
And generated the dt node for interrupts.
Signed-off-by: Mostafa Saleh <smostafa@google.com>
---
include/kvm/vfio.h | 9 +++-
vfio/platform.c | 113 ++++++++++++++++++++++++++++++++++++++++++++-
2 files changed, 119 insertions(+), 3 deletions(-)
diff --git a/include/kvm/vfio.h b/include/kvm/vfio.h
index f641292..b3034a0 100644
--- a/include/kvm/vfio.h
+++ b/include/kvm/vfio.h
@@ -89,6 +89,10 @@ struct vfio_pci_device {
struct vfio_pci_msix_pba msix_pba;
};
+struct vfio_platform_device {
+ struct vfio_irq *irqs;
+};
+
struct vfio_region {
struct vfio_region_info info;
struct vfio_device *vdev;
@@ -109,7 +113,10 @@ struct vfio_device {
char *sysfs_path;
- struct vfio_pci_device pci;
+ union {
+ struct vfio_pci_device pci;
+ struct vfio_platform_device platform;
+ };
};
struct vfio_device_params {
diff --git a/vfio/platform.c b/vfio/platform.c
index c5b447f..22052a6 100644
--- a/vfio/platform.c
+++ b/vfio/platform.c
@@ -1,5 +1,6 @@
#include "linux/sizes.h"
+#include "kvm/irq.h"
#include "kvm/kvm.h"
#include "kvm/vfio.h"
@@ -28,6 +29,36 @@ static int vfio_mmio_alloc_io_space(u64 size, u64 *addr)
}
#ifdef CONFIG_HAS_LIBFDT
+static void generate_interrupts_prop(void *fdt, struct vfio_device *vdev,
+ fdt_irq_fn generate_irq_prop)
+{
+ struct vfio_platform_device *pdev = &vdev->platform;
+ unsigned int i, num_irqs = vdev->info.num_irqs;
+ enum irq_type *irq_types = NULL;
+ u8 *irqs = NULL;
+
+ if (num_irqs) {
+ irqs = calloc(num_irqs, sizeof(*irqs));
+ irq_types = calloc(num_irqs, sizeof(*irq_types));
+ if (!irqs || !irq_types)
+ die("Failed to allocate the interrupts property");
+
+ for (i = 0; i < num_irqs; i++) {
+ struct vfio_irq *irq = &pdev->irqs[i];
+
+ irqs[i] = irq->gsi + KVM_IRQ_OFFSET;
+ irq_types[i] = irq->unmask_fd >= 0 ?
+ IRQ_TYPE_LEVEL_HIGH :
+ IRQ_TYPE_EDGE_RISING;
+ }
+ }
+
+ generate_irq_prop(fdt, irqs, irq_types, num_irqs);
+
+ free(irqs);
+ free(irq_types);
+}
+
static void generate_mmio_fdt_node(void *fdt,
struct device_header *dev_hdr,
fdt_irq_fn generate_irq_prop)
@@ -53,6 +84,7 @@ static void generate_mmio_fdt_node(void *fdt,
_FDT(fdt_begin_node(fdt, node_name));
_FDT(fdt_property(fdt, "reg", reg_prop,
2 * sizeof(*reg_prop) * num_regions));
+ generate_interrupts_prop(fdt, vdev, generate_irq_prop);
_FDT(fdt_end_node(fdt));
free(reg_prop);
@@ -123,8 +155,65 @@ err_unmap:
return ret;
}
+static int vfio_platform_setup_irq(struct kvm *kvm, struct vfio_device *vdev,
+ unsigned int index)
+{
+ struct vfio_irq *irq = &vdev->platform.irqs[index];
+ struct vfio_irq_info irq_info = {
+ .argsz = sizeof(irq_info),
+ .index = index,
+ };
+ int ret;
+
+ if (ioctl(vdev->fd, VFIO_DEVICE_GET_IRQ_INFO, &irq_info)) {
+ ret = -errno;
+ vfio_dev_err(vdev, "failed to get irq[%u] info", index);
+ return ret;
+ }
+
+ if (!(irq_info.flags & VFIO_IRQ_INFO_EVENTFD)) {
+ vfio_dev_err(vdev, "irq[%u] is not eventfd capable", index);
+ return -EINVAL;
+ }
+
+ irq->gsi = irq__alloc_line() - KVM_IRQ_OFFSET;
+ irq->trigger_fd = -1;
+
+ return vfio_irq_enable(kvm, vdev, index,
+ irq_info.flags & VFIO_IRQ_INFO_AUTOMASKED, irq);
+}
+
+static int vfio_platform_configure_dev_irqs(struct kvm *kvm, struct vfio_device *vdev)
+{
+ struct vfio_platform_device *pdev = &vdev->platform;
+ unsigned int i, num_irqs = vdev->info.num_irqs;
+ int ret;
+
+ if (!num_irqs)
+ return 0;
+
+ pdev->irqs = calloc(num_irqs, sizeof(*pdev->irqs));
+ if (!pdev->irqs)
+ return -ENOMEM;
+
+ for (i = 0; i < num_irqs; i++) {
+ ret = vfio_platform_setup_irq(kvm, vdev, i);
+ if (ret)
+ goto err_teardown;
+ }
+
+ return 0;
+
+err_teardown:
+ while (i--)
+ vfio_irq_disable(kvm, vdev, i, &pdev->irqs[i]);
+ free(pdev->irqs);
+ return ret;
+}
+
int vfio_platform_setup_device(struct kvm *kvm, struct vfio_device *vdev)
{
+ unsigned int i;
int ret;
ret = vfio_platform_configure_regs(kvm, vdev);
@@ -133,6 +222,12 @@ int vfio_platform_setup_device(struct kvm *kvm, struct vfio_device *vdev)
return ret;
}
+ ret = vfio_platform_configure_dev_irqs(kvm, vdev);
+ if (ret) {
+ vfio_dev_err(vdev, "failed to configure IRQs");
+ goto err_unmap;
+ }
+
vdev->dev_hdr = (struct device_header) {
.bus_type = DEVICE_BUS_MMIO,
#ifdef CONFIG_HAS_LIBFDT
@@ -143,16 +238,30 @@ int vfio_platform_setup_device(struct kvm *kvm, struct vfio_device *vdev)
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;
+ goto err_teardown_irqs;
}
return 0;
+
+err_teardown_irqs:
+ for (i = 0; i < vdev->info.num_irqs; i++)
+ vfio_irq_disable(kvm, vdev, i, &vdev->platform.irqs[i]);
+ free(vdev->platform.irqs);
+err_unmap:
+ vfio_platform_unmap_regions(kvm, vdev, vdev->info.num_regions);
+ return ret;
}
void vfio_platform_teardown_device(struct kvm *kvm, struct vfio_device *vdev)
{
+ size_t i;
+ struct vfio_platform_device *pdev = &vdev->platform;
+
vfio_platform_unmap_regions(kvm, vdev, vdev->info.num_regions);
+ for (i = 0; i < vdev->info.num_irqs; ++i)
+ vfio_irq_disable(kvm, vdev, i, &pdev->irqs[i]);
+
device__unregister(&vdev->dev_hdr);
+ free(pdev->irqs);
}
--
2.56.0.307.g5fe7bd680c-goog
^ permalink raw reply related [flat|nested] 10+ messages in thread
* [PATCH kvmtool 9/9] vfio: platform: Take the guest node from a device tree template
2026-10-24 16:18 [PATCH kvmtool 0/9] vfio: Add support for platform devices Mostafa Saleh
` (7 preceding siblings ...)
2026-10-24 16:19 ` [PATCH kvmtool 8/9] vfio: platform: Add interrupts support Mostafa Saleh
@ 2026-10-24 16:19 ` Mostafa Saleh
8 siblings, 0 replies; 10+ messages in thread
From: Mostafa Saleh @ 2026-10-24 16:19 UTC (permalink / raw)
To: kvm; +Cc: will, julien.thierry.kdev, praan, eric.auger, alex, Mostafa Saleh
At this point the device node has interrupts and regs, which is not
enough to probe a driver in the guest, it at least needs a compatible
string and other device bindings.
To avoid hardcoding those, let the user supply them as a compiled
device tree blob:
--vfio-platform <device>[,<template.dtb>]
Every property of the template's root node, and every subnode, is
copied into the generated node with fdt__copy_node().
Signed-off-by: Mostafa Saleh <smostafa@google.com>
---
builtin-run.c | 2 +-
include/kvm/vfio.h | 2 ++
vfio/core.c | 16 ++++++++++++++-
vfio/platform.c | 50 ++++++++++++++++++++++++++++++++++++++++++++++
4 files changed, 68 insertions(+), 2 deletions(-)
diff --git a/builtin-run.c b/builtin-run.c
index b09fc2e..a6fd8ec 100644
--- a/builtin-run.c
+++ b/builtin-run.c
@@ -262,7 +262,7 @@ static int loglevel_parser(const struct option *opt, const char *arg, int unset)
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", \
+ OPT_CALLBACK('\0', "vfio-platform", NULL, "device[,template.dtb]", \
"Assign a platform device to the virtual machine", \
vfio_device_parser, kvm), \
\
diff --git a/include/kvm/vfio.h b/include/kvm/vfio.h
index b3034a0..de24ba1 100644
--- a/include/kvm/vfio.h
+++ b/include/kvm/vfio.h
@@ -121,6 +121,8 @@ struct vfio_device {
struct vfio_device_params {
char *name;
+ /* Platform devices: DTB whose root node is copied into the guest node */
+ char *dt_template;
const char *bus;
enum vfio_device_type type;
};
diff --git a/vfio/core.c b/vfio/core.c
index 6823a95..3ce1ffd 100644
--- a/vfio/core.c
+++ b/vfio/core.c
@@ -41,16 +41,30 @@ 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 */
+/*
+ * @arg is the name of the device under /sys/bus/platform/devices, optionally
+ * followed by ",<template.dtb>".
+ */
static int vfio_device_platform_parser(const struct option *opt, char *arg,
struct vfio_device_params *dev)
{
+ char *dt_template = strtok(NULL, ",");
+
dev->type = VFIO_DEVICE_PLATFORM;
dev->bus = "platform";
+ dev->dt_template = NULL;
dev->name = strdup(arg);
if (!dev->name)
return -ENOMEM;
+ if (dt_template) {
+ dev->dt_template = strdup(dt_template);
+ if (!dev->dt_template) {
+ free(dev->name);
+ return -ENOMEM;
+ }
+ }
+
return 0;
}
diff --git a/vfio/platform.c b/vfio/platform.c
index 22052a6..2d08f73 100644
--- a/vfio/platform.c
+++ b/vfio/platform.c
@@ -8,7 +8,11 @@
#include <sys/ioctl.h>
#include <stdlib.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <sys/stat.h>
#include "kvm/fdt.h"
+#include "kvm/read-write.h"
static u64 vfio_mmio_io_space_next = KVM_VFIO_MMIO_AREA;
@@ -29,6 +33,48 @@ static int vfio_mmio_alloc_io_space(u64 size, u64 *addr)
}
#ifdef CONFIG_HAS_LIBFDT
+static void vfio_platform_generate_fdt_from_template(void *fdt,
+ struct vfio_device *vdev)
+{
+ int fd;
+ struct stat st;
+ void *tmp_fdt;
+ int root_offset;
+
+ if (!vdev->params->dt_template)
+ return;
+
+ fd = open(vdev->params->dt_template, O_RDONLY);
+ if (fd < 0)
+ die("Failed to open device tree template '%s'", vdev->params->dt_template);
+
+ if (fstat(fd, &st) < 0)
+ die("Failed to stat device tree template");
+
+ if (st.st_size < (off_t)sizeof(struct fdt_header))
+ die("Invalid device tree blob (DTB) provided in '%s'",
+ vdev->params->dt_template);
+
+ tmp_fdt = malloc(st.st_size);
+ if (!tmp_fdt)
+ die("Failed to allocate memory for device tree template");
+
+ if (read_in_full(fd, tmp_fdt, st.st_size) != st.st_size)
+ die("Failed to read device tree template");
+
+ if (fdt_check_header(tmp_fdt))
+ die("Invalid DTB: '%s'", vdev->params->dt_template);
+
+ root_offset = fdt_path_offset(tmp_fdt, "/");
+ if (root_offset < 0)
+ die("Failed to parse device tree template");
+
+ fdt__copy_node(fdt, tmp_fdt, root_offset);
+
+ free(tmp_fdt);
+ close(fd);
+}
+
static void generate_interrupts_prop(void *fdt, struct vfio_device *vdev,
fdt_irq_fn generate_irq_prop)
{
@@ -82,6 +128,9 @@ static void generate_mmio_fdt_node(void *fdt,
vdev->params->name, vdev->regions[0].guest_phys_addr);
_FDT(fdt_begin_node(fdt, node_name));
+ /* Extra user supplied binding. */
+ vfio_platform_generate_fdt_from_template(fdt, vdev);
+
_FDT(fdt_property(fdt, "reg", reg_prop,
2 * sizeof(*reg_prop) * num_regions));
generate_interrupts_prop(fdt, vdev, generate_irq_prop);
@@ -264,4 +313,5 @@ void vfio_platform_teardown_device(struct kvm *kvm, struct vfio_device *vdev)
device__unregister(&vdev->dev_hdr);
free(pdev->irqs);
+ free(vdev->params->dt_template);
}
--
2.56.0.307.g5fe7bd680c-goog
^ permalink raw reply related [flat|nested] 10+ messages in thread
end of thread, other threads:[~2026-10-24 16:20 UTC | newest]
Thread overview: 10+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
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 ` [PATCH kvmtool 7/9] vfio: Add basic support for vfio-platform Mostafa Saleh
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
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox