2 * iommufd container backend
4 * Copyright (C) 2023 Intel Corporation.
5 * Copyright Red Hat, Inc. 2023
7 * Authors: Yi Liu <yi.l.liu@intel.com>
8 * Eric Auger <eric.auger@redhat.com>
10 * SPDX-License-Identifier: GPL-2.0-or-later
13 #include "qemu/osdep.h"
14 #include "sysemu/iommufd.h"
15 #include "qapi/error.h"
16 #include "qemu/module.h"
17 #include "qom/object_interfaces.h"
18 #include "qemu/error-report.h"
19 #include "monitor/monitor.h"
21 #include <sys/ioctl.h>
22 #include <linux/iommufd.h>
24 static void iommufd_backend_init(Object
*obj
)
26 IOMMUFDBackend
*be
= IOMMUFD_BACKEND(obj
);
33 static void iommufd_backend_finalize(Object
*obj
)
35 IOMMUFDBackend
*be
= IOMMUFD_BACKEND(obj
);
43 static void iommufd_backend_set_fd(Object
*obj
, const char *str
, Error
**errp
)
46 IOMMUFDBackend
*be
= IOMMUFD_BACKEND(obj
);
49 fd
= monitor_fd_param(monitor_cur(), str
, errp
);
51 error_prepend(errp
, "Could not parse remote object fd %s:", str
);
56 trace_iommu_backend_set_fd(be
->fd
);
59 static bool iommufd_backend_can_be_deleted(UserCreatable
*uc
)
61 IOMMUFDBackend
*be
= IOMMUFD_BACKEND(uc
);
66 static void iommufd_backend_class_init(ObjectClass
*oc
, void *data
)
68 UserCreatableClass
*ucc
= USER_CREATABLE_CLASS(oc
);
70 ucc
->can_be_deleted
= iommufd_backend_can_be_deleted
;
72 object_class_property_add_str(oc
, "fd", NULL
, iommufd_backend_set_fd
);
75 bool iommufd_backend_connect(IOMMUFDBackend
*be
, Error
**errp
)
79 if (be
->owned
&& !be
->users
) {
80 fd
= qemu_open_old("/dev/iommu", O_RDWR
);
82 error_setg_errno(errp
, errno
, "/dev/iommu opening failed");
89 trace_iommufd_backend_connect(be
->fd
, be
->owned
, be
->users
);
93 void iommufd_backend_disconnect(IOMMUFDBackend
*be
)
99 if (!be
->users
&& be
->owned
) {
104 trace_iommufd_backend_disconnect(be
->fd
, be
->users
);
107 bool iommufd_backend_alloc_ioas(IOMMUFDBackend
*be
, uint32_t *ioas_id
,
111 struct iommu_ioas_alloc alloc_data
= {
112 .size
= sizeof(alloc_data
),
116 if (ioctl(fd
, IOMMU_IOAS_ALLOC
, &alloc_data
)) {
117 error_setg_errno(errp
, errno
, "Failed to allocate ioas");
121 *ioas_id
= alloc_data
.out_ioas_id
;
122 trace_iommufd_backend_alloc_ioas(fd
, *ioas_id
);
127 void iommufd_backend_free_id(IOMMUFDBackend
*be
, uint32_t id
)
129 int ret
, fd
= be
->fd
;
130 struct iommu_destroy des
= {
135 ret
= ioctl(fd
, IOMMU_DESTROY
, &des
);
136 trace_iommufd_backend_free_id(fd
, id
, ret
);
138 error_report("Failed to free id: %u %m", id
);
142 int iommufd_backend_map_dma(IOMMUFDBackend
*be
, uint32_t ioas_id
, hwaddr iova
,
143 ram_addr_t size
, void *vaddr
, bool readonly
)
145 int ret
, fd
= be
->fd
;
146 struct iommu_ioas_map map
= {
148 .flags
= IOMMU_IOAS_MAP_READABLE
|
149 IOMMU_IOAS_MAP_FIXED_IOVA
,
152 .user_va
= (uintptr_t)vaddr
,
158 map
.flags
|= IOMMU_IOAS_MAP_WRITEABLE
;
161 ret
= ioctl(fd
, IOMMU_IOAS_MAP
, &map
);
162 trace_iommufd_backend_map_dma(fd
, ioas_id
, iova
, size
,
163 vaddr
, readonly
, ret
);
167 /* TODO: Not support mapping hardware PCI BAR region for now. */
168 if (errno
== EFAULT
) {
169 warn_report("IOMMU_IOAS_MAP failed: %m, PCI BAR?");
171 error_report("IOMMU_IOAS_MAP failed: %m");
177 int iommufd_backend_unmap_dma(IOMMUFDBackend
*be
, uint32_t ioas_id
,
178 hwaddr iova
, ram_addr_t size
)
180 int ret
, fd
= be
->fd
;
181 struct iommu_ioas_unmap unmap
= {
182 .size
= sizeof(unmap
),
188 ret
= ioctl(fd
, IOMMU_IOAS_UNMAP
, &unmap
);
190 * IOMMUFD takes mapping as some kind of object, unmapping
191 * nonexistent mapping is treated as deleting a nonexistent
192 * object and return ENOENT. This is different from legacy
193 * backend which allows it. vIOMMU may trigger a lot of
194 * redundant unmapping, to avoid flush the log, treat them
195 * as succeess for IOMMUFD just like legacy backend.
197 if (ret
&& errno
== ENOENT
) {
198 trace_iommufd_backend_unmap_dma_non_exist(fd
, ioas_id
, iova
, size
, ret
);
201 trace_iommufd_backend_unmap_dma(fd
, ioas_id
, iova
, size
, ret
);
206 error_report("IOMMU_IOAS_UNMAP failed: %m");
211 bool iommufd_backend_get_device_info(IOMMUFDBackend
*be
, uint32_t devid
,
212 uint32_t *type
, void *data
, uint32_t len
,
215 struct iommu_hw_info info
= {
216 .size
= sizeof(info
),
219 .data_uptr
= (uintptr_t)data
,
222 if (ioctl(be
->fd
, IOMMU_GET_HW_INFO
, &info
)) {
223 error_setg_errno(errp
, errno
, "Failed to get hardware info");
228 *type
= info
.out_data_type
;
233 static int hiod_iommufd_get_cap(HostIOMMUDevice
*hiod
, int cap
, Error
**errp
)
235 HostIOMMUDeviceCaps
*caps
= &hiod
->caps
;
238 case HOST_IOMMU_DEVICE_CAP_IOMMU_TYPE
:
240 case HOST_IOMMU_DEVICE_CAP_AW_BITS
:
241 return caps
->aw_bits
;
243 error_setg(errp
, "%s: unsupported capability %x", hiod
->name
, cap
);
248 static void hiod_iommufd_class_init(ObjectClass
*oc
, void *data
)
250 HostIOMMUDeviceClass
*hioc
= HOST_IOMMU_DEVICE_CLASS(oc
);
252 hioc
->get_cap
= hiod_iommufd_get_cap
;
255 static const TypeInfo types
[] = {
257 .name
= TYPE_IOMMUFD_BACKEND
,
258 .parent
= TYPE_OBJECT
,
259 .instance_size
= sizeof(IOMMUFDBackend
),
260 .instance_init
= iommufd_backend_init
,
261 .instance_finalize
= iommufd_backend_finalize
,
262 .class_size
= sizeof(IOMMUFDBackendClass
),
263 .class_init
= iommufd_backend_class_init
,
264 .interfaces
= (InterfaceInfo
[]) {
265 { TYPE_USER_CREATABLE
},
269 .name
= TYPE_HOST_IOMMU_DEVICE_IOMMUFD
,
270 .parent
= TYPE_HOST_IOMMU_DEVICE
,
271 .class_init
= hiod_iommufd_class_init
,