2 * IOMMU for remote device
4 * Copyright © 2022 Oracle and/or its affiliates.
6 * This work is licensed under the terms of the GNU GPL, version 2 or later.
7 * See the COPYING file in the top-level directory.
11 #include "qemu/osdep.h"
13 #include "hw/remote/iommu.h"
14 #include "hw/pci/pci_bus.h"
15 #include "hw/pci/pci.h"
16 #include "exec/memory.h"
17 #include "exec/address-spaces.h"
21 * IOMMU for TYPE_REMOTE_MACHINE - manages DMA address space isolation
22 * for remote machine. It is used by TYPE_VFIO_USER_SERVER.
24 * - Each TYPE_VFIO_USER_SERVER instance handles one PCIDevice on a PCIBus.
25 * There is one RemoteIommu per PCIBus, so the RemoteIommu tracks multiple
26 * PCIDevices by maintaining a ->elem_by_devfn mapping.
28 * - memory_region_init_iommu() is not used because vfio-user MemoryRegions
29 * will be added to the elem->mr container instead. This is more natural
30 * than implementing the IOMMUMemoryRegionClass APIs since vfio-user
31 * provides something that is close to a full-fledged MemoryRegion and
32 * not like an IOMMU mapping.
34 * - When a device is hot unplugged, the elem->mr reference is dropped so
35 * all vfio-user MemoryRegions associated with this vfio-user server are
39 static AddressSpace
*remote_iommu_find_add_as(PCIBus
*pci_bus
,
40 void *opaque
, int devfn
)
42 RemoteIommu
*iommu
= opaque
;
43 RemoteIommuElem
*elem
= NULL
;
45 qemu_mutex_lock(&iommu
->lock
);
47 elem
= g_hash_table_lookup(iommu
->elem_by_devfn
, INT2VOIDP(devfn
));
50 elem
= g_new0(RemoteIommuElem
, 1);
51 g_hash_table_insert(iommu
->elem_by_devfn
, INT2VOIDP(devfn
), elem
);
55 elem
->mr
= MEMORY_REGION(object_new(TYPE_MEMORY_REGION
));
56 memory_region_set_size(elem
->mr
, UINT64_MAX
);
57 address_space_init(&elem
->as
, elem
->mr
, NULL
);
60 qemu_mutex_unlock(&iommu
->lock
);
65 void remote_iommu_unplug_dev(PCIDevice
*pci_dev
)
67 AddressSpace
*as
= pci_device_iommu_address_space(pci_dev
);
68 RemoteIommuElem
*elem
= NULL
;
70 if (as
== &address_space_memory
) {
74 elem
= container_of(as
, RemoteIommuElem
, as
);
76 address_space_destroy(&elem
->as
);
78 object_unref(elem
->mr
);
83 static void remote_iommu_init(Object
*obj
)
85 RemoteIommu
*iommu
= REMOTE_IOMMU(obj
);
87 iommu
->elem_by_devfn
= g_hash_table_new_full(NULL
, NULL
, NULL
, g_free
);
89 qemu_mutex_init(&iommu
->lock
);
92 static void remote_iommu_finalize(Object
*obj
)
94 RemoteIommu
*iommu
= REMOTE_IOMMU(obj
);
96 qemu_mutex_destroy(&iommu
->lock
);
98 g_hash_table_destroy(iommu
->elem_by_devfn
);
100 iommu
->elem_by_devfn
= NULL
;
103 static const PCIIOMMUOps remote_iommu_ops
= {
104 .get_address_space
= remote_iommu_find_add_as
,
107 void remote_iommu_setup(PCIBus
*pci_bus
)
109 RemoteIommu
*iommu
= NULL
;
113 iommu
= REMOTE_IOMMU(object_new(TYPE_REMOTE_IOMMU
));
115 pci_setup_iommu(pci_bus
, &remote_iommu_ops
, iommu
);
117 object_property_add_child(OBJECT(pci_bus
), "remote-iommu", OBJECT(iommu
));
119 object_unref(OBJECT(iommu
));
122 static const TypeInfo remote_iommu_info
= {
123 .name
= TYPE_REMOTE_IOMMU
,
124 .parent
= TYPE_OBJECT
,
125 .instance_size
= sizeof(RemoteIommu
),
126 .instance_init
= remote_iommu_init
,
127 .instance_finalize
= remote_iommu_finalize
,
130 static void remote_iommu_register_types(void)
132 type_register_static(&remote_iommu_info
);
135 type_init(remote_iommu_register_types
)