iommufd_fail_nth.c 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748
  1. // SPDX-License-Identifier: GPL-2.0-only
  2. /* Copyright (c) 2021-2022, NVIDIA CORPORATION & AFFILIATES
  3. *
  4. * These tests are "kernel integrity" tests. They are looking for kernel
  5. * WARN/OOPS/kasn/etc splats triggered by kernel sanitizers & debugging
  6. * features. It does not attempt to verify that the system calls are doing what
  7. * they are supposed to do.
  8. *
  9. * The basic philosophy is to run a sequence of calls that will succeed and then
  10. * sweep every failure injection point on that call chain to look for
  11. * interesting things in error handling.
  12. *
  13. * This test is best run with:
  14. * echo 1 > /proc/sys/kernel/panic_on_warn
  15. * If something is actually going wrong.
  16. */
  17. #include <fcntl.h>
  18. #include <dirent.h>
  19. #define __EXPORTED_HEADERS__
  20. #include <linux/vfio.h>
  21. #include "iommufd_utils.h"
  22. static bool have_fault_injection;
  23. static int writeat(int dfd, const char *fn, const char *val)
  24. {
  25. size_t val_len = strlen(val);
  26. ssize_t res;
  27. int fd;
  28. fd = openat(dfd, fn, O_WRONLY);
  29. if (fd == -1)
  30. return -1;
  31. res = write(fd, val, val_len);
  32. assert(res == val_len);
  33. close(fd);
  34. return 0;
  35. }
  36. static __attribute__((constructor)) void setup_buffer(void)
  37. {
  38. PAGE_SIZE = sysconf(_SC_PAGE_SIZE);
  39. BUFFER_SIZE = 2*1024*1024;
  40. buffer = mmap(0, BUFFER_SIZE, PROT_READ | PROT_WRITE,
  41. MAP_SHARED | MAP_ANONYMOUS, -1, 0);
  42. mfd_buffer = memfd_mmap(BUFFER_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED,
  43. &mfd);
  44. }
  45. /*
  46. * This sets up fail_injection in a way that is useful for this test.
  47. * It does not attempt to restore things back to how they were.
  48. */
  49. static __attribute__((constructor)) void setup_fault_injection(void)
  50. {
  51. DIR *debugfs = opendir("/sys/kernel/debug/");
  52. struct dirent *dent;
  53. if (!debugfs)
  54. return;
  55. /* Allow any allocation call to be fault injected */
  56. if (writeat(dirfd(debugfs), "failslab/ignore-gfp-wait", "N"))
  57. return;
  58. writeat(dirfd(debugfs), "fail_page_alloc/ignore-gfp-wait", "N");
  59. writeat(dirfd(debugfs), "fail_page_alloc/ignore-gfp-highmem", "N");
  60. while ((dent = readdir(debugfs))) {
  61. char fn[300];
  62. if (strncmp(dent->d_name, "fail", 4) != 0)
  63. continue;
  64. /* We are looking for kernel splats, quiet down the log */
  65. snprintf(fn, sizeof(fn), "%s/verbose", dent->d_name);
  66. writeat(dirfd(debugfs), fn, "0");
  67. }
  68. closedir(debugfs);
  69. have_fault_injection = true;
  70. }
  71. struct fail_nth_state {
  72. int proc_fd;
  73. unsigned int iteration;
  74. };
  75. static void fail_nth_first(struct __test_metadata *_metadata,
  76. struct fail_nth_state *nth_state)
  77. {
  78. char buf[300];
  79. snprintf(buf, sizeof(buf), "/proc/self/task/%u/fail-nth", getpid());
  80. nth_state->proc_fd = open(buf, O_RDWR);
  81. ASSERT_NE(-1, nth_state->proc_fd);
  82. }
  83. static bool fail_nth_next(struct __test_metadata *_metadata,
  84. struct fail_nth_state *nth_state,
  85. int test_result)
  86. {
  87. static const char disable_nth[] = "0";
  88. char buf[300];
  89. /*
  90. * This is just an arbitrary limit based on the current kernel
  91. * situation. Changes in the kernel can dramatically change the number of
  92. * required fault injection sites, so if this hits it doesn't
  93. * necessarily mean a test failure, just that the limit has to be made
  94. * bigger.
  95. */
  96. ASSERT_GT(1000, nth_state->iteration);
  97. if (nth_state->iteration != 0) {
  98. ssize_t res;
  99. ssize_t res2;
  100. buf[0] = 0;
  101. /*
  102. * Annoyingly disabling the nth can also fail. This means
  103. * the test passed without triggering failure
  104. */
  105. res = pread(nth_state->proc_fd, buf, sizeof(buf), 0);
  106. if (res == -1 && errno == EFAULT) {
  107. buf[0] = '1';
  108. buf[1] = '\n';
  109. res = 2;
  110. }
  111. res2 = pwrite(nth_state->proc_fd, disable_nth,
  112. ARRAY_SIZE(disable_nth) - 1, 0);
  113. if (res2 == -1 && errno == EFAULT) {
  114. res2 = pwrite(nth_state->proc_fd, disable_nth,
  115. ARRAY_SIZE(disable_nth) - 1, 0);
  116. buf[0] = '1';
  117. buf[1] = '\n';
  118. }
  119. ASSERT_EQ(ARRAY_SIZE(disable_nth) - 1, res2);
  120. /* printf(" nth %u result=%d nth=%u\n", nth_state->iteration,
  121. test_result, atoi(buf)); */
  122. fflush(stdout);
  123. ASSERT_LT(1, res);
  124. if (res != 2 || buf[0] != '0' || buf[1] != '\n')
  125. return false;
  126. } else {
  127. /* printf(" nth %u result=%d\n", nth_state->iteration,
  128. test_result); */
  129. }
  130. nth_state->iteration++;
  131. return true;
  132. }
  133. /*
  134. * This is called during the test to start failure injection. It allows the test
  135. * to do some setup that has already been swept and thus reduce the required
  136. * iterations.
  137. */
  138. void __fail_nth_enable(struct __test_metadata *_metadata,
  139. struct fail_nth_state *nth_state)
  140. {
  141. char buf[300];
  142. size_t len;
  143. if (!nth_state->iteration)
  144. return;
  145. len = snprintf(buf, sizeof(buf), "%u", nth_state->iteration);
  146. ASSERT_EQ(len, pwrite(nth_state->proc_fd, buf, len, 0));
  147. }
  148. #define fail_nth_enable() __fail_nth_enable(_metadata, _nth_state)
  149. #define TEST_FAIL_NTH(fixture_name, name) \
  150. static int test_nth_##name(struct __test_metadata *_metadata, \
  151. FIXTURE_DATA(fixture_name) *self, \
  152. const FIXTURE_VARIANT(fixture_name) \
  153. *variant, \
  154. struct fail_nth_state *_nth_state); \
  155. TEST_F(fixture_name, name) \
  156. { \
  157. struct fail_nth_state nth_state = {}; \
  158. int test_result = 0; \
  159. \
  160. if (!have_fault_injection) \
  161. SKIP(return, \
  162. "fault injection is not enabled in the kernel"); \
  163. fail_nth_first(_metadata, &nth_state); \
  164. ASSERT_EQ(0, test_nth_##name(_metadata, self, variant, \
  165. &nth_state)); \
  166. while (fail_nth_next(_metadata, &nth_state, test_result)) { \
  167. fixture_name##_teardown(_metadata, self, variant); \
  168. fixture_name##_setup(_metadata, self, variant); \
  169. test_result = test_nth_##name(_metadata, self, \
  170. variant, &nth_state); \
  171. }; \
  172. ASSERT_EQ(0, test_result); \
  173. } \
  174. static int test_nth_##name( \
  175. struct __test_metadata __attribute__((unused)) *_metadata, \
  176. FIXTURE_DATA(fixture_name) __attribute__((unused)) *self, \
  177. const FIXTURE_VARIANT(fixture_name) __attribute__((unused)) \
  178. *variant, \
  179. struct fail_nth_state *_nth_state)
  180. FIXTURE(basic_fail_nth)
  181. {
  182. int fd;
  183. uint32_t access_id;
  184. uint32_t stdev_id;
  185. uint32_t pasid;
  186. };
  187. FIXTURE_SETUP(basic_fail_nth)
  188. {
  189. self->fd = -1;
  190. self->access_id = 0;
  191. self->stdev_id = 0;
  192. self->pasid = 0; //test should use a non-zero value
  193. }
  194. FIXTURE_TEARDOWN(basic_fail_nth)
  195. {
  196. int rc;
  197. if (self->access_id) {
  198. /* The access FD holds the iommufd open until it closes */
  199. rc = _test_cmd_destroy_access(self->access_id);
  200. assert(rc == 0);
  201. }
  202. if (self->pasid && self->stdev_id)
  203. _test_cmd_pasid_detach(self->fd, self->stdev_id, self->pasid);
  204. teardown_iommufd(self->fd, _metadata);
  205. }
  206. /* Cover ioas.c */
  207. TEST_FAIL_NTH(basic_fail_nth, basic)
  208. {
  209. struct iommu_iova_range ranges[10];
  210. uint32_t ioas_id;
  211. __u64 iova;
  212. fail_nth_enable();
  213. self->fd = open("/dev/iommu", O_RDWR);
  214. if (self->fd == -1)
  215. return -1;
  216. if (_test_ioctl_ioas_alloc(self->fd, &ioas_id))
  217. return -1;
  218. {
  219. struct iommu_ioas_iova_ranges ranges_cmd = {
  220. .size = sizeof(ranges_cmd),
  221. .num_iovas = ARRAY_SIZE(ranges),
  222. .ioas_id = ioas_id,
  223. .allowed_iovas = (uintptr_t)ranges,
  224. };
  225. if (ioctl(self->fd, IOMMU_IOAS_IOVA_RANGES, &ranges_cmd))
  226. return -1;
  227. }
  228. {
  229. struct iommu_ioas_allow_iovas allow_cmd = {
  230. .size = sizeof(allow_cmd),
  231. .ioas_id = ioas_id,
  232. .num_iovas = 1,
  233. .allowed_iovas = (uintptr_t)ranges,
  234. };
  235. ranges[0].start = 16*1024;
  236. ranges[0].last = BUFFER_SIZE + 16 * 1024 * 600 - 1;
  237. if (ioctl(self->fd, IOMMU_IOAS_ALLOW_IOVAS, &allow_cmd))
  238. return -1;
  239. }
  240. if (_test_ioctl_ioas_map(self->fd, ioas_id, buffer, BUFFER_SIZE, &iova,
  241. IOMMU_IOAS_MAP_WRITEABLE |
  242. IOMMU_IOAS_MAP_READABLE))
  243. return -1;
  244. {
  245. struct iommu_ioas_copy copy_cmd = {
  246. .size = sizeof(copy_cmd),
  247. .flags = IOMMU_IOAS_MAP_WRITEABLE |
  248. IOMMU_IOAS_MAP_READABLE,
  249. .dst_ioas_id = ioas_id,
  250. .src_ioas_id = ioas_id,
  251. .src_iova = iova,
  252. .length = sizeof(ranges),
  253. };
  254. if (ioctl(self->fd, IOMMU_IOAS_COPY, &copy_cmd))
  255. return -1;
  256. }
  257. if (_test_ioctl_ioas_unmap(self->fd, ioas_id, iova, BUFFER_SIZE,
  258. NULL))
  259. return -1;
  260. /* Failure path of no IOVA to unmap */
  261. _test_ioctl_ioas_unmap(self->fd, ioas_id, iova, BUFFER_SIZE, NULL);
  262. return 0;
  263. }
  264. /* iopt_area_fill_domains() and iopt_area_fill_domain() */
  265. TEST_FAIL_NTH(basic_fail_nth, map_domain)
  266. {
  267. uint32_t ioas_id;
  268. __u32 stdev_id;
  269. __u32 hwpt_id;
  270. __u64 iova;
  271. self->fd = open("/dev/iommu", O_RDWR);
  272. if (self->fd == -1)
  273. return -1;
  274. if (_test_ioctl_ioas_alloc(self->fd, &ioas_id))
  275. return -1;
  276. if (_test_ioctl_set_temp_memory_limit(self->fd, 32))
  277. return -1;
  278. fail_nth_enable();
  279. if (_test_cmd_mock_domain(self->fd, ioas_id, &stdev_id, &hwpt_id, NULL))
  280. return -1;
  281. if (_test_ioctl_ioas_map(self->fd, ioas_id, buffer, 262144, &iova,
  282. IOMMU_IOAS_MAP_WRITEABLE |
  283. IOMMU_IOAS_MAP_READABLE))
  284. return -1;
  285. if (_test_ioctl_destroy(self->fd, stdev_id))
  286. return -1;
  287. if (_test_cmd_mock_domain(self->fd, ioas_id, &stdev_id, &hwpt_id, NULL))
  288. return -1;
  289. return 0;
  290. }
  291. /* iopt_area_fill_domains() and iopt_area_fill_domain() */
  292. TEST_FAIL_NTH(basic_fail_nth, map_file_domain)
  293. {
  294. uint32_t ioas_id;
  295. __u32 stdev_id;
  296. __u32 hwpt_id;
  297. __u64 iova;
  298. self->fd = open("/dev/iommu", O_RDWR);
  299. if (self->fd == -1)
  300. return -1;
  301. if (_test_ioctl_ioas_alloc(self->fd, &ioas_id))
  302. return -1;
  303. if (_test_ioctl_set_temp_memory_limit(self->fd, 32))
  304. return -1;
  305. fail_nth_enable();
  306. if (_test_cmd_mock_domain(self->fd, ioas_id, &stdev_id, &hwpt_id, NULL))
  307. return -1;
  308. if (_test_ioctl_ioas_map_file(self->fd, ioas_id, mfd, 0, 262144, &iova,
  309. IOMMU_IOAS_MAP_WRITEABLE |
  310. IOMMU_IOAS_MAP_READABLE))
  311. return -1;
  312. if (_test_ioctl_destroy(self->fd, stdev_id))
  313. return -1;
  314. if (_test_cmd_mock_domain(self->fd, ioas_id, &stdev_id, &hwpt_id, NULL))
  315. return -1;
  316. return 0;
  317. }
  318. TEST_FAIL_NTH(basic_fail_nth, map_two_domains)
  319. {
  320. uint32_t ioas_id;
  321. __u32 stdev_id2;
  322. __u32 stdev_id;
  323. __u32 hwpt_id2;
  324. __u32 hwpt_id;
  325. __u64 iova;
  326. self->fd = open("/dev/iommu", O_RDWR);
  327. if (self->fd == -1)
  328. return -1;
  329. if (_test_ioctl_ioas_alloc(self->fd, &ioas_id))
  330. return -1;
  331. if (_test_ioctl_set_temp_memory_limit(self->fd, 32))
  332. return -1;
  333. if (_test_cmd_mock_domain(self->fd, ioas_id, &stdev_id, &hwpt_id, NULL))
  334. return -1;
  335. fail_nth_enable();
  336. if (_test_cmd_mock_domain(self->fd, ioas_id, &stdev_id2, &hwpt_id2,
  337. NULL))
  338. return -1;
  339. if (_test_ioctl_ioas_map(self->fd, ioas_id, buffer, 262144, &iova,
  340. IOMMU_IOAS_MAP_WRITEABLE |
  341. IOMMU_IOAS_MAP_READABLE))
  342. return -1;
  343. if (_test_ioctl_destroy(self->fd, stdev_id))
  344. return -1;
  345. if (_test_ioctl_destroy(self->fd, stdev_id2))
  346. return -1;
  347. if (_test_cmd_mock_domain(self->fd, ioas_id, &stdev_id, &hwpt_id, NULL))
  348. return -1;
  349. if (_test_cmd_mock_domain(self->fd, ioas_id, &stdev_id2, &hwpt_id2,
  350. NULL))
  351. return -1;
  352. return 0;
  353. }
  354. TEST_FAIL_NTH(basic_fail_nth, access_rw)
  355. {
  356. uint64_t tmp_big[4096];
  357. uint32_t ioas_id;
  358. uint16_t tmp[32];
  359. __u64 iova;
  360. self->fd = open("/dev/iommu", O_RDWR);
  361. if (self->fd == -1)
  362. return -1;
  363. if (_test_ioctl_ioas_alloc(self->fd, &ioas_id))
  364. return -1;
  365. if (_test_ioctl_set_temp_memory_limit(self->fd, 32))
  366. return -1;
  367. if (_test_ioctl_ioas_map(self->fd, ioas_id, buffer, 262144, &iova,
  368. IOMMU_IOAS_MAP_WRITEABLE |
  369. IOMMU_IOAS_MAP_READABLE))
  370. return -1;
  371. fail_nth_enable();
  372. if (_test_cmd_create_access(self->fd, ioas_id, &self->access_id, 0))
  373. return -1;
  374. {
  375. struct iommu_test_cmd access_cmd = {
  376. .size = sizeof(access_cmd),
  377. .op = IOMMU_TEST_OP_ACCESS_RW,
  378. .id = self->access_id,
  379. .access_rw = { .iova = iova,
  380. .length = sizeof(tmp),
  381. .uptr = (uintptr_t)tmp },
  382. };
  383. // READ
  384. if (ioctl(self->fd, _IOMMU_TEST_CMD(IOMMU_TEST_OP_ACCESS_RW),
  385. &access_cmd))
  386. return -1;
  387. access_cmd.access_rw.flags = MOCK_ACCESS_RW_WRITE;
  388. if (ioctl(self->fd, _IOMMU_TEST_CMD(IOMMU_TEST_OP_ACCESS_RW),
  389. &access_cmd))
  390. return -1;
  391. access_cmd.access_rw.flags = MOCK_ACCESS_RW_SLOW_PATH;
  392. if (ioctl(self->fd, _IOMMU_TEST_CMD(IOMMU_TEST_OP_ACCESS_RW),
  393. &access_cmd))
  394. return -1;
  395. access_cmd.access_rw.flags = MOCK_ACCESS_RW_SLOW_PATH |
  396. MOCK_ACCESS_RW_WRITE;
  397. if (ioctl(self->fd, _IOMMU_TEST_CMD(IOMMU_TEST_OP_ACCESS_RW),
  398. &access_cmd))
  399. return -1;
  400. }
  401. {
  402. struct iommu_test_cmd access_cmd = {
  403. .size = sizeof(access_cmd),
  404. .op = IOMMU_TEST_OP_ACCESS_RW,
  405. .id = self->access_id,
  406. .access_rw = { .iova = iova,
  407. .flags = MOCK_ACCESS_RW_SLOW_PATH,
  408. .length = sizeof(tmp_big),
  409. .uptr = (uintptr_t)tmp_big },
  410. };
  411. if (ioctl(self->fd, _IOMMU_TEST_CMD(IOMMU_TEST_OP_ACCESS_RW),
  412. &access_cmd))
  413. return -1;
  414. }
  415. if (_test_cmd_destroy_access(self->access_id))
  416. return -1;
  417. self->access_id = 0;
  418. return 0;
  419. }
  420. /* pages.c access functions */
  421. TEST_FAIL_NTH(basic_fail_nth, access_pin)
  422. {
  423. uint32_t access_pages_id;
  424. uint32_t ioas_id;
  425. __u64 iova;
  426. self->fd = open("/dev/iommu", O_RDWR);
  427. if (self->fd == -1)
  428. return -1;
  429. if (_test_ioctl_ioas_alloc(self->fd, &ioas_id))
  430. return -1;
  431. if (_test_ioctl_set_temp_memory_limit(self->fd, 32))
  432. return -1;
  433. if (_test_ioctl_ioas_map(self->fd, ioas_id, buffer, BUFFER_SIZE, &iova,
  434. IOMMU_IOAS_MAP_WRITEABLE |
  435. IOMMU_IOAS_MAP_READABLE))
  436. return -1;
  437. if (_test_cmd_create_access(self->fd, ioas_id, &self->access_id,
  438. MOCK_FLAGS_ACCESS_CREATE_NEEDS_PIN_PAGES))
  439. return -1;
  440. fail_nth_enable();
  441. {
  442. struct iommu_test_cmd access_cmd = {
  443. .size = sizeof(access_cmd),
  444. .op = IOMMU_TEST_OP_ACCESS_PAGES,
  445. .id = self->access_id,
  446. .access_pages = { .iova = iova,
  447. .length = BUFFER_SIZE,
  448. .uptr = (uintptr_t)buffer },
  449. };
  450. if (ioctl(self->fd, _IOMMU_TEST_CMD(IOMMU_TEST_OP_ACCESS_RW),
  451. &access_cmd))
  452. return -1;
  453. access_pages_id = access_cmd.access_pages.out_access_pages_id;
  454. }
  455. if (_test_cmd_destroy_access_pages(self->fd, self->access_id,
  456. access_pages_id))
  457. return -1;
  458. if (_test_cmd_destroy_access(self->access_id))
  459. return -1;
  460. self->access_id = 0;
  461. return 0;
  462. }
  463. /* iopt_pages_fill_xarray() */
  464. TEST_FAIL_NTH(basic_fail_nth, access_pin_domain)
  465. {
  466. uint32_t access_pages_id;
  467. uint32_t ioas_id;
  468. __u32 stdev_id;
  469. __u32 hwpt_id;
  470. __u64 iova;
  471. self->fd = open("/dev/iommu", O_RDWR);
  472. if (self->fd == -1)
  473. return -1;
  474. if (_test_ioctl_ioas_alloc(self->fd, &ioas_id))
  475. return -1;
  476. if (_test_ioctl_set_temp_memory_limit(self->fd, 32))
  477. return -1;
  478. if (_test_cmd_mock_domain(self->fd, ioas_id, &stdev_id, &hwpt_id, NULL))
  479. return -1;
  480. if (_test_ioctl_ioas_map(self->fd, ioas_id, buffer, BUFFER_SIZE, &iova,
  481. IOMMU_IOAS_MAP_WRITEABLE |
  482. IOMMU_IOAS_MAP_READABLE))
  483. return -1;
  484. if (_test_cmd_create_access(self->fd, ioas_id, &self->access_id,
  485. MOCK_FLAGS_ACCESS_CREATE_NEEDS_PIN_PAGES))
  486. return -1;
  487. fail_nth_enable();
  488. {
  489. struct iommu_test_cmd access_cmd = {
  490. .size = sizeof(access_cmd),
  491. .op = IOMMU_TEST_OP_ACCESS_PAGES,
  492. .id = self->access_id,
  493. .access_pages = { .iova = iova,
  494. .length = BUFFER_SIZE,
  495. .uptr = (uintptr_t)buffer },
  496. };
  497. if (ioctl(self->fd, _IOMMU_TEST_CMD(IOMMU_TEST_OP_ACCESS_RW),
  498. &access_cmd))
  499. return -1;
  500. access_pages_id = access_cmd.access_pages.out_access_pages_id;
  501. }
  502. if (_test_cmd_destroy_access_pages(self->fd, self->access_id,
  503. access_pages_id))
  504. return -1;
  505. if (_test_cmd_destroy_access(self->access_id))
  506. return -1;
  507. self->access_id = 0;
  508. if (_test_ioctl_destroy(self->fd, stdev_id))
  509. return -1;
  510. return 0;
  511. }
  512. /* device.c */
  513. TEST_FAIL_NTH(basic_fail_nth, device)
  514. {
  515. struct iommu_hwpt_selftest data = {
  516. .iotlb = IOMMU_TEST_IOTLB_DEFAULT,
  517. };
  518. struct iommu_test_hw_info info;
  519. uint32_t fault_id, fault_fd;
  520. uint32_t veventq_id, veventq_fd;
  521. uint32_t fault_hwpt_id;
  522. uint32_t test_hwpt_id;
  523. uint32_t ioas_id;
  524. uint32_t ioas_id2;
  525. uint32_t idev_id;
  526. uint32_t hwpt_id;
  527. uint32_t viommu_id;
  528. uint32_t hw_queue_id;
  529. uint32_t vdev_id;
  530. __u64 iova;
  531. self->fd = open("/dev/iommu", O_RDWR);
  532. if (self->fd == -1)
  533. return -1;
  534. if (_test_ioctl_ioas_alloc(self->fd, &ioas_id))
  535. return -1;
  536. if (_test_ioctl_ioas_alloc(self->fd, &ioas_id2))
  537. return -1;
  538. iova = MOCK_APERTURE_START;
  539. if (_test_ioctl_ioas_map(self->fd, ioas_id, buffer, PAGE_SIZE, &iova,
  540. IOMMU_IOAS_MAP_FIXED_IOVA |
  541. IOMMU_IOAS_MAP_WRITEABLE |
  542. IOMMU_IOAS_MAP_READABLE))
  543. return -1;
  544. if (_test_ioctl_ioas_map(self->fd, ioas_id2, buffer, PAGE_SIZE, &iova,
  545. IOMMU_IOAS_MAP_FIXED_IOVA |
  546. IOMMU_IOAS_MAP_WRITEABLE |
  547. IOMMU_IOAS_MAP_READABLE))
  548. return -1;
  549. fail_nth_enable();
  550. if (_test_cmd_mock_domain_flags(self->fd, ioas_id,
  551. MOCK_FLAGS_DEVICE_PASID,
  552. &self->stdev_id, NULL, &idev_id))
  553. return -1;
  554. if (_test_cmd_get_hw_info(self->fd, idev_id, IOMMU_HW_INFO_TYPE_DEFAULT,
  555. &info, sizeof(info), NULL, NULL))
  556. return -1;
  557. if (_test_cmd_hwpt_alloc(self->fd, idev_id, ioas_id, 0,
  558. IOMMU_HWPT_ALLOC_PASID, &hwpt_id,
  559. IOMMU_HWPT_DATA_NONE, 0, 0))
  560. return -1;
  561. if (_test_cmd_mock_domain_replace(self->fd, self->stdev_id, ioas_id2, NULL))
  562. return -1;
  563. if (_test_cmd_mock_domain_replace(self->fd, self->stdev_id, hwpt_id, NULL))
  564. return -1;
  565. if (_test_cmd_hwpt_alloc(self->fd, idev_id, ioas_id, 0,
  566. IOMMU_HWPT_ALLOC_NEST_PARENT |
  567. IOMMU_HWPT_ALLOC_PASID,
  568. &hwpt_id,
  569. IOMMU_HWPT_DATA_NONE, 0, 0))
  570. return -1;
  571. if (_test_cmd_viommu_alloc(self->fd, idev_id, hwpt_id, 0,
  572. IOMMU_VIOMMU_TYPE_SELFTEST, NULL, 0,
  573. &viommu_id))
  574. return -1;
  575. if (_test_cmd_vdevice_alloc(self->fd, viommu_id, idev_id, 0, &vdev_id))
  576. return -1;
  577. if (_test_cmd_hw_queue_alloc(self->fd, viommu_id,
  578. IOMMU_HW_QUEUE_TYPE_SELFTEST, 0, iova,
  579. PAGE_SIZE, &hw_queue_id))
  580. return -1;
  581. if (_test_ioctl_fault_alloc(self->fd, &fault_id, &fault_fd))
  582. return -1;
  583. close(fault_fd);
  584. if (_test_cmd_hwpt_alloc(self->fd, idev_id, hwpt_id, fault_id,
  585. IOMMU_HWPT_FAULT_ID_VALID, &fault_hwpt_id,
  586. IOMMU_HWPT_DATA_SELFTEST, &data, sizeof(data)))
  587. return -1;
  588. if (_test_cmd_veventq_alloc(self->fd, viommu_id,
  589. IOMMU_VEVENTQ_TYPE_SELFTEST, &veventq_id,
  590. &veventq_fd))
  591. return -1;
  592. close(veventq_fd);
  593. if (_test_cmd_hwpt_alloc(self->fd, idev_id, ioas_id, 0,
  594. IOMMU_HWPT_ALLOC_PASID,
  595. &test_hwpt_id,
  596. IOMMU_HWPT_DATA_NONE, 0, 0))
  597. return -1;
  598. /* Tests for pasid attach/replace/detach */
  599. self->pasid = 200;
  600. if (_test_cmd_pasid_attach(self->fd, self->stdev_id,
  601. self->pasid, hwpt_id)) {
  602. self->pasid = 0;
  603. return -1;
  604. }
  605. if (_test_cmd_pasid_replace(self->fd, self->stdev_id,
  606. self->pasid, test_hwpt_id))
  607. return -1;
  608. if (_test_cmd_pasid_detach(self->fd, self->stdev_id, self->pasid))
  609. return -1;
  610. self->pasid = 0;
  611. return 0;
  612. }
  613. TEST_HARNESS_MAIN