1 /* SPDX-License-Identifier: GPL-2.0-only */ 2 /* Copyright (c) 2021-2022, NVIDIA CORPORATION & AFFILIATES */ 3 #ifndef __SELFTEST_IOMMUFD_UTILS 4 #define __SELFTEST_IOMMUFD_UTILS 5 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_CMD 18 19 /* Imported from include/asm-generic/bitops/generic-non-atomic.h */ 20 #define BITS_PER_BYTE 8 21 #define BITS_PER_LONG __BITS_PER_LONG 22 #define BIT_MASK(nr) (1UL << ((nr) % __BITS_PER_LONG)) 23 #define BIT_WORD(nr) ((nr) / __BITS_PER_LONG) 24 25 static inline void set_bit(unsigned int nr, unsigned long *addr) 26 { 27 unsigned long mask = BIT_MASK(nr); 28 unsigned long *p = ((unsigned long *)addr) + BIT_WORD(nr); 29 30 *p |= mask; 31 } 32 33 static inline bool test_bit(unsigned int nr, unsigned long *addr) 34 { 35 return 1UL & (addr[BIT_WORD(nr)] >> (nr & (BITS_PER_LONG - 1))); 36 } 37 38 static void *buffer; 39 static unsigned long BUFFER_SIZE; 40 41 static unsigned long PAGE_SIZE; 42 43 #define sizeof_field(TYPE, MEMBER) sizeof((((TYPE *)0)->MEMBER)) 44 #define offsetofend(TYPE, MEMBER) \ 45 (offsetof(TYPE, MEMBER) + sizeof_field(TYPE, MEMBER)) 46 47 /* 48 * Have the kernel check the refcount on pages. I don't know why a freshly 49 * mmap'd anon non-compound page starts out with a ref of 3 50 */ 51 #define check_refs(_ptr, _length, _refs) \ 52 ({ \ 53 struct iommu_test_cmd test_cmd = { \ 54 .size = sizeof(test_cmd), \ 55 .op = IOMMU_TEST_OP_MD_CHECK_REFS, \ 56 .check_refs = { .length = _length, \ 57 .uptr = (uintptr_t)(_ptr), \ 58 .refs = _refs }, \ 59 }; \ 60 ASSERT_EQ(0, \ 61 ioctl(self->fd, \ 62 _IOMMU_TEST_CMD(IOMMU_TEST_OP_MD_CHECK_REFS), \ 63 &test_cmd)); \ 64 }) 65 66 static int _test_cmd_mock_domain(int fd, unsigned int ioas_id, __u32 *stdev_id, 67 __u32 *hwpt_id, __u32 *idev_id) 68 { 69 struct iommu_test_cmd cmd = { 70 .size = sizeof(cmd), 71 .op = IOMMU_TEST_OP_MOCK_DOMAIN, 72 .id = ioas_id, 73 .mock_domain = {}, 74 }; 75 int ret; 76 77 ret = ioctl(fd, IOMMU_TEST_CMD, &cmd); 78 if (ret) 79 return ret; 80 if (stdev_id) 81 *stdev_id = cmd.mock_domain.out_stdev_id; 82 assert(cmd.id != 0); 83 if (hwpt_id) 84 *hwpt_id = cmd.mock_domain.out_hwpt_id; 85 if (idev_id) 86 *idev_id = cmd.mock_domain.out_idev_id; 87 return 0; 88 } 89 #define test_cmd_mock_domain(ioas_id, stdev_id, hwpt_id, idev_id) \ 90 ASSERT_EQ(0, _test_cmd_mock_domain(self->fd, ioas_id, stdev_id, \ 91 hwpt_id, idev_id)) 92 #define test_err_mock_domain(_errno, ioas_id, stdev_id, hwpt_id) \ 93 EXPECT_ERRNO(_errno, _test_cmd_mock_domain(self->fd, ioas_id, \ 94 stdev_id, hwpt_id, NULL)) 95 96 static int _test_cmd_mock_domain_flags(int fd, unsigned int ioas_id, 97 __u32 stdev_flags, __u32 *stdev_id, 98 __u32 *hwpt_id, __u32 *idev_id) 99 { 100 struct iommu_test_cmd cmd = { 101 .size = sizeof(cmd), 102 .op = IOMMU_TEST_OP_MOCK_DOMAIN_FLAGS, 103 .id = ioas_id, 104 .mock_domain_flags = { .dev_flags = stdev_flags }, 105 }; 106 int ret; 107 108 ret = ioctl(fd, IOMMU_TEST_CMD, &cmd); 109 if (ret) 110 return ret; 111 if (stdev_id) 112 *stdev_id = cmd.mock_domain_flags.out_stdev_id; 113 assert(cmd.id != 0); 114 if (hwpt_id) 115 *hwpt_id = cmd.mock_domain_flags.out_hwpt_id; 116 if (idev_id) 117 *idev_id = cmd.mock_domain_flags.out_idev_id; 118 return 0; 119 } 120 #define test_cmd_mock_domain_flags(ioas_id, flags, stdev_id, hwpt_id, idev_id) \ 121 ASSERT_EQ(0, _test_cmd_mock_domain_flags(self->fd, ioas_id, flags, \ 122 stdev_id, hwpt_id, idev_id)) 123 #define test_err_mock_domain_flags(_errno, ioas_id, flags, stdev_id, hwpt_id) \ 124 EXPECT_ERRNO(_errno, \ 125 _test_cmd_mock_domain_flags(self->fd, ioas_id, flags, \ 126 stdev_id, hwpt_id, NULL)) 127 128 static int _test_cmd_mock_domain_replace(int fd, __u32 stdev_id, __u32 pt_id, 129 __u32 *hwpt_id) 130 { 131 struct iommu_test_cmd cmd = { 132 .size = sizeof(cmd), 133 .op = IOMMU_TEST_OP_MOCK_DOMAIN_REPLACE, 134 .id = stdev_id, 135 .mock_domain_replace = { 136 .pt_id = pt_id, 137 }, 138 }; 139 int ret; 140 141 ret = ioctl(fd, IOMMU_TEST_CMD, &cmd); 142 if (ret) 143 return ret; 144 if (hwpt_id) 145 *hwpt_id = cmd.mock_domain_replace.pt_id; 146 return 0; 147 } 148 149 #define test_cmd_mock_domain_replace(stdev_id, pt_id) \ 150 ASSERT_EQ(0, _test_cmd_mock_domain_replace(self->fd, stdev_id, pt_id, \ 151 NULL)) 152 #define test_err_mock_domain_replace(_errno, stdev_id, pt_id) \ 153 EXPECT_ERRNO(_errno, _test_cmd_mock_domain_replace(self->fd, stdev_id, \ 154 pt_id, NULL)) 155 156 static int _test_cmd_hwpt_alloc(int fd, __u32 device_id, __u32 pt_id, 157 __u32 flags, __u32 *hwpt_id, __u32 data_type, 158 void *data, size_t data_len) 159 { 160 struct iommu_hwpt_alloc cmd = { 161 .size = sizeof(cmd), 162 .flags = flags, 163 .dev_id = device_id, 164 .pt_id = pt_id, 165 .data_type = data_type, 166 .data_len = data_len, 167 .data_uptr = (uint64_t)data, 168 }; 169 int ret; 170 171 ret = ioctl(fd, IOMMU_HWPT_ALLOC, &cmd); 172 if (ret) 173 return ret; 174 if (hwpt_id) 175 *hwpt_id = cmd.out_hwpt_id; 176 return 0; 177 } 178 179 #define test_cmd_hwpt_alloc(device_id, pt_id, flags, hwpt_id) \ 180 ASSERT_EQ(0, _test_cmd_hwpt_alloc(self->fd, device_id, pt_id, flags, \ 181 hwpt_id, IOMMU_HWPT_DATA_NONE, NULL, \ 182 0)) 183 #define test_err_hwpt_alloc(_errno, device_id, pt_id, flags, hwpt_id) \ 184 EXPECT_ERRNO(_errno, _test_cmd_hwpt_alloc( \ 185 self->fd, device_id, pt_id, flags, \ 186 hwpt_id, IOMMU_HWPT_DATA_NONE, NULL, 0)) 187 188 #define test_cmd_hwpt_alloc_nested(device_id, pt_id, flags, hwpt_id, \ 189 data_type, data, data_len) \ 190 ASSERT_EQ(0, _test_cmd_hwpt_alloc(self->fd, device_id, pt_id, flags, \ 191 hwpt_id, data_type, data, data_len)) 192 #define test_err_hwpt_alloc_nested(_errno, device_id, pt_id, flags, hwpt_id, \ 193 data_type, data, data_len) \ 194 EXPECT_ERRNO(_errno, \ 195 _test_cmd_hwpt_alloc(self->fd, device_id, pt_id, flags, \ 196 hwpt_id, data_type, data, data_len)) 197 198 static int _test_cmd_access_replace_ioas(int fd, __u32 access_id, 199 unsigned int ioas_id) 200 { 201 struct iommu_test_cmd cmd = { 202 .size = sizeof(cmd), 203 .op = IOMMU_TEST_OP_ACCESS_REPLACE_IOAS, 204 .id = access_id, 205 .access_replace_ioas = { .ioas_id = ioas_id }, 206 }; 207 int ret; 208 209 ret = ioctl(fd, IOMMU_TEST_CMD, &cmd); 210 if (ret) 211 return ret; 212 return 0; 213 } 214 #define test_cmd_access_replace_ioas(access_id, ioas_id) \ 215 ASSERT_EQ(0, _test_cmd_access_replace_ioas(self->fd, access_id, ioas_id)) 216 217 static int _test_cmd_set_dirty_tracking(int fd, __u32 hwpt_id, bool enabled) 218 { 219 struct iommu_hwpt_set_dirty_tracking cmd = { 220 .size = sizeof(cmd), 221 .flags = enabled ? IOMMU_HWPT_DIRTY_TRACKING_ENABLE : 0, 222 .hwpt_id = hwpt_id, 223 }; 224 int ret; 225 226 ret = ioctl(fd, IOMMU_HWPT_SET_DIRTY_TRACKING, &cmd); 227 if (ret) 228 return -errno; 229 return 0; 230 } 231 #define test_cmd_set_dirty_tracking(hwpt_id, enabled) \ 232 ASSERT_EQ(0, _test_cmd_set_dirty_tracking(self->fd, hwpt_id, enabled)) 233 234 static int _test_cmd_get_dirty_bitmap(int fd, __u32 hwpt_id, size_t length, 235 __u64 iova, size_t page_size, 236 __u64 *bitmap, __u32 flags) 237 { 238 struct iommu_hwpt_get_dirty_bitmap cmd = { 239 .size = sizeof(cmd), 240 .hwpt_id = hwpt_id, 241 .flags = flags, 242 .iova = iova, 243 .length = length, 244 .page_size = page_size, 245 .data = (uintptr_t)bitmap, 246 }; 247 int ret; 248 249 ret = ioctl(fd, IOMMU_HWPT_GET_DIRTY_BITMAP, &cmd); 250 if (ret) 251 return ret; 252 return 0; 253 } 254 255 #define test_cmd_get_dirty_bitmap(fd, hwpt_id, length, iova, page_size, \ 256 bitmap, flags) \ 257 ASSERT_EQ(0, _test_cmd_get_dirty_bitmap(fd, hwpt_id, length, iova, \ 258 page_size, bitmap, flags)) 259 260 static int _test_cmd_mock_domain_set_dirty(int fd, __u32 hwpt_id, size_t length, 261 __u64 iova, size_t page_size, 262 __u64 *bitmap, __u64 *dirty) 263 { 264 struct iommu_test_cmd cmd = { 265 .size = sizeof(cmd), 266 .op = IOMMU_TEST_OP_DIRTY, 267 .id = hwpt_id, 268 .dirty = { 269 .iova = iova, 270 .length = length, 271 .page_size = page_size, 272 .uptr = (uintptr_t)bitmap, 273 } 274 }; 275 int ret; 276 277 ret = ioctl(fd, _IOMMU_TEST_CMD(IOMMU_TEST_OP_DIRTY), &cmd); 278 if (ret) 279 return -ret; 280 if (dirty) 281 *dirty = cmd.dirty.out_nr_dirty; 282 return 0; 283 } 284 285 #define test_cmd_mock_domain_set_dirty(fd, hwpt_id, length, iova, page_size, \ 286 bitmap, nr) \ 287 ASSERT_EQ(0, \ 288 _test_cmd_mock_domain_set_dirty(fd, hwpt_id, length, iova, \ 289 page_size, bitmap, nr)) 290 291 static int _test_mock_dirty_bitmaps(int fd, __u32 hwpt_id, size_t length, 292 __u64 iova, size_t page_size, __u64 *bitmap, 293 __u64 bitmap_size, __u32 flags, 294 struct __test_metadata *_metadata) 295 { 296 unsigned long i, nbits = bitmap_size * BITS_PER_BYTE; 297 unsigned long nr = nbits / 2; 298 __u64 out_dirty = 0; 299 300 /* Mark all even bits as dirty in the mock domain */ 301 for (i = 0; i < nbits; i += 2) 302 set_bit(i, (unsigned long *)bitmap); 303 304 test_cmd_mock_domain_set_dirty(fd, hwpt_id, length, iova, page_size, 305 bitmap, &out_dirty); 306 ASSERT_EQ(nr, out_dirty); 307 308 /* Expect all even bits as dirty in the user bitmap */ 309 memset(bitmap, 0, bitmap_size); 310 test_cmd_get_dirty_bitmap(fd, hwpt_id, length, iova, page_size, bitmap, 311 flags); 312 /* Beware ASSERT_EQ() is two statements -- braces are not redundant! */ 313 for (i = 0; i < nbits; i++) { 314 ASSERT_EQ(!(i % 2), test_bit(i, (unsigned long *)bitmap)); 315 } 316 317 memset(bitmap, 0, bitmap_size); 318 test_cmd_get_dirty_bitmap(fd, hwpt_id, length, iova, page_size, bitmap, 319 flags); 320 321 /* It as read already -- expect all zeroes */ 322 for (i = 0; i < nbits; i++) { 323 ASSERT_EQ(!(i % 2) && (flags & 324 IOMMU_HWPT_GET_DIRTY_BITMAP_NO_CLEAR), 325 test_bit(i, (unsigned long *)bitmap)); 326 } 327 328 return 0; 329 } 330 #define test_mock_dirty_bitmaps(hwpt_id, length, iova, page_size, bitmap, \ 331 bitmap_size, flags, _metadata) \ 332 ASSERT_EQ(0, _test_mock_dirty_bitmaps(self->fd, hwpt_id, length, iova, \ 333 page_size, bitmap, bitmap_size, \ 334 flags, _metadata)) 335 336 static int _test_cmd_create_access(int fd, unsigned int ioas_id, 337 __u32 *access_id, unsigned int flags) 338 { 339 struct iommu_test_cmd cmd = { 340 .size = sizeof(cmd), 341 .op = IOMMU_TEST_OP_CREATE_ACCESS, 342 .id = ioas_id, 343 .create_access = { .flags = flags }, 344 }; 345 int ret; 346 347 ret = ioctl(fd, IOMMU_TEST_CMD, &cmd); 348 if (ret) 349 return ret; 350 *access_id = cmd.create_access.out_access_fd; 351 return 0; 352 } 353 #define test_cmd_create_access(ioas_id, access_id, flags) \ 354 ASSERT_EQ(0, _test_cmd_create_access(self->fd, ioas_id, access_id, \ 355 flags)) 356 357 static int _test_cmd_destroy_access(unsigned int access_id) 358 { 359 return close(access_id); 360 } 361 #define test_cmd_destroy_access(access_id) \ 362 ASSERT_EQ(0, _test_cmd_destroy_access(access_id)) 363 364 static int _test_cmd_destroy_access_pages(int fd, unsigned int access_id, 365 unsigned int access_pages_id) 366 { 367 struct iommu_test_cmd cmd = { 368 .size = sizeof(cmd), 369 .op = IOMMU_TEST_OP_DESTROY_ACCESS_PAGES, 370 .id = access_id, 371 .destroy_access_pages = { .access_pages_id = access_pages_id }, 372 }; 373 return ioctl(fd, IOMMU_TEST_CMD, &cmd); 374 } 375 #define test_cmd_destroy_access_pages(access_id, access_pages_id) \ 376 ASSERT_EQ(0, _test_cmd_destroy_access_pages(self->fd, access_id, \ 377 access_pages_id)) 378 #define test_err_destroy_access_pages(_errno, access_id, access_pages_id) \ 379 EXPECT_ERRNO(_errno, _test_cmd_destroy_access_pages( \ 380 self->fd, access_id, access_pages_id)) 381 382 static int _test_ioctl_destroy(int fd, unsigned int id) 383 { 384 struct iommu_destroy cmd = { 385 .size = sizeof(cmd), 386 .id = id, 387 }; 388 return ioctl(fd, IOMMU_DESTROY, &cmd); 389 } 390 #define test_ioctl_destroy(id) ASSERT_EQ(0, _test_ioctl_destroy(self->fd, id)) 391 392 static int _test_ioctl_ioas_alloc(int fd, __u32 *id) 393 { 394 struct iommu_ioas_alloc cmd = { 395 .size = sizeof(cmd), 396 }; 397 int ret; 398 399 ret = ioctl(fd, IOMMU_IOAS_ALLOC, &cmd); 400 if (ret) 401 return ret; 402 *id = cmd.out_ioas_id; 403 return 0; 404 } 405 #define test_ioctl_ioas_alloc(id) \ 406 ({ \ 407 ASSERT_EQ(0, _test_ioctl_ioas_alloc(self->fd, id)); \ 408 ASSERT_NE(0, *(id)); \ 409 }) 410 411 static int _test_ioctl_ioas_map(int fd, unsigned int ioas_id, void *buffer, 412 size_t length, __u64 *iova, unsigned int flags) 413 { 414 struct iommu_ioas_map cmd = { 415 .size = sizeof(cmd), 416 .flags = flags, 417 .ioas_id = ioas_id, 418 .user_va = (uintptr_t)buffer, 419 .length = length, 420 }; 421 int ret; 422 423 if (flags & IOMMU_IOAS_MAP_FIXED_IOVA) 424 cmd.iova = *iova; 425 426 ret = ioctl(fd, IOMMU_IOAS_MAP, &cmd); 427 *iova = cmd.iova; 428 return ret; 429 } 430 #define test_ioctl_ioas_map(buffer, length, iova_p) \ 431 ASSERT_EQ(0, _test_ioctl_ioas_map(self->fd, self->ioas_id, buffer, \ 432 length, iova_p, \ 433 IOMMU_IOAS_MAP_WRITEABLE | \ 434 IOMMU_IOAS_MAP_READABLE)) 435 436 #define test_err_ioctl_ioas_map(_errno, buffer, length, iova_p) \ 437 EXPECT_ERRNO(_errno, \ 438 _test_ioctl_ioas_map(self->fd, self->ioas_id, buffer, \ 439 length, iova_p, \ 440 IOMMU_IOAS_MAP_WRITEABLE | \ 441 IOMMU_IOAS_MAP_READABLE)) 442 443 #define test_ioctl_ioas_map_id(ioas_id, buffer, length, iova_p) \ 444 ASSERT_EQ(0, _test_ioctl_ioas_map(self->fd, ioas_id, buffer, length, \ 445 iova_p, \ 446 IOMMU_IOAS_MAP_WRITEABLE | \ 447 IOMMU_IOAS_MAP_READABLE)) 448 449 #define test_ioctl_ioas_map_fixed(buffer, length, iova) \ 450 ({ \ 451 __u64 __iova = iova; \ 452 ASSERT_EQ(0, _test_ioctl_ioas_map( \ 453 self->fd, self->ioas_id, buffer, length, \ 454 &__iova, \ 455 IOMMU_IOAS_MAP_FIXED_IOVA | \ 456 IOMMU_IOAS_MAP_WRITEABLE | \ 457 IOMMU_IOAS_MAP_READABLE)); \ 458 }) 459 460 #define test_ioctl_ioas_map_fixed_id(ioas_id, buffer, length, iova) \ 461 ({ \ 462 __u64 __iova = iova; \ 463 ASSERT_EQ(0, \ 464 _test_ioctl_ioas_map( \ 465 self->fd, ioas_id, buffer, length, &__iova, \ 466 IOMMU_IOAS_MAP_FIXED_IOVA | \ 467 IOMMU_IOAS_MAP_WRITEABLE | \ 468 IOMMU_IOAS_MAP_READABLE)); \ 469 }) 470 471 #define test_err_ioctl_ioas_map_fixed(_errno, buffer, length, iova) \ 472 ({ \ 473 __u64 __iova = iova; \ 474 EXPECT_ERRNO(_errno, \ 475 _test_ioctl_ioas_map( \ 476 self->fd, self->ioas_id, buffer, length, \ 477 &__iova, \ 478 IOMMU_IOAS_MAP_FIXED_IOVA | \ 479 IOMMU_IOAS_MAP_WRITEABLE | \ 480 IOMMU_IOAS_MAP_READABLE)); \ 481 }) 482 483 static int _test_ioctl_ioas_unmap(int fd, unsigned int ioas_id, uint64_t iova, 484 size_t length, uint64_t *out_len) 485 { 486 struct iommu_ioas_unmap cmd = { 487 .size = sizeof(cmd), 488 .ioas_id = ioas_id, 489 .iova = iova, 490 .length = length, 491 }; 492 int ret; 493 494 ret = ioctl(fd, IOMMU_IOAS_UNMAP, &cmd); 495 if (out_len) 496 *out_len = cmd.length; 497 return ret; 498 } 499 #define test_ioctl_ioas_unmap(iova, length) \ 500 ASSERT_EQ(0, _test_ioctl_ioas_unmap(self->fd, self->ioas_id, iova, \ 501 length, NULL)) 502 503 #define test_ioctl_ioas_unmap_id(ioas_id, iova, length) \ 504 ASSERT_EQ(0, _test_ioctl_ioas_unmap(self->fd, ioas_id, iova, length, \ 505 NULL)) 506 507 #define test_err_ioctl_ioas_unmap(_errno, iova, length) \ 508 EXPECT_ERRNO(_errno, _test_ioctl_ioas_unmap(self->fd, self->ioas_id, \ 509 iova, length, NULL)) 510 511 static int _test_ioctl_set_temp_memory_limit(int fd, unsigned int limit) 512 { 513 struct iommu_test_cmd memlimit_cmd = { 514 .size = sizeof(memlimit_cmd), 515 .op = IOMMU_TEST_OP_SET_TEMP_MEMORY_LIMIT, 516 .memory_limit = { .limit = limit }, 517 }; 518 519 return ioctl(fd, _IOMMU_TEST_CMD(IOMMU_TEST_OP_SET_TEMP_MEMORY_LIMIT), 520 &memlimit_cmd); 521 } 522 523 #define test_ioctl_set_temp_memory_limit(limit) \ 524 ASSERT_EQ(0, _test_ioctl_set_temp_memory_limit(self->fd, limit)) 525 526 #define test_ioctl_set_default_memory_limit() \ 527 test_ioctl_set_temp_memory_limit(65536) 528 529 static void teardown_iommufd(int fd, struct __test_metadata *_metadata) 530 { 531 struct iommu_test_cmd test_cmd = { 532 .size = sizeof(test_cmd), 533 .op = IOMMU_TEST_OP_MD_CHECK_REFS, 534 .check_refs = { .length = BUFFER_SIZE, 535 .uptr = (uintptr_t)buffer }, 536 }; 537 538 if (fd == -1) 539 return; 540 541 EXPECT_EQ(0, close(fd)); 542 543 fd = open("/dev/iommu", O_RDWR); 544 EXPECT_NE(-1, fd); 545 EXPECT_EQ(0, ioctl(fd, _IOMMU_TEST_CMD(IOMMU_TEST_OP_MD_CHECK_REFS), 546 &test_cmd)); 547 EXPECT_EQ(0, close(fd)); 548 } 549 550 #define EXPECT_ERRNO(expected_errno, cmd) \ 551 ({ \ 552 ASSERT_EQ(-1, cmd); \ 553 EXPECT_EQ(expected_errno, errno); \ 554 }) 555 556 #endif 557 558 /* @data can be NULL */ 559 static int _test_cmd_get_hw_info(int fd, __u32 device_id, void *data, 560 size_t data_len, uint32_t *capabilities) 561 { 562 struct iommu_test_hw_info *info = (struct iommu_test_hw_info *)data; 563 struct iommu_hw_info cmd = { 564 .size = sizeof(cmd), 565 .dev_id = device_id, 566 .data_len = data_len, 567 .data_uptr = (uint64_t)data, 568 .out_capabilities = 0, 569 }; 570 int ret; 571 572 ret = ioctl(fd, IOMMU_GET_HW_INFO, &cmd); 573 if (ret) 574 return ret; 575 576 assert(cmd.out_data_type == IOMMU_HW_INFO_TYPE_SELFTEST); 577 578 /* 579 * The struct iommu_test_hw_info should be the one defined 580 * by the current kernel. 581 */ 582 assert(cmd.data_len == sizeof(struct iommu_test_hw_info)); 583 584 /* 585 * Trailing bytes should be 0 if user buffer is larger than 586 * the data that kernel reports. 587 */ 588 if (data_len > cmd.data_len) { 589 char *ptr = (char *)(data + cmd.data_len); 590 int idx = 0; 591 592 while (idx < data_len - cmd.data_len) { 593 assert(!*(ptr + idx)); 594 idx++; 595 } 596 } 597 598 if (info) { 599 if (data_len >= offsetofend(struct iommu_test_hw_info, test_reg)) 600 assert(info->test_reg == IOMMU_HW_INFO_SELFTEST_REGVAL); 601 if (data_len >= offsetofend(struct iommu_test_hw_info, flags)) 602 assert(!info->flags); 603 } 604 605 if (capabilities) 606 *capabilities = cmd.out_capabilities; 607 608 return 0; 609 } 610 611 #define test_cmd_get_hw_info(device_id, data, data_len) \ 612 ASSERT_EQ(0, _test_cmd_get_hw_info(self->fd, device_id, data, \ 613 data_len, NULL)) 614 615 #define test_err_get_hw_info(_errno, device_id, data, data_len) \ 616 EXPECT_ERRNO(_errno, _test_cmd_get_hw_info(self->fd, device_id, data, \ 617 data_len, NULL)) 618 619 #define test_cmd_get_hw_capabilities(device_id, caps, mask) \ 620 ASSERT_EQ(0, _test_cmd_get_hw_info(self->fd, device_id, NULL, 0, &caps)) 621