1 /* 2 * self test for change_page_attr. 3 * 4 * Clears the a test pte bit on random pages in the direct mapping, 5 * then reverts and compares page tables forwards and afterwards. 6 */ 7 #include <linux/bootmem.h> 8 #include <linux/kthread.h> 9 #include <linux/random.h> 10 #include <linux/kernel.h> 11 #include <linux/mm.h> 12 13 #include <asm/cacheflush.h> 14 #include <asm/pgtable.h> 15 #include <asm/kdebug.h> 16 17 /* 18 * Only print the results of the first pass: 19 */ 20 static __read_mostly int print = 1; 21 22 enum { 23 NTEST = 400, 24 #ifdef CONFIG_X86_64 25 LPS = (1 << PMD_SHIFT), 26 #elif defined(CONFIG_X86_PAE) 27 LPS = (1 << PMD_SHIFT), 28 #else 29 LPS = (1 << 22), 30 #endif 31 GPS = (1<<30) 32 }; 33 34 #define PAGE_CPA_TEST __pgprot(_PAGE_CPA_TEST) 35 pte_testbit(pte_t pte)36 static int pte_testbit(pte_t pte) 37 { 38 return pte_flags(pte) & _PAGE_SOFTW1; 39 } 40 41 struct split_state { 42 long lpg, gpg, spg, exec; 43 long min_exec, max_exec; 44 }; 45 print_split(struct split_state * s)46 static int print_split(struct split_state *s) 47 { 48 long i, expected, missed = 0; 49 int err = 0; 50 51 s->lpg = s->gpg = s->spg = s->exec = 0; 52 s->min_exec = ~0UL; 53 s->max_exec = 0; 54 for (i = 0; i < max_pfn_mapped; ) { 55 unsigned long addr = (unsigned long)__va(i << PAGE_SHIFT); 56 unsigned int level; 57 pte_t *pte; 58 59 pte = lookup_address(addr, &level); 60 if (!pte) { 61 missed++; 62 i++; 63 continue; 64 } 65 66 if (level == PG_LEVEL_1G && sizeof(long) == 8) { 67 s->gpg++; 68 i += GPS/PAGE_SIZE; 69 } else if (level == PG_LEVEL_2M) { 70 if ((pte_val(*pte) & _PAGE_PRESENT) && !(pte_val(*pte) & _PAGE_PSE)) { 71 printk(KERN_ERR 72 "%lx level %d but not PSE %Lx\n", 73 addr, level, (u64)pte_val(*pte)); 74 err = 1; 75 } 76 s->lpg++; 77 i += LPS/PAGE_SIZE; 78 } else { 79 s->spg++; 80 i++; 81 } 82 if (!(pte_val(*pte) & _PAGE_NX)) { 83 s->exec++; 84 if (addr < s->min_exec) 85 s->min_exec = addr; 86 if (addr > s->max_exec) 87 s->max_exec = addr; 88 } 89 } 90 if (print) { 91 printk(KERN_INFO 92 " 4k %lu large %lu gb %lu x %lu[%lx-%lx] miss %lu\n", 93 s->spg, s->lpg, s->gpg, s->exec, 94 s->min_exec != ~0UL ? s->min_exec : 0, 95 s->max_exec, missed); 96 } 97 98 expected = (s->gpg*GPS + s->lpg*LPS)/PAGE_SIZE + s->spg + missed; 99 if (expected != i) { 100 printk(KERN_ERR "CPA max_pfn_mapped %lu but expected %lu\n", 101 max_pfn_mapped, expected); 102 return 1; 103 } 104 return err; 105 } 106 107 static unsigned long addr[NTEST]; 108 static unsigned int len[NTEST]; 109 110 /* Change the global bit on random pages in the direct mapping */ pageattr_test(void)111 static int pageattr_test(void) 112 { 113 struct split_state sa, sb, sc; 114 unsigned long *bm; 115 pte_t *pte, pte0; 116 int failed = 0; 117 unsigned int level; 118 int i, k; 119 int err; 120 unsigned long test_addr; 121 122 if (print) 123 printk(KERN_INFO "CPA self-test:\n"); 124 125 bm = vzalloc((max_pfn_mapped + 7) / 8); 126 if (!bm) { 127 printk(KERN_ERR "CPA Cannot vmalloc bitmap\n"); 128 return -ENOMEM; 129 } 130 131 failed += print_split(&sa); 132 133 for (i = 0; i < NTEST; i++) { 134 unsigned long pfn = prandom_u32() % max_pfn_mapped; 135 136 addr[i] = (unsigned long)__va(pfn << PAGE_SHIFT); 137 len[i] = prandom_u32() % 100; 138 len[i] = min_t(unsigned long, len[i], max_pfn_mapped - pfn - 1); 139 140 if (len[i] == 0) 141 len[i] = 1; 142 143 pte = NULL; 144 pte0 = pfn_pte(0, __pgprot(0)); /* shut gcc up */ 145 146 for (k = 0; k < len[i]; k++) { 147 pte = lookup_address(addr[i] + k*PAGE_SIZE, &level); 148 if (!pte || pgprot_val(pte_pgprot(*pte)) == 0 || 149 !(pte_val(*pte) & _PAGE_PRESENT)) { 150 addr[i] = 0; 151 break; 152 } 153 if (k == 0) { 154 pte0 = *pte; 155 } else { 156 if (pgprot_val(pte_pgprot(*pte)) != 157 pgprot_val(pte_pgprot(pte0))) { 158 len[i] = k; 159 break; 160 } 161 } 162 if (test_bit(pfn + k, bm)) { 163 len[i] = k; 164 break; 165 } 166 __set_bit(pfn + k, bm); 167 } 168 if (!addr[i] || !pte || !k) { 169 addr[i] = 0; 170 continue; 171 } 172 173 test_addr = addr[i]; 174 err = change_page_attr_set(&test_addr, len[i], PAGE_CPA_TEST, 0); 175 if (err < 0) { 176 printk(KERN_ERR "CPA %d failed %d\n", i, err); 177 failed++; 178 } 179 180 pte = lookup_address(addr[i], &level); 181 if (!pte || !pte_testbit(*pte) || pte_huge(*pte)) { 182 printk(KERN_ERR "CPA %lx: bad pte %Lx\n", addr[i], 183 pte ? (u64)pte_val(*pte) : 0ULL); 184 failed++; 185 } 186 if (level != PG_LEVEL_4K) { 187 printk(KERN_ERR "CPA %lx: unexpected level %d\n", 188 addr[i], level); 189 failed++; 190 } 191 192 } 193 vfree(bm); 194 195 failed += print_split(&sb); 196 197 for (i = 0; i < NTEST; i++) { 198 if (!addr[i]) 199 continue; 200 pte = lookup_address(addr[i], &level); 201 if (!pte) { 202 printk(KERN_ERR "CPA lookup of %lx failed\n", addr[i]); 203 failed++; 204 continue; 205 } 206 test_addr = addr[i]; 207 err = change_page_attr_clear(&test_addr, len[i], PAGE_CPA_TEST, 0); 208 if (err < 0) { 209 printk(KERN_ERR "CPA reverting failed: %d\n", err); 210 failed++; 211 } 212 pte = lookup_address(addr[i], &level); 213 if (!pte || pte_testbit(*pte)) { 214 printk(KERN_ERR "CPA %lx: bad pte after revert %Lx\n", 215 addr[i], pte ? (u64)pte_val(*pte) : 0ULL); 216 failed++; 217 } 218 219 } 220 221 failed += print_split(&sc); 222 223 if (failed) { 224 WARN(1, KERN_ERR "NOT PASSED. Please report.\n"); 225 return -EINVAL; 226 } else { 227 if (print) 228 printk(KERN_INFO "ok.\n"); 229 } 230 231 return 0; 232 } 233 do_pageattr_test(void * __unused)234 static int do_pageattr_test(void *__unused) 235 { 236 while (!kthread_should_stop()) { 237 schedule_timeout_interruptible(HZ*30); 238 if (pageattr_test() < 0) 239 break; 240 if (print) 241 print--; 242 } 243 return 0; 244 } 245 start_pageattr_test(void)246 static int start_pageattr_test(void) 247 { 248 struct task_struct *p; 249 250 p = kthread_create(do_pageattr_test, NULL, "pageattr-test"); 251 if (!IS_ERR(p)) 252 wake_up_process(p); 253 else 254 WARN_ON(1); 255 256 return 0; 257 } 258 259 module_init(start_pageattr_test); 260