pageattr-test.c 5.1 KB

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