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 21 static void dummy_tlb_flush_all(void *cookie) 22 { 23 WARN_ON(cookie != cfg_cookie); 24 } 25 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 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 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 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