Linux-libre 4.19.116-gnu
[librecmc/linux-libre.git] / tools / testing / selftests / vm / va_128TBswitch.c
1 /*
2  *
3  * Authors: Kirill A. Shutemov <kirill.shutemov@linux.intel.com>
4  * Authors: Aneesh Kumar K.V <aneesh.kumar@linux.vnet.ibm.com>
5  *
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.
9
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.
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  * This will work with 16M and 2M hugepage size
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  * >= 128TB is the hint addr value we used to select
35  * large address space.
36  */
37 #define ADDR_SWITCH_HINT (1UL << 47)
38 #define LOW_ADDR        ((void *) (1UL << 30))
39 #define HIGH_ADDR       ((void *) (1UL << 48))
40
41 struct 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
50 static struct testcase testcases[] = {
51         {
52                 /*
53                  * If stack is moved, we could possibly allocate
54                  * this at the requested address.
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                  * 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.
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                  * Exact mapping at 128TB, the area is free we should get that
77                  * even without MAP_FIXED.
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
175 static 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
239 static 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                          * Do a dereference of the address returned so that we catch
263                          * bugs in page fault handling
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
275 static 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
286 int 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 }