va_128TBswitch.c 6.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289
  1. // SPDX-License-Identifier: GPL-2.0-only
  2. /*
  3. *
  4. * Authors: Kirill A. Shutemov <[email protected]>
  5. * Authors: Aneesh Kumar K.V <[email protected]>
  6. */
  7. #include <stdio.h>
  8. #include <sys/mman.h>
  9. #include <string.h>
  10. #include "../kselftest.h"
  11. #ifdef __powerpc64__
  12. #define PAGE_SIZE (64 << 10)
  13. /*
  14. * This will work with 16M and 2M hugepage size
  15. */
  16. #define HUGETLB_SIZE (16 << 20)
  17. #else
  18. #define PAGE_SIZE (4 << 10)
  19. #define HUGETLB_SIZE (2 << 20)
  20. #endif
  21. /*
  22. * >= 128TB is the hint addr value we used to select
  23. * large address space.
  24. */
  25. #define ADDR_SWITCH_HINT (1UL << 47)
  26. #define LOW_ADDR ((void *) (1UL << 30))
  27. #define HIGH_ADDR ((void *) (1UL << 48))
  28. struct testcase {
  29. void *addr;
  30. unsigned long size;
  31. unsigned long flags;
  32. const char *msg;
  33. unsigned int low_addr_required:1;
  34. unsigned int keep_mapped:1;
  35. };
  36. static struct testcase testcases[] = {
  37. {
  38. /*
  39. * If stack is moved, we could possibly allocate
  40. * this at the requested address.
  41. */
  42. .addr = ((void *)(ADDR_SWITCH_HINT - PAGE_SIZE)),
  43. .size = PAGE_SIZE,
  44. .flags = MAP_PRIVATE | MAP_ANONYMOUS,
  45. .msg = "mmap(ADDR_SWITCH_HINT - PAGE_SIZE, PAGE_SIZE)",
  46. .low_addr_required = 1,
  47. },
  48. {
  49. /*
  50. * We should never allocate at the requested address or above it
  51. * The len cross the 128TB boundary. Without MAP_FIXED
  52. * we will always search in the lower address space.
  53. */
  54. .addr = ((void *)(ADDR_SWITCH_HINT - PAGE_SIZE)),
  55. .size = 2 * PAGE_SIZE,
  56. .flags = MAP_PRIVATE | MAP_ANONYMOUS,
  57. .msg = "mmap(ADDR_SWITCH_HINT - PAGE_SIZE, (2 * PAGE_SIZE))",
  58. .low_addr_required = 1,
  59. },
  60. {
  61. /*
  62. * Exact mapping at 128TB, the area is free we should get that
  63. * even without MAP_FIXED.
  64. */
  65. .addr = ((void *)(ADDR_SWITCH_HINT)),
  66. .size = PAGE_SIZE,
  67. .flags = MAP_PRIVATE | MAP_ANONYMOUS,
  68. .msg = "mmap(ADDR_SWITCH_HINT, PAGE_SIZE)",
  69. .keep_mapped = 1,
  70. },
  71. {
  72. .addr = (void *)(ADDR_SWITCH_HINT),
  73. .size = 2 * PAGE_SIZE,
  74. .flags = MAP_PRIVATE | MAP_ANONYMOUS | MAP_FIXED,
  75. .msg = "mmap(ADDR_SWITCH_HINT, 2 * PAGE_SIZE, MAP_FIXED)",
  76. },
  77. {
  78. .addr = NULL,
  79. .size = 2 * PAGE_SIZE,
  80. .flags = MAP_PRIVATE | MAP_ANONYMOUS,
  81. .msg = "mmap(NULL)",
  82. .low_addr_required = 1,
  83. },
  84. {
  85. .addr = LOW_ADDR,
  86. .size = 2 * PAGE_SIZE,
  87. .flags = MAP_PRIVATE | MAP_ANONYMOUS,
  88. .msg = "mmap(LOW_ADDR)",
  89. .low_addr_required = 1,
  90. },
  91. {
  92. .addr = HIGH_ADDR,
  93. .size = 2 * PAGE_SIZE,
  94. .flags = MAP_PRIVATE | MAP_ANONYMOUS,
  95. .msg = "mmap(HIGH_ADDR)",
  96. .keep_mapped = 1,
  97. },
  98. {
  99. .addr = HIGH_ADDR,
  100. .size = 2 * PAGE_SIZE,
  101. .flags = MAP_PRIVATE | MAP_ANONYMOUS,
  102. .msg = "mmap(HIGH_ADDR) again",
  103. .keep_mapped = 1,
  104. },
  105. {
  106. .addr = HIGH_ADDR,
  107. .size = 2 * PAGE_SIZE,
  108. .flags = MAP_PRIVATE | MAP_ANONYMOUS | MAP_FIXED,
  109. .msg = "mmap(HIGH_ADDR, MAP_FIXED)",
  110. },
  111. {
  112. .addr = (void *) -1,
  113. .size = 2 * PAGE_SIZE,
  114. .flags = MAP_PRIVATE | MAP_ANONYMOUS,
  115. .msg = "mmap(-1)",
  116. .keep_mapped = 1,
  117. },
  118. {
  119. .addr = (void *) -1,
  120. .size = 2 * PAGE_SIZE,
  121. .flags = MAP_PRIVATE | MAP_ANONYMOUS,
  122. .msg = "mmap(-1) again",
  123. },
  124. {
  125. .addr = ((void *)(ADDR_SWITCH_HINT - PAGE_SIZE)),
  126. .size = PAGE_SIZE,
  127. .flags = MAP_PRIVATE | MAP_ANONYMOUS,
  128. .msg = "mmap(ADDR_SWITCH_HINT - PAGE_SIZE, PAGE_SIZE)",
  129. .low_addr_required = 1,
  130. },
  131. {
  132. .addr = (void *)(ADDR_SWITCH_HINT - PAGE_SIZE),
  133. .size = 2 * PAGE_SIZE,
  134. .flags = MAP_PRIVATE | MAP_ANONYMOUS,
  135. .msg = "mmap(ADDR_SWITCH_HINT - PAGE_SIZE, 2 * PAGE_SIZE)",
  136. .low_addr_required = 1,
  137. .keep_mapped = 1,
  138. },
  139. {
  140. .addr = (void *)(ADDR_SWITCH_HINT - PAGE_SIZE / 2),
  141. .size = 2 * PAGE_SIZE,
  142. .flags = MAP_PRIVATE | MAP_ANONYMOUS,
  143. .msg = "mmap(ADDR_SWITCH_HINT - PAGE_SIZE/2 , 2 * PAGE_SIZE)",
  144. .low_addr_required = 1,
  145. .keep_mapped = 1,
  146. },
  147. {
  148. .addr = ((void *)(ADDR_SWITCH_HINT)),
  149. .size = PAGE_SIZE,
  150. .flags = MAP_PRIVATE | MAP_ANONYMOUS,
  151. .msg = "mmap(ADDR_SWITCH_HINT, PAGE_SIZE)",
  152. },
  153. {
  154. .addr = (void *)(ADDR_SWITCH_HINT),
  155. .size = 2 * PAGE_SIZE,
  156. .flags = MAP_PRIVATE | MAP_ANONYMOUS | MAP_FIXED,
  157. .msg = "mmap(ADDR_SWITCH_HINT, 2 * PAGE_SIZE, MAP_FIXED)",
  158. },
  159. };
  160. static struct testcase hugetlb_testcases[] = {
  161. {
  162. .addr = NULL,
  163. .size = HUGETLB_SIZE,
  164. .flags = MAP_HUGETLB | MAP_PRIVATE | MAP_ANONYMOUS,
  165. .msg = "mmap(NULL, MAP_HUGETLB)",
  166. .low_addr_required = 1,
  167. },
  168. {
  169. .addr = LOW_ADDR,
  170. .size = HUGETLB_SIZE,
  171. .flags = MAP_HUGETLB | MAP_PRIVATE | MAP_ANONYMOUS,
  172. .msg = "mmap(LOW_ADDR, MAP_HUGETLB)",
  173. .low_addr_required = 1,
  174. },
  175. {
  176. .addr = HIGH_ADDR,
  177. .size = HUGETLB_SIZE,
  178. .flags = MAP_HUGETLB | MAP_PRIVATE | MAP_ANONYMOUS,
  179. .msg = "mmap(HIGH_ADDR, MAP_HUGETLB)",
  180. .keep_mapped = 1,
  181. },
  182. {
  183. .addr = HIGH_ADDR,
  184. .size = HUGETLB_SIZE,
  185. .flags = MAP_HUGETLB | MAP_PRIVATE | MAP_ANONYMOUS,
  186. .msg = "mmap(HIGH_ADDR, MAP_HUGETLB) again",
  187. .keep_mapped = 1,
  188. },
  189. {
  190. .addr = HIGH_ADDR,
  191. .size = HUGETLB_SIZE,
  192. .flags = MAP_HUGETLB | MAP_PRIVATE | MAP_ANONYMOUS | MAP_FIXED,
  193. .msg = "mmap(HIGH_ADDR, MAP_FIXED | MAP_HUGETLB)",
  194. },
  195. {
  196. .addr = (void *) -1,
  197. .size = HUGETLB_SIZE,
  198. .flags = MAP_HUGETLB | MAP_PRIVATE | MAP_ANONYMOUS,
  199. .msg = "mmap(-1, MAP_HUGETLB)",
  200. .keep_mapped = 1,
  201. },
  202. {
  203. .addr = (void *) -1,
  204. .size = HUGETLB_SIZE,
  205. .flags = MAP_HUGETLB | MAP_PRIVATE | MAP_ANONYMOUS,
  206. .msg = "mmap(-1, MAP_HUGETLB) again",
  207. },
  208. {
  209. .addr = (void *)(ADDR_SWITCH_HINT - PAGE_SIZE),
  210. .size = 2 * HUGETLB_SIZE,
  211. .flags = MAP_HUGETLB | MAP_PRIVATE | MAP_ANONYMOUS,
  212. .msg = "mmap(ADDR_SWITCH_HINT - PAGE_SIZE, 2*HUGETLB_SIZE, MAP_HUGETLB)",
  213. .low_addr_required = 1,
  214. .keep_mapped = 1,
  215. },
  216. {
  217. .addr = (void *)(ADDR_SWITCH_HINT),
  218. .size = 2 * HUGETLB_SIZE,
  219. .flags = MAP_HUGETLB | MAP_PRIVATE | MAP_ANONYMOUS | MAP_FIXED,
  220. .msg = "mmap(ADDR_SWITCH_HINT , 2*HUGETLB_SIZE, MAP_FIXED | MAP_HUGETLB)",
  221. },
  222. };
  223. static int run_test(struct testcase *test, int count)
  224. {
  225. void *p;
  226. int i, ret = KSFT_PASS;
  227. for (i = 0; i < count; i++) {
  228. struct testcase *t = test + i;
  229. p = mmap(t->addr, t->size, PROT_READ | PROT_WRITE, t->flags, -1, 0);
  230. printf("%s: %p - ", t->msg, p);
  231. if (p == MAP_FAILED) {
  232. printf("FAILED\n");
  233. ret = KSFT_FAIL;
  234. continue;
  235. }
  236. if (t->low_addr_required && p >= (void *)(ADDR_SWITCH_HINT)) {
  237. printf("FAILED\n");
  238. ret = KSFT_FAIL;
  239. } else {
  240. /*
  241. * Do a dereference of the address returned so that we catch
  242. * bugs in page fault handling
  243. */
  244. memset(p, 0, t->size);
  245. printf("OK\n");
  246. }
  247. if (!t->keep_mapped)
  248. munmap(p, t->size);
  249. }
  250. return ret;
  251. }
  252. static int supported_arch(void)
  253. {
  254. #if defined(__powerpc64__)
  255. return 1;
  256. #elif defined(__x86_64__)
  257. return 1;
  258. #else
  259. return 0;
  260. #endif
  261. }
  262. int main(int argc, char **argv)
  263. {
  264. int ret;
  265. if (!supported_arch())
  266. return KSFT_SKIP;
  267. ret = run_test(testcases, ARRAY_SIZE(testcases));
  268. if (argc == 2 && !strcmp(argv[1], "--run-hugetlb"))
  269. ret = run_test(hugetlb_testcases, ARRAY_SIZE(hugetlb_testcases));
  270. return ret;
  271. }