0001
0002
0003
0004
0005
0006
0007
0008 #include <linux/memblock.h>
0009 #include <linux/kthread.h>
0010 #include <linux/random.h>
0011 #include <linux/kernel.h>
0012 #include <linux/init.h>
0013 #include <linux/mm.h>
0014 #include <linux/vmalloc.h>
0015
0016 #include <asm/cacheflush.h>
0017 #include <asm/kdebug.h>
0018
0019
0020
0021
0022 static __read_mostly int print = 1;
0023
0024 enum {
0025 NTEST = 3 * 100,
0026 NPAGES = 100,
0027 #ifdef CONFIG_X86_64
0028 LPS = (1 << PMD_SHIFT),
0029 #elif defined(CONFIG_X86_PAE)
0030 LPS = (1 << PMD_SHIFT),
0031 #else
0032 LPS = (1 << 22),
0033 #endif
0034 GPS = (1<<30)
0035 };
0036
0037 #define PAGE_CPA_TEST __pgprot(_PAGE_CPA_TEST)
0038
0039 static int pte_testbit(pte_t pte)
0040 {
0041 return pte_flags(pte) & _PAGE_SOFTW1;
0042 }
0043
0044 struct split_state {
0045 long lpg, gpg, spg, exec;
0046 long min_exec, max_exec;
0047 };
0048
0049 static int print_split(struct split_state *s)
0050 {
0051 long i, expected, missed = 0;
0052 int err = 0;
0053
0054 s->lpg = s->gpg = s->spg = s->exec = 0;
0055 s->min_exec = ~0UL;
0056 s->max_exec = 0;
0057 for (i = 0; i < max_pfn_mapped; ) {
0058 unsigned long addr = (unsigned long)__va(i << PAGE_SHIFT);
0059 unsigned int level;
0060 pte_t *pte;
0061
0062 pte = lookup_address(addr, &level);
0063 if (!pte) {
0064 missed++;
0065 i++;
0066 continue;
0067 }
0068
0069 if (level == PG_LEVEL_1G && sizeof(long) == 8) {
0070 s->gpg++;
0071 i += GPS/PAGE_SIZE;
0072 } else if (level == PG_LEVEL_2M) {
0073 if ((pte_val(*pte) & _PAGE_PRESENT) && !(pte_val(*pte) & _PAGE_PSE)) {
0074 printk(KERN_ERR
0075 "%lx level %d but not PSE %Lx\n",
0076 addr, level, (u64)pte_val(*pte));
0077 err = 1;
0078 }
0079 s->lpg++;
0080 i += LPS/PAGE_SIZE;
0081 } else {
0082 s->spg++;
0083 i++;
0084 }
0085 if (!(pte_val(*pte) & _PAGE_NX)) {
0086 s->exec++;
0087 if (addr < s->min_exec)
0088 s->min_exec = addr;
0089 if (addr > s->max_exec)
0090 s->max_exec = addr;
0091 }
0092 }
0093 if (print) {
0094 printk(KERN_INFO
0095 " 4k %lu large %lu gb %lu x %lu[%lx-%lx] miss %lu\n",
0096 s->spg, s->lpg, s->gpg, s->exec,
0097 s->min_exec != ~0UL ? s->min_exec : 0,
0098 s->max_exec, missed);
0099 }
0100
0101 expected = (s->gpg*GPS + s->lpg*LPS)/PAGE_SIZE + s->spg + missed;
0102 if (expected != i) {
0103 printk(KERN_ERR "CPA max_pfn_mapped %lu but expected %lu\n",
0104 max_pfn_mapped, expected);
0105 return 1;
0106 }
0107 return err;
0108 }
0109
0110 static unsigned long addr[NTEST];
0111 static unsigned int len[NTEST];
0112
0113 static struct page *pages[NPAGES];
0114 static unsigned long addrs[NPAGES];
0115
0116
0117 static int pageattr_test(void)
0118 {
0119 struct split_state sa, sb, sc;
0120 unsigned long *bm;
0121 pte_t *pte, pte0;
0122 int failed = 0;
0123 unsigned int level;
0124 int i, k;
0125 int err;
0126
0127 if (print)
0128 printk(KERN_INFO "CPA self-test:\n");
0129
0130 bm = vzalloc((max_pfn_mapped + 7) / 8);
0131 if (!bm) {
0132 printk(KERN_ERR "CPA Cannot vmalloc bitmap\n");
0133 return -ENOMEM;
0134 }
0135
0136 failed += print_split(&sa);
0137
0138 for (i = 0; i < NTEST; i++) {
0139 unsigned long pfn = prandom_u32() % max_pfn_mapped;
0140
0141 addr[i] = (unsigned long)__va(pfn << PAGE_SHIFT);
0142 len[i] = prandom_u32() % NPAGES;
0143 len[i] = min_t(unsigned long, len[i], max_pfn_mapped - pfn - 1);
0144
0145 if (len[i] == 0)
0146 len[i] = 1;
0147
0148 pte = NULL;
0149 pte0 = pfn_pte(0, __pgprot(0));
0150
0151 for (k = 0; k < len[i]; k++) {
0152 pte = lookup_address(addr[i] + k*PAGE_SIZE, &level);
0153 if (!pte || pgprot_val(pte_pgprot(*pte)) == 0 ||
0154 !(pte_val(*pte) & _PAGE_PRESENT)) {
0155 addr[i] = 0;
0156 break;
0157 }
0158 if (k == 0) {
0159 pte0 = *pte;
0160 } else {
0161 if (pgprot_val(pte_pgprot(*pte)) !=
0162 pgprot_val(pte_pgprot(pte0))) {
0163 len[i] = k;
0164 break;
0165 }
0166 }
0167 if (test_bit(pfn + k, bm)) {
0168 len[i] = k;
0169 break;
0170 }
0171 __set_bit(pfn + k, bm);
0172 addrs[k] = addr[i] + k*PAGE_SIZE;
0173 pages[k] = pfn_to_page(pfn + k);
0174 }
0175 if (!addr[i] || !pte || !k) {
0176 addr[i] = 0;
0177 continue;
0178 }
0179
0180 switch (i % 3) {
0181 case 0:
0182 err = change_page_attr_set(&addr[i], len[i], PAGE_CPA_TEST, 0);
0183 break;
0184
0185 case 1:
0186 err = change_page_attr_set(addrs, len[1], PAGE_CPA_TEST, 1);
0187 break;
0188
0189 case 2:
0190 err = cpa_set_pages_array(pages, len[i], PAGE_CPA_TEST);
0191 break;
0192 }
0193
0194
0195 if (err < 0) {
0196 printk(KERN_ERR "CPA %d failed %d\n", i, err);
0197 failed++;
0198 }
0199
0200 pte = lookup_address(addr[i], &level);
0201 if (!pte || !pte_testbit(*pte) || pte_huge(*pte)) {
0202 printk(KERN_ERR "CPA %lx: bad pte %Lx\n", addr[i],
0203 pte ? (u64)pte_val(*pte) : 0ULL);
0204 failed++;
0205 }
0206 if (level != PG_LEVEL_4K) {
0207 printk(KERN_ERR "CPA %lx: unexpected level %d\n",
0208 addr[i], level);
0209 failed++;
0210 }
0211
0212 }
0213 vfree(bm);
0214
0215 failed += print_split(&sb);
0216
0217 for (i = 0; i < NTEST; i++) {
0218 if (!addr[i])
0219 continue;
0220 pte = lookup_address(addr[i], &level);
0221 if (!pte) {
0222 printk(KERN_ERR "CPA lookup of %lx failed\n", addr[i]);
0223 failed++;
0224 continue;
0225 }
0226 err = change_page_attr_clear(&addr[i], len[i], PAGE_CPA_TEST, 0);
0227 if (err < 0) {
0228 printk(KERN_ERR "CPA reverting failed: %d\n", err);
0229 failed++;
0230 }
0231 pte = lookup_address(addr[i], &level);
0232 if (!pte || pte_testbit(*pte)) {
0233 printk(KERN_ERR "CPA %lx: bad pte after revert %Lx\n",
0234 addr[i], pte ? (u64)pte_val(*pte) : 0ULL);
0235 failed++;
0236 }
0237
0238 }
0239
0240 failed += print_split(&sc);
0241
0242 if (failed) {
0243 WARN(1, KERN_ERR "NOT PASSED. Please report.\n");
0244 return -EINVAL;
0245 } else {
0246 if (print)
0247 printk(KERN_INFO "ok.\n");
0248 }
0249
0250 return 0;
0251 }
0252
0253 static int do_pageattr_test(void *__unused)
0254 {
0255 while (!kthread_should_stop()) {
0256 schedule_timeout_interruptible(HZ*30);
0257 if (pageattr_test() < 0)
0258 break;
0259 if (print)
0260 print--;
0261 }
0262 return 0;
0263 }
0264
0265 static int start_pageattr_test(void)
0266 {
0267 struct task_struct *p;
0268
0269 p = kthread_create(do_pageattr_test, NULL, "pageattr-test");
0270 if (!IS_ERR(p))
0271 wake_up_process(p);
0272 else
0273 WARN_ON(1);
0274
0275 return 0;
0276 }
0277 device_initcall(start_pageattr_test);