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