@@ -93,6 +93,12 @@ struct mock_iommu_domain {
93
93
struct xarray pfns ;
94
94
};
95
95
96
+ struct mock_iommu_domain_nested {
97
+ struct iommu_domain domain ;
98
+ struct mock_iommu_domain * parent ;
99
+ u32 iotlb [MOCK_NESTED_DOMAIN_IOTLB_NUM ];
100
+ };
101
+
96
102
enum selftest_obj_type {
97
103
TYPE_IDEV ,
98
104
};
@@ -217,54 +223,99 @@ const struct iommu_dirty_ops dirty_ops = {
217
223
};
218
224
219
225
static const struct iommu_ops mock_ops ;
226
+ static struct iommu_domain_ops domain_nested_ops ;
220
227
221
- static struct iommu_domain * mock_domain_alloc (unsigned int iommu_domain_type )
228
+ static struct iommu_domain *
229
+ __mock_domain_alloc_paging (unsigned int iommu_domain_type , bool needs_dirty_ops )
222
230
{
223
231
struct mock_iommu_domain * mock ;
224
232
225
- if (iommu_domain_type == IOMMU_DOMAIN_BLOCKED )
226
- return & mock_blocking_domain ;
227
-
228
- if (iommu_domain_type != IOMMU_DOMAIN_UNMANAGED )
229
- return NULL ;
230
-
231
233
mock = kzalloc (sizeof (* mock ), GFP_KERNEL );
232
234
if (!mock )
233
- return NULL ;
235
+ return ERR_PTR ( - ENOMEM ) ;
234
236
mock -> domain .geometry .aperture_start = MOCK_APERTURE_START ;
235
237
mock -> domain .geometry .aperture_end = MOCK_APERTURE_LAST ;
236
238
mock -> domain .pgsize_bitmap = MOCK_IO_PAGE_SIZE ;
237
239
mock -> domain .ops = mock_ops .default_domain_ops ;
240
+ if (needs_dirty_ops )
241
+ mock -> domain .dirty_ops = & dirty_ops ;
238
242
mock -> domain .type = iommu_domain_type ;
239
243
xa_init (& mock -> pfns );
240
244
return & mock -> domain ;
241
245
}
242
246
247
+ static struct iommu_domain *
248
+ __mock_domain_alloc_nested (struct mock_iommu_domain * mock_parent ,
249
+ const struct iommu_hwpt_selftest * user_cfg )
250
+ {
251
+ struct mock_iommu_domain_nested * mock_nested ;
252
+ int i ;
253
+
254
+ mock_nested = kzalloc (sizeof (* mock_nested ), GFP_KERNEL );
255
+ if (!mock_nested )
256
+ return ERR_PTR (- ENOMEM );
257
+ mock_nested -> parent = mock_parent ;
258
+ mock_nested -> domain .ops = & domain_nested_ops ;
259
+ mock_nested -> domain .type = IOMMU_DOMAIN_NESTED ;
260
+ for (i = 0 ; i < MOCK_NESTED_DOMAIN_IOTLB_NUM ; i ++ )
261
+ mock_nested -> iotlb [i ] = user_cfg -> iotlb ;
262
+ return & mock_nested -> domain ;
263
+ }
264
+
265
+ static struct iommu_domain * mock_domain_alloc (unsigned int iommu_domain_type )
266
+ {
267
+ struct iommu_domain * domain ;
268
+
269
+ if (iommu_domain_type == IOMMU_DOMAIN_BLOCKED )
270
+ return & mock_blocking_domain ;
271
+ if (iommu_domain_type != IOMMU_DOMAIN_UNMANAGED )
272
+ return NULL ;
273
+ domain = __mock_domain_alloc_paging (iommu_domain_type , false);
274
+ if (IS_ERR (domain ))
275
+ domain = NULL ;
276
+ return domain ;
277
+ }
278
+
243
279
static struct iommu_domain *
244
280
mock_domain_alloc_user (struct device * dev , u32 flags ,
245
281
struct iommu_domain * parent ,
246
282
const struct iommu_user_data * user_data )
247
283
{
248
- struct mock_dev * mdev = container_of (dev , struct mock_dev , dev );
249
- struct iommu_domain * domain ;
284
+ struct mock_iommu_domain * mock_parent ;
285
+ struct iommu_hwpt_selftest user_cfg ;
286
+ int rc ;
250
287
251
- if (flags &
252
- (~(IOMMU_HWPT_ALLOC_NEST_PARENT | IOMMU_HWPT_ALLOC_DIRTY_TRACKING )))
253
- return ERR_PTR (- EOPNOTSUPP );
288
+ /* must be mock_domain */
289
+ if (!parent ) {
290
+ struct mock_dev * mdev = container_of (dev , struct mock_dev , dev );
291
+ bool has_dirty_flag = flags & IOMMU_HWPT_ALLOC_DIRTY_TRACKING ;
292
+ bool no_dirty_ops = mdev -> flags & MOCK_FLAGS_DEVICE_NO_DIRTY ;
293
+
294
+ if (flags & (~(IOMMU_HWPT_ALLOC_NEST_PARENT |
295
+ IOMMU_HWPT_ALLOC_DIRTY_TRACKING )))
296
+ return ERR_PTR (- EOPNOTSUPP );
297
+ if (user_data || (has_dirty_flag && no_dirty_ops ))
298
+ return ERR_PTR (- EOPNOTSUPP );
299
+ return __mock_domain_alloc_paging (IOMMU_DOMAIN_UNMANAGED ,
300
+ has_dirty_flag );
301
+ }
254
302
255
- if (parent || user_data )
303
+ /* must be mock_domain_nested */
304
+ if (user_data -> type != IOMMU_HWPT_DATA_SELFTEST || flags )
256
305
return ERR_PTR (- EOPNOTSUPP );
306
+ if (!parent || parent -> ops != mock_ops .default_domain_ops )
307
+ return ERR_PTR (- EINVAL );
257
308
258
- if (( flags & IOMMU_HWPT_ALLOC_DIRTY_TRACKING ) &&
259
- ( mdev -> flags & MOCK_FLAGS_DEVICE_NO_DIRTY ) )
260
- return ERR_PTR (- EOPNOTSUPP );
309
+ mock_parent = container_of ( parent , struct mock_iommu_domain , domain );
310
+ if (! mock_parent )
311
+ return ERR_PTR (- EINVAL );
261
312
262
- domain = mock_domain_alloc ( IOMMU_DOMAIN_UNMANAGED );
263
- if ( domain && !( mdev -> flags & MOCK_FLAGS_DEVICE_NO_DIRTY ))
264
- domain -> dirty_ops = & dirty_ops ;
265
- if (! domain )
266
- domain = ERR_PTR ( - ENOMEM );
267
- return domain ;
313
+ rc = iommu_copy_struct_from_user ( & user_cfg , user_data ,
314
+ IOMMU_HWPT_DATA_SELFTEST , iotlb );
315
+ if ( rc )
316
+ return ERR_PTR ( rc );
317
+
318
+ return __mock_domain_alloc_nested ( mock_parent , & user_cfg ) ;
268
319
}
269
320
270
321
static void mock_domain_free (struct iommu_domain * domain )
@@ -434,26 +485,67 @@ static const struct iommu_ops mock_ops = {
434
485
},
435
486
};
436
487
488
+ static void mock_domain_free_nested (struct iommu_domain * domain )
489
+ {
490
+ struct mock_iommu_domain_nested * mock_nested =
491
+ container_of (domain , struct mock_iommu_domain_nested , domain );
492
+
493
+ kfree (mock_nested );
494
+ }
495
+
496
+ static struct iommu_domain_ops domain_nested_ops = {
497
+ .free = mock_domain_free_nested ,
498
+ .attach_dev = mock_domain_nop_attach ,
499
+ };
500
+
437
501
static inline struct iommufd_hw_pagetable *
438
- get_md_pagetable (struct iommufd_ucmd * ucmd , u32 mockpt_id ,
439
- struct mock_iommu_domain * * mock )
502
+ __get_md_pagetable (struct iommufd_ucmd * ucmd , u32 mockpt_id , u32 hwpt_type )
440
503
{
441
- struct iommufd_hw_pagetable * hwpt ;
442
504
struct iommufd_object * obj ;
443
505
444
- obj = iommufd_get_object (ucmd -> ictx , mockpt_id ,
445
- IOMMUFD_OBJ_HWPT_PAGING );
506
+ obj = iommufd_get_object (ucmd -> ictx , mockpt_id , hwpt_type );
446
507
if (IS_ERR (obj ))
447
508
return ERR_CAST (obj );
448
- hwpt = container_of (obj , struct iommufd_hw_pagetable , obj );
449
- if (hwpt -> domain -> ops != mock_ops .default_domain_ops ) {
509
+ return container_of (obj , struct iommufd_hw_pagetable , obj );
510
+ }
511
+
512
+ static inline struct iommufd_hw_pagetable *
513
+ get_md_pagetable (struct iommufd_ucmd * ucmd , u32 mockpt_id ,
514
+ struct mock_iommu_domain * * mock )
515
+ {
516
+ struct iommufd_hw_pagetable * hwpt ;
517
+
518
+ hwpt = __get_md_pagetable (ucmd , mockpt_id , IOMMUFD_OBJ_HWPT_PAGING );
519
+ if (IS_ERR (hwpt ))
520
+ return hwpt ;
521
+ if (hwpt -> domain -> type != IOMMU_DOMAIN_UNMANAGED ||
522
+ hwpt -> domain -> ops != mock_ops .default_domain_ops ) {
450
523
iommufd_put_object (& hwpt -> obj );
451
524
return ERR_PTR (- EINVAL );
452
525
}
453
526
* mock = container_of (hwpt -> domain , struct mock_iommu_domain , domain );
454
527
return hwpt ;
455
528
}
456
529
530
+ static inline struct iommufd_hw_pagetable *
531
+ get_md_pagetable_nested (struct iommufd_ucmd * ucmd , u32 mockpt_id ,
532
+ struct mock_iommu_domain_nested * * mock_nested )
533
+ {
534
+ struct iommufd_hw_pagetable * hwpt ;
535
+
536
+ hwpt = __get_md_pagetable (ucmd , mockpt_id , IOMMUFD_OBJ_HWPT_NESTED );
537
+ if (IS_ERR (hwpt ))
538
+ return hwpt ;
539
+ if (hwpt -> domain -> type != IOMMU_DOMAIN_NESTED ||
540
+ hwpt -> domain -> ops != & domain_nested_ops ) {
541
+ iommufd_put_object (& hwpt -> obj );
542
+ return ERR_PTR (- EINVAL );
543
+ }
544
+ * mock_nested = container_of (hwpt -> domain ,
545
+ struct mock_iommu_domain_nested , domain );
546
+ return hwpt ;
547
+ }
548
+
457
549
struct mock_bus_type {
458
550
struct bus_type bus ;
459
551
struct notifier_block nb ;
0 commit comments