1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16#include <stdio.h>
17#include <sys/mman.h>
18#include <string.h>
19
20#define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0]))
21
22#ifdef __powerpc64__
23#define PAGE_SIZE (64 << 10)
24
25
26
27#define HUGETLB_SIZE (16 << 20)
28#else
29#define PAGE_SIZE (4 << 10)
30#define HUGETLB_SIZE (2 << 20)
31#endif
32
33
34
35
36
37#define ADDR_SWITCH_HINT (1UL << 47)
38#define LOW_ADDR ((void *) (1UL << 30))
39#define HIGH_ADDR ((void *) (1UL << 48))
40
41struct testcase {
42 void *addr;
43 unsigned long size;
44 unsigned long flags;
45 const char *msg;
46 unsigned int low_addr_required:1;
47 unsigned int keep_mapped:1;
48};
49
50static struct testcase testcases[] = {
51 {
52
53
54
55
56 .addr = ((void *)(ADDR_SWITCH_HINT - PAGE_SIZE)),
57 .size = PAGE_SIZE,
58 .flags = MAP_PRIVATE | MAP_ANONYMOUS,
59 .msg = "mmap(ADDR_SWITCH_HINT - PAGE_SIZE, PAGE_SIZE)",
60 .low_addr_required = 1,
61 },
62 {
63
64
65
66
67
68 .addr = ((void *)(ADDR_SWITCH_HINT - PAGE_SIZE)),
69 .size = 2 * PAGE_SIZE,
70 .flags = MAP_PRIVATE | MAP_ANONYMOUS,
71 .msg = "mmap(ADDR_SWITCH_HINT - PAGE_SIZE, (2 * PAGE_SIZE))",
72 .low_addr_required = 1,
73 },
74 {
75
76
77
78
79 .addr = ((void *)(ADDR_SWITCH_HINT)),
80 .size = PAGE_SIZE,
81 .flags = MAP_PRIVATE | MAP_ANONYMOUS,
82 .msg = "mmap(ADDR_SWITCH_HINT, PAGE_SIZE)",
83 .keep_mapped = 1,
84 },
85 {
86 .addr = (void *)(ADDR_SWITCH_HINT),
87 .size = 2 * PAGE_SIZE,
88 .flags = MAP_PRIVATE | MAP_ANONYMOUS | MAP_FIXED,
89 .msg = "mmap(ADDR_SWITCH_HINT, 2 * PAGE_SIZE, MAP_FIXED)",
90 },
91 {
92 .addr = NULL,
93 .size = 2 * PAGE_SIZE,
94 .flags = MAP_PRIVATE | MAP_ANONYMOUS,
95 .msg = "mmap(NULL)",
96 .low_addr_required = 1,
97 },
98 {
99 .addr = LOW_ADDR,
100 .size = 2 * PAGE_SIZE,
101 .flags = MAP_PRIVATE | MAP_ANONYMOUS,
102 .msg = "mmap(LOW_ADDR)",
103 .low_addr_required = 1,
104 },
105 {
106 .addr = HIGH_ADDR,
107 .size = 2 * PAGE_SIZE,
108 .flags = MAP_PRIVATE | MAP_ANONYMOUS,
109 .msg = "mmap(HIGH_ADDR)",
110 .keep_mapped = 1,
111 },
112 {
113 .addr = HIGH_ADDR,
114 .size = 2 * PAGE_SIZE,
115 .flags = MAP_PRIVATE | MAP_ANONYMOUS,
116 .msg = "mmap(HIGH_ADDR) again",
117 .keep_mapped = 1,
118 },
119 {
120 .addr = HIGH_ADDR,
121 .size = 2 * PAGE_SIZE,
122 .flags = MAP_PRIVATE | MAP_ANONYMOUS | MAP_FIXED,
123 .msg = "mmap(HIGH_ADDR, MAP_FIXED)",
124 },
125 {
126 .addr = (void *) -1,
127 .size = 2 * PAGE_SIZE,
128 .flags = MAP_PRIVATE | MAP_ANONYMOUS,
129 .msg = "mmap(-1)",
130 .keep_mapped = 1,
131 },
132 {
133 .addr = (void *) -1,
134 .size = 2 * PAGE_SIZE,
135 .flags = MAP_PRIVATE | MAP_ANONYMOUS,
136 .msg = "mmap(-1) again",
137 },
138 {
139 .addr = ((void *)(ADDR_SWITCH_HINT - PAGE_SIZE)),
140 .size = PAGE_SIZE,
141 .flags = MAP_PRIVATE | MAP_ANONYMOUS,
142 .msg = "mmap(ADDR_SWITCH_HINT - PAGE_SIZE, PAGE_SIZE)",
143 .low_addr_required = 1,
144 },
145 {
146 .addr = (void *)(ADDR_SWITCH_HINT - PAGE_SIZE),
147 .size = 2 * PAGE_SIZE,
148 .flags = MAP_PRIVATE | MAP_ANONYMOUS,
149 .msg = "mmap(ADDR_SWITCH_HINT - PAGE_SIZE, 2 * PAGE_SIZE)",
150 .low_addr_required = 1,
151 .keep_mapped = 1,
152 },
153 {
154 .addr = (void *)(ADDR_SWITCH_HINT - PAGE_SIZE / 2),
155 .size = 2 * PAGE_SIZE,
156 .flags = MAP_PRIVATE | MAP_ANONYMOUS,
157 .msg = "mmap(ADDR_SWITCH_HINT - PAGE_SIZE/2 , 2 * PAGE_SIZE)",
158 .low_addr_required = 1,
159 .keep_mapped = 1,
160 },
161 {
162 .addr = ((void *)(ADDR_SWITCH_HINT)),
163 .size = PAGE_SIZE,
164 .flags = MAP_PRIVATE | MAP_ANONYMOUS,
165 .msg = "mmap(ADDR_SWITCH_HINT, PAGE_SIZE)",
166 },
167 {
168 .addr = (void *)(ADDR_SWITCH_HINT),
169 .size = 2 * PAGE_SIZE,
170 .flags = MAP_PRIVATE | MAP_ANONYMOUS | MAP_FIXED,
171 .msg = "mmap(ADDR_SWITCH_HINT, 2 * PAGE_SIZE, MAP_FIXED)",
172 },
173};
174
175static struct testcase hugetlb_testcases[] = {
176 {
177 .addr = NULL,
178 .size = HUGETLB_SIZE,
179 .flags = MAP_HUGETLB | MAP_PRIVATE | MAP_ANONYMOUS,
180 .msg = "mmap(NULL, MAP_HUGETLB)",
181 .low_addr_required = 1,
182 },
183 {
184 .addr = LOW_ADDR,
185 .size = HUGETLB_SIZE,
186 .flags = MAP_HUGETLB | MAP_PRIVATE | MAP_ANONYMOUS,
187 .msg = "mmap(LOW_ADDR, MAP_HUGETLB)",
188 .low_addr_required = 1,
189 },
190 {
191 .addr = HIGH_ADDR,
192 .size = HUGETLB_SIZE,
193 .flags = MAP_HUGETLB | MAP_PRIVATE | MAP_ANONYMOUS,
194 .msg = "mmap(HIGH_ADDR, MAP_HUGETLB)",
195 .keep_mapped = 1,
196 },
197 {
198 .addr = HIGH_ADDR,
199 .size = HUGETLB_SIZE,
200 .flags = MAP_HUGETLB | MAP_PRIVATE | MAP_ANONYMOUS,
201 .msg = "mmap(HIGH_ADDR, MAP_HUGETLB) again",
202 .keep_mapped = 1,
203 },
204 {
205 .addr = HIGH_ADDR,
206 .size = HUGETLB_SIZE,
207 .flags = MAP_HUGETLB | MAP_PRIVATE | MAP_ANONYMOUS | MAP_FIXED,
208 .msg = "mmap(HIGH_ADDR, MAP_FIXED | MAP_HUGETLB)",
209 },
210 {
211 .addr = (void *) -1,
212 .size = HUGETLB_SIZE,
213 .flags = MAP_HUGETLB | MAP_PRIVATE | MAP_ANONYMOUS,
214 .msg = "mmap(-1, MAP_HUGETLB)",
215 .keep_mapped = 1,
216 },
217 {
218 .addr = (void *) -1,
219 .size = HUGETLB_SIZE,
220 .flags = MAP_HUGETLB | MAP_PRIVATE | MAP_ANONYMOUS,
221 .msg = "mmap(-1, MAP_HUGETLB) again",
222 },
223 {
224 .addr = (void *)(ADDR_SWITCH_HINT - PAGE_SIZE),
225 .size = 2 * HUGETLB_SIZE,
226 .flags = MAP_HUGETLB | MAP_PRIVATE | MAP_ANONYMOUS,
227 .msg = "mmap(ADDR_SWITCH_HINT - PAGE_SIZE, 2*HUGETLB_SIZE, MAP_HUGETLB)",
228 .low_addr_required = 1,
229 .keep_mapped = 1,
230 },
231 {
232 .addr = (void *)(ADDR_SWITCH_HINT),
233 .size = 2 * HUGETLB_SIZE,
234 .flags = MAP_HUGETLB | MAP_PRIVATE | MAP_ANONYMOUS | MAP_FIXED,
235 .msg = "mmap(ADDR_SWITCH_HINT , 2*HUGETLB_SIZE, MAP_FIXED | MAP_HUGETLB)",
236 },
237};
238
239static int run_test(struct testcase *test, int count)
240{
241 void *p;
242 int i, ret = 0;
243
244 for (i = 0; i < count; i++) {
245 struct testcase *t = test + i;
246
247 p = mmap(t->addr, t->size, PROT_READ | PROT_WRITE, t->flags, -1, 0);
248
249 printf("%s: %p - ", t->msg, p);
250
251 if (p == MAP_FAILED) {
252 printf("FAILED\n");
253 ret = 1;
254 continue;
255 }
256
257 if (t->low_addr_required && p >= (void *)(ADDR_SWITCH_HINT)) {
258 printf("FAILED\n");
259 ret = 1;
260 } else {
261
262
263
264
265 memset(p, 0, t->size);
266 printf("OK\n");
267 }
268 if (!t->keep_mapped)
269 munmap(p, t->size);
270 }
271
272 return ret;
273}
274
275static int supported_arch(void)
276{
277#if defined(__powerpc64__)
278 return 1;
279#elif defined(__x86_64__)
280 return 1;
281#else
282 return 0;
283#endif
284}
285
286int main(int argc, char **argv)
287{
288 int ret;
289
290 if (!supported_arch())
291 return 0;
292
293 ret = run_test(testcases, ARRAY_SIZE(testcases));
294 if (argc == 2 && !strcmp(argv[1], "--run-hugetlb"))
295 ret = run_test(hugetlb_testcases, ARRAY_SIZE(hugetlb_testcases));
296 return ret;
297}
298