0001
0002
0003
0004
0005
0006
0007
0008 #include <stdio.h>
0009 #include <sys/mman.h>
0010 #include <string.h>
0011
0012 #include "../kselftest.h"
0013
0014 #ifdef __powerpc64__
0015 #define PAGE_SIZE (64 << 10)
0016
0017
0018
0019 #define HUGETLB_SIZE (16 << 20)
0020 #else
0021 #define PAGE_SIZE (4 << 10)
0022 #define HUGETLB_SIZE (2 << 20)
0023 #endif
0024
0025
0026
0027
0028
0029 #define ADDR_SWITCH_HINT (1UL << 47)
0030 #define LOW_ADDR ((void *) (1UL << 30))
0031 #define HIGH_ADDR ((void *) (1UL << 48))
0032
0033 struct testcase {
0034 void *addr;
0035 unsigned long size;
0036 unsigned long flags;
0037 const char *msg;
0038 unsigned int low_addr_required:1;
0039 unsigned int keep_mapped:1;
0040 };
0041
0042 static struct testcase testcases[] = {
0043 {
0044
0045
0046
0047
0048 .addr = ((void *)(ADDR_SWITCH_HINT - PAGE_SIZE)),
0049 .size = PAGE_SIZE,
0050 .flags = MAP_PRIVATE | MAP_ANONYMOUS,
0051 .msg = "mmap(ADDR_SWITCH_HINT - PAGE_SIZE, PAGE_SIZE)",
0052 .low_addr_required = 1,
0053 },
0054 {
0055
0056
0057
0058
0059
0060 .addr = ((void *)(ADDR_SWITCH_HINT - PAGE_SIZE)),
0061 .size = 2 * PAGE_SIZE,
0062 .flags = MAP_PRIVATE | MAP_ANONYMOUS,
0063 .msg = "mmap(ADDR_SWITCH_HINT - PAGE_SIZE, (2 * PAGE_SIZE))",
0064 .low_addr_required = 1,
0065 },
0066 {
0067
0068
0069
0070
0071 .addr = ((void *)(ADDR_SWITCH_HINT)),
0072 .size = PAGE_SIZE,
0073 .flags = MAP_PRIVATE | MAP_ANONYMOUS,
0074 .msg = "mmap(ADDR_SWITCH_HINT, PAGE_SIZE)",
0075 .keep_mapped = 1,
0076 },
0077 {
0078 .addr = (void *)(ADDR_SWITCH_HINT),
0079 .size = 2 * PAGE_SIZE,
0080 .flags = MAP_PRIVATE | MAP_ANONYMOUS | MAP_FIXED,
0081 .msg = "mmap(ADDR_SWITCH_HINT, 2 * PAGE_SIZE, MAP_FIXED)",
0082 },
0083 {
0084 .addr = NULL,
0085 .size = 2 * PAGE_SIZE,
0086 .flags = MAP_PRIVATE | MAP_ANONYMOUS,
0087 .msg = "mmap(NULL)",
0088 .low_addr_required = 1,
0089 },
0090 {
0091 .addr = LOW_ADDR,
0092 .size = 2 * PAGE_SIZE,
0093 .flags = MAP_PRIVATE | MAP_ANONYMOUS,
0094 .msg = "mmap(LOW_ADDR)",
0095 .low_addr_required = 1,
0096 },
0097 {
0098 .addr = HIGH_ADDR,
0099 .size = 2 * PAGE_SIZE,
0100 .flags = MAP_PRIVATE | MAP_ANONYMOUS,
0101 .msg = "mmap(HIGH_ADDR)",
0102 .keep_mapped = 1,
0103 },
0104 {
0105 .addr = HIGH_ADDR,
0106 .size = 2 * PAGE_SIZE,
0107 .flags = MAP_PRIVATE | MAP_ANONYMOUS,
0108 .msg = "mmap(HIGH_ADDR) again",
0109 .keep_mapped = 1,
0110 },
0111 {
0112 .addr = HIGH_ADDR,
0113 .size = 2 * PAGE_SIZE,
0114 .flags = MAP_PRIVATE | MAP_ANONYMOUS | MAP_FIXED,
0115 .msg = "mmap(HIGH_ADDR, MAP_FIXED)",
0116 },
0117 {
0118 .addr = (void *) -1,
0119 .size = 2 * PAGE_SIZE,
0120 .flags = MAP_PRIVATE | MAP_ANONYMOUS,
0121 .msg = "mmap(-1)",
0122 .keep_mapped = 1,
0123 },
0124 {
0125 .addr = (void *) -1,
0126 .size = 2 * PAGE_SIZE,
0127 .flags = MAP_PRIVATE | MAP_ANONYMOUS,
0128 .msg = "mmap(-1) again",
0129 },
0130 {
0131 .addr = ((void *)(ADDR_SWITCH_HINT - PAGE_SIZE)),
0132 .size = PAGE_SIZE,
0133 .flags = MAP_PRIVATE | MAP_ANONYMOUS,
0134 .msg = "mmap(ADDR_SWITCH_HINT - PAGE_SIZE, PAGE_SIZE)",
0135 .low_addr_required = 1,
0136 },
0137 {
0138 .addr = (void *)(ADDR_SWITCH_HINT - PAGE_SIZE),
0139 .size = 2 * PAGE_SIZE,
0140 .flags = MAP_PRIVATE | MAP_ANONYMOUS,
0141 .msg = "mmap(ADDR_SWITCH_HINT - PAGE_SIZE, 2 * PAGE_SIZE)",
0142 .low_addr_required = 1,
0143 .keep_mapped = 1,
0144 },
0145 {
0146 .addr = (void *)(ADDR_SWITCH_HINT - PAGE_SIZE / 2),
0147 .size = 2 * PAGE_SIZE,
0148 .flags = MAP_PRIVATE | MAP_ANONYMOUS,
0149 .msg = "mmap(ADDR_SWITCH_HINT - PAGE_SIZE/2 , 2 * PAGE_SIZE)",
0150 .low_addr_required = 1,
0151 .keep_mapped = 1,
0152 },
0153 {
0154 .addr = ((void *)(ADDR_SWITCH_HINT)),
0155 .size = PAGE_SIZE,
0156 .flags = MAP_PRIVATE | MAP_ANONYMOUS,
0157 .msg = "mmap(ADDR_SWITCH_HINT, PAGE_SIZE)",
0158 },
0159 {
0160 .addr = (void *)(ADDR_SWITCH_HINT),
0161 .size = 2 * PAGE_SIZE,
0162 .flags = MAP_PRIVATE | MAP_ANONYMOUS | MAP_FIXED,
0163 .msg = "mmap(ADDR_SWITCH_HINT, 2 * PAGE_SIZE, MAP_FIXED)",
0164 },
0165 };
0166
0167 static struct testcase hugetlb_testcases[] = {
0168 {
0169 .addr = NULL,
0170 .size = HUGETLB_SIZE,
0171 .flags = MAP_HUGETLB | MAP_PRIVATE | MAP_ANONYMOUS,
0172 .msg = "mmap(NULL, MAP_HUGETLB)",
0173 .low_addr_required = 1,
0174 },
0175 {
0176 .addr = LOW_ADDR,
0177 .size = HUGETLB_SIZE,
0178 .flags = MAP_HUGETLB | MAP_PRIVATE | MAP_ANONYMOUS,
0179 .msg = "mmap(LOW_ADDR, MAP_HUGETLB)",
0180 .low_addr_required = 1,
0181 },
0182 {
0183 .addr = HIGH_ADDR,
0184 .size = HUGETLB_SIZE,
0185 .flags = MAP_HUGETLB | MAP_PRIVATE | MAP_ANONYMOUS,
0186 .msg = "mmap(HIGH_ADDR, MAP_HUGETLB)",
0187 .keep_mapped = 1,
0188 },
0189 {
0190 .addr = HIGH_ADDR,
0191 .size = HUGETLB_SIZE,
0192 .flags = MAP_HUGETLB | MAP_PRIVATE | MAP_ANONYMOUS,
0193 .msg = "mmap(HIGH_ADDR, MAP_HUGETLB) again",
0194 .keep_mapped = 1,
0195 },
0196 {
0197 .addr = HIGH_ADDR,
0198 .size = HUGETLB_SIZE,
0199 .flags = MAP_HUGETLB | MAP_PRIVATE | MAP_ANONYMOUS | MAP_FIXED,
0200 .msg = "mmap(HIGH_ADDR, MAP_FIXED | MAP_HUGETLB)",
0201 },
0202 {
0203 .addr = (void *) -1,
0204 .size = HUGETLB_SIZE,
0205 .flags = MAP_HUGETLB | MAP_PRIVATE | MAP_ANONYMOUS,
0206 .msg = "mmap(-1, MAP_HUGETLB)",
0207 .keep_mapped = 1,
0208 },
0209 {
0210 .addr = (void *) -1,
0211 .size = HUGETLB_SIZE,
0212 .flags = MAP_HUGETLB | MAP_PRIVATE | MAP_ANONYMOUS,
0213 .msg = "mmap(-1, MAP_HUGETLB) again",
0214 },
0215 {
0216 .addr = (void *)(ADDR_SWITCH_HINT - PAGE_SIZE),
0217 .size = 2 * HUGETLB_SIZE,
0218 .flags = MAP_HUGETLB | MAP_PRIVATE | MAP_ANONYMOUS,
0219 .msg = "mmap(ADDR_SWITCH_HINT - PAGE_SIZE, 2*HUGETLB_SIZE, MAP_HUGETLB)",
0220 .low_addr_required = 1,
0221 .keep_mapped = 1,
0222 },
0223 {
0224 .addr = (void *)(ADDR_SWITCH_HINT),
0225 .size = 2 * HUGETLB_SIZE,
0226 .flags = MAP_HUGETLB | MAP_PRIVATE | MAP_ANONYMOUS | MAP_FIXED,
0227 .msg = "mmap(ADDR_SWITCH_HINT , 2*HUGETLB_SIZE, MAP_FIXED | MAP_HUGETLB)",
0228 },
0229 };
0230
0231 static int run_test(struct testcase *test, int count)
0232 {
0233 void *p;
0234 int i, ret = KSFT_PASS;
0235
0236 for (i = 0; i < count; i++) {
0237 struct testcase *t = test + i;
0238
0239 p = mmap(t->addr, t->size, PROT_READ | PROT_WRITE, t->flags, -1, 0);
0240
0241 printf("%s: %p - ", t->msg, p);
0242
0243 if (p == MAP_FAILED) {
0244 printf("FAILED\n");
0245 ret = KSFT_FAIL;
0246 continue;
0247 }
0248
0249 if (t->low_addr_required && p >= (void *)(ADDR_SWITCH_HINT)) {
0250 printf("FAILED\n");
0251 ret = KSFT_FAIL;
0252 } else {
0253
0254
0255
0256
0257 memset(p, 0, t->size);
0258 printf("OK\n");
0259 }
0260 if (!t->keep_mapped)
0261 munmap(p, t->size);
0262 }
0263
0264 return ret;
0265 }
0266
0267 static int supported_arch(void)
0268 {
0269 #if defined(__powerpc64__)
0270 return 1;
0271 #elif defined(__x86_64__)
0272 return 1;
0273 #else
0274 return 0;
0275 #endif
0276 }
0277
0278 int main(int argc, char **argv)
0279 {
0280 int ret;
0281
0282 if (!supported_arch())
0283 return KSFT_SKIP;
0284
0285 ret = run_test(testcases, ARRAY_SIZE(testcases));
0286 if (argc == 2 && !strcmp(argv[1], "--run-hugetlb"))
0287 ret = run_test(hugetlb_testcases, ARRAY_SIZE(hugetlb_testcases));
0288 return ret;
0289 }