xref: /linux/drivers/iommu/io-pgtable-arm-selftests.c (revision ce5cfb0fa20dc6454da039612e34325b7b4a8243)
1 // SPDX-License-Identifier: GPL-2.0-only
2 /*
3  * CPU-agnostic ARM page table allocator.
4  *
5  * Copyright (C) 2014 ARM Limited
6  *
7  * Author: Will Deacon <will.deacon@arm.com>
8  */
9 
10 #define pr_fmt(fmt)	"arm-lpae io-pgtable: " fmt
11 
12 #include <kunit/device.h>
13 #include <kunit/test.h>
14 #include <linux/io-pgtable.h>
15 #include <linux/kernel.h>
16 
17 #include "io-pgtable-arm.h"
18 
19 static struct io_pgtable_cfg *cfg_cookie;
20 
dummy_tlb_flush_all(void * cookie)21 static void dummy_tlb_flush_all(void *cookie)
22 {
23 	WARN_ON(cookie != cfg_cookie);
24 }
25 
dummy_tlb_flush(unsigned long iova,size_t size,size_t granule,void * cookie)26 static void dummy_tlb_flush(unsigned long iova, size_t size,
27 			    size_t granule, void *cookie)
28 {
29 	WARN_ON(cookie != cfg_cookie);
30 	WARN_ON(!(size & cfg_cookie->pgsize_bitmap));
31 }
32 
dummy_tlb_add_page(struct iommu_iotlb_gather * gather,unsigned long iova,size_t granule,void * cookie)33 static void dummy_tlb_add_page(struct iommu_iotlb_gather *gather,
34 			       unsigned long iova, size_t granule,
35 			       void *cookie)
36 {
37 	dummy_tlb_flush(iova, granule, granule, cookie);
38 }
39 
40 static const struct iommu_flush_ops dummy_tlb_ops = {
41 	.tlb_flush_all	= dummy_tlb_flush_all,
42 	.tlb_flush_walk	= dummy_tlb_flush,
43 	.tlb_add_page	= dummy_tlb_add_page,
44 };
45 
46 #define __FAIL(test, i) ({							\
47 		KUNIT_FAIL(test, "test failed for fmt idx %d\n", (i));		\
48 		-EFAULT;							\
49 })
50 
arm_lpae_run_tests(struct kunit * test,struct io_pgtable_cfg * cfg)51 static int arm_lpae_run_tests(struct kunit *test, struct io_pgtable_cfg *cfg)
52 {
53 	static const enum io_pgtable_fmt fmts[] = {
54 		ARM_64_LPAE_S1,
55 		ARM_64_LPAE_S2,
56 	};
57 
58 	int i, j;
59 	unsigned long iova;
60 	size_t size, mapped;
61 	struct io_pgtable_ops *ops;
62 
63 	for (i = 0; i < ARRAY_SIZE(fmts); ++i) {
64 		cfg_cookie = cfg;
65 		ops = alloc_io_pgtable_ops(fmts[i], cfg, cfg);
66 		if (!ops) {
67 			kunit_err(test, "failed to allocate io pgtable ops\n");
68 			return -ENOMEM;
69 		}
70 
71 		/*
72 		 * Initial sanity checks.
73 		 * Empty page tables shouldn't provide any translations.
74 		 */
75 		if (ops->iova_to_phys(ops, 42))
76 			return __FAIL(test, i);
77 
78 		if (ops->iova_to_phys(ops, SZ_1G + 42))
79 			return __FAIL(test, i);
80 
81 		if (ops->iova_to_phys(ops, SZ_2G + 42))
82 			return __FAIL(test, i);
83 
84 		/*
85 		 * Distinct mappings of different granule sizes.
86 		 */
87 		iova = 0;
88 		for_each_set_bit(j, &cfg->pgsize_bitmap, BITS_PER_LONG) {
89 			size = 1UL << j;
90 
91 			if (ops->map_pages(ops, iova, iova, size, 1,
92 					   IOMMU_READ | IOMMU_WRITE |
93 					   IOMMU_NOEXEC | IOMMU_CACHE,
94 					   GFP_KERNEL, &mapped))
95 				return __FAIL(test, i);
96 
97 			/* Overlapping mappings */
98 			if (!ops->map_pages(ops, iova, iova + size, size, 1,
99 					    IOMMU_READ | IOMMU_NOEXEC,
100 					    GFP_KERNEL, &mapped))
101 				return __FAIL(test, i);
102 
103 			if (ops->iova_to_phys(ops, iova + 42) != (iova + 42))
104 				return __FAIL(test, i);
105 
106 			iova += SZ_1G;
107 		}
108 
109 		/* Full unmap */
110 		iova = 0;
111 		for_each_set_bit(j, &cfg->pgsize_bitmap, BITS_PER_LONG) {
112 			size = 1UL << j;
113 
114 			if (ops->unmap_pages(ops, iova, size, 1, NULL) != size)
115 				return __FAIL(test, i);
116 
117 			if (ops->iova_to_phys(ops, iova + 42))
118 				return __FAIL(test, i);
119 
120 			/* Remap full block */
121 			if (ops->map_pages(ops, iova, iova, size, 1,
122 					   IOMMU_WRITE, GFP_KERNEL, &mapped))
123 				return __FAIL(test, i);
124 
125 			if (ops->iova_to_phys(ops, iova + 42) != (iova + 42))
126 				return __FAIL(test, i);
127 
128 			iova += SZ_1G;
129 		}
130 
131 		/*
132 		 * Map/unmap the last largest supported page of the IAS, this can
133 		 * trigger corner cases in the concatednated page tables.
134 		 */
135 		mapped = 0;
136 		size = 1UL << __fls(cfg->pgsize_bitmap);
137 		iova = (1UL << cfg->ias) - size;
138 		if (ops->map_pages(ops, iova, iova, size, 1,
139 				   IOMMU_READ | IOMMU_WRITE |
140 				   IOMMU_NOEXEC | IOMMU_CACHE,
141 				   GFP_KERNEL, &mapped))
142 			return __FAIL(test, i);
143 		if (mapped != size)
144 			return __FAIL(test, i);
145 		if (ops->unmap_pages(ops, iova, size, 1, NULL) != size)
146 			return __FAIL(test, i);
147 
148 		free_io_pgtable_ops(ops);
149 	}
150 
151 	return 0;
152 }
153 
arm_lpae_do_selftests(struct kunit * test)154 static void arm_lpae_do_selftests(struct kunit *test)
155 {
156 	static const unsigned long pgsize[] = {
157 		SZ_4K | SZ_2M | SZ_1G,
158 		SZ_16K | SZ_32M,
159 		SZ_64K | SZ_512M,
160 	};
161 
162 	static const unsigned int address_size[] = {
163 		32, 36, 40, 42, 44, 48,
164 	};
165 
166 	int i, j, k, pass = 0, fail = 0;
167 	struct device *dev;
168 	struct io_pgtable_cfg cfg = {
169 		.tlb = &dummy_tlb_ops,
170 		.coherent_walk = true,
171 		.quirks = IO_PGTABLE_QUIRK_NO_WARN,
172 	};
173 
174 	dev = kunit_device_register(test, "io-pgtable-test");
175 	KUNIT_EXPECT_NOT_ERR_OR_NULL(test, dev);
176 	if (IS_ERR_OR_NULL(dev))
177 		return;
178 
179 	cfg.iommu_dev = dev;
180 
181 	for (i = 0; i < ARRAY_SIZE(pgsize); ++i) {
182 		for (j = 0; j < ARRAY_SIZE(address_size); ++j) {
183 			/* Don't use ias > oas as it is not valid for stage-2. */
184 			for (k = 0; k <= j; ++k) {
185 				cfg.pgsize_bitmap = pgsize[i];
186 				cfg.ias = address_size[k];
187 				cfg.oas = address_size[j];
188 				kunit_info(test, "pgsize_bitmap 0x%08lx, IAS %u OAS %u\n",
189 					   pgsize[i], cfg.ias, cfg.oas);
190 				if (arm_lpae_run_tests(test, &cfg))
191 					fail++;
192 				else
193 					pass++;
194 			}
195 		}
196 	}
197 
198 	kunit_info(test, "completed with %d PASS %d FAIL\n", pass, fail);
199 }
200 
201 static struct kunit_case io_pgtable_arm_test_cases[] = {
202 	KUNIT_CASE(arm_lpae_do_selftests),
203 	{},
204 };
205 
206 static struct kunit_suite io_pgtable_arm_test = {
207 	.name = "io-pgtable-arm-test",
208 	.test_cases = io_pgtable_arm_test_cases,
209 };
210 
211 kunit_test_suite(io_pgtable_arm_test);
212 
213 MODULE_DESCRIPTION("io-pgtable-arm library kunit tests");
214 MODULE_LICENSE("GPL");
215