1 // SPDX-License-Identifier: GPL-2.0-only
4 * Authors: Kirill A. Shutemov <kirill.shutemov@linux.intel.com>
5 * Authors: Aneesh Kumar K.V <aneesh.kumar@linux.vnet.ibm.com>
12 #define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0]))
15 #define PAGE_SIZE (64 << 10)
17 * This will work with 16M and 2M hugepage size
19 #define HUGETLB_SIZE (16 << 20)
21 #define PAGE_SIZE (4 << 10)
22 #define HUGETLB_SIZE (2 << 20)
26 * >= 128TB is the hint addr value we used to select
27 * large address space.
29 #define ADDR_SWITCH_HINT (1UL << 47)
30 #define LOW_ADDR ((void *) (1UL << 30))
31 #define HIGH_ADDR ((void *) (1UL << 48))
38 unsigned int low_addr_required
:1;
39 unsigned int keep_mapped
:1;
42 static struct testcase testcases
[] = {
45 * If stack is moved, we could possibly allocate
46 * this at the requested address.
48 .addr
= ((void *)(ADDR_SWITCH_HINT
- PAGE_SIZE
)),
50 .flags
= MAP_PRIVATE
| MAP_ANONYMOUS
,
51 .msg
= "mmap(ADDR_SWITCH_HINT - PAGE_SIZE, PAGE_SIZE)",
52 .low_addr_required
= 1,
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.
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,
68 * Exact mapping at 128TB, the area is free we should get that
69 * even without MAP_FIXED.
71 .addr
= ((void *)(ADDR_SWITCH_HINT
)),
73 .flags
= MAP_PRIVATE
| MAP_ANONYMOUS
,
74 .msg
= "mmap(ADDR_SWITCH_HINT, PAGE_SIZE)",
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)",
85 .size
= 2 * PAGE_SIZE
,
86 .flags
= MAP_PRIVATE
| MAP_ANONYMOUS
,
88 .low_addr_required
= 1,
92 .size
= 2 * PAGE_SIZE
,
93 .flags
= MAP_PRIVATE
| MAP_ANONYMOUS
,
94 .msg
= "mmap(LOW_ADDR)",
95 .low_addr_required
= 1,
99 .size
= 2 * PAGE_SIZE
,
100 .flags
= MAP_PRIVATE
| MAP_ANONYMOUS
,
101 .msg
= "mmap(HIGH_ADDR)",
106 .size
= 2 * PAGE_SIZE
,
107 .flags
= MAP_PRIVATE
| MAP_ANONYMOUS
,
108 .msg
= "mmap(HIGH_ADDR) again",
113 .size
= 2 * PAGE_SIZE
,
114 .flags
= MAP_PRIVATE
| MAP_ANONYMOUS
| MAP_FIXED
,
115 .msg
= "mmap(HIGH_ADDR, MAP_FIXED)",
119 .size
= 2 * PAGE_SIZE
,
120 .flags
= MAP_PRIVATE
| MAP_ANONYMOUS
,
126 .size
= 2 * PAGE_SIZE
,
127 .flags
= MAP_PRIVATE
| MAP_ANONYMOUS
,
128 .msg
= "mmap(-1) again",
131 .addr
= ((void *)(ADDR_SWITCH_HINT
- PAGE_SIZE
)),
133 .flags
= MAP_PRIVATE
| MAP_ANONYMOUS
,
134 .msg
= "mmap(ADDR_SWITCH_HINT - PAGE_SIZE, PAGE_SIZE)",
135 .low_addr_required
= 1,
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,
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,
154 .addr
= ((void *)(ADDR_SWITCH_HINT
)),
156 .flags
= MAP_PRIVATE
| MAP_ANONYMOUS
,
157 .msg
= "mmap(ADDR_SWITCH_HINT, PAGE_SIZE)",
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)",
167 static struct testcase hugetlb_testcases
[] = {
170 .size
= HUGETLB_SIZE
,
171 .flags
= MAP_HUGETLB
| MAP_PRIVATE
| MAP_ANONYMOUS
,
172 .msg
= "mmap(NULL, MAP_HUGETLB)",
173 .low_addr_required
= 1,
177 .size
= HUGETLB_SIZE
,
178 .flags
= MAP_HUGETLB
| MAP_PRIVATE
| MAP_ANONYMOUS
,
179 .msg
= "mmap(LOW_ADDR, MAP_HUGETLB)",
180 .low_addr_required
= 1,
184 .size
= HUGETLB_SIZE
,
185 .flags
= MAP_HUGETLB
| MAP_PRIVATE
| MAP_ANONYMOUS
,
186 .msg
= "mmap(HIGH_ADDR, MAP_HUGETLB)",
191 .size
= HUGETLB_SIZE
,
192 .flags
= MAP_HUGETLB
| MAP_PRIVATE
| MAP_ANONYMOUS
,
193 .msg
= "mmap(HIGH_ADDR, MAP_HUGETLB) again",
198 .size
= HUGETLB_SIZE
,
199 .flags
= MAP_HUGETLB
| MAP_PRIVATE
| MAP_ANONYMOUS
| MAP_FIXED
,
200 .msg
= "mmap(HIGH_ADDR, MAP_FIXED | MAP_HUGETLB)",
204 .size
= HUGETLB_SIZE
,
205 .flags
= MAP_HUGETLB
| MAP_PRIVATE
| MAP_ANONYMOUS
,
206 .msg
= "mmap(-1, MAP_HUGETLB)",
211 .size
= HUGETLB_SIZE
,
212 .flags
= MAP_HUGETLB
| MAP_PRIVATE
| MAP_ANONYMOUS
,
213 .msg
= "mmap(-1, MAP_HUGETLB) again",
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,
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)",
231 static int run_test(struct testcase
*test
, int count
)
236 for (i
= 0; i
< count
; i
++) {
237 struct testcase
*t
= test
+ i
;
239 p
= mmap(t
->addr
, t
->size
, PROT_READ
| PROT_WRITE
, t
->flags
, -1, 0);
241 printf("%s: %p - ", t
->msg
, p
);
243 if (p
== MAP_FAILED
) {
249 if (t
->low_addr_required
&& p
>= (void *)(ADDR_SWITCH_HINT
)) {
254 * Do a dereference of the address returned so that we catch
255 * bugs in page fault handling
257 memset(p
, 0, t
->size
);
267 static int supported_arch(void)
269 #if defined(__powerpc64__)
271 #elif defined(__x86_64__)
278 int main(int argc
, char **argv
)
282 if (!supported_arch())
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
));