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