3 * Authors: Kirill A. Shutemov <kirill.shutemov@linux.intel.com>
4 * Authors: Aneesh Kumar K.V <aneesh.kumar@linux.vnet.ibm.com>
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License, version 2, as
8 * published by the Free Software Foundation.
10 * This program is distributed in the hope that it would be useful, but
11 * WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
20 #define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0]))
23 #define PAGE_SIZE (64 << 10)
25 * This will work with 16M and 2M hugepage size
27 #define HUGETLB_SIZE (16 << 20)
29 #define PAGE_SIZE (4 << 10)
30 #define HUGETLB_SIZE (2 << 20)
34 * >= 128TB is the hint addr value we used to select
35 * large address space.
37 #define ADDR_SWITCH_HINT (1UL << 47)
38 #define LOW_ADDR ((void *) (1UL << 30))
39 #define HIGH_ADDR ((void *) (1UL << 48))
46 unsigned int low_addr_required
:1;
47 unsigned int keep_mapped
:1;
50 static struct testcase testcases
[] = {
53 * If stack is moved, we could possibly allocate
54 * this at the requested address.
56 .addr
= ((void *)(ADDR_SWITCH_HINT
- PAGE_SIZE
)),
58 .flags
= MAP_PRIVATE
| MAP_ANONYMOUS
,
59 .msg
= "mmap(ADDR_SWITCH_HINT - PAGE_SIZE, PAGE_SIZE)",
60 .low_addr_required
= 1,
64 * We should never allocate at the requested address or above it
65 * The len cross the 128TB boundary. Without MAP_FIXED
66 * we will always search in the lower address space.
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,
76 * Exact mapping at 128TB, the area is free we should get that
77 * even without MAP_FIXED.
79 .addr
= ((void *)(ADDR_SWITCH_HINT
)),
81 .flags
= MAP_PRIVATE
| MAP_ANONYMOUS
,
82 .msg
= "mmap(ADDR_SWITCH_HINT, PAGE_SIZE)",
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)",
93 .size
= 2 * PAGE_SIZE
,
94 .flags
= MAP_PRIVATE
| MAP_ANONYMOUS
,
96 .low_addr_required
= 1,
100 .size
= 2 * PAGE_SIZE
,
101 .flags
= MAP_PRIVATE
| MAP_ANONYMOUS
,
102 .msg
= "mmap(LOW_ADDR)",
103 .low_addr_required
= 1,
107 .size
= 2 * PAGE_SIZE
,
108 .flags
= MAP_PRIVATE
| MAP_ANONYMOUS
,
109 .msg
= "mmap(HIGH_ADDR)",
114 .size
= 2 * PAGE_SIZE
,
115 .flags
= MAP_PRIVATE
| MAP_ANONYMOUS
,
116 .msg
= "mmap(HIGH_ADDR) again",
121 .size
= 2 * PAGE_SIZE
,
122 .flags
= MAP_PRIVATE
| MAP_ANONYMOUS
| MAP_FIXED
,
123 .msg
= "mmap(HIGH_ADDR, MAP_FIXED)",
127 .size
= 2 * PAGE_SIZE
,
128 .flags
= MAP_PRIVATE
| MAP_ANONYMOUS
,
134 .size
= 2 * PAGE_SIZE
,
135 .flags
= MAP_PRIVATE
| MAP_ANONYMOUS
,
136 .msg
= "mmap(-1) again",
139 .addr
= ((void *)(ADDR_SWITCH_HINT
- PAGE_SIZE
)),
141 .flags
= MAP_PRIVATE
| MAP_ANONYMOUS
,
142 .msg
= "mmap(ADDR_SWITCH_HINT - PAGE_SIZE, PAGE_SIZE)",
143 .low_addr_required
= 1,
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,
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,
162 .addr
= ((void *)(ADDR_SWITCH_HINT
)),
164 .flags
= MAP_PRIVATE
| MAP_ANONYMOUS
,
165 .msg
= "mmap(ADDR_SWITCH_HINT, PAGE_SIZE)",
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)",
175 static struct testcase hugetlb_testcases
[] = {
178 .size
= HUGETLB_SIZE
,
179 .flags
= MAP_HUGETLB
| MAP_PRIVATE
| MAP_ANONYMOUS
,
180 .msg
= "mmap(NULL, MAP_HUGETLB)",
181 .low_addr_required
= 1,
185 .size
= HUGETLB_SIZE
,
186 .flags
= MAP_HUGETLB
| MAP_PRIVATE
| MAP_ANONYMOUS
,
187 .msg
= "mmap(LOW_ADDR, MAP_HUGETLB)",
188 .low_addr_required
= 1,
192 .size
= HUGETLB_SIZE
,
193 .flags
= MAP_HUGETLB
| MAP_PRIVATE
| MAP_ANONYMOUS
,
194 .msg
= "mmap(HIGH_ADDR, MAP_HUGETLB)",
199 .size
= HUGETLB_SIZE
,
200 .flags
= MAP_HUGETLB
| MAP_PRIVATE
| MAP_ANONYMOUS
,
201 .msg
= "mmap(HIGH_ADDR, MAP_HUGETLB) again",
206 .size
= HUGETLB_SIZE
,
207 .flags
= MAP_HUGETLB
| MAP_PRIVATE
| MAP_ANONYMOUS
| MAP_FIXED
,
208 .msg
= "mmap(HIGH_ADDR, MAP_FIXED | MAP_HUGETLB)",
212 .size
= HUGETLB_SIZE
,
213 .flags
= MAP_HUGETLB
| MAP_PRIVATE
| MAP_ANONYMOUS
,
214 .msg
= "mmap(-1, MAP_HUGETLB)",
219 .size
= HUGETLB_SIZE
,
220 .flags
= MAP_HUGETLB
| MAP_PRIVATE
| MAP_ANONYMOUS
,
221 .msg
= "mmap(-1, MAP_HUGETLB) again",
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,
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)",
239 static int run_test(struct testcase
*test
, int count
)
244 for (i
= 0; i
< count
; i
++) {
245 struct testcase
*t
= test
+ i
;
247 p
= mmap(t
->addr
, t
->size
, PROT_READ
| PROT_WRITE
, t
->flags
, -1, 0);
249 printf("%s: %p - ", t
->msg
, p
);
251 if (p
== MAP_FAILED
) {
257 if (t
->low_addr_required
&& p
>= (void *)(ADDR_SWITCH_HINT
)) {
262 * Do a dereference of the address returned so that we catch
263 * bugs in page fault handling
265 memset(p
, 0, t
->size
);
275 static int supported_arch(void)
277 #if defined(__powerpc64__)
279 #elif defined(__x86_64__)
286 int main(int argc
, char **argv
)
290 if (!supported_arch())
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
));