1616#include "qemu/module.h"
1717#include "qom/object_interfaces.h"
1818#include "qemu/error-report.h"
19+ #include "migration/cpr.h"
1920#include "monitor/monitor.h"
2021#include "trace.h"
2122#include "hw/vfio/vfio-device.h"
2223#include <sys/ioctl.h>
2324#include <linux/iommufd.h>
2425
26+ static const char * iommufd_fd_name (IOMMUFDBackend * be )
27+ {
28+ return object_get_canonical_path_component (OBJECT (be ));
29+ }
30+
2531static void iommufd_backend_init (Object * obj )
2632{
2733 IOMMUFDBackend * be = IOMMUFD_BACKEND (obj );
@@ -64,26 +70,73 @@ static bool iommufd_backend_can_be_deleted(UserCreatable *uc)
6470 return !be -> users ;
6571}
6672
73+ static void iommufd_backend_complete (UserCreatable * uc , Error * * errp )
74+ {
75+ IOMMUFDBackend * be = IOMMUFD_BACKEND (uc );
76+ const char * name = iommufd_fd_name (be );
77+
78+ if (!be -> owned ) {
79+ /* fd came from the command line. Fetch updated value from cpr state. */
80+ if (cpr_is_incoming ()) {
81+ be -> fd = cpr_find_fd (name , 0 );
82+ } else {
83+ cpr_save_fd (name , 0 , be -> fd );
84+ }
85+ }
86+ }
87+
6788static void iommufd_backend_class_init (ObjectClass * oc , const void * data )
6889{
6990 UserCreatableClass * ucc = USER_CREATABLE_CLASS (oc );
7091
7192 ucc -> can_be_deleted = iommufd_backend_can_be_deleted ;
93+ ucc -> complete = iommufd_backend_complete ;
7294
7395 object_class_property_add_str (oc , "fd" , NULL , iommufd_backend_set_fd );
7496}
7597
98+ bool iommufd_change_process_capable (IOMMUFDBackend * be )
99+ {
100+ struct iommu_ioas_change_process args = {.size = sizeof (args )};
101+
102+ /*
103+ * Call IOMMU_IOAS_CHANGE_PROCESS to verify it is a recognized ioctl.
104+ * This is a no-op if the process has not changed since DMA was mapped.
105+ */
106+ return !ioctl (be -> fd , IOMMU_IOAS_CHANGE_PROCESS , & args );
107+ }
108+
109+ bool iommufd_change_process (IOMMUFDBackend * be , Error * * errp )
110+ {
111+ struct iommu_ioas_change_process args = {.size = sizeof (args )};
112+ bool ret = !ioctl (be -> fd , IOMMU_IOAS_CHANGE_PROCESS , & args );
113+
114+ if (!ret ) {
115+ error_setg_errno (errp , errno , "IOMMU_IOAS_CHANGE_PROCESS fd %d failed" ,
116+ be -> fd );
117+ }
118+ trace_iommufd_change_process (be -> fd , ret );
119+ return ret ;
120+ }
121+
76122bool iommufd_backend_connect (IOMMUFDBackend * be , Error * * errp )
77123{
78124 int fd ;
79125
80126 if (be -> owned && !be -> users ) {
81- fd = qemu_open ("/dev/iommu" , O_RDWR , errp );
127+ fd = cpr_open_fd ("/dev/iommu" , O_RDWR , iommufd_fd_name ( be ), 0 , errp );
82128 if (fd < 0 ) {
83129 return false;
84130 }
85131 be -> fd = fd ;
86132 }
133+ if (!be -> users && !vfio_iommufd_cpr_register_iommufd (be , errp )) {
134+ if (be -> owned ) {
135+ close (be -> fd );
136+ be -> fd = -1 ;
137+ }
138+ return false;
139+ }
87140 be -> users ++ ;
88141
89142 trace_iommufd_backend_connect (be -> fd , be -> owned , be -> users );
@@ -96,9 +149,13 @@ void iommufd_backend_disconnect(IOMMUFDBackend *be)
96149 goto out ;
97150 }
98151 be -> users -- ;
99- if (!be -> users && be -> owned ) {
100- close (be -> fd );
101- be -> fd = -1 ;
152+ if (!be -> users ) {
153+ vfio_iommufd_cpr_unregister_iommufd (be );
154+ if (be -> owned ) {
155+ cpr_delete_fd (iommufd_fd_name (be ), 0 );
156+ close (be -> fd );
157+ be -> fd = -1 ;
158+ }
102159 }
103160out :
104161 trace_iommufd_backend_disconnect (be -> fd , be -> users );
@@ -172,6 +229,44 @@ int iommufd_backend_map_dma(IOMMUFDBackend *be, uint32_t ioas_id, hwaddr iova,
172229 return ret ;
173230}
174231
232+ int iommufd_backend_map_file_dma (IOMMUFDBackend * be , uint32_t ioas_id ,
233+ hwaddr iova , ram_addr_t size ,
234+ int mfd , unsigned long start , bool readonly )
235+ {
236+ int ret , fd = be -> fd ;
237+ struct iommu_ioas_map_file map = {
238+ .size = sizeof (map ),
239+ .flags = IOMMU_IOAS_MAP_READABLE |
240+ IOMMU_IOAS_MAP_FIXED_IOVA ,
241+ .ioas_id = ioas_id ,
242+ .fd = mfd ,
243+ .start = start ,
244+ .iova = iova ,
245+ .length = size ,
246+ };
247+
248+ if (cpr_is_incoming ()) {
249+ return 0 ;
250+ }
251+
252+ if (!readonly ) {
253+ map .flags |= IOMMU_IOAS_MAP_WRITEABLE ;
254+ }
255+
256+ ret = ioctl (fd , IOMMU_IOAS_MAP_FILE , & map );
257+ trace_iommufd_backend_map_file_dma (fd , ioas_id , iova , size , mfd , start ,
258+ readonly , ret );
259+ if (ret ) {
260+ ret = - errno ;
261+
262+ /* TODO: Not support mapping hardware PCI BAR region for now. */
263+ if (errno == EFAULT ) {
264+ warn_report ("IOMMU_IOAS_MAP_FILE failed: %m, PCI BAR?" );
265+ }
266+ }
267+ return ret ;
268+ }
269+
175270int iommufd_backend_unmap_dma (IOMMUFDBackend * be , uint32_t ioas_id ,
176271 hwaddr iova , ram_addr_t size )
177272{
@@ -183,6 +278,10 @@ int iommufd_backend_unmap_dma(IOMMUFDBackend *be, uint32_t ioas_id,
183278 .length = size ,
184279 };
185280
281+ if (cpr_is_incoming ()) {
282+ return 0 ;
283+ }
284+
186285 ret = ioctl (fd , IOMMU_IOAS_UNMAP , & unmap );
187286 /*
188287 * IOMMUFD takes mapping as some kind of object, unmapping
0 commit comments