History

iommufd/selftest: Add coverage for IOMMU_GET_HW_INFO ioctl

Add a mock_domain_hw_info function and an iommu_test_hw_info data structure. This allows to test the IOMMU_GET_HW_INFO ioctl passing the test_reg value for the mock_dev.

Nicolin Chen committed 3 years ago

Commit af4fde91 parent 55dd4025 files · +128 −1Browse files

Unified · Split

5 files
  1. drivers/iommu/iommufd/iommufd_test.h +9 −0
  2. drivers/iommu/iommufd/selftest.c +16 −0
  3. tools/testing/selftests/iommu/iommufd.c +37 −1
  4. tools/testing/selftests/iommu/iommufd_fail_nth.c +4 −0
  5. tools/testing/selftests/iommu/iommufd_utils.h +62 −0
drivers/iommu/iommufd/iommufd_test.h+9−0
@@ -100,4 +100,13 @@ struct iommu_test_cmd { · 99 unmodified lines
100};100};
101#define IOMMU_TEST_CMD _IO(IOMMUFD_TYPE, IOMMUFD_CMD_BASE + 32)101#define IOMMU_TEST_CMD _IO(IOMMUFD_TYPE, IOMMUFD_CMD_BASE + 32)
102 102
103/* Mock structs for IOMMU_DEVICE_GET_HW_INFO ioctl */
104#define IOMMU_HW_INFO_TYPE_SELFTEST 0xfeedbeef
105#define IOMMU_HW_INFO_SELFTEST_REGVAL 0xdeadbeef
106
107struct iommu_test_hw_info {
108 __u32 flags;
109 __u32 test_reg;
110};
111
103#endif112#endif
drivers/iommu/iommufd/selftest.c+16−0
@@ -131,6 +131,21 @@ static struct iommu_domain mock_blocking_domain = { · 130 unmodified lines
131 .ops = &mock_blocking_ops,131 .ops = &mock_blocking_ops,
132};132};
133 133
134static void *mock_domain_hw_info(struct device *dev, u32 *length, u32 *type)
135{
136 struct iommu_test_hw_info *info;
137
138 info = kzalloc(sizeof(*info), GFP_KERNEL);
139 if (!info)
140 return ERR_PTR(-ENOMEM);
141
142 info->test_reg = IOMMU_HW_INFO_SELFTEST_REGVAL;
143 *length = sizeof(*info);
144 *type = IOMMU_HW_INFO_TYPE_SELFTEST;
145
146 return info;
147}
148
134static struct iommu_domain *mock_domain_alloc(unsigned int iommu_domain_type)149static struct iommu_domain *mock_domain_alloc(unsigned int iommu_domain_type)
135{150{
136 struct mock_iommu_domain *mock;151 struct mock_iommu_domain *mock;
@@ -290,6 +305,7 @@ static struct iommu_device *mock_probe_device(struct device *dev) · 153 unmodified lines
290static const struct iommu_ops mock_ops = {305static const struct iommu_ops mock_ops = {
291 .owner = THIS_MODULE,306 .owner = THIS_MODULE,
292 .pgsize_bitmap = MOCK_IO_PAGE_SIZE,307 .pgsize_bitmap = MOCK_IO_PAGE_SIZE,
308 .hw_info = mock_domain_hw_info,
293 .domain_alloc = mock_domain_alloc,309 .domain_alloc = mock_domain_alloc,
294 .capable = mock_domain_capable,310 .capable = mock_domain_capable,
295 .set_platform_dma_ops = mock_domain_set_plaform_dma_ops,311 .set_platform_dma_ops = mock_domain_set_plaform_dma_ops,
tools/testing/selftests/iommu/iommufd.c+37−1
@@ -113,6 +113,7 @@ TEST_F(iommufd, cmd_length) · 112 unmodified lines
113 }113 }
114 114
115 TEST_LENGTH(iommu_destroy, IOMMU_DESTROY);115 TEST_LENGTH(iommu_destroy, IOMMU_DESTROY);
116 TEST_LENGTH(iommu_hw_info, IOMMU_GET_HW_INFO);
116 TEST_LENGTH(iommu_ioas_alloc, IOMMU_IOAS_ALLOC);117 TEST_LENGTH(iommu_ioas_alloc, IOMMU_IOAS_ALLOC);
117 TEST_LENGTH(iommu_ioas_iova_ranges, IOMMU_IOAS_IOVA_RANGES);118 TEST_LENGTH(iommu_ioas_iova_ranges, IOMMU_IOAS_IOVA_RANGES);
118 TEST_LENGTH(iommu_ioas_allow_iovas, IOMMU_IOAS_ALLOW_IOVAS);119 TEST_LENGTH(iommu_ioas_allow_iovas, IOMMU_IOAS_ALLOW_IOVAS);
@@ -185,6 +186,7 @@ FIXTURE(iommufd_ioas) · 66 unmodified lines
185 uint32_t ioas_id;186 uint32_t ioas_id;
186 uint32_t stdev_id;187 uint32_t stdev_id;
187 uint32_t hwpt_id;188 uint32_t hwpt_id;
189 uint32_t device_id;
188 uint64_t base_iova;190 uint64_t base_iova;
189};191};
190 192
@@ -211,7 +213,7 @@ FIXTURE_SETUP(iommufd_ioas) · 20 unmodified lines
211 213
212 for (i = 0; i != variant->mock_domains; i++) {214 for (i = 0; i != variant->mock_domains; i++) {
213 test_cmd_mock_domain(self->ioas_id, &self->stdev_id,215 test_cmd_mock_domain(self->ioas_id, &self->stdev_id,
214 &self->hwpt_id, NULL);216 &self->hwpt_id, &self->device_id);
215 self->base_iova = MOCK_APERTURE_START;217 self->base_iova = MOCK_APERTURE_START;
216 }218 }
217}219}
@@ -290,6 +292,40 @@ TEST_F(iommufd_ioas, ioas_area_auto_destroy) · 72 unmodified lines
290 }292 }
291}293}
292 294
295TEST_F(iommufd_ioas, get_hw_info)
296{
297 struct iommu_test_hw_info buffer_exact;
298 struct iommu_test_hw_info_buffer_larger {
299 struct iommu_test_hw_info info;
300 uint64_t trailing_bytes;
301 } buffer_larger;
302 struct iommu_test_hw_info_buffer_smaller {
303 __u32 flags;
304 } buffer_smaller;
305
306 if (self->device_id) {
307 /* Provide a zero-size user_buffer */
308 test_cmd_get_hw_info(self->device_id, NULL, 0);
309 /* Provide a user_buffer with exact size */
310 test_cmd_get_hw_info(self->device_id, &buffer_exact, sizeof(buffer_exact));
311 /*
312 * Provide a user_buffer with size larger than the exact size to check if
313 * kernel zero the trailing bytes.
314 */
315 test_cmd_get_hw_info(self->device_id, &buffer_larger, sizeof(buffer_larger));
316 /*
317 * Provide a user_buffer with size smaller than the exact size to check if
318 * the fields within the size range still gets updated.
319 */
320 test_cmd_get_hw_info(self->device_id, &buffer_smaller, sizeof(buffer_smaller));
321 } else {
322 test_err_get_hw_info(ENOENT, self->device_id,
323 &buffer_exact, sizeof(buffer_exact));
324 test_err_get_hw_info(ENOENT, self->device_id,
325 &buffer_larger, sizeof(buffer_larger));
326 }
327}
328
293TEST_F(iommufd_ioas, area)329TEST_F(iommufd_ioas, area)
294{330{
295 int i;331 int i;
tools/testing/selftests/iommu/iommufd_fail_nth.c+4−0
@@ -576,6 +576,7 @@ TEST_FAIL_NTH(basic_fail_nth, access_pin_domain) · 575 unmodified lines
576/* device.c */576/* device.c */
577TEST_FAIL_NTH(basic_fail_nth, device)577TEST_FAIL_NTH(basic_fail_nth, device)
578{578{
579 struct iommu_test_hw_info info;
579 uint32_t ioas_id;580 uint32_t ioas_id;
580 uint32_t ioas_id2;581 uint32_t ioas_id2;
581 uint32_t stdev_id;582 uint32_t stdev_id;
@@ -611,6 +612,9 @@ TEST_FAIL_NTH(basic_fail_nth, device) · 29 unmodified lines
611 &idev_id))612 &idev_id))
612 return -1;613 return -1;
613 614
615 if (_test_cmd_get_hw_info(self->fd, idev_id, &info, sizeof(info)))
616 return -1;
617
614 if (_test_cmd_hwpt_alloc(self->fd, idev_id, ioas_id, &hwpt_id))618 if (_test_cmd_hwpt_alloc(self->fd, idev_id, ioas_id, &hwpt_id))
615 return -1;619 return -1;
616 620
tools/testing/selftests/iommu/iommufd_utils.h+62−0
@@ -21,6 +21,10 @@ static unsigned long BUFFER_SIZE; · 20 unmodified lines
21 21
22static unsigned long PAGE_SIZE;22static unsigned long PAGE_SIZE;
23 23
24#define sizeof_field(TYPE, MEMBER) sizeof((((TYPE *)0)->MEMBER))
25#define offsetofend(TYPE, MEMBER) \
26 (offsetof(TYPE, MEMBER) + sizeof_field(TYPE, MEMBER))
27
24/*28/*
25 * Have the kernel check the refcount on pages. I don't know why a freshly29 * Have the kernel check the refcount on pages. I don't know why a freshly
26 * mmap'd anon non-compound page starts out with a ref of 330 * mmap'd anon non-compound page starts out with a ref of 3
@@ -348,3 +352,61 @@ static void teardown_iommufd(int fd, struct __test_metadata *_metadata) · 321 unmodified lines
348 })352 })
349 353
350#endif354#endif
355
356/* @data can be NULL */
357static int _test_cmd_get_hw_info(int fd, __u32 device_id,
358 void *data, size_t data_len)
359{
360 struct iommu_test_hw_info *info = (struct iommu_test_hw_info *)data;
361 struct iommu_hw_info cmd = {
362 .size = sizeof(cmd),
363 .dev_id = device_id,
364 .data_len = data_len,
365 .data_uptr = (uint64_t)data,
366 };
367 int ret;
368
369 ret = ioctl(fd, IOMMU_GET_HW_INFO, &cmd);
370 if (ret)
371 return ret;
372
373 assert(cmd.out_data_type == IOMMU_HW_INFO_TYPE_SELFTEST);
374
375 /*
376 * The struct iommu_test_hw_info should be the one defined
377 * by the current kernel.
378 */
379 assert(cmd.data_len == sizeof(struct iommu_test_hw_info));
380
381 /*
382 * Trailing bytes should be 0 if user buffer is larger than
383 * the data that kernel reports.
384 */
385 if (data_len > cmd.data_len) {
386 char *ptr = (char *)(data + cmd.data_len);
387 int idx = 0;
388
389 while (idx < data_len - cmd.data_len) {
390 assert(!*(ptr + idx));
391 idx++;
392 }
393 }
394
395 if (info) {
396 if (data_len >= offsetofend(struct iommu_test_hw_info, test_reg))
397 assert(info->test_reg == IOMMU_HW_INFO_SELFTEST_REGVAL);
398 if (data_len >= offsetofend(struct iommu_test_hw_info, flags))
399 assert(!info->flags);
400 }
401
402 return 0;
403}
404
405#define test_cmd_get_hw_info(device_id, data, data_len) \
406 ASSERT_EQ(0, _test_cmd_get_hw_info(self->fd, device_id, \
407 data, data_len))
408
409#define test_err_get_hw_info(_errno, device_id, data, data_len) \
410 EXPECT_ERRNO(_errno, \
411 _test_cmd_get_hw_info(self->fd, device_id, \
412 data, data_len))

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t