brintos

brintos / linux-shallow public Read only

0
0
Text · 67.8 KiB · 4927b9a Raw
2390 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2/* 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#define MOCK_HUGE_PAGE_SIZE (512 * MOCK_PAGE_SIZE)16 17static unsigned long get_huge_page_size(void)18{19	char buf[80];20	int ret;21	int fd;22 23	fd = open("/sys/kernel/mm/transparent_hugepage/hpage_pmd_size",24		  O_RDONLY);25	if (fd < 0)26		return 2 * 1024 * 1024;27 28	ret = read(fd, buf, sizeof(buf));29	close(fd);30	if (ret <= 0 || ret == sizeof(buf))31		return 2 * 1024 * 1024;32	buf[ret] = 0;33	return strtoul(buf, NULL, 10);34}35 36static __attribute__((constructor)) void setup_sizes(void)37{38	void *vrc;39	int rc;40 41	PAGE_SIZE = sysconf(_SC_PAGE_SIZE);42	HUGEPAGE_SIZE = get_huge_page_size();43 44	BUFFER_SIZE = PAGE_SIZE * 16;45	rc = posix_memalign(&buffer, HUGEPAGE_SIZE, BUFFER_SIZE);46	assert(!rc);47	assert(buffer);48	assert((uintptr_t)buffer % HUGEPAGE_SIZE == 0);49	vrc = mmap(buffer, BUFFER_SIZE, PROT_READ | PROT_WRITE,50		   MAP_SHARED | MAP_ANONYMOUS | MAP_FIXED, -1, 0);51	assert(vrc == buffer);52}53 54FIXTURE(iommufd)55{56	int fd;57};58 59FIXTURE_SETUP(iommufd)60{61	self->fd = open("/dev/iommu", O_RDWR);62	ASSERT_NE(-1, self->fd);63}64 65FIXTURE_TEARDOWN(iommufd)66{67	teardown_iommufd(self->fd, _metadata);68}69 70TEST_F(iommufd, simple_close)71{72}73 74TEST_F(iommufd, cmd_fail)75{76	struct iommu_destroy cmd = { .size = sizeof(cmd), .id = 0 };77 78	/* object id is invalid */79	EXPECT_ERRNO(ENOENT, _test_ioctl_destroy(self->fd, 0));80	/* Bad pointer */81	EXPECT_ERRNO(EFAULT, ioctl(self->fd, IOMMU_DESTROY, NULL));82	/* Unknown ioctl */83	EXPECT_ERRNO(ENOTTY,84		     ioctl(self->fd, _IO(IOMMUFD_TYPE, IOMMUFD_CMD_BASE - 1),85			   &cmd));86}87 88TEST_F(iommufd, cmd_length)89{90#define TEST_LENGTH(_struct, _ioctl, _last)                              \91	{                                                                \92		size_t min_size = offsetofend(struct _struct, _last);    \93		struct {                                                 \94			struct _struct cmd;                              \95			uint8_t extra;                                   \96		} cmd = { .cmd = { .size = min_size - 1 },               \97			  .extra = UINT8_MAX };                          \98		int old_errno;                                           \99		int rc;                                                  \100									 \101		EXPECT_ERRNO(EINVAL, ioctl(self->fd, _ioctl, &cmd));     \102		cmd.cmd.size = sizeof(struct _struct) + 1;               \103		EXPECT_ERRNO(E2BIG, ioctl(self->fd, _ioctl, &cmd));      \104		cmd.cmd.size = sizeof(struct _struct);                   \105		rc = ioctl(self->fd, _ioctl, &cmd);                      \106		old_errno = errno;                                       \107		cmd.cmd.size = sizeof(struct _struct) + 1;               \108		cmd.extra = 0;                                           \109		if (rc) {                                                \110			EXPECT_ERRNO(old_errno,                          \111				     ioctl(self->fd, _ioctl, &cmd));     \112		} else {                                                 \113			ASSERT_EQ(0, ioctl(self->fd, _ioctl, &cmd));     \114		}                                                        \115	}116 117	TEST_LENGTH(iommu_destroy, IOMMU_DESTROY, id);118	TEST_LENGTH(iommu_hw_info, IOMMU_GET_HW_INFO, __reserved);119	TEST_LENGTH(iommu_hwpt_alloc, IOMMU_HWPT_ALLOC, __reserved);120	TEST_LENGTH(iommu_hwpt_invalidate, IOMMU_HWPT_INVALIDATE, __reserved);121	TEST_LENGTH(iommu_ioas_alloc, IOMMU_IOAS_ALLOC, out_ioas_id);122	TEST_LENGTH(iommu_ioas_iova_ranges, IOMMU_IOAS_IOVA_RANGES,123		    out_iova_alignment);124	TEST_LENGTH(iommu_ioas_allow_iovas, IOMMU_IOAS_ALLOW_IOVAS,125		    allowed_iovas);126	TEST_LENGTH(iommu_ioas_map, IOMMU_IOAS_MAP, iova);127	TEST_LENGTH(iommu_ioas_copy, IOMMU_IOAS_COPY, src_iova);128	TEST_LENGTH(iommu_ioas_unmap, IOMMU_IOAS_UNMAP, length);129	TEST_LENGTH(iommu_option, IOMMU_OPTION, val64);130	TEST_LENGTH(iommu_vfio_ioas, IOMMU_VFIO_IOAS, __reserved);131#undef TEST_LENGTH132}133 134TEST_F(iommufd, cmd_ex_fail)135{136	struct {137		struct iommu_destroy cmd;138		__u64 future;139	} cmd = { .cmd = { .size = sizeof(cmd), .id = 0 } };140 141	/* object id is invalid and command is longer */142	EXPECT_ERRNO(ENOENT, ioctl(self->fd, IOMMU_DESTROY, &cmd));143	/* future area is non-zero */144	cmd.future = 1;145	EXPECT_ERRNO(E2BIG, ioctl(self->fd, IOMMU_DESTROY, &cmd));146	/* Original command "works" */147	cmd.cmd.size = sizeof(cmd.cmd);148	EXPECT_ERRNO(ENOENT, ioctl(self->fd, IOMMU_DESTROY, &cmd));149	/* Short command fails */150	cmd.cmd.size = sizeof(cmd.cmd) - 1;151	EXPECT_ERRNO(EINVAL, ioctl(self->fd, IOMMU_DESTROY, &cmd));152}153 154TEST_F(iommufd, global_options)155{156	struct iommu_option cmd = {157		.size = sizeof(cmd),158		.option_id = IOMMU_OPTION_RLIMIT_MODE,159		.op = IOMMU_OPTION_OP_GET,160		.val64 = 1,161	};162 163	cmd.option_id = IOMMU_OPTION_RLIMIT_MODE;164	ASSERT_EQ(0, ioctl(self->fd, IOMMU_OPTION, &cmd));165	ASSERT_EQ(0, cmd.val64);166 167	/* This requires root */168	cmd.op = IOMMU_OPTION_OP_SET;169	cmd.val64 = 1;170	ASSERT_EQ(0, ioctl(self->fd, IOMMU_OPTION, &cmd));171	cmd.val64 = 2;172	EXPECT_ERRNO(EINVAL, ioctl(self->fd, IOMMU_OPTION, &cmd));173 174	cmd.op = IOMMU_OPTION_OP_GET;175	ASSERT_EQ(0, ioctl(self->fd, IOMMU_OPTION, &cmd));176	ASSERT_EQ(1, cmd.val64);177 178	cmd.op = IOMMU_OPTION_OP_SET;179	cmd.val64 = 0;180	ASSERT_EQ(0, ioctl(self->fd, IOMMU_OPTION, &cmd));181 182	cmd.op = IOMMU_OPTION_OP_GET;183	cmd.option_id = IOMMU_OPTION_HUGE_PAGES;184	EXPECT_ERRNO(ENOENT, ioctl(self->fd, IOMMU_OPTION, &cmd));185	cmd.op = IOMMU_OPTION_OP_SET;186	EXPECT_ERRNO(ENOENT, ioctl(self->fd, IOMMU_OPTION, &cmd));187}188 189FIXTURE(iommufd_ioas)190{191	int fd;192	uint32_t ioas_id;193	uint32_t stdev_id;194	uint32_t hwpt_id;195	uint32_t device_id;196	uint64_t base_iova;197};198 199FIXTURE_VARIANT(iommufd_ioas)200{201	unsigned int mock_domains;202	unsigned int memory_limit;203};204 205FIXTURE_SETUP(iommufd_ioas)206{207	unsigned int i;208 209 210	self->fd = open("/dev/iommu", O_RDWR);211	ASSERT_NE(-1, self->fd);212	test_ioctl_ioas_alloc(&self->ioas_id);213 214	if (!variant->memory_limit) {215		test_ioctl_set_default_memory_limit();216	} else {217		test_ioctl_set_temp_memory_limit(variant->memory_limit);218	}219 220	for (i = 0; i != variant->mock_domains; i++) {221		test_cmd_mock_domain(self->ioas_id, &self->stdev_id,222				     &self->hwpt_id, &self->device_id);223		self->base_iova = MOCK_APERTURE_START;224	}225}226 227FIXTURE_TEARDOWN(iommufd_ioas)228{229	test_ioctl_set_default_memory_limit();230	teardown_iommufd(self->fd, _metadata);231}232 233FIXTURE_VARIANT_ADD(iommufd_ioas, no_domain)234{235};236 237FIXTURE_VARIANT_ADD(iommufd_ioas, mock_domain)238{239	.mock_domains = 1,240};241 242FIXTURE_VARIANT_ADD(iommufd_ioas, two_mock_domain)243{244	.mock_domains = 2,245};246 247FIXTURE_VARIANT_ADD(iommufd_ioas, mock_domain_limit)248{249	.mock_domains = 1,250	.memory_limit = 16,251};252 253TEST_F(iommufd_ioas, ioas_auto_destroy)254{255}256 257TEST_F(iommufd_ioas, ioas_destroy)258{259	if (self->stdev_id) {260		/* IOAS cannot be freed while a device has a HWPT using it */261		EXPECT_ERRNO(EBUSY,262			     _test_ioctl_destroy(self->fd, self->ioas_id));263	} else {264		/* Can allocate and manually free an IOAS table */265		test_ioctl_destroy(self->ioas_id);266	}267}268 269TEST_F(iommufd_ioas, alloc_hwpt_nested)270{271	const uint32_t min_data_len =272		offsetofend(struct iommu_hwpt_selftest, iotlb);273	struct iommu_hwpt_selftest data = {274		.iotlb = IOMMU_TEST_IOTLB_DEFAULT,275	};276	struct iommu_hwpt_invalidate_selftest inv_reqs[2] = {};277	uint32_t nested_hwpt_id[2] = {};278	uint32_t num_inv;279	uint32_t parent_hwpt_id = 0;280	uint32_t parent_hwpt_id_not_work = 0;281	uint32_t test_hwpt_id = 0;282	uint32_t iopf_hwpt_id;283	uint32_t fault_id;284	uint32_t fault_fd;285 286	if (self->device_id) {287		/* Negative tests */288		test_err_hwpt_alloc(ENOENT, self->ioas_id, self->device_id, 0,289				    &test_hwpt_id);290		test_err_hwpt_alloc(EINVAL, self->device_id, self->device_id, 0,291				    &test_hwpt_id);292 293		test_cmd_hwpt_alloc(self->device_id, self->ioas_id,294				    IOMMU_HWPT_ALLOC_NEST_PARENT,295				    &parent_hwpt_id);296 297		test_cmd_hwpt_alloc(self->device_id, self->ioas_id, 0,298				    &parent_hwpt_id_not_work);299 300		/* Negative nested tests */301		test_err_hwpt_alloc_nested(EINVAL, self->device_id,302					   parent_hwpt_id, 0,303					   &nested_hwpt_id[0],304					   IOMMU_HWPT_DATA_NONE, &data,305					   sizeof(data));306		test_err_hwpt_alloc_nested(EOPNOTSUPP, self->device_id,307					   parent_hwpt_id, 0,308					   &nested_hwpt_id[0],309					   IOMMU_HWPT_DATA_SELFTEST + 1, &data,310					   sizeof(data));311		test_err_hwpt_alloc_nested(EINVAL, self->device_id,312					   parent_hwpt_id, 0,313					   &nested_hwpt_id[0],314					   IOMMU_HWPT_DATA_SELFTEST, &data,315					   min_data_len - 1);316		test_err_hwpt_alloc_nested(EFAULT, self->device_id,317					   parent_hwpt_id, 0,318					   &nested_hwpt_id[0],319					   IOMMU_HWPT_DATA_SELFTEST, NULL,320					   sizeof(data));321		test_err_hwpt_alloc_nested(322			EOPNOTSUPP, self->device_id, parent_hwpt_id,323			IOMMU_HWPT_ALLOC_NEST_PARENT, &nested_hwpt_id[0],324			IOMMU_HWPT_DATA_SELFTEST, &data, sizeof(data));325		test_err_hwpt_alloc_nested(EINVAL, self->device_id,326					   parent_hwpt_id_not_work, 0,327					   &nested_hwpt_id[0],328					   IOMMU_HWPT_DATA_SELFTEST, &data,329					   sizeof(data));330 331		/* Allocate two nested hwpts sharing one common parent hwpt */332		test_ioctl_fault_alloc(&fault_id, &fault_fd);333		test_cmd_hwpt_alloc_nested(self->device_id, parent_hwpt_id, 0,334					   &nested_hwpt_id[0],335					   IOMMU_HWPT_DATA_SELFTEST, &data,336					   sizeof(data));337		test_cmd_hwpt_alloc_nested(self->device_id, parent_hwpt_id, 0,338					   &nested_hwpt_id[1],339					   IOMMU_HWPT_DATA_SELFTEST, &data,340					   sizeof(data));341		test_err_hwpt_alloc_iopf(ENOENT, self->device_id, parent_hwpt_id,342					 UINT32_MAX, IOMMU_HWPT_FAULT_ID_VALID,343					 &iopf_hwpt_id, IOMMU_HWPT_DATA_SELFTEST,344					 &data, sizeof(data));345		test_cmd_hwpt_alloc_iopf(self->device_id, parent_hwpt_id, fault_id,346					 IOMMU_HWPT_FAULT_ID_VALID, &iopf_hwpt_id,347					 IOMMU_HWPT_DATA_SELFTEST, &data,348					 sizeof(data));349		test_cmd_hwpt_check_iotlb_all(nested_hwpt_id[0],350					      IOMMU_TEST_IOTLB_DEFAULT);351		test_cmd_hwpt_check_iotlb_all(nested_hwpt_id[1],352					      IOMMU_TEST_IOTLB_DEFAULT);353 354		/* Negative test: a nested hwpt on top of a nested hwpt */355		test_err_hwpt_alloc_nested(EINVAL, self->device_id,356					   nested_hwpt_id[0], 0, &test_hwpt_id,357					   IOMMU_HWPT_DATA_SELFTEST, &data,358					   sizeof(data));359		/* Negative test: parent hwpt now cannot be freed */360		EXPECT_ERRNO(EBUSY,361			     _test_ioctl_destroy(self->fd, parent_hwpt_id));362 363		/* hwpt_invalidate only supports a user-managed hwpt (nested) */364		num_inv = 1;365		test_err_hwpt_invalidate(ENOENT, parent_hwpt_id, inv_reqs,366					 IOMMU_HWPT_INVALIDATE_DATA_SELFTEST,367					 sizeof(*inv_reqs), &num_inv);368		assert(!num_inv);369 370		/* Check data_type by passing zero-length array */371		num_inv = 0;372		test_cmd_hwpt_invalidate(nested_hwpt_id[0], inv_reqs,373					 IOMMU_HWPT_INVALIDATE_DATA_SELFTEST,374					 sizeof(*inv_reqs), &num_inv);375		assert(!num_inv);376 377		/* Negative test: Invalid data_type */378		num_inv = 1;379		test_err_hwpt_invalidate(EINVAL, nested_hwpt_id[0], inv_reqs,380					 IOMMU_HWPT_INVALIDATE_DATA_SELFTEST_INVALID,381					 sizeof(*inv_reqs), &num_inv);382		assert(!num_inv);383 384		/* Negative test: structure size sanity */385		num_inv = 1;386		test_err_hwpt_invalidate(EINVAL, nested_hwpt_id[0], inv_reqs,387					 IOMMU_HWPT_INVALIDATE_DATA_SELFTEST,388					 sizeof(*inv_reqs) + 1, &num_inv);389		assert(!num_inv);390 391		num_inv = 1;392		test_err_hwpt_invalidate(EINVAL, nested_hwpt_id[0], inv_reqs,393					 IOMMU_HWPT_INVALIDATE_DATA_SELFTEST,394					 1, &num_inv);395		assert(!num_inv);396 397		/* Negative test: invalid flag is passed */398		num_inv = 1;399		inv_reqs[0].flags = 0xffffffff;400		test_err_hwpt_invalidate(EOPNOTSUPP, nested_hwpt_id[0], inv_reqs,401					 IOMMU_HWPT_INVALIDATE_DATA_SELFTEST,402					 sizeof(*inv_reqs), &num_inv);403		assert(!num_inv);404 405		/* Negative test: invalid data_uptr when array is not empty */406		num_inv = 1;407		inv_reqs[0].flags = 0;408		test_err_hwpt_invalidate(EINVAL, nested_hwpt_id[0], NULL,409					 IOMMU_HWPT_INVALIDATE_DATA_SELFTEST,410					 sizeof(*inv_reqs), &num_inv);411		assert(!num_inv);412 413		/* Negative test: invalid entry_len when array is not empty */414		num_inv = 1;415		inv_reqs[0].flags = 0;416		test_err_hwpt_invalidate(EINVAL, nested_hwpt_id[0], inv_reqs,417					 IOMMU_HWPT_INVALIDATE_DATA_SELFTEST,418					 0, &num_inv);419		assert(!num_inv);420 421		/* Negative test: invalid iotlb_id */422		num_inv = 1;423		inv_reqs[0].flags = 0;424		inv_reqs[0].iotlb_id = MOCK_NESTED_DOMAIN_IOTLB_ID_MAX + 1;425		test_err_hwpt_invalidate(EINVAL, nested_hwpt_id[0], inv_reqs,426					 IOMMU_HWPT_INVALIDATE_DATA_SELFTEST,427					 sizeof(*inv_reqs), &num_inv);428		assert(!num_inv);429 430		/*431		 * Invalidate the 1st iotlb entry but fail the 2nd request432		 * due to invalid flags configuration in the 2nd request.433		 */434		num_inv = 2;435		inv_reqs[0].flags = 0;436		inv_reqs[0].iotlb_id = 0;437		inv_reqs[1].flags = 0xffffffff;438		inv_reqs[1].iotlb_id = 1;439		test_err_hwpt_invalidate(EOPNOTSUPP, nested_hwpt_id[0], inv_reqs,440					 IOMMU_HWPT_INVALIDATE_DATA_SELFTEST,441					 sizeof(*inv_reqs), &num_inv);442		assert(num_inv == 1);443		test_cmd_hwpt_check_iotlb(nested_hwpt_id[0], 0, 0);444		test_cmd_hwpt_check_iotlb(nested_hwpt_id[0], 1,445					  IOMMU_TEST_IOTLB_DEFAULT);446		test_cmd_hwpt_check_iotlb(nested_hwpt_id[0], 2,447					  IOMMU_TEST_IOTLB_DEFAULT);448		test_cmd_hwpt_check_iotlb(nested_hwpt_id[0], 3,449					  IOMMU_TEST_IOTLB_DEFAULT);450 451		/*452		 * Invalidate the 1st iotlb entry but fail the 2nd request453		 * due to invalid iotlb_id configuration in the 2nd request.454		 */455		num_inv = 2;456		inv_reqs[0].flags = 0;457		inv_reqs[0].iotlb_id = 0;458		inv_reqs[1].flags = 0;459		inv_reqs[1].iotlb_id = MOCK_NESTED_DOMAIN_IOTLB_ID_MAX + 1;460		test_err_hwpt_invalidate(EINVAL, nested_hwpt_id[0], inv_reqs,461					 IOMMU_HWPT_INVALIDATE_DATA_SELFTEST,462					 sizeof(*inv_reqs), &num_inv);463		assert(num_inv == 1);464		test_cmd_hwpt_check_iotlb(nested_hwpt_id[0], 0, 0);465		test_cmd_hwpt_check_iotlb(nested_hwpt_id[0], 1,466					  IOMMU_TEST_IOTLB_DEFAULT);467		test_cmd_hwpt_check_iotlb(nested_hwpt_id[0], 2,468					  IOMMU_TEST_IOTLB_DEFAULT);469		test_cmd_hwpt_check_iotlb(nested_hwpt_id[0], 3,470					  IOMMU_TEST_IOTLB_DEFAULT);471 472		/* Invalidate the 2nd iotlb entry and verify */473		num_inv = 1;474		inv_reqs[0].flags = 0;475		inv_reqs[0].iotlb_id = 1;476		test_cmd_hwpt_invalidate(nested_hwpt_id[0], inv_reqs,477					 IOMMU_HWPT_INVALIDATE_DATA_SELFTEST,478					 sizeof(*inv_reqs), &num_inv);479		assert(num_inv == 1);480		test_cmd_hwpt_check_iotlb(nested_hwpt_id[0], 0, 0);481		test_cmd_hwpt_check_iotlb(nested_hwpt_id[0], 1, 0);482		test_cmd_hwpt_check_iotlb(nested_hwpt_id[0], 2,483					  IOMMU_TEST_IOTLB_DEFAULT);484		test_cmd_hwpt_check_iotlb(nested_hwpt_id[0], 3,485					  IOMMU_TEST_IOTLB_DEFAULT);486 487		/* Invalidate the 3rd and 4th iotlb entries and verify */488		num_inv = 2;489		inv_reqs[0].flags = 0;490		inv_reqs[0].iotlb_id = 2;491		inv_reqs[1].flags = 0;492		inv_reqs[1].iotlb_id = 3;493		test_cmd_hwpt_invalidate(nested_hwpt_id[0], inv_reqs,494					 IOMMU_HWPT_INVALIDATE_DATA_SELFTEST,495					 sizeof(*inv_reqs), &num_inv);496		assert(num_inv == 2);497		test_cmd_hwpt_check_iotlb_all(nested_hwpt_id[0], 0);498 499		/* Invalidate all iotlb entries for nested_hwpt_id[1] and verify */500		num_inv = 1;501		inv_reqs[0].flags = IOMMU_TEST_INVALIDATE_FLAG_ALL;502		test_cmd_hwpt_invalidate(nested_hwpt_id[1], inv_reqs,503					 IOMMU_HWPT_INVALIDATE_DATA_SELFTEST,504					 sizeof(*inv_reqs), &num_inv);505		assert(num_inv == 1);506		test_cmd_hwpt_check_iotlb_all(nested_hwpt_id[1], 0);507 508		/* Attach device to nested_hwpt_id[0] that then will be busy */509		test_cmd_mock_domain_replace(self->stdev_id, nested_hwpt_id[0]);510		EXPECT_ERRNO(EBUSY,511			     _test_ioctl_destroy(self->fd, nested_hwpt_id[0]));512 513		/* Switch from nested_hwpt_id[0] to nested_hwpt_id[1] */514		test_cmd_mock_domain_replace(self->stdev_id, nested_hwpt_id[1]);515		EXPECT_ERRNO(EBUSY,516			     _test_ioctl_destroy(self->fd, nested_hwpt_id[1]));517		test_ioctl_destroy(nested_hwpt_id[0]);518 519		/* Switch from nested_hwpt_id[1] to iopf_hwpt_id */520		test_cmd_mock_domain_replace(self->stdev_id, iopf_hwpt_id);521		EXPECT_ERRNO(EBUSY,522			     _test_ioctl_destroy(self->fd, iopf_hwpt_id));523		/* Trigger an IOPF on the device */524		test_cmd_trigger_iopf(self->device_id, fault_fd);525 526		/* Detach from nested_hwpt_id[1] and destroy it */527		test_cmd_mock_domain_replace(self->stdev_id, parent_hwpt_id);528		test_ioctl_destroy(nested_hwpt_id[1]);529		test_ioctl_destroy(iopf_hwpt_id);530 531		/* Detach from the parent hw_pagetable and destroy it */532		test_cmd_mock_domain_replace(self->stdev_id, self->ioas_id);533		test_ioctl_destroy(parent_hwpt_id);534		test_ioctl_destroy(parent_hwpt_id_not_work);535		close(fault_fd);536		test_ioctl_destroy(fault_id);537	} else {538		test_err_hwpt_alloc(ENOENT, self->device_id, self->ioas_id, 0,539				    &parent_hwpt_id);540		test_err_hwpt_alloc_nested(ENOENT, self->device_id,541					   parent_hwpt_id, 0,542					   &nested_hwpt_id[0],543					   IOMMU_HWPT_DATA_SELFTEST, &data,544					   sizeof(data));545		test_err_hwpt_alloc_nested(ENOENT, self->device_id,546					   parent_hwpt_id, 0,547					   &nested_hwpt_id[1],548					   IOMMU_HWPT_DATA_SELFTEST, &data,549					   sizeof(data));550		test_err_mock_domain_replace(ENOENT, self->stdev_id,551					     nested_hwpt_id[0]);552		test_err_mock_domain_replace(ENOENT, self->stdev_id,553					     nested_hwpt_id[1]);554	}555}556 557TEST_F(iommufd_ioas, hwpt_attach)558{559	/* Create a device attached directly to a hwpt */560	if (self->stdev_id) {561		test_cmd_mock_domain(self->hwpt_id, NULL, NULL, NULL);562	} else {563		test_err_mock_domain(ENOENT, self->hwpt_id, NULL, NULL);564	}565}566 567TEST_F(iommufd_ioas, ioas_area_destroy)568{569	/* Adding an area does not change ability to destroy */570	test_ioctl_ioas_map_fixed(buffer, PAGE_SIZE, self->base_iova);571	if (self->stdev_id)572		EXPECT_ERRNO(EBUSY,573			     _test_ioctl_destroy(self->fd, self->ioas_id));574	else575		test_ioctl_destroy(self->ioas_id);576}577 578TEST_F(iommufd_ioas, ioas_area_auto_destroy)579{580	int i;581 582	/* Can allocate and automatically free an IOAS table with many areas */583	for (i = 0; i != 10; i++) {584		test_ioctl_ioas_map_fixed(buffer, PAGE_SIZE,585					  self->base_iova + i * PAGE_SIZE);586	}587}588 589TEST_F(iommufd_ioas, get_hw_info)590{591	struct iommu_test_hw_info buffer_exact;592	struct iommu_test_hw_info_buffer_larger {593		struct iommu_test_hw_info info;594		uint64_t trailing_bytes;595	} buffer_larger;596	struct iommu_test_hw_info_buffer_smaller {597		__u32 flags;598	} buffer_smaller;599 600	if (self->device_id) {601		/* Provide a zero-size user_buffer */602		test_cmd_get_hw_info(self->device_id, NULL, 0);603		/* Provide a user_buffer with exact size */604		test_cmd_get_hw_info(self->device_id, &buffer_exact, sizeof(buffer_exact));605		/*606		 * Provide a user_buffer with size larger than the exact size to check if607		 * kernel zero the trailing bytes.608		 */609		test_cmd_get_hw_info(self->device_id, &buffer_larger, sizeof(buffer_larger));610		/*611		 * Provide a user_buffer with size smaller than the exact size to check if612		 * the fields within the size range still gets updated.613		 */614		test_cmd_get_hw_info(self->device_id, &buffer_smaller, sizeof(buffer_smaller));615	} else {616		test_err_get_hw_info(ENOENT, self->device_id,617				     &buffer_exact, sizeof(buffer_exact));618		test_err_get_hw_info(ENOENT, self->device_id,619				     &buffer_larger, sizeof(buffer_larger));620	}621}622 623TEST_F(iommufd_ioas, area)624{625	int i;626 627	/* Unmap fails if nothing is mapped */628	for (i = 0; i != 10; i++)629		test_err_ioctl_ioas_unmap(ENOENT, i * PAGE_SIZE, PAGE_SIZE);630 631	/* Unmap works */632	for (i = 0; i != 10; i++)633		test_ioctl_ioas_map_fixed(buffer, PAGE_SIZE,634					  self->base_iova + i * PAGE_SIZE);635	for (i = 0; i != 10; i++)636		test_ioctl_ioas_unmap(self->base_iova + i * PAGE_SIZE,637				      PAGE_SIZE);638 639	/* Split fails */640	test_ioctl_ioas_map_fixed(buffer, PAGE_SIZE * 2,641				  self->base_iova + 16 * PAGE_SIZE);642	test_err_ioctl_ioas_unmap(ENOENT, self->base_iova + 16 * PAGE_SIZE,643				  PAGE_SIZE);644	test_err_ioctl_ioas_unmap(ENOENT, self->base_iova + 17 * PAGE_SIZE,645				  PAGE_SIZE);646 647	/* Over map fails */648	test_err_ioctl_ioas_map_fixed(EEXIST, buffer, PAGE_SIZE * 2,649				      self->base_iova + 16 * PAGE_SIZE);650	test_err_ioctl_ioas_map_fixed(EEXIST, buffer, PAGE_SIZE,651				      self->base_iova + 16 * PAGE_SIZE);652	test_err_ioctl_ioas_map_fixed(EEXIST, buffer, PAGE_SIZE,653				      self->base_iova + 17 * PAGE_SIZE);654	test_err_ioctl_ioas_map_fixed(EEXIST, buffer, PAGE_SIZE * 2,655				      self->base_iova + 15 * PAGE_SIZE);656	test_err_ioctl_ioas_map_fixed(EEXIST, buffer, PAGE_SIZE * 3,657				      self->base_iova + 15 * PAGE_SIZE);658 659	/* unmap all works */660	test_ioctl_ioas_unmap(0, UINT64_MAX);661 662	/* Unmap all succeeds on an empty IOAS */663	test_ioctl_ioas_unmap(0, UINT64_MAX);664}665 666TEST_F(iommufd_ioas, unmap_fully_contained_areas)667{668	uint64_t unmap_len;669	int i;670 671	/* Give no_domain some space to rewind base_iova */672	self->base_iova += 4 * PAGE_SIZE;673 674	for (i = 0; i != 4; i++)675		test_ioctl_ioas_map_fixed(buffer, 8 * PAGE_SIZE,676					  self->base_iova + i * 16 * PAGE_SIZE);677 678	/* Unmap not fully contained area doesn't work */679	test_err_ioctl_ioas_unmap(ENOENT, self->base_iova - 4 * PAGE_SIZE,680				  8 * PAGE_SIZE);681	test_err_ioctl_ioas_unmap(ENOENT,682				  self->base_iova + 3 * 16 * PAGE_SIZE +683					  8 * PAGE_SIZE - 4 * PAGE_SIZE,684				  8 * PAGE_SIZE);685 686	/* Unmap fully contained areas works */687	ASSERT_EQ(0, _test_ioctl_ioas_unmap(self->fd, self->ioas_id,688					    self->base_iova - 4 * PAGE_SIZE,689					    3 * 16 * PAGE_SIZE + 8 * PAGE_SIZE +690						    4 * PAGE_SIZE,691					    &unmap_len));692	ASSERT_EQ(32 * PAGE_SIZE, unmap_len);693}694 695TEST_F(iommufd_ioas, area_auto_iova)696{697	struct iommu_test_cmd test_cmd = {698		.size = sizeof(test_cmd),699		.op = IOMMU_TEST_OP_ADD_RESERVED,700		.id = self->ioas_id,701		.add_reserved = { .start = PAGE_SIZE * 4,702				  .length = PAGE_SIZE * 100 },703	};704	struct iommu_iova_range ranges[1] = {};705	struct iommu_ioas_allow_iovas allow_cmd = {706		.size = sizeof(allow_cmd),707		.ioas_id = self->ioas_id,708		.num_iovas = 1,709		.allowed_iovas = (uintptr_t)ranges,710	};711	__u64 iovas[10];712	int i;713 714	/* Simple 4k pages */715	for (i = 0; i != 10; i++)716		test_ioctl_ioas_map(buffer, PAGE_SIZE, &iovas[i]);717	for (i = 0; i != 10; i++)718		test_ioctl_ioas_unmap(iovas[i], PAGE_SIZE);719 720	/* Kernel automatically aligns IOVAs properly */721	for (i = 0; i != 10; i++) {722		size_t length = PAGE_SIZE * (i + 1);723 724		if (self->stdev_id) {725			test_ioctl_ioas_map(buffer, length, &iovas[i]);726		} else {727			test_ioctl_ioas_map((void *)(1UL << 31), length,728					    &iovas[i]);729		}730		EXPECT_EQ(0, iovas[i] % (1UL << (ffs(length) - 1)));731	}732	for (i = 0; i != 10; i++)733		test_ioctl_ioas_unmap(iovas[i], PAGE_SIZE * (i + 1));734 735	/* Avoids a reserved region */736	ASSERT_EQ(0,737		  ioctl(self->fd, _IOMMU_TEST_CMD(IOMMU_TEST_OP_ADD_RESERVED),738			&test_cmd));739	for (i = 0; i != 10; i++) {740		size_t length = PAGE_SIZE * (i + 1);741 742		test_ioctl_ioas_map(buffer, length, &iovas[i]);743		EXPECT_EQ(0, iovas[i] % (1UL << (ffs(length) - 1)));744		EXPECT_EQ(false,745			  iovas[i] > test_cmd.add_reserved.start &&746				  iovas[i] <747					  test_cmd.add_reserved.start +748						  test_cmd.add_reserved.length);749	}750	for (i = 0; i != 10; i++)751		test_ioctl_ioas_unmap(iovas[i], PAGE_SIZE * (i + 1));752 753	/* Allowed region intersects with a reserved region */754	ranges[0].start = PAGE_SIZE;755	ranges[0].last = PAGE_SIZE * 600;756	EXPECT_ERRNO(EADDRINUSE,757		     ioctl(self->fd, IOMMU_IOAS_ALLOW_IOVAS, &allow_cmd));758 759	/* Allocate from an allowed region */760	if (self->stdev_id) {761		ranges[0].start = MOCK_APERTURE_START + PAGE_SIZE;762		ranges[0].last = MOCK_APERTURE_START + PAGE_SIZE * 600 - 1;763	} else {764		ranges[0].start = PAGE_SIZE * 200;765		ranges[0].last = PAGE_SIZE * 600 - 1;766	}767	ASSERT_EQ(0, ioctl(self->fd, IOMMU_IOAS_ALLOW_IOVAS, &allow_cmd));768	for (i = 0; i != 10; i++) {769		size_t length = PAGE_SIZE * (i + 1);770 771		test_ioctl_ioas_map(buffer, length, &iovas[i]);772		EXPECT_EQ(0, iovas[i] % (1UL << (ffs(length) - 1)));773		EXPECT_EQ(true, iovas[i] >= ranges[0].start);774		EXPECT_EQ(true, iovas[i] <= ranges[0].last);775		EXPECT_EQ(true, iovas[i] + length > ranges[0].start);776		EXPECT_EQ(true, iovas[i] + length <= ranges[0].last + 1);777	}778	for (i = 0; i != 10; i++)779		test_ioctl_ioas_unmap(iovas[i], PAGE_SIZE * (i + 1));780}781 782TEST_F(iommufd_ioas, area_allowed)783{784	struct iommu_test_cmd test_cmd = {785		.size = sizeof(test_cmd),786		.op = IOMMU_TEST_OP_ADD_RESERVED,787		.id = self->ioas_id,788		.add_reserved = { .start = PAGE_SIZE * 4,789				  .length = PAGE_SIZE * 100 },790	};791	struct iommu_iova_range ranges[1] = {};792	struct iommu_ioas_allow_iovas allow_cmd = {793		.size = sizeof(allow_cmd),794		.ioas_id = self->ioas_id,795		.num_iovas = 1,796		.allowed_iovas = (uintptr_t)ranges,797	};798 799	/* Reserved intersects an allowed */800	allow_cmd.num_iovas = 1;801	ranges[0].start = self->base_iova;802	ranges[0].last = ranges[0].start + PAGE_SIZE * 600;803	ASSERT_EQ(0, ioctl(self->fd, IOMMU_IOAS_ALLOW_IOVAS, &allow_cmd));804	test_cmd.add_reserved.start = ranges[0].start + PAGE_SIZE;805	test_cmd.add_reserved.length = PAGE_SIZE;806	EXPECT_ERRNO(EADDRINUSE,807		     ioctl(self->fd,808			   _IOMMU_TEST_CMD(IOMMU_TEST_OP_ADD_RESERVED),809			   &test_cmd));810	allow_cmd.num_iovas = 0;811	ASSERT_EQ(0, ioctl(self->fd, IOMMU_IOAS_ALLOW_IOVAS, &allow_cmd));812 813	/* Allowed intersects a reserved */814	ASSERT_EQ(0,815		  ioctl(self->fd, _IOMMU_TEST_CMD(IOMMU_TEST_OP_ADD_RESERVED),816			&test_cmd));817	allow_cmd.num_iovas = 1;818	ranges[0].start = self->base_iova;819	ranges[0].last = ranges[0].start + PAGE_SIZE * 600;820	EXPECT_ERRNO(EADDRINUSE,821		     ioctl(self->fd, IOMMU_IOAS_ALLOW_IOVAS, &allow_cmd));822}823 824TEST_F(iommufd_ioas, copy_area)825{826	struct iommu_ioas_copy copy_cmd = {827		.size = sizeof(copy_cmd),828		.flags = IOMMU_IOAS_MAP_FIXED_IOVA | IOMMU_IOAS_MAP_WRITEABLE,829		.dst_ioas_id = self->ioas_id,830		.src_ioas_id = self->ioas_id,831		.length = PAGE_SIZE,832	};833 834	test_ioctl_ioas_map_fixed(buffer, PAGE_SIZE, self->base_iova);835 836	/* Copy inside a single IOAS */837	copy_cmd.src_iova = self->base_iova;838	copy_cmd.dst_iova = self->base_iova + PAGE_SIZE;839	ASSERT_EQ(0, ioctl(self->fd, IOMMU_IOAS_COPY, &copy_cmd));840 841	/* Copy between IOAS's */842	copy_cmd.src_iova = self->base_iova;843	copy_cmd.dst_iova = 0;844	test_ioctl_ioas_alloc(&copy_cmd.dst_ioas_id);845	ASSERT_EQ(0, ioctl(self->fd, IOMMU_IOAS_COPY, &copy_cmd));846}847 848TEST_F(iommufd_ioas, iova_ranges)849{850	struct iommu_test_cmd test_cmd = {851		.size = sizeof(test_cmd),852		.op = IOMMU_TEST_OP_ADD_RESERVED,853		.id = self->ioas_id,854		.add_reserved = { .start = PAGE_SIZE, .length = PAGE_SIZE },855	};856	struct iommu_iova_range *ranges = buffer;857	struct iommu_ioas_iova_ranges ranges_cmd = {858		.size = sizeof(ranges_cmd),859		.ioas_id = self->ioas_id,860		.num_iovas = BUFFER_SIZE / sizeof(*ranges),861		.allowed_iovas = (uintptr_t)ranges,862	};863 864	/* Range can be read */865	ASSERT_EQ(0, ioctl(self->fd, IOMMU_IOAS_IOVA_RANGES, &ranges_cmd));866	EXPECT_EQ(1, ranges_cmd.num_iovas);867	if (!self->stdev_id) {868		EXPECT_EQ(0, ranges[0].start);869		EXPECT_EQ(SIZE_MAX, ranges[0].last);870		EXPECT_EQ(1, ranges_cmd.out_iova_alignment);871	} else {872		EXPECT_EQ(MOCK_APERTURE_START, ranges[0].start);873		EXPECT_EQ(MOCK_APERTURE_LAST, ranges[0].last);874		EXPECT_EQ(MOCK_PAGE_SIZE, ranges_cmd.out_iova_alignment);875	}876 877	/* Buffer too small */878	memset(ranges, 0, BUFFER_SIZE);879	ranges_cmd.num_iovas = 0;880	EXPECT_ERRNO(EMSGSIZE,881		     ioctl(self->fd, IOMMU_IOAS_IOVA_RANGES, &ranges_cmd));882	EXPECT_EQ(1, ranges_cmd.num_iovas);883	EXPECT_EQ(0, ranges[0].start);884	EXPECT_EQ(0, ranges[0].last);885 886	/* 2 ranges */887	ASSERT_EQ(0,888		  ioctl(self->fd, _IOMMU_TEST_CMD(IOMMU_TEST_OP_ADD_RESERVED),889			&test_cmd));890	ranges_cmd.num_iovas = BUFFER_SIZE / sizeof(*ranges);891	ASSERT_EQ(0, ioctl(self->fd, IOMMU_IOAS_IOVA_RANGES, &ranges_cmd));892	if (!self->stdev_id) {893		EXPECT_EQ(2, ranges_cmd.num_iovas);894		EXPECT_EQ(0, ranges[0].start);895		EXPECT_EQ(PAGE_SIZE - 1, ranges[0].last);896		EXPECT_EQ(PAGE_SIZE * 2, ranges[1].start);897		EXPECT_EQ(SIZE_MAX, ranges[1].last);898	} else {899		EXPECT_EQ(1, ranges_cmd.num_iovas);900		EXPECT_EQ(MOCK_APERTURE_START, ranges[0].start);901		EXPECT_EQ(MOCK_APERTURE_LAST, ranges[0].last);902	}903 904	/* Buffer too small */905	memset(ranges, 0, BUFFER_SIZE);906	ranges_cmd.num_iovas = 1;907	if (!self->stdev_id) {908		EXPECT_ERRNO(EMSGSIZE, ioctl(self->fd, IOMMU_IOAS_IOVA_RANGES,909					     &ranges_cmd));910		EXPECT_EQ(2, ranges_cmd.num_iovas);911		EXPECT_EQ(0, ranges[0].start);912		EXPECT_EQ(PAGE_SIZE - 1, ranges[0].last);913	} else {914		ASSERT_EQ(0,915			  ioctl(self->fd, IOMMU_IOAS_IOVA_RANGES, &ranges_cmd));916		EXPECT_EQ(1, ranges_cmd.num_iovas);917		EXPECT_EQ(MOCK_APERTURE_START, ranges[0].start);918		EXPECT_EQ(MOCK_APERTURE_LAST, ranges[0].last);919	}920	EXPECT_EQ(0, ranges[1].start);921	EXPECT_EQ(0, ranges[1].last);922}923 924TEST_F(iommufd_ioas, access_domain_destory)925{926	struct iommu_test_cmd access_cmd = {927		.size = sizeof(access_cmd),928		.op = IOMMU_TEST_OP_ACCESS_PAGES,929		.access_pages = { .iova = self->base_iova + PAGE_SIZE,930				  .length = PAGE_SIZE},931	};932	size_t buf_size = 2 * HUGEPAGE_SIZE;933	uint8_t *buf;934 935	buf = mmap(0, buf_size, PROT_READ | PROT_WRITE,936		   MAP_SHARED | MAP_ANONYMOUS | MAP_HUGETLB | MAP_POPULATE, -1,937		   0);938	ASSERT_NE(MAP_FAILED, buf);939	test_ioctl_ioas_map_fixed(buf, buf_size, self->base_iova);940 941	test_cmd_create_access(self->ioas_id, &access_cmd.id,942			       MOCK_FLAGS_ACCESS_CREATE_NEEDS_PIN_PAGES);943	access_cmd.access_pages.uptr = (uintptr_t)buf + PAGE_SIZE;944	ASSERT_EQ(0,945		  ioctl(self->fd, _IOMMU_TEST_CMD(IOMMU_TEST_OP_ACCESS_PAGES),946			&access_cmd));947 948	/* Causes a complicated unpin across a huge page boundary */949	if (self->stdev_id)950		test_ioctl_destroy(self->stdev_id);951 952	test_cmd_destroy_access_pages(953		access_cmd.id, access_cmd.access_pages.out_access_pages_id);954	test_cmd_destroy_access(access_cmd.id);955	ASSERT_EQ(0, munmap(buf, buf_size));956}957 958TEST_F(iommufd_ioas, access_pin)959{960	struct iommu_test_cmd access_cmd = {961		.size = sizeof(access_cmd),962		.op = IOMMU_TEST_OP_ACCESS_PAGES,963		.access_pages = { .iova = MOCK_APERTURE_START,964				  .length = BUFFER_SIZE,965				  .uptr = (uintptr_t)buffer },966	};967	struct iommu_test_cmd check_map_cmd = {968		.size = sizeof(check_map_cmd),969		.op = IOMMU_TEST_OP_MD_CHECK_MAP,970		.check_map = { .iova = MOCK_APERTURE_START,971			       .length = BUFFER_SIZE,972			       .uptr = (uintptr_t)buffer },973	};974	uint32_t access_pages_id;975	unsigned int npages;976 977	test_cmd_create_access(self->ioas_id, &access_cmd.id,978			       MOCK_FLAGS_ACCESS_CREATE_NEEDS_PIN_PAGES);979 980	for (npages = 1; npages < BUFFER_SIZE / PAGE_SIZE; npages++) {981		uint32_t mock_stdev_id;982		uint32_t mock_hwpt_id;983 984		access_cmd.access_pages.length = npages * PAGE_SIZE;985 986		/* Single map/unmap */987		test_ioctl_ioas_map_fixed(buffer, BUFFER_SIZE,988					  MOCK_APERTURE_START);989		ASSERT_EQ(0, ioctl(self->fd,990				   _IOMMU_TEST_CMD(IOMMU_TEST_OP_ACCESS_PAGES),991				   &access_cmd));992		test_cmd_destroy_access_pages(993			access_cmd.id,994			access_cmd.access_pages.out_access_pages_id);995 996		/* Double user */997		ASSERT_EQ(0, ioctl(self->fd,998				   _IOMMU_TEST_CMD(IOMMU_TEST_OP_ACCESS_PAGES),999				   &access_cmd));1000		access_pages_id = access_cmd.access_pages.out_access_pages_id;1001		ASSERT_EQ(0, ioctl(self->fd,1002				   _IOMMU_TEST_CMD(IOMMU_TEST_OP_ACCESS_PAGES),1003				   &access_cmd));1004		test_cmd_destroy_access_pages(1005			access_cmd.id,1006			access_cmd.access_pages.out_access_pages_id);1007		test_cmd_destroy_access_pages(access_cmd.id, access_pages_id);1008 1009		/* Add/remove a domain with a user */1010		ASSERT_EQ(0, ioctl(self->fd,1011				   _IOMMU_TEST_CMD(IOMMU_TEST_OP_ACCESS_PAGES),1012				   &access_cmd));1013		test_cmd_mock_domain(self->ioas_id, &mock_stdev_id,1014				     &mock_hwpt_id, NULL);1015		check_map_cmd.id = mock_hwpt_id;1016		ASSERT_EQ(0, ioctl(self->fd,1017				   _IOMMU_TEST_CMD(IOMMU_TEST_OP_MD_CHECK_MAP),1018				   &check_map_cmd));1019 1020		test_ioctl_destroy(mock_stdev_id);1021		test_cmd_destroy_access_pages(1022			access_cmd.id,1023			access_cmd.access_pages.out_access_pages_id);1024 1025		test_ioctl_ioas_unmap(MOCK_APERTURE_START, BUFFER_SIZE);1026	}1027	test_cmd_destroy_access(access_cmd.id);1028}1029 1030TEST_F(iommufd_ioas, access_pin_unmap)1031{1032	struct iommu_test_cmd access_pages_cmd = {1033		.size = sizeof(access_pages_cmd),1034		.op = IOMMU_TEST_OP_ACCESS_PAGES,1035		.access_pages = { .iova = MOCK_APERTURE_START,1036				  .length = BUFFER_SIZE,1037				  .uptr = (uintptr_t)buffer },1038	};1039 1040	test_cmd_create_access(self->ioas_id, &access_pages_cmd.id,1041			       MOCK_FLAGS_ACCESS_CREATE_NEEDS_PIN_PAGES);1042	test_ioctl_ioas_map_fixed(buffer, BUFFER_SIZE, MOCK_APERTURE_START);1043	ASSERT_EQ(0,1044		  ioctl(self->fd, _IOMMU_TEST_CMD(IOMMU_TEST_OP_ACCESS_PAGES),1045			&access_pages_cmd));1046 1047	/* Trigger the unmap op */1048	test_ioctl_ioas_unmap(MOCK_APERTURE_START, BUFFER_SIZE);1049 1050	/* kernel removed the item for us */1051	test_err_destroy_access_pages(1052		ENOENT, access_pages_cmd.id,1053		access_pages_cmd.access_pages.out_access_pages_id);1054}1055 1056static void check_access_rw(struct __test_metadata *_metadata, int fd,1057			    unsigned int access_id, uint64_t iova,1058			    unsigned int def_flags)1059{1060	uint16_t tmp[32];1061	struct iommu_test_cmd access_cmd = {1062		.size = sizeof(access_cmd),1063		.op = IOMMU_TEST_OP_ACCESS_RW,1064		.id = access_id,1065		.access_rw = { .uptr = (uintptr_t)tmp },1066	};1067	uint16_t *buffer16 = buffer;1068	unsigned int i;1069	void *tmp2;1070 1071	for (i = 0; i != BUFFER_SIZE / sizeof(*buffer16); i++)1072		buffer16[i] = rand();1073 1074	for (access_cmd.access_rw.iova = iova + PAGE_SIZE - 50;1075	     access_cmd.access_rw.iova < iova + PAGE_SIZE + 50;1076	     access_cmd.access_rw.iova++) {1077		for (access_cmd.access_rw.length = 1;1078		     access_cmd.access_rw.length < sizeof(tmp);1079		     access_cmd.access_rw.length++) {1080			access_cmd.access_rw.flags = def_flags;1081			ASSERT_EQ(0, ioctl(fd,1082					   _IOMMU_TEST_CMD(1083						   IOMMU_TEST_OP_ACCESS_RW),1084					   &access_cmd));1085			ASSERT_EQ(0,1086				  memcmp(buffer + (access_cmd.access_rw.iova -1087						   iova),1088					 tmp, access_cmd.access_rw.length));1089 1090			for (i = 0; i != ARRAY_SIZE(tmp); i++)1091				tmp[i] = rand();1092			access_cmd.access_rw.flags = def_flags |1093						     MOCK_ACCESS_RW_WRITE;1094			ASSERT_EQ(0, ioctl(fd,1095					   _IOMMU_TEST_CMD(1096						   IOMMU_TEST_OP_ACCESS_RW),1097					   &access_cmd));1098			ASSERT_EQ(0,1099				  memcmp(buffer + (access_cmd.access_rw.iova -1100						   iova),1101					 tmp, access_cmd.access_rw.length));1102		}1103	}1104 1105	/* Multi-page test */1106	tmp2 = malloc(BUFFER_SIZE);1107	ASSERT_NE(NULL, tmp2);1108	access_cmd.access_rw.iova = iova;1109	access_cmd.access_rw.length = BUFFER_SIZE;1110	access_cmd.access_rw.flags = def_flags;1111	access_cmd.access_rw.uptr = (uintptr_t)tmp2;1112	ASSERT_EQ(0, ioctl(fd, _IOMMU_TEST_CMD(IOMMU_TEST_OP_ACCESS_RW),1113			   &access_cmd));1114	ASSERT_EQ(0, memcmp(buffer, tmp2, access_cmd.access_rw.length));1115	free(tmp2);1116}1117 1118TEST_F(iommufd_ioas, access_rw)1119{1120	__u32 access_id;1121	__u64 iova;1122 1123	test_cmd_create_access(self->ioas_id, &access_id, 0);1124	test_ioctl_ioas_map(buffer, BUFFER_SIZE, &iova);1125	check_access_rw(_metadata, self->fd, access_id, iova, 0);1126	check_access_rw(_metadata, self->fd, access_id, iova,1127			MOCK_ACCESS_RW_SLOW_PATH);1128	test_ioctl_ioas_unmap(iova, BUFFER_SIZE);1129	test_cmd_destroy_access(access_id);1130}1131 1132TEST_F(iommufd_ioas, access_rw_unaligned)1133{1134	__u32 access_id;1135	__u64 iova;1136 1137	test_cmd_create_access(self->ioas_id, &access_id, 0);1138 1139	/* Unaligned pages */1140	iova = self->base_iova + MOCK_PAGE_SIZE;1141	test_ioctl_ioas_map_fixed(buffer, BUFFER_SIZE, iova);1142	check_access_rw(_metadata, self->fd, access_id, iova, 0);1143	test_ioctl_ioas_unmap(iova, BUFFER_SIZE);1144	test_cmd_destroy_access(access_id);1145}1146 1147TEST_F(iommufd_ioas, fork_gone)1148{1149	__u32 access_id;1150	pid_t child;1151 1152	test_cmd_create_access(self->ioas_id, &access_id, 0);1153 1154	/* Create a mapping with a different mm */1155	child = fork();1156	if (!child) {1157		test_ioctl_ioas_map_fixed(buffer, BUFFER_SIZE,1158					  MOCK_APERTURE_START);1159		exit(0);1160	}1161	ASSERT_NE(-1, child);1162	ASSERT_EQ(child, waitpid(child, NULL, 0));1163 1164	if (self->stdev_id) {1165		/*1166		 * If a domain already existed then everything was pinned within1167		 * the fork, so this copies from one domain to another.1168		 */1169		test_cmd_mock_domain(self->ioas_id, NULL, NULL, NULL);1170		check_access_rw(_metadata, self->fd, access_id,1171				MOCK_APERTURE_START, 0);1172 1173	} else {1174		/*1175		 * Otherwise we need to actually pin pages which can't happen1176		 * since the fork is gone.1177		 */1178		test_err_mock_domain(EFAULT, self->ioas_id, NULL, NULL);1179	}1180 1181	test_cmd_destroy_access(access_id);1182}1183 1184TEST_F(iommufd_ioas, fork_present)1185{1186	__u32 access_id;1187	int pipefds[2];1188	uint64_t tmp;1189	pid_t child;1190	int efd;1191 1192	test_cmd_create_access(self->ioas_id, &access_id, 0);1193 1194	ASSERT_EQ(0, pipe2(pipefds, O_CLOEXEC));1195	efd = eventfd(0, EFD_CLOEXEC);1196	ASSERT_NE(-1, efd);1197 1198	/* Create a mapping with a different mm */1199	child = fork();1200	if (!child) {1201		__u64 iova;1202		uint64_t one = 1;1203 1204		close(pipefds[1]);1205		test_ioctl_ioas_map_fixed(buffer, BUFFER_SIZE,1206					  MOCK_APERTURE_START);1207		if (write(efd, &one, sizeof(one)) != sizeof(one))1208			exit(100);1209		if (read(pipefds[0], &iova, 1) != 1)1210			exit(100);1211		exit(0);1212	}1213	close(pipefds[0]);1214	ASSERT_NE(-1, child);1215	ASSERT_EQ(8, read(efd, &tmp, sizeof(tmp)));1216 1217	/* Read pages from the remote process */1218	test_cmd_mock_domain(self->ioas_id, NULL, NULL, NULL);1219	check_access_rw(_metadata, self->fd, access_id, MOCK_APERTURE_START, 0);1220 1221	ASSERT_EQ(0, close(pipefds[1]));1222	ASSERT_EQ(child, waitpid(child, NULL, 0));1223 1224	test_cmd_destroy_access(access_id);1225}1226 1227TEST_F(iommufd_ioas, ioas_option_huge_pages)1228{1229	struct iommu_option cmd = {1230		.size = sizeof(cmd),1231		.option_id = IOMMU_OPTION_HUGE_PAGES,1232		.op = IOMMU_OPTION_OP_GET,1233		.val64 = 3,1234		.object_id = self->ioas_id,1235	};1236 1237	ASSERT_EQ(0, ioctl(self->fd, IOMMU_OPTION, &cmd));1238	ASSERT_EQ(1, cmd.val64);1239 1240	cmd.op = IOMMU_OPTION_OP_SET;1241	cmd.val64 = 0;1242	ASSERT_EQ(0, ioctl(self->fd, IOMMU_OPTION, &cmd));1243 1244	cmd.op = IOMMU_OPTION_OP_GET;1245	cmd.val64 = 3;1246	ASSERT_EQ(0, ioctl(self->fd, IOMMU_OPTION, &cmd));1247	ASSERT_EQ(0, cmd.val64);1248 1249	cmd.op = IOMMU_OPTION_OP_SET;1250	cmd.val64 = 2;1251	EXPECT_ERRNO(EINVAL, ioctl(self->fd, IOMMU_OPTION, &cmd));1252 1253	cmd.op = IOMMU_OPTION_OP_SET;1254	cmd.val64 = 1;1255	ASSERT_EQ(0, ioctl(self->fd, IOMMU_OPTION, &cmd));1256}1257 1258TEST_F(iommufd_ioas, ioas_iova_alloc)1259{1260	unsigned int length;1261	__u64 iova;1262 1263	for (length = 1; length != PAGE_SIZE * 2; length++) {1264		if (variant->mock_domains && (length % MOCK_PAGE_SIZE)) {1265			test_err_ioctl_ioas_map(EINVAL, buffer, length, &iova);1266		} else {1267			test_ioctl_ioas_map(buffer, length, &iova);1268			test_ioctl_ioas_unmap(iova, length);1269		}1270	}1271}1272 1273TEST_F(iommufd_ioas, ioas_align_change)1274{1275	struct iommu_option cmd = {1276		.size = sizeof(cmd),1277		.option_id = IOMMU_OPTION_HUGE_PAGES,1278		.op = IOMMU_OPTION_OP_SET,1279		.object_id = self->ioas_id,1280		/* 0 means everything must be aligned to PAGE_SIZE */1281		.val64 = 0,1282	};1283 1284	/*1285	 * We cannot upgrade the alignment using OPTION_HUGE_PAGES when a domain1286	 * and map are present.1287	 */1288	if (variant->mock_domains)1289		return;1290 1291	/*1292	 * We can upgrade to PAGE_SIZE alignment when things are aligned right1293	 */1294	test_ioctl_ioas_map_fixed(buffer, PAGE_SIZE, MOCK_APERTURE_START);1295	ASSERT_EQ(0, ioctl(self->fd, IOMMU_OPTION, &cmd));1296 1297	/* Misalignment is rejected at map time */1298	test_err_ioctl_ioas_map_fixed(EINVAL, buffer + MOCK_PAGE_SIZE,1299				      PAGE_SIZE,1300				      MOCK_APERTURE_START + PAGE_SIZE);1301	ASSERT_EQ(0, ioctl(self->fd, IOMMU_OPTION, &cmd));1302 1303	/* Reduce alignment */1304	cmd.val64 = 1;1305	ASSERT_EQ(0, ioctl(self->fd, IOMMU_OPTION, &cmd));1306 1307	/* Confirm misalignment is rejected during alignment upgrade */1308	test_ioctl_ioas_map_fixed(buffer + MOCK_PAGE_SIZE, PAGE_SIZE,1309				  MOCK_APERTURE_START + PAGE_SIZE);1310	cmd.val64 = 0;1311	EXPECT_ERRNO(EADDRINUSE, ioctl(self->fd, IOMMU_OPTION, &cmd));1312 1313	test_ioctl_ioas_unmap(MOCK_APERTURE_START + PAGE_SIZE, PAGE_SIZE);1314	test_ioctl_ioas_unmap(MOCK_APERTURE_START, PAGE_SIZE);1315}1316 1317TEST_F(iommufd_ioas, copy_sweep)1318{1319	struct iommu_ioas_copy copy_cmd = {1320		.size = sizeof(copy_cmd),1321		.flags = IOMMU_IOAS_MAP_FIXED_IOVA | IOMMU_IOAS_MAP_WRITEABLE,1322		.src_ioas_id = self->ioas_id,1323		.dst_iova = MOCK_APERTURE_START,1324		.length = MOCK_PAGE_SIZE,1325	};1326	unsigned int dst_ioas_id;1327	uint64_t last_iova;1328	uint64_t iova;1329 1330	test_ioctl_ioas_alloc(&dst_ioas_id);1331	copy_cmd.dst_ioas_id = dst_ioas_id;1332 1333	if (variant->mock_domains)1334		last_iova = MOCK_APERTURE_START + BUFFER_SIZE - 1;1335	else1336		last_iova = MOCK_APERTURE_START + BUFFER_SIZE - 2;1337 1338	test_ioctl_ioas_map_fixed(buffer, last_iova - MOCK_APERTURE_START + 1,1339				  MOCK_APERTURE_START);1340 1341	for (iova = MOCK_APERTURE_START - PAGE_SIZE; iova <= last_iova;1342	     iova += 511) {1343		copy_cmd.src_iova = iova;1344		if (iova < MOCK_APERTURE_START ||1345		    iova + copy_cmd.length - 1 > last_iova) {1346			EXPECT_ERRNO(ENOENT, ioctl(self->fd, IOMMU_IOAS_COPY,1347						   &copy_cmd));1348		} else {1349			ASSERT_EQ(0,1350				  ioctl(self->fd, IOMMU_IOAS_COPY, &copy_cmd));1351			test_ioctl_ioas_unmap_id(dst_ioas_id, copy_cmd.dst_iova,1352						 copy_cmd.length);1353		}1354	}1355 1356	test_ioctl_destroy(dst_ioas_id);1357}1358 1359FIXTURE(iommufd_mock_domain)1360{1361	int fd;1362	uint32_t ioas_id;1363	uint32_t hwpt_id;1364	uint32_t hwpt_ids[2];1365	uint32_t stdev_ids[2];1366	uint32_t idev_ids[2];1367	int mmap_flags;1368	size_t mmap_buf_size;1369};1370 1371FIXTURE_VARIANT(iommufd_mock_domain)1372{1373	unsigned int mock_domains;1374	bool hugepages;1375};1376 1377FIXTURE_SETUP(iommufd_mock_domain)1378{1379	unsigned int i;1380 1381	self->fd = open("/dev/iommu", O_RDWR);1382	ASSERT_NE(-1, self->fd);1383	test_ioctl_ioas_alloc(&self->ioas_id);1384 1385	ASSERT_GE(ARRAY_SIZE(self->hwpt_ids), variant->mock_domains);1386 1387	for (i = 0; i != variant->mock_domains; i++)1388		test_cmd_mock_domain(self->ioas_id, &self->stdev_ids[i],1389				     &self->hwpt_ids[i], &self->idev_ids[i]);1390	self->hwpt_id = self->hwpt_ids[0];1391 1392	self->mmap_flags = MAP_SHARED | MAP_ANONYMOUS;1393	self->mmap_buf_size = PAGE_SIZE * 8;1394	if (variant->hugepages) {1395		/*1396		 * MAP_POPULATE will cause the kernel to fail mmap if THPs are1397		 * not available.1398		 */1399		self->mmap_flags |= MAP_HUGETLB | MAP_POPULATE;1400		self->mmap_buf_size = HUGEPAGE_SIZE * 2;1401	}1402}1403 1404FIXTURE_TEARDOWN(iommufd_mock_domain)1405{1406	teardown_iommufd(self->fd, _metadata);1407}1408 1409FIXTURE_VARIANT_ADD(iommufd_mock_domain, one_domain)1410{1411	.mock_domains = 1,1412	.hugepages = false,1413};1414 1415FIXTURE_VARIANT_ADD(iommufd_mock_domain, two_domains)1416{1417	.mock_domains = 2,1418	.hugepages = false,1419};1420 1421FIXTURE_VARIANT_ADD(iommufd_mock_domain, one_domain_hugepage)1422{1423	.mock_domains = 1,1424	.hugepages = true,1425};1426 1427FIXTURE_VARIANT_ADD(iommufd_mock_domain, two_domains_hugepage)1428{1429	.mock_domains = 2,1430	.hugepages = true,1431};1432 1433/* Have the kernel check that the user pages made it to the iommu_domain */1434#define check_mock_iova(_ptr, _iova, _length)                                \1435	({                                                                   \1436		struct iommu_test_cmd check_map_cmd = {                      \1437			.size = sizeof(check_map_cmd),                       \1438			.op = IOMMU_TEST_OP_MD_CHECK_MAP,                    \1439			.id = self->hwpt_id,                                 \1440			.check_map = { .iova = _iova,                        \1441				       .length = _length,                    \1442				       .uptr = (uintptr_t)(_ptr) },          \1443		};                                                           \1444		ASSERT_EQ(0,                                                 \1445			  ioctl(self->fd,                                    \1446				_IOMMU_TEST_CMD(IOMMU_TEST_OP_MD_CHECK_MAP), \1447				&check_map_cmd));                            \1448		if (self->hwpt_ids[1]) {                                     \1449			check_map_cmd.id = self->hwpt_ids[1];                \1450			ASSERT_EQ(0,                                         \1451				  ioctl(self->fd,                            \1452					_IOMMU_TEST_CMD(                     \1453						IOMMU_TEST_OP_MD_CHECK_MAP), \1454					&check_map_cmd));                    \1455		}                                                            \1456	})1457 1458TEST_F(iommufd_mock_domain, basic)1459{1460	size_t buf_size = self->mmap_buf_size;1461	uint8_t *buf;1462	__u64 iova;1463 1464	/* Simple one page map */1465	test_ioctl_ioas_map(buffer, PAGE_SIZE, &iova);1466	check_mock_iova(buffer, iova, PAGE_SIZE);1467 1468	buf = mmap(0, buf_size, PROT_READ | PROT_WRITE, self->mmap_flags, -1,1469		   0);1470	ASSERT_NE(MAP_FAILED, buf);1471 1472	/* EFAULT half way through mapping */1473	ASSERT_EQ(0, munmap(buf + buf_size / 2, buf_size / 2));1474	test_err_ioctl_ioas_map(EFAULT, buf, buf_size, &iova);1475 1476	/* EFAULT on first page */1477	ASSERT_EQ(0, munmap(buf, buf_size / 2));1478	test_err_ioctl_ioas_map(EFAULT, buf, buf_size, &iova);1479}1480 1481TEST_F(iommufd_mock_domain, ro_unshare)1482{1483	uint8_t *buf;1484	__u64 iova;1485	int fd;1486 1487	fd = open("/proc/self/exe", O_RDONLY);1488	ASSERT_NE(-1, fd);1489 1490	buf = mmap(0, PAGE_SIZE, PROT_READ | PROT_WRITE, MAP_PRIVATE, fd, 0);1491	ASSERT_NE(MAP_FAILED, buf);1492	close(fd);1493 1494	/*1495	 * There have been lots of changes to the "unshare" mechanism in1496	 * get_user_pages(), make sure it works right. The write to the page1497	 * after we map it for reading should not change the assigned PFN.1498	 */1499	ASSERT_EQ(0,1500		  _test_ioctl_ioas_map(self->fd, self->ioas_id, buf, PAGE_SIZE,1501				       &iova, IOMMU_IOAS_MAP_READABLE));1502	check_mock_iova(buf, iova, PAGE_SIZE);1503	memset(buf, 1, PAGE_SIZE);1504	check_mock_iova(buf, iova, PAGE_SIZE);1505	ASSERT_EQ(0, munmap(buf, PAGE_SIZE));1506}1507 1508TEST_F(iommufd_mock_domain, all_aligns)1509{1510	size_t test_step = variant->hugepages ? (self->mmap_buf_size / 16) :1511						MOCK_PAGE_SIZE;1512	size_t buf_size = self->mmap_buf_size;1513	unsigned int start;1514	unsigned int end;1515	uint8_t *buf;1516 1517	buf = mmap(0, buf_size, PROT_READ | PROT_WRITE, self->mmap_flags, -1,1518		   0);1519	ASSERT_NE(MAP_FAILED, buf);1520	check_refs(buf, buf_size, 0);1521 1522	/*1523	 * Map every combination of page size and alignment within a big region,1524	 * less for hugepage case as it takes so long to finish.1525	 */1526	for (start = 0; start < buf_size; start += test_step) {1527		if (variant->hugepages)1528			end = buf_size;1529		else1530			end = start + MOCK_PAGE_SIZE;1531		for (; end < buf_size; end += MOCK_PAGE_SIZE) {1532			size_t length = end - start;1533			__u64 iova;1534 1535			test_ioctl_ioas_map(buf + start, length, &iova);1536			check_mock_iova(buf + start, iova, length);1537			check_refs(buf + start / PAGE_SIZE * PAGE_SIZE,1538				   end / PAGE_SIZE * PAGE_SIZE -1539					   start / PAGE_SIZE * PAGE_SIZE,1540				   1);1541 1542			test_ioctl_ioas_unmap(iova, length);1543		}1544	}1545	check_refs(buf, buf_size, 0);1546	ASSERT_EQ(0, munmap(buf, buf_size));1547}1548 1549TEST_F(iommufd_mock_domain, all_aligns_copy)1550{1551	size_t test_step = variant->hugepages ? self->mmap_buf_size / 16 :1552						MOCK_PAGE_SIZE;1553	size_t buf_size = self->mmap_buf_size;1554	unsigned int start;1555	unsigned int end;1556	uint8_t *buf;1557 1558	buf = mmap(0, buf_size, PROT_READ | PROT_WRITE, self->mmap_flags, -1,1559		   0);1560	ASSERT_NE(MAP_FAILED, buf);1561	check_refs(buf, buf_size, 0);1562 1563	/*1564	 * Map every combination of page size and alignment within a big region,1565	 * less for hugepage case as it takes so long to finish.1566	 */1567	for (start = 0; start < buf_size; start += test_step) {1568		if (variant->hugepages)1569			end = buf_size;1570		else1571			end = start + MOCK_PAGE_SIZE;1572		for (; end < buf_size; end += MOCK_PAGE_SIZE) {1573			size_t length = end - start;1574			unsigned int old_id;1575			uint32_t mock_stdev_id;1576			__u64 iova;1577 1578			test_ioctl_ioas_map(buf + start, length, &iova);1579 1580			/* Add and destroy a domain while the area exists */1581			old_id = self->hwpt_ids[1];1582			test_cmd_mock_domain(self->ioas_id, &mock_stdev_id,1583					     &self->hwpt_ids[1], NULL);1584 1585			check_mock_iova(buf + start, iova, length);1586			check_refs(buf + start / PAGE_SIZE * PAGE_SIZE,1587				   end / PAGE_SIZE * PAGE_SIZE -1588					   start / PAGE_SIZE * PAGE_SIZE,1589				   1);1590 1591			test_ioctl_destroy(mock_stdev_id);1592			self->hwpt_ids[1] = old_id;1593 1594			test_ioctl_ioas_unmap(iova, length);1595		}1596	}1597	check_refs(buf, buf_size, 0);1598	ASSERT_EQ(0, munmap(buf, buf_size));1599}1600 1601TEST_F(iommufd_mock_domain, user_copy)1602{1603	struct iommu_test_cmd access_cmd = {1604		.size = sizeof(access_cmd),1605		.op = IOMMU_TEST_OP_ACCESS_PAGES,1606		.access_pages = { .length = BUFFER_SIZE,1607				  .uptr = (uintptr_t)buffer },1608	};1609	struct iommu_ioas_copy copy_cmd = {1610		.size = sizeof(copy_cmd),1611		.flags = IOMMU_IOAS_MAP_FIXED_IOVA | IOMMU_IOAS_MAP_WRITEABLE,1612		.dst_ioas_id = self->ioas_id,1613		.dst_iova = MOCK_APERTURE_START,1614		.length = BUFFER_SIZE,1615	};1616	struct iommu_ioas_unmap unmap_cmd = {1617		.size = sizeof(unmap_cmd),1618		.ioas_id = self->ioas_id,1619		.iova = MOCK_APERTURE_START,1620		.length = BUFFER_SIZE,1621	};1622	unsigned int new_ioas_id, ioas_id;1623 1624	/* Pin the pages in an IOAS with no domains then copy to an IOAS with domains */1625	test_ioctl_ioas_alloc(&ioas_id);1626	test_ioctl_ioas_map_id(ioas_id, buffer, BUFFER_SIZE,1627			       &copy_cmd.src_iova);1628 1629	test_cmd_create_access(ioas_id, &access_cmd.id,1630			       MOCK_FLAGS_ACCESS_CREATE_NEEDS_PIN_PAGES);1631 1632	access_cmd.access_pages.iova = copy_cmd.src_iova;1633	ASSERT_EQ(0,1634		  ioctl(self->fd, _IOMMU_TEST_CMD(IOMMU_TEST_OP_ACCESS_PAGES),1635			&access_cmd));1636	copy_cmd.src_ioas_id = ioas_id;1637	ASSERT_EQ(0, ioctl(self->fd, IOMMU_IOAS_COPY, &copy_cmd));1638	check_mock_iova(buffer, MOCK_APERTURE_START, BUFFER_SIZE);1639 1640	/* Now replace the ioas with a new one */1641	test_ioctl_ioas_alloc(&new_ioas_id);1642	test_ioctl_ioas_map_id(new_ioas_id, buffer, BUFFER_SIZE,1643			       &copy_cmd.src_iova);1644	test_cmd_access_replace_ioas(access_cmd.id, new_ioas_id);1645 1646	/* Destroy the old ioas and cleanup copied mapping */1647	ASSERT_EQ(0, ioctl(self->fd, IOMMU_IOAS_UNMAP, &unmap_cmd));1648	test_ioctl_destroy(ioas_id);1649 1650	/* Then run the same test again with the new ioas */1651	access_cmd.access_pages.iova = copy_cmd.src_iova;1652	ASSERT_EQ(0,1653		  ioctl(self->fd, _IOMMU_TEST_CMD(IOMMU_TEST_OP_ACCESS_PAGES),1654			&access_cmd));1655	copy_cmd.src_ioas_id = new_ioas_id;1656	ASSERT_EQ(0, ioctl(self->fd, IOMMU_IOAS_COPY, &copy_cmd));1657	check_mock_iova(buffer, MOCK_APERTURE_START, BUFFER_SIZE);1658 1659	test_cmd_destroy_access_pages(1660		access_cmd.id, access_cmd.access_pages.out_access_pages_id);1661	test_cmd_destroy_access(access_cmd.id);1662 1663	test_ioctl_destroy(new_ioas_id);1664}1665 1666TEST_F(iommufd_mock_domain, replace)1667{1668	uint32_t ioas_id;1669 1670	test_ioctl_ioas_alloc(&ioas_id);1671 1672	test_cmd_mock_domain_replace(self->stdev_ids[0], ioas_id);1673 1674	/*1675	 * Replacing the IOAS causes the prior HWPT to be deallocated, thus we1676	 * should get enoent when we try to use it.1677	 */1678	if (variant->mock_domains == 1)1679		test_err_mock_domain_replace(ENOENT, self->stdev_ids[0],1680					     self->hwpt_ids[0]);1681 1682	test_cmd_mock_domain_replace(self->stdev_ids[0], ioas_id);1683	if (variant->mock_domains >= 2) {1684		test_cmd_mock_domain_replace(self->stdev_ids[0],1685					     self->hwpt_ids[1]);1686		test_cmd_mock_domain_replace(self->stdev_ids[0],1687					     self->hwpt_ids[1]);1688		test_cmd_mock_domain_replace(self->stdev_ids[0],1689					     self->hwpt_ids[0]);1690	}1691 1692	test_cmd_mock_domain_replace(self->stdev_ids[0], self->ioas_id);1693	test_ioctl_destroy(ioas_id);1694}1695 1696TEST_F(iommufd_mock_domain, alloc_hwpt)1697{1698	int i;1699 1700	for (i = 0; i != variant->mock_domains; i++) {1701		uint32_t hwpt_id[2];1702		uint32_t stddev_id;1703 1704		test_err_hwpt_alloc(EOPNOTSUPP,1705				    self->idev_ids[i], self->ioas_id,1706				    ~IOMMU_HWPT_ALLOC_NEST_PARENT, &hwpt_id[0]);1707		test_cmd_hwpt_alloc(self->idev_ids[i], self->ioas_id,1708				    0, &hwpt_id[0]);1709		test_cmd_hwpt_alloc(self->idev_ids[i], self->ioas_id,1710				    IOMMU_HWPT_ALLOC_NEST_PARENT, &hwpt_id[1]);1711 1712		/* Do a hw_pagetable rotation test */1713		test_cmd_mock_domain_replace(self->stdev_ids[i], hwpt_id[0]);1714		EXPECT_ERRNO(EBUSY, _test_ioctl_destroy(self->fd, hwpt_id[0]));1715		test_cmd_mock_domain_replace(self->stdev_ids[i], hwpt_id[1]);1716		EXPECT_ERRNO(EBUSY, _test_ioctl_destroy(self->fd, hwpt_id[1]));1717		test_cmd_mock_domain_replace(self->stdev_ids[i], self->ioas_id);1718		test_ioctl_destroy(hwpt_id[1]);1719 1720		test_cmd_mock_domain(hwpt_id[0], &stddev_id, NULL, NULL);1721		test_ioctl_destroy(stddev_id);1722		test_ioctl_destroy(hwpt_id[0]);1723	}1724}1725 1726FIXTURE(iommufd_dirty_tracking)1727{1728	int fd;1729	uint32_t ioas_id;1730	uint32_t hwpt_id;1731	uint32_t stdev_id;1732	uint32_t idev_id;1733	unsigned long page_size;1734	unsigned long bitmap_size;1735	void *bitmap;1736	void *buffer;1737};1738 1739FIXTURE_VARIANT(iommufd_dirty_tracking)1740{1741	unsigned long buffer_size;1742	bool hugepages;1743};1744 1745FIXTURE_SETUP(iommufd_dirty_tracking)1746{1747	unsigned long size;1748	int mmap_flags;1749	void *vrc;1750	int rc;1751 1752	if (variant->buffer_size < MOCK_PAGE_SIZE) {1753		SKIP(return,1754		     "Skipping buffer_size=%lu, less than MOCK_PAGE_SIZE=%lu",1755		     variant->buffer_size, MOCK_PAGE_SIZE);1756	}1757 1758	self->fd = open("/dev/iommu", O_RDWR);1759	ASSERT_NE(-1, self->fd);1760 1761	rc = posix_memalign(&self->buffer, HUGEPAGE_SIZE, variant->buffer_size);1762	if (rc || !self->buffer) {1763		SKIP(return, "Skipping buffer_size=%lu due to errno=%d",1764			   variant->buffer_size, rc);1765	}1766 1767	mmap_flags = MAP_SHARED | MAP_ANONYMOUS | MAP_FIXED;1768	if (variant->hugepages) {1769		/*1770		 * MAP_POPULATE will cause the kernel to fail mmap if THPs are1771		 * not available.1772		 */1773		mmap_flags |= MAP_HUGETLB | MAP_POPULATE;1774	}1775	assert((uintptr_t)self->buffer % HUGEPAGE_SIZE == 0);1776	vrc = mmap(self->buffer, variant->buffer_size, PROT_READ | PROT_WRITE,1777		   mmap_flags, -1, 0);1778	assert(vrc == self->buffer);1779 1780	self->page_size = MOCK_PAGE_SIZE;1781	self->bitmap_size = variant->buffer_size / self->page_size;1782 1783	/* Provision with an extra (PAGE_SIZE) for the unaligned case */1784	size = DIV_ROUND_UP(self->bitmap_size, BITS_PER_BYTE);1785	rc = posix_memalign(&self->bitmap, PAGE_SIZE, size + PAGE_SIZE);1786	assert(!rc);1787	assert(self->bitmap);1788	assert((uintptr_t)self->bitmap % PAGE_SIZE == 0);1789 1790	test_ioctl_ioas_alloc(&self->ioas_id);1791	/* Enable 1M mock IOMMU hugepages */1792	if (variant->hugepages) {1793		test_cmd_mock_domain_flags(self->ioas_id,1794					   MOCK_FLAGS_DEVICE_HUGE_IOVA,1795					   &self->stdev_id, &self->hwpt_id,1796					   &self->idev_id);1797	} else {1798		test_cmd_mock_domain(self->ioas_id, &self->stdev_id,1799				     &self->hwpt_id, &self->idev_id);1800	}1801}1802 1803FIXTURE_TEARDOWN(iommufd_dirty_tracking)1804{1805	munmap(self->buffer, variant->buffer_size);1806	munmap(self->bitmap, DIV_ROUND_UP(self->bitmap_size, BITS_PER_BYTE));1807	teardown_iommufd(self->fd, _metadata);1808}1809 1810FIXTURE_VARIANT_ADD(iommufd_dirty_tracking, domain_dirty8k)1811{1812	/* half of an u8 index bitmap */1813	.buffer_size = 8UL * 1024UL,1814};1815 1816FIXTURE_VARIANT_ADD(iommufd_dirty_tracking, domain_dirty16k)1817{1818	/* one u8 index bitmap */1819	.buffer_size = 16UL * 1024UL,1820};1821 1822FIXTURE_VARIANT_ADD(iommufd_dirty_tracking, domain_dirty64k)1823{1824	/* one u32 index bitmap */1825	.buffer_size = 64UL * 1024UL,1826};1827 1828FIXTURE_VARIANT_ADD(iommufd_dirty_tracking, domain_dirty128k)1829{1830	/* one u64 index bitmap */1831	.buffer_size = 128UL * 1024UL,1832};1833 1834FIXTURE_VARIANT_ADD(iommufd_dirty_tracking, domain_dirty320k)1835{1836	/* two u64 index and trailing end bitmap */1837	.buffer_size = 320UL * 1024UL,1838};1839 1840FIXTURE_VARIANT_ADD(iommufd_dirty_tracking, domain_dirty64M)1841{1842	/* 4K bitmap (64M IOVA range) */1843	.buffer_size = 64UL * 1024UL * 1024UL,1844};1845 1846FIXTURE_VARIANT_ADD(iommufd_dirty_tracking, domain_dirty64M_huge)1847{1848	/* 4K bitmap (64M IOVA range) */1849	.buffer_size = 64UL * 1024UL * 1024UL,1850	.hugepages = true,1851};1852 1853FIXTURE_VARIANT_ADD(iommufd_dirty_tracking, domain_dirty128M)1854{1855	/* 8K bitmap (128M IOVA range) */1856	.buffer_size = 128UL * 1024UL * 1024UL,1857};1858 1859FIXTURE_VARIANT_ADD(iommufd_dirty_tracking, domain_dirty128M_huge)1860{1861	/* 8K bitmap (128M IOVA range) */1862	.buffer_size = 128UL * 1024UL * 1024UL,1863	.hugepages = true,1864};1865 1866TEST_F(iommufd_dirty_tracking, enforce_dirty)1867{1868	uint32_t ioas_id, stddev_id, idev_id;1869	uint32_t hwpt_id, _hwpt_id;1870	uint32_t dev_flags;1871 1872	/* Regular case */1873	dev_flags = MOCK_FLAGS_DEVICE_NO_DIRTY;1874	test_cmd_hwpt_alloc(self->idev_id, self->ioas_id,1875			    IOMMU_HWPT_ALLOC_DIRTY_TRACKING, &hwpt_id);1876	test_cmd_mock_domain(hwpt_id, &stddev_id, NULL, NULL);1877	test_err_mock_domain_flags(EINVAL, hwpt_id, dev_flags, &stddev_id,1878				   NULL);1879	test_ioctl_destroy(stddev_id);1880	test_ioctl_destroy(hwpt_id);1881 1882	/* IOMMU device does not support dirty tracking */1883	test_ioctl_ioas_alloc(&ioas_id);1884	test_cmd_mock_domain_flags(ioas_id, dev_flags, &stddev_id, &_hwpt_id,1885				   &idev_id);1886	test_err_hwpt_alloc(EOPNOTSUPP, idev_id, ioas_id,1887			    IOMMU_HWPT_ALLOC_DIRTY_TRACKING, &hwpt_id);1888	test_ioctl_destroy(stddev_id);1889}1890 1891TEST_F(iommufd_dirty_tracking, set_dirty_tracking)1892{1893	uint32_t stddev_id;1894	uint32_t hwpt_id;1895 1896	test_cmd_hwpt_alloc(self->idev_id, self->ioas_id,1897			    IOMMU_HWPT_ALLOC_DIRTY_TRACKING, &hwpt_id);1898	test_cmd_mock_domain(hwpt_id, &stddev_id, NULL, NULL);1899	test_cmd_set_dirty_tracking(hwpt_id, true);1900	test_cmd_set_dirty_tracking(hwpt_id, false);1901 1902	test_ioctl_destroy(stddev_id);1903	test_ioctl_destroy(hwpt_id);1904}1905 1906TEST_F(iommufd_dirty_tracking, device_dirty_capability)1907{1908	uint32_t caps = 0;1909	uint32_t stddev_id;1910	uint32_t hwpt_id;1911 1912	test_cmd_hwpt_alloc(self->idev_id, self->ioas_id, 0, &hwpt_id);1913	test_cmd_mock_domain(hwpt_id, &stddev_id, NULL, NULL);1914	test_cmd_get_hw_capabilities(self->idev_id, caps,1915				     IOMMU_HW_CAP_DIRTY_TRACKING);1916	ASSERT_EQ(IOMMU_HW_CAP_DIRTY_TRACKING,1917		  caps & IOMMU_HW_CAP_DIRTY_TRACKING);1918 1919	test_ioctl_destroy(stddev_id);1920	test_ioctl_destroy(hwpt_id);1921}1922 1923TEST_F(iommufd_dirty_tracking, get_dirty_bitmap)1924{1925	uint32_t page_size = MOCK_PAGE_SIZE;1926	uint32_t hwpt_id;1927	uint32_t ioas_id;1928 1929	if (variant->hugepages)1930		page_size = MOCK_HUGE_PAGE_SIZE;1931 1932	test_ioctl_ioas_alloc(&ioas_id);1933	test_ioctl_ioas_map_fixed_id(ioas_id, self->buffer,1934				     variant->buffer_size, MOCK_APERTURE_START);1935 1936	test_cmd_hwpt_alloc(self->idev_id, ioas_id,1937			    IOMMU_HWPT_ALLOC_DIRTY_TRACKING, &hwpt_id);1938 1939	test_cmd_set_dirty_tracking(hwpt_id, true);1940 1941	test_mock_dirty_bitmaps(hwpt_id, variant->buffer_size,1942				MOCK_APERTURE_START, self->page_size, page_size,1943				self->bitmap, self->bitmap_size, 0, _metadata);1944 1945	/* PAGE_SIZE unaligned bitmap */1946	test_mock_dirty_bitmaps(hwpt_id, variant->buffer_size,1947				MOCK_APERTURE_START, self->page_size, page_size,1948				self->bitmap + MOCK_PAGE_SIZE,1949				self->bitmap_size, 0, _metadata);1950 1951	/* u64 unaligned bitmap */1952	test_mock_dirty_bitmaps(hwpt_id, variant->buffer_size,1953				MOCK_APERTURE_START, self->page_size, page_size,1954				self->bitmap + 0xff1, self->bitmap_size, 0,1955				_metadata);1956 1957	test_ioctl_destroy(hwpt_id);1958}1959 1960TEST_F(iommufd_dirty_tracking, get_dirty_bitmap_no_clear)1961{1962	uint32_t page_size = MOCK_PAGE_SIZE;1963	uint32_t hwpt_id;1964	uint32_t ioas_id;1965 1966	if (variant->hugepages)1967		page_size = MOCK_HUGE_PAGE_SIZE;1968 1969	test_ioctl_ioas_alloc(&ioas_id);1970	test_ioctl_ioas_map_fixed_id(ioas_id, self->buffer,1971				     variant->buffer_size, MOCK_APERTURE_START);1972 1973	test_cmd_hwpt_alloc(self->idev_id, ioas_id,1974			    IOMMU_HWPT_ALLOC_DIRTY_TRACKING, &hwpt_id);1975 1976	test_cmd_set_dirty_tracking(hwpt_id, true);1977 1978	test_mock_dirty_bitmaps(hwpt_id, variant->buffer_size,1979				MOCK_APERTURE_START, self->page_size, page_size,1980				self->bitmap, self->bitmap_size,1981				IOMMU_HWPT_GET_DIRTY_BITMAP_NO_CLEAR,1982				_metadata);1983 1984	/* Unaligned bitmap */1985	test_mock_dirty_bitmaps(hwpt_id, variant->buffer_size,1986				MOCK_APERTURE_START, self->page_size, page_size,1987				self->bitmap + MOCK_PAGE_SIZE,1988				self->bitmap_size,1989				IOMMU_HWPT_GET_DIRTY_BITMAP_NO_CLEAR,1990				_metadata);1991 1992	/* u64 unaligned bitmap */1993	test_mock_dirty_bitmaps(hwpt_id, variant->buffer_size,1994				MOCK_APERTURE_START, self->page_size, page_size,1995				self->bitmap + 0xff1, self->bitmap_size,1996				IOMMU_HWPT_GET_DIRTY_BITMAP_NO_CLEAR,1997				_metadata);1998 1999	test_ioctl_destroy(hwpt_id);2000}2001 2002/* VFIO compatibility IOCTLs */2003 2004TEST_F(iommufd, simple_ioctls)2005{2006	ASSERT_EQ(VFIO_API_VERSION, ioctl(self->fd, VFIO_GET_API_VERSION));2007	ASSERT_EQ(1, ioctl(self->fd, VFIO_CHECK_EXTENSION, VFIO_TYPE1v2_IOMMU));2008}2009 2010TEST_F(iommufd, unmap_cmd)2011{2012	struct vfio_iommu_type1_dma_unmap unmap_cmd = {2013		.iova = MOCK_APERTURE_START,2014		.size = PAGE_SIZE,2015	};2016 2017	unmap_cmd.argsz = 1;2018	EXPECT_ERRNO(EINVAL, ioctl(self->fd, VFIO_IOMMU_UNMAP_DMA, &unmap_cmd));2019 2020	unmap_cmd.argsz = sizeof(unmap_cmd);2021	unmap_cmd.flags = 1 << 31;2022	EXPECT_ERRNO(EINVAL, ioctl(self->fd, VFIO_IOMMU_UNMAP_DMA, &unmap_cmd));2023 2024	unmap_cmd.flags = 0;2025	EXPECT_ERRNO(ENODEV, ioctl(self->fd, VFIO_IOMMU_UNMAP_DMA, &unmap_cmd));2026}2027 2028TEST_F(iommufd, map_cmd)2029{2030	struct vfio_iommu_type1_dma_map map_cmd = {2031		.iova = MOCK_APERTURE_START,2032		.size = PAGE_SIZE,2033		.vaddr = (__u64)buffer,2034	};2035 2036	map_cmd.argsz = 1;2037	EXPECT_ERRNO(EINVAL, ioctl(self->fd, VFIO_IOMMU_MAP_DMA, &map_cmd));2038 2039	map_cmd.argsz = sizeof(map_cmd);2040	map_cmd.flags = 1 << 31;2041	EXPECT_ERRNO(EINVAL, ioctl(self->fd, VFIO_IOMMU_MAP_DMA, &map_cmd));2042 2043	/* Requires a domain to be attached */2044	map_cmd.flags = VFIO_DMA_MAP_FLAG_READ | VFIO_DMA_MAP_FLAG_WRITE;2045	EXPECT_ERRNO(ENODEV, ioctl(self->fd, VFIO_IOMMU_MAP_DMA, &map_cmd));2046}2047 2048TEST_F(iommufd, info_cmd)2049{2050	struct vfio_iommu_type1_info info_cmd = {};2051 2052	/* Invalid argsz */2053	info_cmd.argsz = 1;2054	EXPECT_ERRNO(EINVAL, ioctl(self->fd, VFIO_IOMMU_GET_INFO, &info_cmd));2055 2056	info_cmd.argsz = sizeof(info_cmd);2057	EXPECT_ERRNO(ENODEV, ioctl(self->fd, VFIO_IOMMU_GET_INFO, &info_cmd));2058}2059 2060TEST_F(iommufd, set_iommu_cmd)2061{2062	/* Requires a domain to be attached */2063	EXPECT_ERRNO(ENODEV,2064		     ioctl(self->fd, VFIO_SET_IOMMU, VFIO_TYPE1v2_IOMMU));2065	EXPECT_ERRNO(ENODEV, ioctl(self->fd, VFIO_SET_IOMMU, VFIO_TYPE1_IOMMU));2066}2067 2068TEST_F(iommufd, vfio_ioas)2069{2070	struct iommu_vfio_ioas vfio_ioas_cmd = {2071		.size = sizeof(vfio_ioas_cmd),2072		.op = IOMMU_VFIO_IOAS_GET,2073	};2074	__u32 ioas_id;2075 2076	/* ENODEV if there is no compat ioas */2077	EXPECT_ERRNO(ENODEV, ioctl(self->fd, IOMMU_VFIO_IOAS, &vfio_ioas_cmd));2078 2079	/* Invalid id for set */2080	vfio_ioas_cmd.op = IOMMU_VFIO_IOAS_SET;2081	EXPECT_ERRNO(ENOENT, ioctl(self->fd, IOMMU_VFIO_IOAS, &vfio_ioas_cmd));2082 2083	/* Valid id for set*/2084	test_ioctl_ioas_alloc(&ioas_id);2085	vfio_ioas_cmd.ioas_id = ioas_id;2086	ASSERT_EQ(0, ioctl(self->fd, IOMMU_VFIO_IOAS, &vfio_ioas_cmd));2087 2088	/* Same id comes back from get */2089	vfio_ioas_cmd.op = IOMMU_VFIO_IOAS_GET;2090	ASSERT_EQ(0, ioctl(self->fd, IOMMU_VFIO_IOAS, &vfio_ioas_cmd));2091	ASSERT_EQ(ioas_id, vfio_ioas_cmd.ioas_id);2092 2093	/* Clear works */2094	vfio_ioas_cmd.op = IOMMU_VFIO_IOAS_CLEAR;2095	ASSERT_EQ(0, ioctl(self->fd, IOMMU_VFIO_IOAS, &vfio_ioas_cmd));2096	vfio_ioas_cmd.op = IOMMU_VFIO_IOAS_GET;2097	EXPECT_ERRNO(ENODEV, ioctl(self->fd, IOMMU_VFIO_IOAS, &vfio_ioas_cmd));2098}2099 2100FIXTURE(vfio_compat_mock_domain)2101{2102	int fd;2103	uint32_t ioas_id;2104};2105 2106FIXTURE_VARIANT(vfio_compat_mock_domain)2107{2108	unsigned int version;2109};2110 2111FIXTURE_SETUP(vfio_compat_mock_domain)2112{2113	struct iommu_vfio_ioas vfio_ioas_cmd = {2114		.size = sizeof(vfio_ioas_cmd),2115		.op = IOMMU_VFIO_IOAS_SET,2116	};2117 2118	self->fd = open("/dev/iommu", O_RDWR);2119	ASSERT_NE(-1, self->fd);2120 2121	/* Create what VFIO would consider a group */2122	test_ioctl_ioas_alloc(&self->ioas_id);2123	test_cmd_mock_domain(self->ioas_id, NULL, NULL, NULL);2124 2125	/* Attach it to the vfio compat */2126	vfio_ioas_cmd.ioas_id = self->ioas_id;2127	ASSERT_EQ(0, ioctl(self->fd, IOMMU_VFIO_IOAS, &vfio_ioas_cmd));2128	ASSERT_EQ(0, ioctl(self->fd, VFIO_SET_IOMMU, variant->version));2129}2130 2131FIXTURE_TEARDOWN(vfio_compat_mock_domain)2132{2133	teardown_iommufd(self->fd, _metadata);2134}2135 2136FIXTURE_VARIANT_ADD(vfio_compat_mock_domain, Ver1v2)2137{2138	.version = VFIO_TYPE1v2_IOMMU,2139};2140 2141FIXTURE_VARIANT_ADD(vfio_compat_mock_domain, Ver1v0)2142{2143	.version = VFIO_TYPE1_IOMMU,2144};2145 2146TEST_F(vfio_compat_mock_domain, simple_close)2147{2148}2149 2150TEST_F(vfio_compat_mock_domain, option_huge_pages)2151{2152	struct iommu_option cmd = {2153		.size = sizeof(cmd),2154		.option_id = IOMMU_OPTION_HUGE_PAGES,2155		.op = IOMMU_OPTION_OP_GET,2156		.val64 = 3,2157		.object_id = self->ioas_id,2158	};2159 2160	ASSERT_EQ(0, ioctl(self->fd, IOMMU_OPTION, &cmd));2161	if (variant->version == VFIO_TYPE1_IOMMU) {2162		ASSERT_EQ(0, cmd.val64);2163	} else {2164		ASSERT_EQ(1, cmd.val64);2165	}2166}2167 2168/*2169 * Execute an ioctl command stored in buffer and check that the result does not2170 * overflow memory.2171 */2172static bool is_filled(const void *buf, uint8_t c, size_t len)2173{2174	const uint8_t *cbuf = buf;2175 2176	for (; len; cbuf++, len--)2177		if (*cbuf != c)2178			return false;2179	return true;2180}2181 2182#define ioctl_check_buf(fd, cmd)                                         \2183	({                                                               \2184		size_t _cmd_len = *(__u32 *)buffer;                      \2185									 \2186		memset(buffer + _cmd_len, 0xAA, BUFFER_SIZE - _cmd_len); \2187		ASSERT_EQ(0, ioctl(fd, cmd, buffer));                    \2188		ASSERT_EQ(true, is_filled(buffer + _cmd_len, 0xAA,       \2189					  BUFFER_SIZE - _cmd_len));      \2190	})2191 2192static void check_vfio_info_cap_chain(struct __test_metadata *_metadata,2193				      struct vfio_iommu_type1_info *info_cmd)2194{2195	const struct vfio_info_cap_header *cap;2196 2197	ASSERT_GE(info_cmd->argsz, info_cmd->cap_offset + sizeof(*cap));2198	cap = buffer + info_cmd->cap_offset;2199	while (true) {2200		size_t cap_size;2201 2202		if (cap->next)2203			cap_size = (buffer + cap->next) - (void *)cap;2204		else2205			cap_size = (buffer + info_cmd->argsz) - (void *)cap;2206 2207		switch (cap->id) {2208		case VFIO_IOMMU_TYPE1_INFO_CAP_IOVA_RANGE: {2209			struct vfio_iommu_type1_info_cap_iova_range *data =2210				(void *)cap;2211 2212			ASSERT_EQ(1, data->header.version);2213			ASSERT_EQ(1, data->nr_iovas);2214			EXPECT_EQ(MOCK_APERTURE_START,2215				  data->iova_ranges[0].start);2216			EXPECT_EQ(MOCK_APERTURE_LAST, data->iova_ranges[0].end);2217			break;2218		}2219		case VFIO_IOMMU_TYPE1_INFO_DMA_AVAIL: {2220			struct vfio_iommu_type1_info_dma_avail *data =2221				(void *)cap;2222 2223			ASSERT_EQ(1, data->header.version);2224			ASSERT_EQ(sizeof(*data), cap_size);2225			break;2226		}2227		default:2228			ASSERT_EQ(false, true);2229			break;2230		}2231		if (!cap->next)2232			break;2233 2234		ASSERT_GE(info_cmd->argsz, cap->next + sizeof(*cap));2235		ASSERT_GE(buffer + cap->next, (void *)cap);2236		cap = buffer + cap->next;2237	}2238}2239 2240TEST_F(vfio_compat_mock_domain, get_info)2241{2242	struct vfio_iommu_type1_info *info_cmd = buffer;2243	unsigned int i;2244	size_t caplen;2245 2246	/* Pre-cap ABI */2247	*info_cmd = (struct vfio_iommu_type1_info){2248		.argsz = offsetof(struct vfio_iommu_type1_info, cap_offset),2249	};2250	ioctl_check_buf(self->fd, VFIO_IOMMU_GET_INFO);2251	ASSERT_NE(0, info_cmd->iova_pgsizes);2252	ASSERT_EQ(VFIO_IOMMU_INFO_PGSIZES | VFIO_IOMMU_INFO_CAPS,2253		  info_cmd->flags);2254 2255	/* Read the cap chain size */2256	*info_cmd = (struct vfio_iommu_type1_info){2257		.argsz = sizeof(*info_cmd),2258	};2259	ioctl_check_buf(self->fd, VFIO_IOMMU_GET_INFO);2260	ASSERT_NE(0, info_cmd->iova_pgsizes);2261	ASSERT_EQ(VFIO_IOMMU_INFO_PGSIZES | VFIO_IOMMU_INFO_CAPS,2262		  info_cmd->flags);2263	ASSERT_EQ(0, info_cmd->cap_offset);2264	ASSERT_LT(sizeof(*info_cmd), info_cmd->argsz);2265 2266	/* Read the caps, kernel should never create a corrupted caps */2267	caplen = info_cmd->argsz;2268	for (i = sizeof(*info_cmd); i < caplen; i++) {2269		*info_cmd = (struct vfio_iommu_type1_info){2270			.argsz = i,2271		};2272		ioctl_check_buf(self->fd, VFIO_IOMMU_GET_INFO);2273		ASSERT_EQ(VFIO_IOMMU_INFO_PGSIZES | VFIO_IOMMU_INFO_CAPS,2274			  info_cmd->flags);2275		if (!info_cmd->cap_offset)2276			continue;2277		check_vfio_info_cap_chain(_metadata, info_cmd);2278	}2279}2280 2281static void shuffle_array(unsigned long *array, size_t nelms)2282{2283	unsigned int i;2284 2285	/* Shuffle */2286	for (i = 0; i != nelms; i++) {2287		unsigned long tmp = array[i];2288		unsigned int other = rand() % (nelms - i);2289 2290		array[i] = array[other];2291		array[other] = tmp;2292	}2293}2294 2295TEST_F(vfio_compat_mock_domain, map)2296{2297	struct vfio_iommu_type1_dma_map map_cmd = {2298		.argsz = sizeof(map_cmd),2299		.flags = VFIO_DMA_MAP_FLAG_READ | VFIO_DMA_MAP_FLAG_WRITE,2300		.vaddr = (uintptr_t)buffer,2301		.size = BUFFER_SIZE,2302		.iova = MOCK_APERTURE_START,2303	};2304	struct vfio_iommu_type1_dma_unmap unmap_cmd = {2305		.argsz = sizeof(unmap_cmd),2306		.size = BUFFER_SIZE,2307		.iova = MOCK_APERTURE_START,2308	};2309	unsigned long pages_iova[BUFFER_SIZE / PAGE_SIZE];2310	unsigned int i;2311 2312	/* Simple map/unmap */2313	ASSERT_EQ(0, ioctl(self->fd, VFIO_IOMMU_MAP_DMA, &map_cmd));2314	ASSERT_EQ(0, ioctl(self->fd, VFIO_IOMMU_UNMAP_DMA, &unmap_cmd));2315	ASSERT_EQ(BUFFER_SIZE, unmap_cmd.size);2316 2317	/* UNMAP_FLAG_ALL requires 0 iova/size */2318	ASSERT_EQ(0, ioctl(self->fd, VFIO_IOMMU_MAP_DMA, &map_cmd));2319	unmap_cmd.flags = VFIO_DMA_UNMAP_FLAG_ALL;2320	EXPECT_ERRNO(EINVAL, ioctl(self->fd, VFIO_IOMMU_UNMAP_DMA, &unmap_cmd));2321 2322	unmap_cmd.iova = 0;2323	unmap_cmd.size = 0;2324	ASSERT_EQ(0, ioctl(self->fd, VFIO_IOMMU_UNMAP_DMA, &unmap_cmd));2325	ASSERT_EQ(BUFFER_SIZE, unmap_cmd.size);2326 2327	/* Small pages */2328	for (i = 0; i != ARRAY_SIZE(pages_iova); i++) {2329		map_cmd.iova = pages_iova[i] =2330			MOCK_APERTURE_START + i * PAGE_SIZE;2331		map_cmd.vaddr = (uintptr_t)buffer + i * PAGE_SIZE;2332		map_cmd.size = PAGE_SIZE;2333		ASSERT_EQ(0, ioctl(self->fd, VFIO_IOMMU_MAP_DMA, &map_cmd));2334	}2335	shuffle_array(pages_iova, ARRAY_SIZE(pages_iova));2336 2337	unmap_cmd.flags = 0;2338	unmap_cmd.size = PAGE_SIZE;2339	for (i = 0; i != ARRAY_SIZE(pages_iova); i++) {2340		unmap_cmd.iova = pages_iova[i];2341		ASSERT_EQ(0, ioctl(self->fd, VFIO_IOMMU_UNMAP_DMA, &unmap_cmd));2342	}2343}2344 2345TEST_F(vfio_compat_mock_domain, huge_map)2346{2347	size_t buf_size = HUGEPAGE_SIZE * 2;2348	struct vfio_iommu_type1_dma_map map_cmd = {2349		.argsz = sizeof(map_cmd),2350		.flags = VFIO_DMA_MAP_FLAG_READ | VFIO_DMA_MAP_FLAG_WRITE,2351		.size = buf_size,2352		.iova = MOCK_APERTURE_START,2353	};2354	struct vfio_iommu_type1_dma_unmap unmap_cmd = {2355		.argsz = sizeof(unmap_cmd),2356	};2357	unsigned long pages_iova[16];2358	unsigned int i;2359	void *buf;2360 2361	/* Test huge pages and splitting */2362	buf = mmap(0, buf_size, PROT_READ | PROT_WRITE,2363		   MAP_SHARED | MAP_ANONYMOUS | MAP_HUGETLB | MAP_POPULATE, -1,2364		   0);2365	ASSERT_NE(MAP_FAILED, buf);2366	map_cmd.vaddr = (uintptr_t)buf;2367	ASSERT_EQ(0, ioctl(self->fd, VFIO_IOMMU_MAP_DMA, &map_cmd));2368 2369	unmap_cmd.size = buf_size / ARRAY_SIZE(pages_iova);2370	for (i = 0; i != ARRAY_SIZE(pages_iova); i++)2371		pages_iova[i] = MOCK_APERTURE_START + (i * unmap_cmd.size);2372	shuffle_array(pages_iova, ARRAY_SIZE(pages_iova));2373 2374	/* type1 mode can cut up larger mappings, type1v2 always fails */2375	for (i = 0; i != ARRAY_SIZE(pages_iova); i++) {2376		unmap_cmd.iova = pages_iova[i];2377		unmap_cmd.size = buf_size / ARRAY_SIZE(pages_iova);2378		if (variant->version == VFIO_TYPE1_IOMMU) {2379			ASSERT_EQ(0, ioctl(self->fd, VFIO_IOMMU_UNMAP_DMA,2380					   &unmap_cmd));2381		} else {2382			EXPECT_ERRNO(ENOENT,2383				     ioctl(self->fd, VFIO_IOMMU_UNMAP_DMA,2384					   &unmap_cmd));2385		}2386	}2387}2388 2389TEST_HARNESS_MAIN2390