brintos

brintos / linux-shallow public Read only

0
0
Text · 23.9 KiB · 40f6f14 Raw
765 lines · c
1/* SPDX-License-Identifier: GPL-2.0-only */2/* Copyright (c) 2021-2022, NVIDIA CORPORATION & AFFILIATES */3#ifndef __SELFTEST_IOMMUFD_UTILS4#define __SELFTEST_IOMMUFD_UTILS5 6#include <unistd.h>7#include <stddef.h>8#include <sys/fcntl.h>9#include <sys/ioctl.h>10#include <stdint.h>11#include <assert.h>12 13#include "../kselftest_harness.h"14#include "../../../../drivers/iommu/iommufd/iommufd_test.h"15 16/* Hack to make assertions more readable */17#define _IOMMU_TEST_CMD(x) IOMMU_TEST_CMD18 19/* Imported from include/asm-generic/bitops/generic-non-atomic.h */20#define BITS_PER_BYTE 821#define BITS_PER_LONG __BITS_PER_LONG22#define BIT_MASK(nr) (1UL << ((nr) % __BITS_PER_LONG))23#define BIT_WORD(nr) ((nr) / __BITS_PER_LONG)24 25#define DIV_ROUND_UP(n, d) (((n) + (d) - 1) / (d))26 27static inline void set_bit(unsigned int nr, unsigned long *addr)28{29	unsigned long mask = BIT_MASK(nr);30	unsigned long *p = ((unsigned long *)addr) + BIT_WORD(nr);31 32	*p |= mask;33}34 35static inline bool test_bit(unsigned int nr, unsigned long *addr)36{37	return 1UL & (addr[BIT_WORD(nr)] >> (nr & (BITS_PER_LONG - 1)));38}39 40static void *buffer;41static unsigned long BUFFER_SIZE;42 43static unsigned long PAGE_SIZE;44 45#define sizeof_field(TYPE, MEMBER) sizeof((((TYPE *)0)->MEMBER))46#define offsetofend(TYPE, MEMBER) \47	(offsetof(TYPE, MEMBER) + sizeof_field(TYPE, MEMBER))48 49/*50 * Have the kernel check the refcount on pages. I don't know why a freshly51 * mmap'd anon non-compound page starts out with a ref of 352 */53#define check_refs(_ptr, _length, _refs)                                      \54	({                                                                    \55		struct iommu_test_cmd test_cmd = {                            \56			.size = sizeof(test_cmd),                             \57			.op = IOMMU_TEST_OP_MD_CHECK_REFS,                    \58			.check_refs = { .length = _length,                    \59					.uptr = (uintptr_t)(_ptr),            \60					.refs = _refs },                      \61		};                                                            \62		ASSERT_EQ(0,                                                  \63			  ioctl(self->fd,                                     \64				_IOMMU_TEST_CMD(IOMMU_TEST_OP_MD_CHECK_REFS), \65				&test_cmd));                                  \66	})67 68static int _test_cmd_mock_domain(int fd, unsigned int ioas_id, __u32 *stdev_id,69				 __u32 *hwpt_id, __u32 *idev_id)70{71	struct iommu_test_cmd cmd = {72		.size = sizeof(cmd),73		.op = IOMMU_TEST_OP_MOCK_DOMAIN,74		.id = ioas_id,75		.mock_domain = {},76	};77	int ret;78 79	ret = ioctl(fd, IOMMU_TEST_CMD, &cmd);80	if (ret)81		return ret;82	if (stdev_id)83		*stdev_id = cmd.mock_domain.out_stdev_id;84	assert(cmd.id != 0);85	if (hwpt_id)86		*hwpt_id = cmd.mock_domain.out_hwpt_id;87	if (idev_id)88		*idev_id = cmd.mock_domain.out_idev_id;89	return 0;90}91#define test_cmd_mock_domain(ioas_id, stdev_id, hwpt_id, idev_id)       \92	ASSERT_EQ(0, _test_cmd_mock_domain(self->fd, ioas_id, stdev_id, \93					   hwpt_id, idev_id))94#define test_err_mock_domain(_errno, ioas_id, stdev_id, hwpt_id)      \95	EXPECT_ERRNO(_errno, _test_cmd_mock_domain(self->fd, ioas_id, \96						   stdev_id, hwpt_id, NULL))97 98static int _test_cmd_mock_domain_flags(int fd, unsigned int ioas_id,99				       __u32 stdev_flags, __u32 *stdev_id,100				       __u32 *hwpt_id, __u32 *idev_id)101{102	struct iommu_test_cmd cmd = {103		.size = sizeof(cmd),104		.op = IOMMU_TEST_OP_MOCK_DOMAIN_FLAGS,105		.id = ioas_id,106		.mock_domain_flags = { .dev_flags = stdev_flags },107	};108	int ret;109 110	ret = ioctl(fd, IOMMU_TEST_CMD, &cmd);111	if (ret)112		return ret;113	if (stdev_id)114		*stdev_id = cmd.mock_domain_flags.out_stdev_id;115	assert(cmd.id != 0);116	if (hwpt_id)117		*hwpt_id = cmd.mock_domain_flags.out_hwpt_id;118	if (idev_id)119		*idev_id = cmd.mock_domain_flags.out_idev_id;120	return 0;121}122#define test_cmd_mock_domain_flags(ioas_id, flags, stdev_id, hwpt_id, idev_id) \123	ASSERT_EQ(0, _test_cmd_mock_domain_flags(self->fd, ioas_id, flags,     \124						 stdev_id, hwpt_id, idev_id))125#define test_err_mock_domain_flags(_errno, ioas_id, flags, stdev_id, hwpt_id) \126	EXPECT_ERRNO(_errno,                                                  \127		     _test_cmd_mock_domain_flags(self->fd, ioas_id, flags,    \128						 stdev_id, hwpt_id, NULL))129 130static int _test_cmd_mock_domain_replace(int fd, __u32 stdev_id, __u32 pt_id,131					 __u32 *hwpt_id)132{133	struct iommu_test_cmd cmd = {134		.size = sizeof(cmd),135		.op = IOMMU_TEST_OP_MOCK_DOMAIN_REPLACE,136		.id = stdev_id,137		.mock_domain_replace = {138			.pt_id = pt_id,139		},140	};141	int ret;142 143	ret = ioctl(fd, IOMMU_TEST_CMD, &cmd);144	if (ret)145		return ret;146	if (hwpt_id)147		*hwpt_id = cmd.mock_domain_replace.pt_id;148	return 0;149}150 151#define test_cmd_mock_domain_replace(stdev_id, pt_id)                         \152	ASSERT_EQ(0, _test_cmd_mock_domain_replace(self->fd, stdev_id, pt_id, \153						   NULL))154#define test_err_mock_domain_replace(_errno, stdev_id, pt_id)                  \155	EXPECT_ERRNO(_errno, _test_cmd_mock_domain_replace(self->fd, stdev_id, \156							   pt_id, NULL))157 158static int _test_cmd_hwpt_alloc(int fd, __u32 device_id, __u32 pt_id, __u32 ft_id,159				__u32 flags, __u32 *hwpt_id, __u32 data_type,160				void *data, size_t data_len)161{162	struct iommu_hwpt_alloc cmd = {163		.size = sizeof(cmd),164		.flags = flags,165		.dev_id = device_id,166		.pt_id = pt_id,167		.data_type = data_type,168		.data_len = data_len,169		.data_uptr = (uint64_t)data,170		.fault_id = ft_id,171	};172	int ret;173 174	ret = ioctl(fd, IOMMU_HWPT_ALLOC, &cmd);175	if (ret)176		return ret;177	if (hwpt_id)178		*hwpt_id = cmd.out_hwpt_id;179	return 0;180}181 182#define test_cmd_hwpt_alloc(device_id, pt_id, flags, hwpt_id)                  \183	ASSERT_EQ(0, _test_cmd_hwpt_alloc(self->fd, device_id, pt_id, 0, flags,   \184					  hwpt_id, IOMMU_HWPT_DATA_NONE, NULL, \185					  0))186#define test_err_hwpt_alloc(_errno, device_id, pt_id, flags, hwpt_id)   \187	EXPECT_ERRNO(_errno, _test_cmd_hwpt_alloc(                      \188				     self->fd, device_id, pt_id, 0, flags, \189				     hwpt_id, IOMMU_HWPT_DATA_NONE, NULL, 0))190 191#define test_cmd_hwpt_alloc_nested(device_id, pt_id, flags, hwpt_id,         \192				   data_type, data, data_len)                \193	ASSERT_EQ(0, _test_cmd_hwpt_alloc(self->fd, device_id, pt_id, 0, flags, \194					  hwpt_id, data_type, data, data_len))195#define test_err_hwpt_alloc_nested(_errno, device_id, pt_id, flags, hwpt_id, \196				   data_type, data, data_len)                \197	EXPECT_ERRNO(_errno,                                                 \198		     _test_cmd_hwpt_alloc(self->fd, device_id, pt_id, 0, flags, \199					  hwpt_id, data_type, data, data_len))200 201#define test_cmd_hwpt_alloc_iopf(device_id, pt_id, fault_id, flags, hwpt_id,    \202				   data_type, data, data_len)                   \203	ASSERT_EQ(0, _test_cmd_hwpt_alloc(self->fd, device_id, pt_id, fault_id, \204					  flags, hwpt_id, data_type, data,      \205					  data_len))206#define test_err_hwpt_alloc_iopf(_errno, device_id, pt_id, fault_id, flags,     \207				 hwpt_id, data_type, data, data_len)            \208	EXPECT_ERRNO(_errno,                                                    \209		     _test_cmd_hwpt_alloc(self->fd, device_id, pt_id, fault_id, \210					  flags, hwpt_id, data_type, data,      \211					  data_len))212 213#define test_cmd_hwpt_check_iotlb(hwpt_id, iotlb_id, expected)                 \214	({                                                                     \215		struct iommu_test_cmd test_cmd = {                             \216			.size = sizeof(test_cmd),                              \217			.op = IOMMU_TEST_OP_MD_CHECK_IOTLB,                    \218			.id = hwpt_id,                                         \219			.check_iotlb = {                                       \220				.id = iotlb_id,                                \221				.iotlb = expected,                             \222			},                                                     \223		};                                                             \224		ASSERT_EQ(0,                                                   \225			  ioctl(self->fd,                                      \226				_IOMMU_TEST_CMD(IOMMU_TEST_OP_MD_CHECK_IOTLB), \227				&test_cmd));                                   \228	})229 230#define test_cmd_hwpt_check_iotlb_all(hwpt_id, expected)                       \231	({                                                                     \232		int i;                                                         \233		for (i = 0; i < MOCK_NESTED_DOMAIN_IOTLB_NUM; i++)             \234			test_cmd_hwpt_check_iotlb(hwpt_id, i, expected);       \235	})236 237static int _test_cmd_hwpt_invalidate(int fd, __u32 hwpt_id, void *reqs,238				     uint32_t data_type, uint32_t lreq,239				     uint32_t *nreqs)240{241	struct iommu_hwpt_invalidate cmd = {242		.size = sizeof(cmd),243		.hwpt_id = hwpt_id,244		.data_type = data_type,245		.data_uptr = (uint64_t)reqs,246		.entry_len = lreq,247		.entry_num = *nreqs,248	};249	int rc = ioctl(fd, IOMMU_HWPT_INVALIDATE, &cmd);250	*nreqs = cmd.entry_num;251	return rc;252}253 254#define test_cmd_hwpt_invalidate(hwpt_id, reqs, data_type, lreq, nreqs)       \255	({                                                                    \256		ASSERT_EQ(0,                                                  \257			  _test_cmd_hwpt_invalidate(self->fd, hwpt_id, reqs,  \258						    data_type, lreq, nreqs)); \259	})260#define test_err_hwpt_invalidate(_errno, hwpt_id, reqs, data_type, lreq, \261				 nreqs)                                  \262	({                                                               \263		EXPECT_ERRNO(_errno, _test_cmd_hwpt_invalidate(          \264					     self->fd, hwpt_id, reqs,    \265					     data_type, lreq, nreqs));   \266	})267 268static int _test_cmd_access_replace_ioas(int fd, __u32 access_id,269					 unsigned int ioas_id)270{271	struct iommu_test_cmd cmd = {272		.size = sizeof(cmd),273		.op = IOMMU_TEST_OP_ACCESS_REPLACE_IOAS,274		.id = access_id,275		.access_replace_ioas = { .ioas_id = ioas_id },276	};277	int ret;278 279	ret = ioctl(fd, IOMMU_TEST_CMD, &cmd);280	if (ret)281		return ret;282	return 0;283}284#define test_cmd_access_replace_ioas(access_id, ioas_id) \285	ASSERT_EQ(0, _test_cmd_access_replace_ioas(self->fd, access_id, ioas_id))286 287static int _test_cmd_set_dirty_tracking(int fd, __u32 hwpt_id, bool enabled)288{289	struct iommu_hwpt_set_dirty_tracking cmd = {290		.size = sizeof(cmd),291		.flags = enabled ? IOMMU_HWPT_DIRTY_TRACKING_ENABLE : 0,292		.hwpt_id = hwpt_id,293	};294	int ret;295 296	ret = ioctl(fd, IOMMU_HWPT_SET_DIRTY_TRACKING, &cmd);297	if (ret)298		return -errno;299	return 0;300}301#define test_cmd_set_dirty_tracking(hwpt_id, enabled) \302	ASSERT_EQ(0, _test_cmd_set_dirty_tracking(self->fd, hwpt_id, enabled))303 304static int _test_cmd_get_dirty_bitmap(int fd, __u32 hwpt_id, size_t length,305				      __u64 iova, size_t page_size,306				      __u64 *bitmap, __u32 flags)307{308	struct iommu_hwpt_get_dirty_bitmap cmd = {309		.size = sizeof(cmd),310		.hwpt_id = hwpt_id,311		.flags = flags,312		.iova = iova,313		.length = length,314		.page_size = page_size,315		.data = (uintptr_t)bitmap,316	};317	int ret;318 319	ret = ioctl(fd, IOMMU_HWPT_GET_DIRTY_BITMAP, &cmd);320	if (ret)321		return ret;322	return 0;323}324 325#define test_cmd_get_dirty_bitmap(fd, hwpt_id, length, iova, page_size,    \326				  bitmap, flags)                           \327	ASSERT_EQ(0, _test_cmd_get_dirty_bitmap(fd, hwpt_id, length, iova, \328						page_size, bitmap, flags))329 330static int _test_cmd_mock_domain_set_dirty(int fd, __u32 hwpt_id, size_t length,331					   __u64 iova, size_t page_size,332					   __u64 *bitmap, __u64 *dirty)333{334	struct iommu_test_cmd cmd = {335		.size = sizeof(cmd),336		.op = IOMMU_TEST_OP_DIRTY,337		.id = hwpt_id,338		.dirty = {339			.iova = iova,340			.length = length,341			.page_size = page_size,342			.uptr = (uintptr_t)bitmap,343		}344	};345	int ret;346 347	ret = ioctl(fd, _IOMMU_TEST_CMD(IOMMU_TEST_OP_DIRTY), &cmd);348	if (ret)349		return -ret;350	if (dirty)351		*dirty = cmd.dirty.out_nr_dirty;352	return 0;353}354 355#define test_cmd_mock_domain_set_dirty(fd, hwpt_id, length, iova, page_size, \356				       bitmap, nr)                           \357	ASSERT_EQ(0,                                                         \358		  _test_cmd_mock_domain_set_dirty(fd, hwpt_id, length, iova, \359						  page_size, bitmap, nr))360 361static int _test_mock_dirty_bitmaps(int fd, __u32 hwpt_id, size_t length,362				    __u64 iova, size_t page_size,363				    size_t pte_page_size, __u64 *bitmap,364				    __u64 nbits, __u32 flags,365				    struct __test_metadata *_metadata)366{367	unsigned long npte = pte_page_size / page_size, pteset = 2 * npte;368	unsigned long j, i, nr = nbits / pteset ?: 1;369	unsigned long bitmap_size = DIV_ROUND_UP(nbits, BITS_PER_BYTE);370	__u64 out_dirty = 0;371 372	/* Mark all even bits as dirty in the mock domain */373	memset(bitmap, 0, bitmap_size);374	for (i = 0; i < nbits; i += pteset)375		set_bit(i, (unsigned long *)bitmap);376 377	test_cmd_mock_domain_set_dirty(fd, hwpt_id, length, iova, page_size,378				       bitmap, &out_dirty);379	ASSERT_EQ(nr, out_dirty);380 381	/* Expect all even bits as dirty in the user bitmap */382	memset(bitmap, 0, bitmap_size);383	test_cmd_get_dirty_bitmap(fd, hwpt_id, length, iova, page_size, bitmap,384				  flags);385	/* Beware ASSERT_EQ() is two statements -- braces are not redundant! */386	for (i = 0; i < nbits; i += pteset) {387		for (j = 0; j < pteset; j++) {388			ASSERT_EQ(j < npte,389				  test_bit(i + j, (unsigned long *)bitmap));390		}391		ASSERT_EQ(!(i % pteset), test_bit(i, (unsigned long *)bitmap));392	}393 394	memset(bitmap, 0, bitmap_size);395	test_cmd_get_dirty_bitmap(fd, hwpt_id, length, iova, page_size, bitmap,396				  flags);397 398	/* It as read already -- expect all zeroes */399	for (i = 0; i < nbits; i += pteset) {400		for (j = 0; j < pteset; j++) {401			ASSERT_EQ(402				(j < npte) &&403					(flags &404					 IOMMU_HWPT_GET_DIRTY_BITMAP_NO_CLEAR),405				test_bit(i + j, (unsigned long *)bitmap));406		}407	}408 409	return 0;410}411#define test_mock_dirty_bitmaps(hwpt_id, length, iova, page_size, pte_size,\412				bitmap, bitmap_size, flags, _metadata)     \413	ASSERT_EQ(0, _test_mock_dirty_bitmaps(self->fd, hwpt_id, length, iova, \414					      page_size, pte_size, bitmap,     \415					      bitmap_size, flags, _metadata))416 417static int _test_cmd_create_access(int fd, unsigned int ioas_id,418				   __u32 *access_id, unsigned int flags)419{420	struct iommu_test_cmd cmd = {421		.size = sizeof(cmd),422		.op = IOMMU_TEST_OP_CREATE_ACCESS,423		.id = ioas_id,424		.create_access = { .flags = flags },425	};426	int ret;427 428	ret = ioctl(fd, IOMMU_TEST_CMD, &cmd);429	if (ret)430		return ret;431	*access_id = cmd.create_access.out_access_fd;432	return 0;433}434#define test_cmd_create_access(ioas_id, access_id, flags)                  \435	ASSERT_EQ(0, _test_cmd_create_access(self->fd, ioas_id, access_id, \436					     flags))437 438static int _test_cmd_destroy_access(unsigned int access_id)439{440	return close(access_id);441}442#define test_cmd_destroy_access(access_id) \443	ASSERT_EQ(0, _test_cmd_destroy_access(access_id))444 445static int _test_cmd_destroy_access_pages(int fd, unsigned int access_id,446					  unsigned int access_pages_id)447{448	struct iommu_test_cmd cmd = {449		.size = sizeof(cmd),450		.op = IOMMU_TEST_OP_DESTROY_ACCESS_PAGES,451		.id = access_id,452		.destroy_access_pages = { .access_pages_id = access_pages_id },453	};454	return ioctl(fd, IOMMU_TEST_CMD, &cmd);455}456#define test_cmd_destroy_access_pages(access_id, access_pages_id)        \457	ASSERT_EQ(0, _test_cmd_destroy_access_pages(self->fd, access_id, \458						    access_pages_id))459#define test_err_destroy_access_pages(_errno, access_id, access_pages_id) \460	EXPECT_ERRNO(_errno, _test_cmd_destroy_access_pages(              \461				     self->fd, access_id, access_pages_id))462 463static int _test_ioctl_destroy(int fd, unsigned int id)464{465	struct iommu_destroy cmd = {466		.size = sizeof(cmd),467		.id = id,468	};469	return ioctl(fd, IOMMU_DESTROY, &cmd);470}471#define test_ioctl_destroy(id) ASSERT_EQ(0, _test_ioctl_destroy(self->fd, id))472 473static int _test_ioctl_ioas_alloc(int fd, __u32 *id)474{475	struct iommu_ioas_alloc cmd = {476		.size = sizeof(cmd),477	};478	int ret;479 480	ret = ioctl(fd, IOMMU_IOAS_ALLOC, &cmd);481	if (ret)482		return ret;483	*id = cmd.out_ioas_id;484	return 0;485}486#define test_ioctl_ioas_alloc(id)                                   \487	({                                                          \488		ASSERT_EQ(0, _test_ioctl_ioas_alloc(self->fd, id)); \489		ASSERT_NE(0, *(id));                                \490	})491 492static int _test_ioctl_ioas_map(int fd, unsigned int ioas_id, void *buffer,493				size_t length, __u64 *iova, unsigned int flags)494{495	struct iommu_ioas_map cmd = {496		.size = sizeof(cmd),497		.flags = flags,498		.ioas_id = ioas_id,499		.user_va = (uintptr_t)buffer,500		.length = length,501	};502	int ret;503 504	if (flags & IOMMU_IOAS_MAP_FIXED_IOVA)505		cmd.iova = *iova;506 507	ret = ioctl(fd, IOMMU_IOAS_MAP, &cmd);508	*iova = cmd.iova;509	return ret;510}511#define test_ioctl_ioas_map(buffer, length, iova_p)                        \512	ASSERT_EQ(0, _test_ioctl_ioas_map(self->fd, self->ioas_id, buffer, \513					  length, iova_p,                  \514					  IOMMU_IOAS_MAP_WRITEABLE |       \515						  IOMMU_IOAS_MAP_READABLE))516 517#define test_err_ioctl_ioas_map(_errno, buffer, length, iova_p)            \518	EXPECT_ERRNO(_errno,                                               \519		     _test_ioctl_ioas_map(self->fd, self->ioas_id, buffer, \520					  length, iova_p,                  \521					  IOMMU_IOAS_MAP_WRITEABLE |       \522						  IOMMU_IOAS_MAP_READABLE))523 524#define test_ioctl_ioas_map_id(ioas_id, buffer, length, iova_p)              \525	ASSERT_EQ(0, _test_ioctl_ioas_map(self->fd, ioas_id, buffer, length, \526					  iova_p,                            \527					  IOMMU_IOAS_MAP_WRITEABLE |         \528						  IOMMU_IOAS_MAP_READABLE))529 530#define test_ioctl_ioas_map_fixed(buffer, length, iova)                       \531	({                                                                    \532		__u64 __iova = iova;                                          \533		ASSERT_EQ(0, _test_ioctl_ioas_map(                            \534				     self->fd, self->ioas_id, buffer, length, \535				     &__iova,                                 \536				     IOMMU_IOAS_MAP_FIXED_IOVA |              \537					     IOMMU_IOAS_MAP_WRITEABLE |       \538					     IOMMU_IOAS_MAP_READABLE));       \539	})540 541#define test_ioctl_ioas_map_fixed_id(ioas_id, buffer, length, iova)           \542	({                                                                    \543		__u64 __iova = iova;                                          \544		ASSERT_EQ(0,                                                  \545			  _test_ioctl_ioas_map(                               \546				  self->fd, ioas_id, buffer, length, &__iova, \547				  IOMMU_IOAS_MAP_FIXED_IOVA |                 \548					  IOMMU_IOAS_MAP_WRITEABLE |          \549					  IOMMU_IOAS_MAP_READABLE));          \550	})551 552#define test_err_ioctl_ioas_map_fixed(_errno, buffer, length, iova)           \553	({                                                                    \554		__u64 __iova = iova;                                          \555		EXPECT_ERRNO(_errno,                                          \556			     _test_ioctl_ioas_map(                            \557				     self->fd, self->ioas_id, buffer, length, \558				     &__iova,                                 \559				     IOMMU_IOAS_MAP_FIXED_IOVA |              \560					     IOMMU_IOAS_MAP_WRITEABLE |       \561					     IOMMU_IOAS_MAP_READABLE));       \562	})563 564static int _test_ioctl_ioas_unmap(int fd, unsigned int ioas_id, uint64_t iova,565				  size_t length, uint64_t *out_len)566{567	struct iommu_ioas_unmap cmd = {568		.size = sizeof(cmd),569		.ioas_id = ioas_id,570		.iova = iova,571		.length = length,572	};573	int ret;574 575	ret = ioctl(fd, IOMMU_IOAS_UNMAP, &cmd);576	if (out_len)577		*out_len = cmd.length;578	return ret;579}580#define test_ioctl_ioas_unmap(iova, length)                                \581	ASSERT_EQ(0, _test_ioctl_ioas_unmap(self->fd, self->ioas_id, iova, \582					    length, NULL))583 584#define test_ioctl_ioas_unmap_id(ioas_id, iova, length)                      \585	ASSERT_EQ(0, _test_ioctl_ioas_unmap(self->fd, ioas_id, iova, length, \586					    NULL))587 588#define test_err_ioctl_ioas_unmap(_errno, iova, length)                      \589	EXPECT_ERRNO(_errno, _test_ioctl_ioas_unmap(self->fd, self->ioas_id, \590						    iova, length, NULL))591 592static int _test_ioctl_set_temp_memory_limit(int fd, unsigned int limit)593{594	struct iommu_test_cmd memlimit_cmd = {595		.size = sizeof(memlimit_cmd),596		.op = IOMMU_TEST_OP_SET_TEMP_MEMORY_LIMIT,597		.memory_limit = { .limit = limit },598	};599 600	return ioctl(fd, _IOMMU_TEST_CMD(IOMMU_TEST_OP_SET_TEMP_MEMORY_LIMIT),601		     &memlimit_cmd);602}603 604#define test_ioctl_set_temp_memory_limit(limit) \605	ASSERT_EQ(0, _test_ioctl_set_temp_memory_limit(self->fd, limit))606 607#define test_ioctl_set_default_memory_limit() \608	test_ioctl_set_temp_memory_limit(65536)609 610static void teardown_iommufd(int fd, struct __test_metadata *_metadata)611{612	struct iommu_test_cmd test_cmd = {613		.size = sizeof(test_cmd),614		.op = IOMMU_TEST_OP_MD_CHECK_REFS,615		.check_refs = { .length = BUFFER_SIZE,616				.uptr = (uintptr_t)buffer },617	};618 619	if (fd == -1)620		return;621 622	EXPECT_EQ(0, close(fd));623 624	fd = open("/dev/iommu", O_RDWR);625	EXPECT_NE(-1, fd);626	EXPECT_EQ(0, ioctl(fd, _IOMMU_TEST_CMD(IOMMU_TEST_OP_MD_CHECK_REFS),627			   &test_cmd));628	EXPECT_EQ(0, close(fd));629}630 631#define EXPECT_ERRNO(expected_errno, cmd)         \632	({                                        \633		ASSERT_EQ(-1, cmd);               \634		EXPECT_EQ(expected_errno, errno); \635	})636 637#endif638 639/* @data can be NULL */640static int _test_cmd_get_hw_info(int fd, __u32 device_id, void *data,641				 size_t data_len, uint32_t *capabilities)642{643	struct iommu_test_hw_info *info = (struct iommu_test_hw_info *)data;644	struct iommu_hw_info cmd = {645		.size = sizeof(cmd),646		.dev_id = device_id,647		.data_len = data_len,648		.data_uptr = (uint64_t)data,649		.out_capabilities = 0,650	};651	int ret;652 653	ret = ioctl(fd, IOMMU_GET_HW_INFO, &cmd);654	if (ret)655		return ret;656 657	assert(cmd.out_data_type == IOMMU_HW_INFO_TYPE_SELFTEST);658 659	/*660	 * The struct iommu_test_hw_info should be the one defined661	 * by the current kernel.662	 */663	assert(cmd.data_len == sizeof(struct iommu_test_hw_info));664 665	/*666	 * Trailing bytes should be 0 if user buffer is larger than667	 * the data that kernel reports.668	 */669	if (data_len > cmd.data_len) {670		char *ptr = (char *)(data + cmd.data_len);671		int idx = 0;672 673		while (idx < data_len - cmd.data_len) {674			assert(!*(ptr + idx));675			idx++;676		}677	}678 679	if (info) {680		if (data_len >= offsetofend(struct iommu_test_hw_info, test_reg))681			assert(info->test_reg == IOMMU_HW_INFO_SELFTEST_REGVAL);682		if (data_len >= offsetofend(struct iommu_test_hw_info, flags))683			assert(!info->flags);684	}685 686	if (capabilities)687		*capabilities = cmd.out_capabilities;688 689	return 0;690}691 692#define test_cmd_get_hw_info(device_id, data, data_len)               \693	ASSERT_EQ(0, _test_cmd_get_hw_info(self->fd, device_id, data, \694					   data_len, NULL))695 696#define test_err_get_hw_info(_errno, device_id, data, data_len)               \697	EXPECT_ERRNO(_errno, _test_cmd_get_hw_info(self->fd, device_id, data, \698						   data_len, NULL))699 700#define test_cmd_get_hw_capabilities(device_id, caps, mask) \701	ASSERT_EQ(0, _test_cmd_get_hw_info(self->fd, device_id, NULL, 0, &caps))702 703static int _test_ioctl_fault_alloc(int fd, __u32 *fault_id, __u32 *fault_fd)704{705	struct iommu_fault_alloc cmd = {706		.size = sizeof(cmd),707	};708	int ret;709 710	ret = ioctl(fd, IOMMU_FAULT_QUEUE_ALLOC, &cmd);711	if (ret)712		return ret;713	*fault_id = cmd.out_fault_id;714	*fault_fd = cmd.out_fault_fd;715	return 0;716}717 718#define test_ioctl_fault_alloc(fault_id, fault_fd)                       \719	({                                                               \720		ASSERT_EQ(0, _test_ioctl_fault_alloc(self->fd, fault_id, \721						     fault_fd));         \722		ASSERT_NE(0, *(fault_id));                               \723		ASSERT_NE(0, *(fault_fd));                               \724	})725 726static int _test_cmd_trigger_iopf(int fd, __u32 device_id, __u32 fault_fd)727{728	struct iommu_test_cmd trigger_iopf_cmd = {729		.size = sizeof(trigger_iopf_cmd),730		.op = IOMMU_TEST_OP_TRIGGER_IOPF,731		.trigger_iopf = {732			.dev_id = device_id,733			.pasid = 0x1,734			.grpid = 0x2,735			.perm = IOMMU_PGFAULT_PERM_READ | IOMMU_PGFAULT_PERM_WRITE,736			.addr = 0xdeadbeaf,737		},738	};739	struct iommu_hwpt_page_response response = {740		.code = IOMMUFD_PAGE_RESP_SUCCESS,741	};742	struct iommu_hwpt_pgfault fault = {};743	ssize_t bytes;744	int ret;745 746	ret = ioctl(fd, _IOMMU_TEST_CMD(IOMMU_TEST_OP_TRIGGER_IOPF), &trigger_iopf_cmd);747	if (ret)748		return ret;749 750	bytes = read(fault_fd, &fault, sizeof(fault));751	if (bytes <= 0)752		return -EIO;753 754	response.cookie = fault.cookie;755 756	bytes = write(fault_fd, &response, sizeof(response));757	if (bytes <= 0)758		return -EIO;759 760	return 0;761}762 763#define test_cmd_trigger_iopf(device_id, fault_fd) \764	ASSERT_EQ(0, _test_cmd_trigger_iopf(self->fd, device_id, fault_fd))765