pageattr-test.c 5.3 KB

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