1 // SPDX-License-Identifier: GPL-2.0-only
2 /* Copyright (c) 2021-2022, NVIDIA CORPORATION & AFFILIATES */
3 #include <stdlib.h>
4 #include <sys/mman.h>
5 #include <sys/eventfd.h>
6 
7 #define __EXPORTED_HEADERS__
8 #include <linux/vfio.h>
9 
10 #include "iommufd_utils.h"
11 
12 static void *buffer;
13 
14 static unsigned long PAGE_SIZE;
15 static unsigned long HUGEPAGE_SIZE;
16 
17 #define MOCK_PAGE_SIZE (PAGE_SIZE / 2)
18 
19 static unsigned long get_huge_page_size(void)
20 {
21 	char buf[80];
22 	int ret;
23 	int fd;
24 
25 	fd = open("/sys/kernel/mm/transparent_hugepage/hpage_pmd_size",
26 		  O_RDONLY);
27 	if (fd < 0)
28 		return 2 * 1024 * 1024;
29 
30 	ret = read(fd, buf, sizeof(buf));
31 	close(fd);
32 	if (ret <= 0 || ret == sizeof(buf))
33 		return 2 * 1024 * 1024;
34 	buf[ret] = 0;
35 	return strtoul(buf, NULL, 10);
36 }
37 
38 static __attribute__((constructor)) void setup_sizes(void)
39 {
40 	void *vrc;
41 	int rc;
42 
43 	PAGE_SIZE = sysconf(_SC_PAGE_SIZE);
44 	HUGEPAGE_SIZE = get_huge_page_size();
45 
46 	BUFFER_SIZE = PAGE_SIZE * 16;
47 	rc = posix_memalign(&buffer, HUGEPAGE_SIZE, BUFFER_SIZE);
48 	assert(!rc);
49 	assert(buffer);
50 	assert((uintptr_t)buffer % HUGEPAGE_SIZE == 0);
51 	vrc = mmap(buffer, BUFFER_SIZE, PROT_READ | PROT_WRITE,
52 		   MAP_SHARED | MAP_ANONYMOUS | MAP_FIXED, -1, 0);
53 	assert(vrc == buffer);
54 }
55 
56 FIXTURE(iommufd)
57 {
58 	int fd;
59 };
60 
61 FIXTURE_SETUP(iommufd)
62 {
63 	self->fd = open("/dev/iommu", O_RDWR);
64 	ASSERT_NE(-1, self->fd);
65 }
66 
67 FIXTURE_TEARDOWN(iommufd)
68 {
69 	teardown_iommufd(self->fd, _metadata);
70 }
71 
72 TEST_F(iommufd, simple_close)
73 {
74 }
75 
76 TEST_F(iommufd, cmd_fail)
77 {
78 	struct iommu_destroy cmd = { .size = sizeof(cmd), .id = 0 };
79 
80 	/* object id is invalid */
81 	EXPECT_ERRNO(ENOENT, _test_ioctl_destroy(self->fd, 0));
82 	/* Bad pointer */
83 	EXPECT_ERRNO(EFAULT, ioctl(self->fd, IOMMU_DESTROY, NULL));
84 	/* Unknown ioctl */
85 	EXPECT_ERRNO(ENOTTY,
86 		     ioctl(self->fd, _IO(IOMMUFD_TYPE, IOMMUFD_CMD_BASE - 1),
87 			   &cmd));
88 }
89 
90 TEST_F(iommufd, cmd_length)
91 {
92 #define TEST_LENGTH(_struct, _ioctl)                                     \
93 	{                                                                \
94 		struct {                                                 \
95 			struct _struct cmd;                              \
96 			uint8_t extra;                                   \
97 		} cmd = { .cmd = { .size = sizeof(struct _struct) - 1 }, \
98 			  .extra = UINT8_MAX };                          \
99 		int old_errno;                                           \
100 		int rc;                                                  \
101 									 \
102 		EXPECT_ERRNO(EINVAL, ioctl(self->fd, _ioctl, &cmd));     \
103 		cmd.cmd.size = sizeof(struct _struct) + 1;               \
104 		EXPECT_ERRNO(E2BIG, ioctl(self->fd, _ioctl, &cmd));      \
105 		cmd.cmd.size = sizeof(struct _struct);                   \
106 		rc = ioctl(self->fd, _ioctl, &cmd);                      \
107 		old_errno = errno;                                       \
108 		cmd.cmd.size = sizeof(struct _struct) + 1;               \
109 		cmd.extra = 0;                                           \
110 		if (rc) {                                                \
111 			EXPECT_ERRNO(old_errno,                          \
112 				     ioctl(self->fd, _ioctl, &cmd));     \
113 		} else {                                                 \
114 			ASSERT_EQ(0, ioctl(self->fd, _ioctl, &cmd));     \
115 		}                                                        \
116 	}
117 
118 	TEST_LENGTH(iommu_destroy, IOMMU_DESTROY);
119 	TEST_LENGTH(iommu_ioas_alloc, IOMMU_IOAS_ALLOC);
120 	TEST_LENGTH(iommu_ioas_iova_ranges, IOMMU_IOAS_IOVA_RANGES);
121 	TEST_LENGTH(iommu_ioas_allow_iovas, IOMMU_IOAS_ALLOW_IOVAS);
122 	TEST_LENGTH(iommu_ioas_map, IOMMU_IOAS_MAP);
123 	TEST_LENGTH(iommu_ioas_copy, IOMMU_IOAS_COPY);
124 	TEST_LENGTH(iommu_ioas_unmap, IOMMU_IOAS_UNMAP);
125 	TEST_LENGTH(iommu_option, IOMMU_OPTION);
126 	TEST_LENGTH(iommu_vfio_ioas, IOMMU_VFIO_IOAS);
127 #undef TEST_LENGTH
128 }
129 
130 TEST_F(iommufd, cmd_ex_fail)
131 {
132 	struct {
133 		struct iommu_destroy cmd;
134 		__u64 future;
135 	} cmd = { .cmd = { .size = sizeof(cmd), .id = 0 } };
136 
137 	/* object id is invalid and command is longer */
138 	EXPECT_ERRNO(ENOENT, ioctl(self->fd, IOMMU_DESTROY, &cmd));
139 	/* future area is non-zero */
140 	cmd.future = 1;
141 	EXPECT_ERRNO(E2BIG, ioctl(self->fd, IOMMU_DESTROY, &cmd));
142 	/* Original command "works" */
143 	cmd.cmd.size = sizeof(cmd.cmd);
144 	EXPECT_ERRNO(ENOENT, ioctl(self->fd, IOMMU_DESTROY, &cmd));
145 	/* Short command fails */
146 	cmd.cmd.size = sizeof(cmd.cmd) - 1;
147 	EXPECT_ERRNO(EINVAL, ioctl(self->fd, IOMMU_DESTROY, &cmd));
148 }
149 
150 TEST_F(iommufd, global_options)
151 {
152 	struct iommu_option cmd = {
153 		.size = sizeof(cmd),
154 		.option_id = IOMMU_OPTION_RLIMIT_MODE,
155 		.op = IOMMU_OPTION_OP_GET,
156 		.val64 = 1,
157 	};
158 
159 	cmd.option_id = IOMMU_OPTION_RLIMIT_MODE;
160 	ASSERT_EQ(0, ioctl(self->fd, IOMMU_OPTION, &cmd));
161 	ASSERT_EQ(0, cmd.val64);
162 
163 	/* This requires root */
164 	cmd.op = IOMMU_OPTION_OP_SET;
165 	cmd.val64 = 1;
166 	ASSERT_EQ(0, ioctl(self->fd, IOMMU_OPTION, &cmd));
167 	cmd.val64 = 2;
168 	EXPECT_ERRNO(EINVAL, ioctl(self->fd, IOMMU_OPTION, &cmd));
169 
170 	cmd.op = IOMMU_OPTION_OP_GET;
171 	ASSERT_EQ(0, ioctl(self->fd, IOMMU_OPTION, &cmd));
172 	ASSERT_EQ(1, cmd.val64);
173 
174 	cmd.op = IOMMU_OPTION_OP_SET;
175 	cmd.val64 = 0;
176 	ASSERT_EQ(0, ioctl(self->fd, IOMMU_OPTION, &cmd));
177 
178 	cmd.op = IOMMU_OPTION_OP_GET;
179 	cmd.option_id = IOMMU_OPTION_HUGE_PAGES;
180 	EXPECT_ERRNO(ENOENT, ioctl(self->fd, IOMMU_OPTION, &cmd));
181 	cmd.op = IOMMU_OPTION_OP_SET;
182 	EXPECT_ERRNO(ENOENT, ioctl(self->fd, IOMMU_OPTION, &cmd));
183 }
184 
185 FIXTURE(iommufd_ioas)
186 {
187 	int fd;
188 	uint32_t ioas_id;
189 	uint32_t domain_id;
190 	uint64_t base_iova;
191 };
192 
193 FIXTURE_VARIANT(iommufd_ioas)
194 {
195 	unsigned int mock_domains;
196 	unsigned int memory_limit;
197 };
198 
199 FIXTURE_SETUP(iommufd_ioas)
200 {
201 	unsigned int i;
202 
203 
204 	self->fd = open("/dev/iommu", O_RDWR);
205 	ASSERT_NE(-1, self->fd);
206 	test_ioctl_ioas_alloc(&self->ioas_id);
207 
208 	if (!variant->memory_limit) {
209 		test_ioctl_set_default_memory_limit();
210 	} else {
211 		test_ioctl_set_temp_memory_limit(variant->memory_limit);
212 	}
213 
214 	for (i = 0; i != variant->mock_domains; i++) {
215 		test_cmd_mock_domain(self->ioas_id, NULL, &self->domain_id);
216 		self->base_iova = MOCK_APERTURE_START;
217 	}
218 }
219 
220 FIXTURE_TEARDOWN(iommufd_ioas)
221 {
222 	test_ioctl_set_default_memory_limit();
223 	teardown_iommufd(self->fd, _metadata);
224 }
225 
226 FIXTURE_VARIANT_ADD(iommufd_ioas, no_domain)
227 {
228 };
229 
230 FIXTURE_VARIANT_ADD(iommufd_ioas, mock_domain)
231 {
232 	.mock_domains = 1,
233 };
234 
235 FIXTURE_VARIANT_ADD(iommufd_ioas, two_mock_domain)
236 {
237 	.mock_domains = 2,
238 };
239 
240 FIXTURE_VARIANT_ADD(iommufd_ioas, mock_domain_limit)
241 {
242 	.mock_domains = 1,
243 	.memory_limit = 16,
244 };
245 
246 TEST_F(iommufd_ioas, ioas_auto_destroy)
247 {
248 }
249 
250 TEST_F(iommufd_ioas, ioas_destroy)
251 {
252 	if (self->domain_id) {
253 		/* IOAS cannot be freed while a domain is on it */
254 		EXPECT_ERRNO(EBUSY,
255 			     _test_ioctl_destroy(self->fd, self->ioas_id));
256 	} else {
257 		/* Can allocate and manually free an IOAS table */
258 		test_ioctl_destroy(self->ioas_id);
259 	}
260 }
261 
262 TEST_F(iommufd_ioas, ioas_area_destroy)
263 {
264 	/* Adding an area does not change ability to destroy */
265 	test_ioctl_ioas_map_fixed(buffer, PAGE_SIZE, self->base_iova);
266 	if (self->domain_id)
267 		EXPECT_ERRNO(EBUSY,
268 			     _test_ioctl_destroy(self->fd, self->ioas_id));
269 	else
270 		test_ioctl_destroy(self->ioas_id);
271 }
272 
273 TEST_F(iommufd_ioas, ioas_area_auto_destroy)
274 {
275 	int i;
276 
277 	/* Can allocate and automatically free an IOAS table with many areas */
278 	for (i = 0; i != 10; i++) {
279 		test_ioctl_ioas_map_fixed(buffer, PAGE_SIZE,
280 					  self->base_iova + i * PAGE_SIZE);
281 	}
282 }
283 
284 TEST_F(iommufd_ioas, area)
285 {
286 	int i;
287 
288 	/* Unmap fails if nothing is mapped */
289 	for (i = 0; i != 10; i++)
290 		test_err_ioctl_ioas_unmap(ENOENT, i * PAGE_SIZE, PAGE_SIZE);
291 
292 	/* Unmap works */
293 	for (i = 0; i != 10; i++)
294 		test_ioctl_ioas_map_fixed(buffer, PAGE_SIZE,
295 					  self->base_iova + i * PAGE_SIZE);
296 	for (i = 0; i != 10; i++)
297 		test_ioctl_ioas_unmap(self->base_iova + i * PAGE_SIZE,
298 				      PAGE_SIZE);
299 
300 	/* Split fails */
301 	test_ioctl_ioas_map_fixed(buffer, PAGE_SIZE * 2,
302 				  self->base_iova + 16 * PAGE_SIZE);
303 	test_err_ioctl_ioas_unmap(ENOENT, self->base_iova + 16 * PAGE_SIZE,
304 				  PAGE_SIZE);
305 	test_err_ioctl_ioas_unmap(ENOENT, self->base_iova + 17 * PAGE_SIZE,
306 				  PAGE_SIZE);
307 
308 	/* Over map fails */
309 	test_err_ioctl_ioas_map_fixed(EEXIST, buffer, PAGE_SIZE * 2,
310 				      self->base_iova + 16 * PAGE_SIZE);
311 	test_err_ioctl_ioas_map_fixed(EEXIST, buffer, PAGE_SIZE,
312 				      self->base_iova + 16 * PAGE_SIZE);
313 	test_err_ioctl_ioas_map_fixed(EEXIST, buffer, PAGE_SIZE,
314 				      self->base_iova + 17 * PAGE_SIZE);
315 	test_err_ioctl_ioas_map_fixed(EEXIST, buffer, PAGE_SIZE * 2,
316 				      self->base_iova + 15 * PAGE_SIZE);
317 	test_err_ioctl_ioas_map_fixed(EEXIST, buffer, PAGE_SIZE * 3,
318 				      self->base_iova + 15 * PAGE_SIZE);
319 
320 	/* unmap all works */
321 	test_ioctl_ioas_unmap(0, UINT64_MAX);
322 
323 	/* Unmap all succeeds on an empty IOAS */
324 	test_ioctl_ioas_unmap(0, UINT64_MAX);
325 }
326 
327 TEST_F(iommufd_ioas, unmap_fully_contained_areas)
328 {
329 	uint64_t unmap_len;
330 	int i;
331 
332 	/* Give no_domain some space to rewind base_iova */
333 	self->base_iova += 4 * PAGE_SIZE;
334 
335 	for (i = 0; i != 4; i++)
336 		test_ioctl_ioas_map_fixed(buffer, 8 * PAGE_SIZE,
337 					  self->base_iova + i * 16 * PAGE_SIZE);
338 
339 	/* Unmap not fully contained area doesn't work */
340 	test_err_ioctl_ioas_unmap(ENOENT, self->base_iova - 4 * PAGE_SIZE,
341 				  8 * PAGE_SIZE);
342 	test_err_ioctl_ioas_unmap(ENOENT,
343 				  self->base_iova + 3 * 16 * PAGE_SIZE +
344 					  8 * PAGE_SIZE - 4 * PAGE_SIZE,
345 				  8 * PAGE_SIZE);
346 
347 	/* Unmap fully contained areas works */
348 	ASSERT_EQ(0, _test_ioctl_ioas_unmap(self->fd, self->ioas_id,
349 					    self->base_iova - 4 * PAGE_SIZE,
350 					    3 * 16 * PAGE_SIZE + 8 * PAGE_SIZE +
351 						    4 * PAGE_SIZE,
352 					    &unmap_len));
353 	ASSERT_EQ(32 * PAGE_SIZE, unmap_len);
354 }
355 
356 TEST_F(iommufd_ioas, area_auto_iova)
357 {
358 	struct iommu_test_cmd test_cmd = {
359 		.size = sizeof(test_cmd),
360 		.op = IOMMU_TEST_OP_ADD_RESERVED,
361 		.id = self->ioas_id,
362 		.add_reserved = { .start = PAGE_SIZE * 4,
363 				  .length = PAGE_SIZE * 100 },
364 	};
365 	struct iommu_iova_range ranges[1] = {};
366 	struct iommu_ioas_allow_iovas allow_cmd = {
367 		.size = sizeof(allow_cmd),
368 		.ioas_id = self->ioas_id,
369 		.num_iovas = 1,
370 		.allowed_iovas = (uintptr_t)ranges,
371 	};
372 	__u64 iovas[10];
373 	int i;
374 
375 	/* Simple 4k pages */
376 	for (i = 0; i != 10; i++)
377 		test_ioctl_ioas_map(buffer, PAGE_SIZE, &iovas[i]);
378 	for (i = 0; i != 10; i++)
379 		test_ioctl_ioas_unmap(iovas[i], PAGE_SIZE);
380 
381 	/* Kernel automatically aligns IOVAs properly */
382 	for (i = 0; i != 10; i++) {
383 		size_t length = PAGE_SIZE * (i + 1);
384 
385 		if (self->domain_id) {
386 			test_ioctl_ioas_map(buffer, length, &iovas[i]);
387 		} else {
388 			test_ioctl_ioas_map((void *)(1UL << 31), length,
389 					    &iovas[i]);
390 		}
391 		EXPECT_EQ(0, iovas[i] % (1UL << (ffs(length) - 1)));
392 	}
393 	for (i = 0; i != 10; i++)
394 		test_ioctl_ioas_unmap(iovas[i], PAGE_SIZE * (i + 1));
395 
396 	/* Avoids a reserved region */
397 	ASSERT_EQ(0,
398 		  ioctl(self->fd, _IOMMU_TEST_CMD(IOMMU_TEST_OP_ADD_RESERVED),
399 			&test_cmd));
400 	for (i = 0; i != 10; i++) {
401 		size_t length = PAGE_SIZE * (i + 1);
402 
403 		test_ioctl_ioas_map(buffer, length, &iovas[i]);
404 		EXPECT_EQ(0, iovas[i] % (1UL << (ffs(length) - 1)));
405 		EXPECT_EQ(false,
406 			  iovas[i] > test_cmd.add_reserved.start &&
407 				  iovas[i] <
408 					  test_cmd.add_reserved.start +
409 						  test_cmd.add_reserved.length);
410 	}
411 	for (i = 0; i != 10; i++)
412 		test_ioctl_ioas_unmap(iovas[i], PAGE_SIZE * (i + 1));
413 
414 	/* Allowed region intersects with a reserved region */
415 	ranges[0].start = PAGE_SIZE;
416 	ranges[0].last = PAGE_SIZE * 600;
417 	EXPECT_ERRNO(EADDRINUSE,
418 		     ioctl(self->fd, IOMMU_IOAS_ALLOW_IOVAS, &allow_cmd));
419 
420 	/* Allocate from an allowed region */
421 	if (self->domain_id) {
422 		ranges[0].start = MOCK_APERTURE_START + PAGE_SIZE;
423 		ranges[0].last = MOCK_APERTURE_START + PAGE_SIZE * 600 - 1;
424 	} else {
425 		ranges[0].start = PAGE_SIZE * 200;
426 		ranges[0].last = PAGE_SIZE * 600 - 1;
427 	}
428 	ASSERT_EQ(0, ioctl(self->fd, IOMMU_IOAS_ALLOW_IOVAS, &allow_cmd));
429 	for (i = 0; i != 10; i++) {
430 		size_t length = PAGE_SIZE * (i + 1);
431 
432 		test_ioctl_ioas_map(buffer, length, &iovas[i]);
433 		EXPECT_EQ(0, iovas[i] % (1UL << (ffs(length) - 1)));
434 		EXPECT_EQ(true, iovas[i] >= ranges[0].start);
435 		EXPECT_EQ(true, iovas[i] <= ranges[0].last);
436 		EXPECT_EQ(true, iovas[i] + length > ranges[0].start);
437 		EXPECT_EQ(true, iovas[i] + length <= ranges[0].last + 1);
438 	}
439 	for (i = 0; i != 10; i++)
440 		test_ioctl_ioas_unmap(iovas[i], PAGE_SIZE * (i + 1));
441 }
442 
443 TEST_F(iommufd_ioas, area_allowed)
444 {
445 	struct iommu_test_cmd test_cmd = {
446 		.size = sizeof(test_cmd),
447 		.op = IOMMU_TEST_OP_ADD_RESERVED,
448 		.id = self->ioas_id,
449 		.add_reserved = { .start = PAGE_SIZE * 4,
450 				  .length = PAGE_SIZE * 100 },
451 	};
452 	struct iommu_iova_range ranges[1] = {};
453 	struct iommu_ioas_allow_iovas allow_cmd = {
454 		.size = sizeof(allow_cmd),
455 		.ioas_id = self->ioas_id,
456 		.num_iovas = 1,
457 		.allowed_iovas = (uintptr_t)ranges,
458 	};
459 
460 	/* Reserved intersects an allowed */
461 	allow_cmd.num_iovas = 1;
462 	ranges[0].start = self->base_iova;
463 	ranges[0].last = ranges[0].start + PAGE_SIZE * 600;
464 	ASSERT_EQ(0, ioctl(self->fd, IOMMU_IOAS_ALLOW_IOVAS, &allow_cmd));
465 	test_cmd.add_reserved.start = ranges[0].start + PAGE_SIZE;
466 	test_cmd.add_reserved.length = PAGE_SIZE;
467 	EXPECT_ERRNO(EADDRINUSE,
468 		     ioctl(self->fd,
469 			   _IOMMU_TEST_CMD(IOMMU_TEST_OP_ADD_RESERVED),
470 			   &test_cmd));
471 	allow_cmd.num_iovas = 0;
472 	ASSERT_EQ(0, ioctl(self->fd, IOMMU_IOAS_ALLOW_IOVAS, &allow_cmd));
473 
474 	/* Allowed intersects a reserved */
475 	ASSERT_EQ(0,
476 		  ioctl(self->fd, _IOMMU_TEST_CMD(IOMMU_TEST_OP_ADD_RESERVED),
477 			&test_cmd));
478 	allow_cmd.num_iovas = 1;
479 	ranges[0].start = self->base_iova;
480 	ranges[0].last = ranges[0].start + PAGE_SIZE * 600;
481 	EXPECT_ERRNO(EADDRINUSE,
482 		     ioctl(self->fd, IOMMU_IOAS_ALLOW_IOVAS, &allow_cmd));
483 }
484 
485 TEST_F(iommufd_ioas, copy_area)
486 {
487 	struct iommu_ioas_copy copy_cmd = {
488 		.size = sizeof(copy_cmd),
489 		.flags = IOMMU_IOAS_MAP_FIXED_IOVA,
490 		.dst_ioas_id = self->ioas_id,
491 		.src_ioas_id = self->ioas_id,
492 		.length = PAGE_SIZE,
493 	};
494 
495 	test_ioctl_ioas_map_fixed(buffer, PAGE_SIZE, self->base_iova);
496 
497 	/* Copy inside a single IOAS */
498 	copy_cmd.src_iova = self->base_iova;
499 	copy_cmd.dst_iova = self->base_iova + PAGE_SIZE;
500 	ASSERT_EQ(0, ioctl(self->fd, IOMMU_IOAS_COPY, &copy_cmd));
501 
502 	/* Copy between IOAS's */
503 	copy_cmd.src_iova = self->base_iova;
504 	copy_cmd.dst_iova = 0;
505 	test_ioctl_ioas_alloc(&copy_cmd.dst_ioas_id);
506 	ASSERT_EQ(0, ioctl(self->fd, IOMMU_IOAS_COPY, &copy_cmd));
507 }
508 
509 TEST_F(iommufd_ioas, iova_ranges)
510 {
511 	struct iommu_test_cmd test_cmd = {
512 		.size = sizeof(test_cmd),
513 		.op = IOMMU_TEST_OP_ADD_RESERVED,
514 		.id = self->ioas_id,
515 		.add_reserved = { .start = PAGE_SIZE, .length = PAGE_SIZE },
516 	};
517 	struct iommu_iova_range *ranges = buffer;
518 	struct iommu_ioas_iova_ranges ranges_cmd = {
519 		.size = sizeof(ranges_cmd),
520 		.ioas_id = self->ioas_id,
521 		.num_iovas = BUFFER_SIZE / sizeof(*ranges),
522 		.allowed_iovas = (uintptr_t)ranges,
523 	};
524 
525 	/* Range can be read */
526 	ASSERT_EQ(0, ioctl(self->fd, IOMMU_IOAS_IOVA_RANGES, &ranges_cmd));
527 	EXPECT_EQ(1, ranges_cmd.num_iovas);
528 	if (!self->domain_id) {
529 		EXPECT_EQ(0, ranges[0].start);
530 		EXPECT_EQ(SIZE_MAX, ranges[0].last);
531 		EXPECT_EQ(1, ranges_cmd.out_iova_alignment);
532 	} else {
533 		EXPECT_EQ(MOCK_APERTURE_START, ranges[0].start);
534 		EXPECT_EQ(MOCK_APERTURE_LAST, ranges[0].last);
535 		EXPECT_EQ(MOCK_PAGE_SIZE, ranges_cmd.out_iova_alignment);
536 	}
537 
538 	/* Buffer too small */
539 	memset(ranges, 0, BUFFER_SIZE);
540 	ranges_cmd.num_iovas = 0;
541 	EXPECT_ERRNO(EMSGSIZE,
542 		     ioctl(self->fd, IOMMU_IOAS_IOVA_RANGES, &ranges_cmd));
543 	EXPECT_EQ(1, ranges_cmd.num_iovas);
544 	EXPECT_EQ(0, ranges[0].start);
545 	EXPECT_EQ(0, ranges[0].last);
546 
547 	/* 2 ranges */
548 	ASSERT_EQ(0,
549 		  ioctl(self->fd, _IOMMU_TEST_CMD(IOMMU_TEST_OP_ADD_RESERVED),
550 			&test_cmd));
551 	ranges_cmd.num_iovas = BUFFER_SIZE / sizeof(*ranges);
552 	ASSERT_EQ(0, ioctl(self->fd, IOMMU_IOAS_IOVA_RANGES, &ranges_cmd));
553 	if (!self->domain_id) {
554 		EXPECT_EQ(2, ranges_cmd.num_iovas);
555 		EXPECT_EQ(0, ranges[0].start);
556 		EXPECT_EQ(PAGE_SIZE - 1, ranges[0].last);
557 		EXPECT_EQ(PAGE_SIZE * 2, ranges[1].start);
558 		EXPECT_EQ(SIZE_MAX, ranges[1].last);
559 	} else {
560 		EXPECT_EQ(1, ranges_cmd.num_iovas);
561 		EXPECT_EQ(MOCK_APERTURE_START, ranges[0].start);
562 		EXPECT_EQ(MOCK_APERTURE_LAST, ranges[0].last);
563 	}
564 
565 	/* Buffer too small */
566 	memset(ranges, 0, BUFFER_SIZE);
567 	ranges_cmd.num_iovas = 1;
568 	if (!self->domain_id) {
569 		EXPECT_ERRNO(EMSGSIZE, ioctl(self->fd, IOMMU_IOAS_IOVA_RANGES,
570 					     &ranges_cmd));
571 		EXPECT_EQ(2, ranges_cmd.num_iovas);
572 		EXPECT_EQ(0, ranges[0].start);
573 		EXPECT_EQ(PAGE_SIZE - 1, ranges[0].last);
574 	} else {
575 		ASSERT_EQ(0,
576 			  ioctl(self->fd, IOMMU_IOAS_IOVA_RANGES, &ranges_cmd));
577 		EXPECT_EQ(1, ranges_cmd.num_iovas);
578 		EXPECT_EQ(MOCK_APERTURE_START, ranges[0].start);
579 		EXPECT_EQ(MOCK_APERTURE_LAST, ranges[0].last);
580 	}
581 	EXPECT_EQ(0, ranges[1].start);
582 	EXPECT_EQ(0, ranges[1].last);
583 }
584 
585 TEST_F(iommufd_ioas, access_pin)
586 {
587 	struct iommu_test_cmd access_cmd = {
588 		.size = sizeof(access_cmd),
589 		.op = IOMMU_TEST_OP_ACCESS_PAGES,
590 		.access_pages = { .iova = MOCK_APERTURE_START,
591 				  .length = BUFFER_SIZE,
592 				  .uptr = (uintptr_t)buffer },
593 	};
594 	struct iommu_test_cmd check_map_cmd = {
595 		.size = sizeof(check_map_cmd),
596 		.op = IOMMU_TEST_OP_MD_CHECK_MAP,
597 		.check_map = { .iova = MOCK_APERTURE_START,
598 			       .length = BUFFER_SIZE,
599 			       .uptr = (uintptr_t)buffer },
600 	};
601 	uint32_t access_pages_id;
602 	unsigned int npages;
603 
604 	test_cmd_create_access(self->ioas_id, &access_cmd.id,
605 			       MOCK_FLAGS_ACCESS_CREATE_NEEDS_PIN_PAGES);
606 
607 	for (npages = 1; npages < BUFFER_SIZE / PAGE_SIZE; npages++) {
608 		uint32_t mock_device_id;
609 		uint32_t mock_hwpt_id;
610 
611 		access_cmd.access_pages.length = npages * PAGE_SIZE;
612 
613 		/* Single map/unmap */
614 		test_ioctl_ioas_map_fixed(buffer, BUFFER_SIZE,
615 					  MOCK_APERTURE_START);
616 		ASSERT_EQ(0, ioctl(self->fd,
617 				   _IOMMU_TEST_CMD(IOMMU_TEST_OP_ACCESS_PAGES),
618 				   &access_cmd));
619 		test_cmd_destroy_access_pages(
620 			access_cmd.id,
621 			access_cmd.access_pages.out_access_pages_id);
622 
623 		/* Double user */
624 		ASSERT_EQ(0, ioctl(self->fd,
625 				   _IOMMU_TEST_CMD(IOMMU_TEST_OP_ACCESS_PAGES),
626 				   &access_cmd));
627 		access_pages_id = access_cmd.access_pages.out_access_pages_id;
628 		ASSERT_EQ(0, ioctl(self->fd,
629 				   _IOMMU_TEST_CMD(IOMMU_TEST_OP_ACCESS_PAGES),
630 				   &access_cmd));
631 		test_cmd_destroy_access_pages(
632 			access_cmd.id,
633 			access_cmd.access_pages.out_access_pages_id);
634 		test_cmd_destroy_access_pages(access_cmd.id, access_pages_id);
635 
636 		/* Add/remove a domain with a user */
637 		ASSERT_EQ(0, ioctl(self->fd,
638 				   _IOMMU_TEST_CMD(IOMMU_TEST_OP_ACCESS_PAGES),
639 				   &access_cmd));
640 		test_cmd_mock_domain(self->ioas_id, &mock_device_id,
641 				     &mock_hwpt_id);
642 		check_map_cmd.id = mock_hwpt_id;
643 		ASSERT_EQ(0, ioctl(self->fd,
644 				   _IOMMU_TEST_CMD(IOMMU_TEST_OP_MD_CHECK_MAP),
645 				   &check_map_cmd));
646 
647 		test_ioctl_destroy(mock_device_id);
648 		test_ioctl_destroy(mock_hwpt_id);
649 		test_cmd_destroy_access_pages(
650 			access_cmd.id,
651 			access_cmd.access_pages.out_access_pages_id);
652 
653 		test_ioctl_ioas_unmap(MOCK_APERTURE_START, BUFFER_SIZE);
654 	}
655 	test_cmd_destroy_access(access_cmd.id);
656 }
657 
658 TEST_F(iommufd_ioas, access_pin_unmap)
659 {
660 	struct iommu_test_cmd access_pages_cmd = {
661 		.size = sizeof(access_pages_cmd),
662 		.op = IOMMU_TEST_OP_ACCESS_PAGES,
663 		.access_pages = { .iova = MOCK_APERTURE_START,
664 				  .length = BUFFER_SIZE,
665 				  .uptr = (uintptr_t)buffer },
666 	};
667 
668 	test_cmd_create_access(self->ioas_id, &access_pages_cmd.id,
669 			       MOCK_FLAGS_ACCESS_CREATE_NEEDS_PIN_PAGES);
670 	test_ioctl_ioas_map_fixed(buffer, BUFFER_SIZE, MOCK_APERTURE_START);
671 	ASSERT_EQ(0,
672 		  ioctl(self->fd, _IOMMU_TEST_CMD(IOMMU_TEST_OP_ACCESS_PAGES),
673 			&access_pages_cmd));
674 
675 	/* Trigger the unmap op */
676 	test_ioctl_ioas_unmap(MOCK_APERTURE_START, BUFFER_SIZE);
677 
678 	/* kernel removed the item for us */
679 	test_err_destroy_access_pages(
680 		ENOENT, access_pages_cmd.id,
681 		access_pages_cmd.access_pages.out_access_pages_id);
682 }
683 
684 static void check_access_rw(struct __test_metadata *_metadata, int fd,
685 			    unsigned int access_id, uint64_t iova,
686 			    unsigned int def_flags)
687 {
688 	uint16_t tmp[32];
689 	struct iommu_test_cmd access_cmd = {
690 		.size = sizeof(access_cmd),
691 		.op = IOMMU_TEST_OP_ACCESS_RW,
692 		.id = access_id,
693 		.access_rw = { .uptr = (uintptr_t)tmp },
694 	};
695 	uint16_t *buffer16 = buffer;
696 	unsigned int i;
697 	void *tmp2;
698 
699 	for (i = 0; i != BUFFER_SIZE / sizeof(*buffer16); i++)
700 		buffer16[i] = rand();
701 
702 	for (access_cmd.access_rw.iova = iova + PAGE_SIZE - 50;
703 	     access_cmd.access_rw.iova < iova + PAGE_SIZE + 50;
704 	     access_cmd.access_rw.iova++) {
705 		for (access_cmd.access_rw.length = 1;
706 		     access_cmd.access_rw.length < sizeof(tmp);
707 		     access_cmd.access_rw.length++) {
708 			access_cmd.access_rw.flags = def_flags;
709 			ASSERT_EQ(0, ioctl(fd,
710 					   _IOMMU_TEST_CMD(
711 						   IOMMU_TEST_OP_ACCESS_RW),
712 					   &access_cmd));
713 			ASSERT_EQ(0,
714 				  memcmp(buffer + (access_cmd.access_rw.iova -
715 						   iova),
716 					 tmp, access_cmd.access_rw.length));
717 
718 			for (i = 0; i != ARRAY_SIZE(tmp); i++)
719 				tmp[i] = rand();
720 			access_cmd.access_rw.flags = def_flags |
721 						     MOCK_ACCESS_RW_WRITE;
722 			ASSERT_EQ(0, ioctl(fd,
723 					   _IOMMU_TEST_CMD(
724 						   IOMMU_TEST_OP_ACCESS_RW),
725 					   &access_cmd));
726 			ASSERT_EQ(0,
727 				  memcmp(buffer + (access_cmd.access_rw.iova -
728 						   iova),
729 					 tmp, access_cmd.access_rw.length));
730 		}
731 	}
732 
733 	/* Multi-page test */
734 	tmp2 = malloc(BUFFER_SIZE);
735 	ASSERT_NE(NULL, tmp2);
736 	access_cmd.access_rw.iova = iova;
737 	access_cmd.access_rw.length = BUFFER_SIZE;
738 	access_cmd.access_rw.flags = def_flags;
739 	access_cmd.access_rw.uptr = (uintptr_t)tmp2;
740 	ASSERT_EQ(0, ioctl(fd, _IOMMU_TEST_CMD(IOMMU_TEST_OP_ACCESS_RW),
741 			   &access_cmd));
742 	ASSERT_EQ(0, memcmp(buffer, tmp2, access_cmd.access_rw.length));
743 	free(tmp2);
744 }
745 
746 TEST_F(iommufd_ioas, access_rw)
747 {
748 	__u32 access_id;
749 	__u64 iova;
750 
751 	test_cmd_create_access(self->ioas_id, &access_id, 0);
752 	test_ioctl_ioas_map(buffer, BUFFER_SIZE, &iova);
753 	check_access_rw(_metadata, self->fd, access_id, iova, 0);
754 	check_access_rw(_metadata, self->fd, access_id, iova,
755 			MOCK_ACCESS_RW_SLOW_PATH);
756 	test_ioctl_ioas_unmap(iova, BUFFER_SIZE);
757 	test_cmd_destroy_access(access_id);
758 }
759 
760 TEST_F(iommufd_ioas, access_rw_unaligned)
761 {
762 	__u32 access_id;
763 	__u64 iova;
764 
765 	test_cmd_create_access(self->ioas_id, &access_id, 0);
766 
767 	/* Unaligned pages */
768 	iova = self->base_iova + MOCK_PAGE_SIZE;
769 	test_ioctl_ioas_map_fixed(buffer, BUFFER_SIZE, iova);
770 	check_access_rw(_metadata, self->fd, access_id, iova, 0);
771 	test_ioctl_ioas_unmap(iova, BUFFER_SIZE);
772 	test_cmd_destroy_access(access_id);
773 }
774 
775 TEST_F(iommufd_ioas, fork_gone)
776 {
777 	__u32 access_id;
778 	pid_t child;
779 
780 	test_cmd_create_access(self->ioas_id, &access_id, 0);
781 
782 	/* Create a mapping with a different mm */
783 	child = fork();
784 	if (!child) {
785 		test_ioctl_ioas_map_fixed(buffer, BUFFER_SIZE,
786 					  MOCK_APERTURE_START);
787 		exit(0);
788 	}
789 	ASSERT_NE(-1, child);
790 	ASSERT_EQ(child, waitpid(child, NULL, 0));
791 
792 	if (self->domain_id) {
793 		/*
794 		 * If a domain already existed then everything was pinned within
795 		 * the fork, so this copies from one domain to another.
796 		 */
797 		test_cmd_mock_domain(self->ioas_id, NULL, NULL);
798 		check_access_rw(_metadata, self->fd, access_id,
799 				MOCK_APERTURE_START, 0);
800 
801 	} else {
802 		/*
803 		 * Otherwise we need to actually pin pages which can't happen
804 		 * since the fork is gone.
805 		 */
806 		test_err_mock_domain(EFAULT, self->ioas_id, NULL, NULL);
807 	}
808 
809 	test_cmd_destroy_access(access_id);
810 }
811 
812 TEST_F(iommufd_ioas, fork_present)
813 {
814 	__u32 access_id;
815 	int pipefds[2];
816 	uint64_t tmp;
817 	pid_t child;
818 	int efd;
819 
820 	test_cmd_create_access(self->ioas_id, &access_id, 0);
821 
822 	ASSERT_EQ(0, pipe2(pipefds, O_CLOEXEC));
823 	efd = eventfd(0, EFD_CLOEXEC);
824 	ASSERT_NE(-1, efd);
825 
826 	/* Create a mapping with a different mm */
827 	child = fork();
828 	if (!child) {
829 		__u64 iova;
830 		uint64_t one = 1;
831 
832 		close(pipefds[1]);
833 		test_ioctl_ioas_map_fixed(buffer, BUFFER_SIZE,
834 					  MOCK_APERTURE_START);
835 		if (write(efd, &one, sizeof(one)) != sizeof(one))
836 			exit(100);
837 		if (read(pipefds[0], &iova, 1) != 1)
838 			exit(100);
839 		exit(0);
840 	}
841 	close(pipefds[0]);
842 	ASSERT_NE(-1, child);
843 	ASSERT_EQ(8, read(efd, &tmp, sizeof(tmp)));
844 
845 	/* Read pages from the remote process */
846 	test_cmd_mock_domain(self->ioas_id, NULL, NULL);
847 	check_access_rw(_metadata, self->fd, access_id, MOCK_APERTURE_START, 0);
848 
849 	ASSERT_EQ(0, close(pipefds[1]));
850 	ASSERT_EQ(child, waitpid(child, NULL, 0));
851 
852 	test_cmd_destroy_access(access_id);
853 }
854 
855 TEST_F(iommufd_ioas, ioas_option_huge_pages)
856 {
857 	struct iommu_option cmd = {
858 		.size = sizeof(cmd),
859 		.option_id = IOMMU_OPTION_HUGE_PAGES,
860 		.op = IOMMU_OPTION_OP_GET,
861 		.val64 = 3,
862 		.object_id = self->ioas_id,
863 	};
864 
865 	ASSERT_EQ(0, ioctl(self->fd, IOMMU_OPTION, &cmd));
866 	ASSERT_EQ(1, cmd.val64);
867 
868 	cmd.op = IOMMU_OPTION_OP_SET;
869 	cmd.val64 = 0;
870 	ASSERT_EQ(0, ioctl(self->fd, IOMMU_OPTION, &cmd));
871 
872 	cmd.op = IOMMU_OPTION_OP_GET;
873 	cmd.val64 = 3;
874 	ASSERT_EQ(0, ioctl(self->fd, IOMMU_OPTION, &cmd));
875 	ASSERT_EQ(0, cmd.val64);
876 
877 	cmd.op = IOMMU_OPTION_OP_SET;
878 	cmd.val64 = 2;
879 	EXPECT_ERRNO(EINVAL, ioctl(self->fd, IOMMU_OPTION, &cmd));
880 
881 	cmd.op = IOMMU_OPTION_OP_SET;
882 	cmd.val64 = 1;
883 	ASSERT_EQ(0, ioctl(self->fd, IOMMU_OPTION, &cmd));
884 }
885 
886 TEST_F(iommufd_ioas, ioas_iova_alloc)
887 {
888 	unsigned int length;
889 	__u64 iova;
890 
891 	for (length = 1; length != PAGE_SIZE * 2; length++) {
892 		if (variant->mock_domains && (length % MOCK_PAGE_SIZE)) {
893 			test_err_ioctl_ioas_map(EINVAL, buffer, length, &iova);
894 		} else {
895 			test_ioctl_ioas_map(buffer, length, &iova);
896 			test_ioctl_ioas_unmap(iova, length);
897 		}
898 	}
899 }
900 
901 TEST_F(iommufd_ioas, ioas_align_change)
902 {
903 	struct iommu_option cmd = {
904 		.size = sizeof(cmd),
905 		.option_id = IOMMU_OPTION_HUGE_PAGES,
906 		.op = IOMMU_OPTION_OP_SET,
907 		.object_id = self->ioas_id,
908 		/* 0 means everything must be aligned to PAGE_SIZE */
909 		.val64 = 0,
910 	};
911 
912 	/*
913 	 * We cannot upgrade the alignment using OPTION_HUGE_PAGES when a domain
914 	 * and map are present.
915 	 */
916 	if (variant->mock_domains)
917 		return;
918 
919 	/*
920 	 * We can upgrade to PAGE_SIZE alignment when things are aligned right
921 	 */
922 	test_ioctl_ioas_map_fixed(buffer, PAGE_SIZE, MOCK_APERTURE_START);
923 	ASSERT_EQ(0, ioctl(self->fd, IOMMU_OPTION, &cmd));
924 
925 	/* Misalignment is rejected at map time */
926 	test_err_ioctl_ioas_map_fixed(EINVAL, buffer + MOCK_PAGE_SIZE,
927 				      PAGE_SIZE,
928 				      MOCK_APERTURE_START + PAGE_SIZE);
929 	ASSERT_EQ(0, ioctl(self->fd, IOMMU_OPTION, &cmd));
930 
931 	/* Reduce alignment */
932 	cmd.val64 = 1;
933 	ASSERT_EQ(0, ioctl(self->fd, IOMMU_OPTION, &cmd));
934 
935 	/* Confirm misalignment is rejected during alignment upgrade */
936 	test_ioctl_ioas_map_fixed(buffer + MOCK_PAGE_SIZE, PAGE_SIZE,
937 				  MOCK_APERTURE_START + PAGE_SIZE);
938 	cmd.val64 = 0;
939 	EXPECT_ERRNO(EADDRINUSE, ioctl(self->fd, IOMMU_OPTION, &cmd));
940 
941 	test_ioctl_ioas_unmap(MOCK_APERTURE_START + PAGE_SIZE, PAGE_SIZE);
942 	test_ioctl_ioas_unmap(MOCK_APERTURE_START, PAGE_SIZE);
943 }
944 
945 TEST_F(iommufd_ioas, copy_sweep)
946 {
947 	struct iommu_ioas_copy copy_cmd = {
948 		.size = sizeof(copy_cmd),
949 		.flags = IOMMU_IOAS_MAP_FIXED_IOVA,
950 		.src_ioas_id = self->ioas_id,
951 		.dst_iova = MOCK_APERTURE_START,
952 		.length = MOCK_PAGE_SIZE,
953 	};
954 	unsigned int dst_ioas_id;
955 	uint64_t last_iova;
956 	uint64_t iova;
957 
958 	test_ioctl_ioas_alloc(&dst_ioas_id);
959 	copy_cmd.dst_ioas_id = dst_ioas_id;
960 
961 	if (variant->mock_domains)
962 		last_iova = MOCK_APERTURE_START + BUFFER_SIZE - 1;
963 	else
964 		last_iova = MOCK_APERTURE_START + BUFFER_SIZE - 2;
965 
966 	test_ioctl_ioas_map_fixed(buffer, last_iova - MOCK_APERTURE_START + 1,
967 				  MOCK_APERTURE_START);
968 
969 	for (iova = MOCK_APERTURE_START - PAGE_SIZE; iova <= last_iova;
970 	     iova += 511) {
971 		copy_cmd.src_iova = iova;
972 		if (iova < MOCK_APERTURE_START ||
973 		    iova + copy_cmd.length - 1 > last_iova) {
974 			EXPECT_ERRNO(ENOENT, ioctl(self->fd, IOMMU_IOAS_COPY,
975 						   &copy_cmd));
976 		} else {
977 			ASSERT_EQ(0,
978 				  ioctl(self->fd, IOMMU_IOAS_COPY, &copy_cmd));
979 			test_ioctl_ioas_unmap_id(dst_ioas_id, copy_cmd.dst_iova,
980 						 copy_cmd.length);
981 		}
982 	}
983 
984 	test_ioctl_destroy(dst_ioas_id);
985 }
986 
987 FIXTURE(iommufd_mock_domain)
988 {
989 	int fd;
990 	uint32_t ioas_id;
991 	uint32_t domain_id;
992 	uint32_t domain_ids[2];
993 	int mmap_flags;
994 	size_t mmap_buf_size;
995 };
996 
997 FIXTURE_VARIANT(iommufd_mock_domain)
998 {
999 	unsigned int mock_domains;
1000 	bool hugepages;
1001 };
1002 
1003 FIXTURE_SETUP(iommufd_mock_domain)
1004 {
1005 	unsigned int i;
1006 
1007 	self->fd = open("/dev/iommu", O_RDWR);
1008 	ASSERT_NE(-1, self->fd);
1009 	test_ioctl_ioas_alloc(&self->ioas_id);
1010 
1011 	ASSERT_GE(ARRAY_SIZE(self->domain_ids), variant->mock_domains);
1012 
1013 	for (i = 0; i != variant->mock_domains; i++)
1014 		test_cmd_mock_domain(self->ioas_id, NULL, &self->domain_ids[i]);
1015 	self->domain_id = self->domain_ids[0];
1016 
1017 	self->mmap_flags = MAP_SHARED | MAP_ANONYMOUS;
1018 	self->mmap_buf_size = PAGE_SIZE * 8;
1019 	if (variant->hugepages) {
1020 		/*
1021 		 * MAP_POPULATE will cause the kernel to fail mmap if THPs are
1022 		 * not available.
1023 		 */
1024 		self->mmap_flags |= MAP_HUGETLB | MAP_POPULATE;
1025 		self->mmap_buf_size = HUGEPAGE_SIZE * 2;
1026 	}
1027 }
1028 
1029 FIXTURE_TEARDOWN(iommufd_mock_domain)
1030 {
1031 	teardown_iommufd(self->fd, _metadata);
1032 }
1033 
1034 FIXTURE_VARIANT_ADD(iommufd_mock_domain, one_domain)
1035 {
1036 	.mock_domains = 1,
1037 	.hugepages = false,
1038 };
1039 
1040 FIXTURE_VARIANT_ADD(iommufd_mock_domain, two_domains)
1041 {
1042 	.mock_domains = 2,
1043 	.hugepages = false,
1044 };
1045 
1046 FIXTURE_VARIANT_ADD(iommufd_mock_domain, one_domain_hugepage)
1047 {
1048 	.mock_domains = 1,
1049 	.hugepages = true,
1050 };
1051 
1052 FIXTURE_VARIANT_ADD(iommufd_mock_domain, two_domains_hugepage)
1053 {
1054 	.mock_domains = 2,
1055 	.hugepages = true,
1056 };
1057 
1058 /* Have the kernel check that the user pages made it to the iommu_domain */
1059 #define check_mock_iova(_ptr, _iova, _length)                                \
1060 	({                                                                   \
1061 		struct iommu_test_cmd check_map_cmd = {                      \
1062 			.size = sizeof(check_map_cmd),                       \
1063 			.op = IOMMU_TEST_OP_MD_CHECK_MAP,                    \
1064 			.id = self->domain_id,                               \
1065 			.check_map = { .iova = _iova,                        \
1066 				       .length = _length,                    \
1067 				       .uptr = (uintptr_t)(_ptr) },          \
1068 		};                                                           \
1069 		ASSERT_EQ(0,                                                 \
1070 			  ioctl(self->fd,                                    \
1071 				_IOMMU_TEST_CMD(IOMMU_TEST_OP_MD_CHECK_MAP), \
1072 				&check_map_cmd));                            \
1073 		if (self->domain_ids[1]) {                                   \
1074 			check_map_cmd.id = self->domain_ids[1];              \
1075 			ASSERT_EQ(0,                                         \
1076 				  ioctl(self->fd,                            \
1077 					_IOMMU_TEST_CMD(                     \
1078 						IOMMU_TEST_OP_MD_CHECK_MAP), \
1079 					&check_map_cmd));                    \
1080 		}                                                            \
1081 	})
1082 
1083 TEST_F(iommufd_mock_domain, basic)
1084 {
1085 	size_t buf_size = self->mmap_buf_size;
1086 	uint8_t *buf;
1087 	__u64 iova;
1088 
1089 	/* Simple one page map */
1090 	test_ioctl_ioas_map(buffer, PAGE_SIZE, &iova);
1091 	check_mock_iova(buffer, iova, PAGE_SIZE);
1092 
1093 	buf = mmap(0, buf_size, PROT_READ | PROT_WRITE, self->mmap_flags, -1,
1094 		   0);
1095 	ASSERT_NE(MAP_FAILED, buf);
1096 
1097 	/* EFAULT half way through mapping */
1098 	ASSERT_EQ(0, munmap(buf + buf_size / 2, buf_size / 2));
1099 	test_err_ioctl_ioas_map(EFAULT, buf, buf_size, &iova);
1100 
1101 	/* EFAULT on first page */
1102 	ASSERT_EQ(0, munmap(buf, buf_size / 2));
1103 	test_err_ioctl_ioas_map(EFAULT, buf, buf_size, &iova);
1104 }
1105 
1106 TEST_F(iommufd_mock_domain, ro_unshare)
1107 {
1108 	uint8_t *buf;
1109 	__u64 iova;
1110 	int fd;
1111 
1112 	fd = open("/proc/self/exe", O_RDONLY);
1113 	ASSERT_NE(-1, fd);
1114 
1115 	buf = mmap(0, PAGE_SIZE, PROT_READ | PROT_WRITE, MAP_PRIVATE, fd, 0);
1116 	ASSERT_NE(MAP_FAILED, buf);
1117 	close(fd);
1118 
1119 	/*
1120 	 * There have been lots of changes to the "unshare" mechanism in
1121 	 * get_user_pages(), make sure it works right. The write to the page
1122 	 * after we map it for reading should not change the assigned PFN.
1123 	 */
1124 	ASSERT_EQ(0,
1125 		  _test_ioctl_ioas_map(self->fd, self->ioas_id, buf, PAGE_SIZE,
1126 				       &iova, IOMMU_IOAS_MAP_READABLE));
1127 	check_mock_iova(buf, iova, PAGE_SIZE);
1128 	memset(buf, 1, PAGE_SIZE);
1129 	check_mock_iova(buf, iova, PAGE_SIZE);
1130 	ASSERT_EQ(0, munmap(buf, PAGE_SIZE));
1131 }
1132 
1133 TEST_F(iommufd_mock_domain, all_aligns)
1134 {
1135 	size_t test_step = variant->hugepages ? (self->mmap_buf_size / 16) :
1136 						MOCK_PAGE_SIZE;
1137 	size_t buf_size = self->mmap_buf_size;
1138 	unsigned int start;
1139 	unsigned int end;
1140 	uint8_t *buf;
1141 
1142 	buf = mmap(0, buf_size, PROT_READ | PROT_WRITE, self->mmap_flags, -1,
1143 		   0);
1144 	ASSERT_NE(MAP_FAILED, buf);
1145 	check_refs(buf, buf_size, 0);
1146 
1147 	/*
1148 	 * Map every combination of page size and alignment within a big region,
1149 	 * less for hugepage case as it takes so long to finish.
1150 	 */
1151 	for (start = 0; start < buf_size; start += test_step) {
1152 		if (variant->hugepages)
1153 			end = buf_size;
1154 		else
1155 			end = start + MOCK_PAGE_SIZE;
1156 		for (; end < buf_size; end += MOCK_PAGE_SIZE) {
1157 			size_t length = end - start;
1158 			__u64 iova;
1159 
1160 			test_ioctl_ioas_map(buf + start, length, &iova);
1161 			check_mock_iova(buf + start, iova, length);
1162 			check_refs(buf + start / PAGE_SIZE * PAGE_SIZE,
1163 				   end / PAGE_SIZE * PAGE_SIZE -
1164 					   start / PAGE_SIZE * PAGE_SIZE,
1165 				   1);
1166 
1167 			test_ioctl_ioas_unmap(iova, length);
1168 		}
1169 	}
1170 	check_refs(buf, buf_size, 0);
1171 	ASSERT_EQ(0, munmap(buf, buf_size));
1172 }
1173 
1174 TEST_F(iommufd_mock_domain, all_aligns_copy)
1175 {
1176 	size_t test_step = variant->hugepages ? self->mmap_buf_size / 16 :
1177 						MOCK_PAGE_SIZE;
1178 	size_t buf_size = self->mmap_buf_size;
1179 	unsigned int start;
1180 	unsigned int end;
1181 	uint8_t *buf;
1182 
1183 	buf = mmap(0, buf_size, PROT_READ | PROT_WRITE, self->mmap_flags, -1,
1184 		   0);
1185 	ASSERT_NE(MAP_FAILED, buf);
1186 	check_refs(buf, buf_size, 0);
1187 
1188 	/*
1189 	 * Map every combination of page size and alignment within a big region,
1190 	 * less for hugepage case as it takes so long to finish.
1191 	 */
1192 	for (start = 0; start < buf_size; start += test_step) {
1193 		if (variant->hugepages)
1194 			end = buf_size;
1195 		else
1196 			end = start + MOCK_PAGE_SIZE;
1197 		for (; end < buf_size; end += MOCK_PAGE_SIZE) {
1198 			size_t length = end - start;
1199 			unsigned int old_id;
1200 			uint32_t mock_device_id;
1201 			__u64 iova;
1202 
1203 			test_ioctl_ioas_map(buf + start, length, &iova);
1204 
1205 			/* Add and destroy a domain while the area exists */
1206 			old_id = self->domain_ids[1];
1207 			test_cmd_mock_domain(self->ioas_id, &mock_device_id,
1208 					     &self->domain_ids[1]);
1209 
1210 			check_mock_iova(buf + start, iova, length);
1211 			check_refs(buf + start / PAGE_SIZE * PAGE_SIZE,
1212 				   end / PAGE_SIZE * PAGE_SIZE -
1213 					   start / PAGE_SIZE * PAGE_SIZE,
1214 				   1);
1215 
1216 			test_ioctl_destroy(mock_device_id);
1217 			test_ioctl_destroy(self->domain_ids[1]);
1218 			self->domain_ids[1] = old_id;
1219 
1220 			test_ioctl_ioas_unmap(iova, length);
1221 		}
1222 	}
1223 	check_refs(buf, buf_size, 0);
1224 	ASSERT_EQ(0, munmap(buf, buf_size));
1225 }
1226 
1227 TEST_F(iommufd_mock_domain, user_copy)
1228 {
1229 	struct iommu_test_cmd access_cmd = {
1230 		.size = sizeof(access_cmd),
1231 		.op = IOMMU_TEST_OP_ACCESS_PAGES,
1232 		.access_pages = { .length = BUFFER_SIZE,
1233 				  .uptr = (uintptr_t)buffer },
1234 	};
1235 	struct iommu_ioas_copy copy_cmd = {
1236 		.size = sizeof(copy_cmd),
1237 		.flags = IOMMU_IOAS_MAP_FIXED_IOVA,
1238 		.dst_ioas_id = self->ioas_id,
1239 		.dst_iova = MOCK_APERTURE_START,
1240 		.length = BUFFER_SIZE,
1241 	};
1242 	unsigned int ioas_id;
1243 
1244 	/* Pin the pages in an IOAS with no domains then copy to an IOAS with domains */
1245 	test_ioctl_ioas_alloc(&ioas_id);
1246 	test_ioctl_ioas_map_id(ioas_id, buffer, BUFFER_SIZE,
1247 			       &copy_cmd.src_iova);
1248 
1249 	test_cmd_create_access(ioas_id, &access_cmd.id,
1250 			       MOCK_FLAGS_ACCESS_CREATE_NEEDS_PIN_PAGES);
1251 
1252 	access_cmd.access_pages.iova = copy_cmd.src_iova;
1253 	ASSERT_EQ(0,
1254 		  ioctl(self->fd, _IOMMU_TEST_CMD(IOMMU_TEST_OP_ACCESS_PAGES),
1255 			&access_cmd));
1256 	copy_cmd.src_ioas_id = ioas_id;
1257 	ASSERT_EQ(0, ioctl(self->fd, IOMMU_IOAS_COPY, &copy_cmd));
1258 	check_mock_iova(buffer, MOCK_APERTURE_START, BUFFER_SIZE);
1259 
1260 	test_cmd_destroy_access_pages(
1261 		access_cmd.id, access_cmd.access_pages.out_access_pages_id);
1262 	test_cmd_destroy_access(access_cmd.id);
1263 
1264 	test_ioctl_destroy(ioas_id);
1265 }
1266 
1267 /* VFIO compatibility IOCTLs */
1268 
1269 TEST_F(iommufd, simple_ioctls)
1270 {
1271 	ASSERT_EQ(VFIO_API_VERSION, ioctl(self->fd, VFIO_GET_API_VERSION));
1272 	ASSERT_EQ(1, ioctl(self->fd, VFIO_CHECK_EXTENSION, VFIO_TYPE1v2_IOMMU));
1273 }
1274 
1275 TEST_F(iommufd, unmap_cmd)
1276 {
1277 	struct vfio_iommu_type1_dma_unmap unmap_cmd = {
1278 		.iova = MOCK_APERTURE_START,
1279 		.size = PAGE_SIZE,
1280 	};
1281 
1282 	unmap_cmd.argsz = 1;
1283 	EXPECT_ERRNO(EINVAL, ioctl(self->fd, VFIO_IOMMU_UNMAP_DMA, &unmap_cmd));
1284 
1285 	unmap_cmd.argsz = sizeof(unmap_cmd);
1286 	unmap_cmd.flags = 1 << 31;
1287 	EXPECT_ERRNO(EINVAL, ioctl(self->fd, VFIO_IOMMU_UNMAP_DMA, &unmap_cmd));
1288 
1289 	unmap_cmd.flags = 0;
1290 	EXPECT_ERRNO(ENODEV, ioctl(self->fd, VFIO_IOMMU_UNMAP_DMA, &unmap_cmd));
1291 }
1292 
1293 TEST_F(iommufd, map_cmd)
1294 {
1295 	struct vfio_iommu_type1_dma_map map_cmd = {
1296 		.iova = MOCK_APERTURE_START,
1297 		.size = PAGE_SIZE,
1298 		.vaddr = (__u64)buffer,
1299 	};
1300 
1301 	map_cmd.argsz = 1;
1302 	EXPECT_ERRNO(EINVAL, ioctl(self->fd, VFIO_IOMMU_MAP_DMA, &map_cmd));
1303 
1304 	map_cmd.argsz = sizeof(map_cmd);
1305 	map_cmd.flags = 1 << 31;
1306 	EXPECT_ERRNO(EINVAL, ioctl(self->fd, VFIO_IOMMU_MAP_DMA, &map_cmd));
1307 
1308 	/* Requires a domain to be attached */
1309 	map_cmd.flags = VFIO_DMA_MAP_FLAG_READ | VFIO_DMA_MAP_FLAG_WRITE;
1310 	EXPECT_ERRNO(ENODEV, ioctl(self->fd, VFIO_IOMMU_MAP_DMA, &map_cmd));
1311 }
1312 
1313 TEST_F(iommufd, info_cmd)
1314 {
1315 	struct vfio_iommu_type1_info info_cmd = {};
1316 
1317 	/* Invalid argsz */
1318 	info_cmd.argsz = 1;
1319 	EXPECT_ERRNO(EINVAL, ioctl(self->fd, VFIO_IOMMU_GET_INFO, &info_cmd));
1320 
1321 	info_cmd.argsz = sizeof(info_cmd);
1322 	EXPECT_ERRNO(ENODEV, ioctl(self->fd, VFIO_IOMMU_GET_INFO, &info_cmd));
1323 }
1324 
1325 TEST_F(iommufd, set_iommu_cmd)
1326 {
1327 	/* Requires a domain to be attached */
1328 	EXPECT_ERRNO(ENODEV,
1329 		     ioctl(self->fd, VFIO_SET_IOMMU, VFIO_TYPE1v2_IOMMU));
1330 	EXPECT_ERRNO(ENODEV, ioctl(self->fd, VFIO_SET_IOMMU, VFIO_TYPE1_IOMMU));
1331 }
1332 
1333 TEST_F(iommufd, vfio_ioas)
1334 {
1335 	struct iommu_vfio_ioas vfio_ioas_cmd = {
1336 		.size = sizeof(vfio_ioas_cmd),
1337 		.op = IOMMU_VFIO_IOAS_GET,
1338 	};
1339 	__u32 ioas_id;
1340 
1341 	/* ENODEV if there is no compat ioas */
1342 	EXPECT_ERRNO(ENODEV, ioctl(self->fd, IOMMU_VFIO_IOAS, &vfio_ioas_cmd));
1343 
1344 	/* Invalid id for set */
1345 	vfio_ioas_cmd.op = IOMMU_VFIO_IOAS_SET;
1346 	EXPECT_ERRNO(ENOENT, ioctl(self->fd, IOMMU_VFIO_IOAS, &vfio_ioas_cmd));
1347 
1348 	/* Valid id for set*/
1349 	test_ioctl_ioas_alloc(&ioas_id);
1350 	vfio_ioas_cmd.ioas_id = ioas_id;
1351 	ASSERT_EQ(0, ioctl(self->fd, IOMMU_VFIO_IOAS, &vfio_ioas_cmd));
1352 
1353 	/* Same id comes back from get */
1354 	vfio_ioas_cmd.op = IOMMU_VFIO_IOAS_GET;
1355 	ASSERT_EQ(0, ioctl(self->fd, IOMMU_VFIO_IOAS, &vfio_ioas_cmd));
1356 	ASSERT_EQ(ioas_id, vfio_ioas_cmd.ioas_id);
1357 
1358 	/* Clear works */
1359 	vfio_ioas_cmd.op = IOMMU_VFIO_IOAS_CLEAR;
1360 	ASSERT_EQ(0, ioctl(self->fd, IOMMU_VFIO_IOAS, &vfio_ioas_cmd));
1361 	vfio_ioas_cmd.op = IOMMU_VFIO_IOAS_GET;
1362 	EXPECT_ERRNO(ENODEV, ioctl(self->fd, IOMMU_VFIO_IOAS, &vfio_ioas_cmd));
1363 }
1364 
1365 FIXTURE(vfio_compat_mock_domain)
1366 {
1367 	int fd;
1368 	uint32_t ioas_id;
1369 };
1370 
1371 FIXTURE_VARIANT(vfio_compat_mock_domain)
1372 {
1373 	unsigned int version;
1374 };
1375 
1376 FIXTURE_SETUP(vfio_compat_mock_domain)
1377 {
1378 	struct iommu_vfio_ioas vfio_ioas_cmd = {
1379 		.size = sizeof(vfio_ioas_cmd),
1380 		.op = IOMMU_VFIO_IOAS_SET,
1381 	};
1382 
1383 	self->fd = open("/dev/iommu", O_RDWR);
1384 	ASSERT_NE(-1, self->fd);
1385 
1386 	/* Create what VFIO would consider a group */
1387 	test_ioctl_ioas_alloc(&self->ioas_id);
1388 	test_cmd_mock_domain(self->ioas_id, NULL, NULL);
1389 
1390 	/* Attach it to the vfio compat */
1391 	vfio_ioas_cmd.ioas_id = self->ioas_id;
1392 	ASSERT_EQ(0, ioctl(self->fd, IOMMU_VFIO_IOAS, &vfio_ioas_cmd));
1393 	ASSERT_EQ(0, ioctl(self->fd, VFIO_SET_IOMMU, variant->version));
1394 }
1395 
1396 FIXTURE_TEARDOWN(vfio_compat_mock_domain)
1397 {
1398 	teardown_iommufd(self->fd, _metadata);
1399 }
1400 
1401 FIXTURE_VARIANT_ADD(vfio_compat_mock_domain, Ver1v2)
1402 {
1403 	.version = VFIO_TYPE1v2_IOMMU,
1404 };
1405 
1406 FIXTURE_VARIANT_ADD(vfio_compat_mock_domain, Ver1v0)
1407 {
1408 	.version = VFIO_TYPE1_IOMMU,
1409 };
1410 
1411 TEST_F(vfio_compat_mock_domain, simple_close)
1412 {
1413 }
1414 
1415 TEST_F(vfio_compat_mock_domain, option_huge_pages)
1416 {
1417 	struct iommu_option cmd = {
1418 		.size = sizeof(cmd),
1419 		.option_id = IOMMU_OPTION_HUGE_PAGES,
1420 		.op = IOMMU_OPTION_OP_GET,
1421 		.val64 = 3,
1422 		.object_id = self->ioas_id,
1423 	};
1424 
1425 	ASSERT_EQ(0, ioctl(self->fd, IOMMU_OPTION, &cmd));
1426 	if (variant->version == VFIO_TYPE1_IOMMU) {
1427 		ASSERT_EQ(0, cmd.val64);
1428 	} else {
1429 		ASSERT_EQ(1, cmd.val64);
1430 	}
1431 }
1432 
1433 /*
1434  * Execute an ioctl command stored in buffer and check that the result does not
1435  * overflow memory.
1436  */
1437 static bool is_filled(const void *buf, uint8_t c, size_t len)
1438 {
1439 	const uint8_t *cbuf = buf;
1440 
1441 	for (; len; cbuf++, len--)
1442 		if (*cbuf != c)
1443 			return false;
1444 	return true;
1445 }
1446 
1447 #define ioctl_check_buf(fd, cmd)                                         \
1448 	({                                                               \
1449 		size_t _cmd_len = *(__u32 *)buffer;                      \
1450 									 \
1451 		memset(buffer + _cmd_len, 0xAA, BUFFER_SIZE - _cmd_len); \
1452 		ASSERT_EQ(0, ioctl(fd, cmd, buffer));                    \
1453 		ASSERT_EQ(true, is_filled(buffer + _cmd_len, 0xAA,       \
1454 					  BUFFER_SIZE - _cmd_len));      \
1455 	})
1456 
1457 static void check_vfio_info_cap_chain(struct __test_metadata *_metadata,
1458 				      struct vfio_iommu_type1_info *info_cmd)
1459 {
1460 	const struct vfio_info_cap_header *cap;
1461 
1462 	ASSERT_GE(info_cmd->argsz, info_cmd->cap_offset + sizeof(*cap));
1463 	cap = buffer + info_cmd->cap_offset;
1464 	while (true) {
1465 		size_t cap_size;
1466 
1467 		if (cap->next)
1468 			cap_size = (buffer + cap->next) - (void *)cap;
1469 		else
1470 			cap_size = (buffer + info_cmd->argsz) - (void *)cap;
1471 
1472 		switch (cap->id) {
1473 		case VFIO_IOMMU_TYPE1_INFO_CAP_IOVA_RANGE: {
1474 			struct vfio_iommu_type1_info_cap_iova_range *data =
1475 				(void *)cap;
1476 
1477 			ASSERT_EQ(1, data->header.version);
1478 			ASSERT_EQ(1, data->nr_iovas);
1479 			EXPECT_EQ(MOCK_APERTURE_START,
1480 				  data->iova_ranges[0].start);
1481 			EXPECT_EQ(MOCK_APERTURE_LAST, data->iova_ranges[0].end);
1482 			break;
1483 		}
1484 		case VFIO_IOMMU_TYPE1_INFO_DMA_AVAIL: {
1485 			struct vfio_iommu_type1_info_dma_avail *data =
1486 				(void *)cap;
1487 
1488 			ASSERT_EQ(1, data->header.version);
1489 			ASSERT_EQ(sizeof(*data), cap_size);
1490 			break;
1491 		}
1492 		default:
1493 			ASSERT_EQ(false, true);
1494 			break;
1495 		}
1496 		if (!cap->next)
1497 			break;
1498 
1499 		ASSERT_GE(info_cmd->argsz, cap->next + sizeof(*cap));
1500 		ASSERT_GE(buffer + cap->next, (void *)cap);
1501 		cap = buffer + cap->next;
1502 	}
1503 }
1504 
1505 TEST_F(vfio_compat_mock_domain, get_info)
1506 {
1507 	struct vfio_iommu_type1_info *info_cmd = buffer;
1508 	unsigned int i;
1509 	size_t caplen;
1510 
1511 	/* Pre-cap ABI */
1512 	*info_cmd = (struct vfio_iommu_type1_info){
1513 		.argsz = offsetof(struct vfio_iommu_type1_info, cap_offset),
1514 	};
1515 	ioctl_check_buf(self->fd, VFIO_IOMMU_GET_INFO);
1516 	ASSERT_NE(0, info_cmd->iova_pgsizes);
1517 	ASSERT_EQ(VFIO_IOMMU_INFO_PGSIZES | VFIO_IOMMU_INFO_CAPS,
1518 		  info_cmd->flags);
1519 
1520 	/* Read the cap chain size */
1521 	*info_cmd = (struct vfio_iommu_type1_info){
1522 		.argsz = sizeof(*info_cmd),
1523 	};
1524 	ioctl_check_buf(self->fd, VFIO_IOMMU_GET_INFO);
1525 	ASSERT_NE(0, info_cmd->iova_pgsizes);
1526 	ASSERT_EQ(VFIO_IOMMU_INFO_PGSIZES | VFIO_IOMMU_INFO_CAPS,
1527 		  info_cmd->flags);
1528 	ASSERT_EQ(0, info_cmd->cap_offset);
1529 	ASSERT_LT(sizeof(*info_cmd), info_cmd->argsz);
1530 
1531 	/* Read the caps, kernel should never create a corrupted caps */
1532 	caplen = info_cmd->argsz;
1533 	for (i = sizeof(*info_cmd); i < caplen; i++) {
1534 		*info_cmd = (struct vfio_iommu_type1_info){
1535 			.argsz = i,
1536 		};
1537 		ioctl_check_buf(self->fd, VFIO_IOMMU_GET_INFO);
1538 		ASSERT_EQ(VFIO_IOMMU_INFO_PGSIZES | VFIO_IOMMU_INFO_CAPS,
1539 			  info_cmd->flags);
1540 		if (!info_cmd->cap_offset)
1541 			continue;
1542 		check_vfio_info_cap_chain(_metadata, info_cmd);
1543 	}
1544 }
1545 
1546 static void shuffle_array(unsigned long *array, size_t nelms)
1547 {
1548 	unsigned int i;
1549 
1550 	/* Shuffle */
1551 	for (i = 0; i != nelms; i++) {
1552 		unsigned long tmp = array[i];
1553 		unsigned int other = rand() % (nelms - i);
1554 
1555 		array[i] = array[other];
1556 		array[other] = tmp;
1557 	}
1558 }
1559 
1560 TEST_F(vfio_compat_mock_domain, map)
1561 {
1562 	struct vfio_iommu_type1_dma_map map_cmd = {
1563 		.argsz = sizeof(map_cmd),
1564 		.flags = VFIO_DMA_MAP_FLAG_READ | VFIO_DMA_MAP_FLAG_WRITE,
1565 		.vaddr = (uintptr_t)buffer,
1566 		.size = BUFFER_SIZE,
1567 		.iova = MOCK_APERTURE_START,
1568 	};
1569 	struct vfio_iommu_type1_dma_unmap unmap_cmd = {
1570 		.argsz = sizeof(unmap_cmd),
1571 		.size = BUFFER_SIZE,
1572 		.iova = MOCK_APERTURE_START,
1573 	};
1574 	unsigned long pages_iova[BUFFER_SIZE / PAGE_SIZE];
1575 	unsigned int i;
1576 
1577 	/* Simple map/unmap */
1578 	ASSERT_EQ(0, ioctl(self->fd, VFIO_IOMMU_MAP_DMA, &map_cmd));
1579 	ASSERT_EQ(0, ioctl(self->fd, VFIO_IOMMU_UNMAP_DMA, &unmap_cmd));
1580 	ASSERT_EQ(BUFFER_SIZE, unmap_cmd.size);
1581 
1582 	/* UNMAP_FLAG_ALL requres 0 iova/size */
1583 	ASSERT_EQ(0, ioctl(self->fd, VFIO_IOMMU_MAP_DMA, &map_cmd));
1584 	unmap_cmd.flags = VFIO_DMA_UNMAP_FLAG_ALL;
1585 	EXPECT_ERRNO(EINVAL, ioctl(self->fd, VFIO_IOMMU_UNMAP_DMA, &unmap_cmd));
1586 
1587 	unmap_cmd.iova = 0;
1588 	unmap_cmd.size = 0;
1589 	ASSERT_EQ(0, ioctl(self->fd, VFIO_IOMMU_UNMAP_DMA, &unmap_cmd));
1590 	ASSERT_EQ(BUFFER_SIZE, unmap_cmd.size);
1591 
1592 	/* Small pages */
1593 	for (i = 0; i != ARRAY_SIZE(pages_iova); i++) {
1594 		map_cmd.iova = pages_iova[i] =
1595 			MOCK_APERTURE_START + i * PAGE_SIZE;
1596 		map_cmd.vaddr = (uintptr_t)buffer + i * PAGE_SIZE;
1597 		map_cmd.size = PAGE_SIZE;
1598 		ASSERT_EQ(0, ioctl(self->fd, VFIO_IOMMU_MAP_DMA, &map_cmd));
1599 	}
1600 	shuffle_array(pages_iova, ARRAY_SIZE(pages_iova));
1601 
1602 	unmap_cmd.flags = 0;
1603 	unmap_cmd.size = PAGE_SIZE;
1604 	for (i = 0; i != ARRAY_SIZE(pages_iova); i++) {
1605 		unmap_cmd.iova = pages_iova[i];
1606 		ASSERT_EQ(0, ioctl(self->fd, VFIO_IOMMU_UNMAP_DMA, &unmap_cmd));
1607 	}
1608 }
1609 
1610 TEST_F(vfio_compat_mock_domain, huge_map)
1611 {
1612 	size_t buf_size = HUGEPAGE_SIZE * 2;
1613 	struct vfio_iommu_type1_dma_map map_cmd = {
1614 		.argsz = sizeof(map_cmd),
1615 		.flags = VFIO_DMA_MAP_FLAG_READ | VFIO_DMA_MAP_FLAG_WRITE,
1616 		.size = buf_size,
1617 		.iova = MOCK_APERTURE_START,
1618 	};
1619 	struct vfio_iommu_type1_dma_unmap unmap_cmd = {
1620 		.argsz = sizeof(unmap_cmd),
1621 	};
1622 	unsigned long pages_iova[16];
1623 	unsigned int i;
1624 	void *buf;
1625 
1626 	/* Test huge pages and splitting */
1627 	buf = mmap(0, buf_size, PROT_READ | PROT_WRITE,
1628 		   MAP_SHARED | MAP_ANONYMOUS | MAP_HUGETLB | MAP_POPULATE, -1,
1629 		   0);
1630 	ASSERT_NE(MAP_FAILED, buf);
1631 	map_cmd.vaddr = (uintptr_t)buf;
1632 	ASSERT_EQ(0, ioctl(self->fd, VFIO_IOMMU_MAP_DMA, &map_cmd));
1633 
1634 	unmap_cmd.size = buf_size / ARRAY_SIZE(pages_iova);
1635 	for (i = 0; i != ARRAY_SIZE(pages_iova); i++)
1636 		pages_iova[i] = MOCK_APERTURE_START + (i * unmap_cmd.size);
1637 	shuffle_array(pages_iova, ARRAY_SIZE(pages_iova));
1638 
1639 	/* type1 mode can cut up larger mappings, type1v2 always fails */
1640 	for (i = 0; i != ARRAY_SIZE(pages_iova); i++) {
1641 		unmap_cmd.iova = pages_iova[i];
1642 		unmap_cmd.size = buf_size / ARRAY_SIZE(pages_iova);
1643 		if (variant->version == VFIO_TYPE1_IOMMU) {
1644 			ASSERT_EQ(0, ioctl(self->fd, VFIO_IOMMU_UNMAP_DMA,
1645 					   &unmap_cmd));
1646 		} else {
1647 			EXPECT_ERRNO(ENOENT,
1648 				     ioctl(self->fd, VFIO_IOMMU_UNMAP_DMA,
1649 					   &unmap_cmd));
1650 		}
1651 	}
1652 }
1653 
1654 TEST_HARNESS_MAIN
1655