Linux Audio

Check our new training course

Loading...
Note: File does not exist in v3.15.
  1// SPDX-License-Identifier: GPL-2.0-only
  2/*
  3 *
  4 * Authors: Kirill A. Shutemov <kirill.shutemov@linux.intel.com>
  5 * Authors: Aneesh Kumar K.V <aneesh.kumar@linux.vnet.ibm.com>
  6 */
  7
  8#include <stdio.h>
  9#include <sys/mman.h>
 10#include <string.h>
 11
 12#define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0]))
 13
 14#ifdef __powerpc64__
 15#define PAGE_SIZE	(64 << 10)
 16/*
 17 * This will work with 16M and 2M hugepage size
 18 */
 19#define HUGETLB_SIZE	(16 << 20)
 20#else
 21#define PAGE_SIZE	(4 << 10)
 22#define HUGETLB_SIZE	(2 << 20)
 23#endif
 24
 25/*
 26 * >= 128TB is the hint addr value we used to select
 27 * large address space.
 28 */
 29#define ADDR_SWITCH_HINT (1UL << 47)
 30#define LOW_ADDR	((void *) (1UL << 30))
 31#define HIGH_ADDR	((void *) (1UL << 48))
 32
 33struct testcase {
 34	void *addr;
 35	unsigned long size;
 36	unsigned long flags;
 37	const char *msg;
 38	unsigned int low_addr_required:1;
 39	unsigned int keep_mapped:1;
 40};
 41
 42static struct testcase testcases[] = {
 43	{
 44		/*
 45		 * If stack is moved, we could possibly allocate
 46		 * this at the requested address.
 47		 */
 48		.addr = ((void *)(ADDR_SWITCH_HINT - PAGE_SIZE)),
 49		.size = PAGE_SIZE,
 50		.flags = MAP_PRIVATE | MAP_ANONYMOUS,
 51		.msg = "mmap(ADDR_SWITCH_HINT - PAGE_SIZE, PAGE_SIZE)",
 52		.low_addr_required = 1,
 53	},
 54	{
 55		/*
 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.
 59		 */
 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,
 65	},
 66	{
 67		/*
 68		 * Exact mapping at 128TB, the area is free we should get that
 69		 * even without MAP_FIXED.
 70		 */
 71		.addr = ((void *)(ADDR_SWITCH_HINT)),
 72		.size = PAGE_SIZE,
 73		.flags = MAP_PRIVATE | MAP_ANONYMOUS,
 74		.msg = "mmap(ADDR_SWITCH_HINT, PAGE_SIZE)",
 75		.keep_mapped = 1,
 76	},
 77	{
 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)",
 82	},
 83	{
 84		.addr = NULL,
 85		.size = 2 * PAGE_SIZE,
 86		.flags = MAP_PRIVATE | MAP_ANONYMOUS,
 87		.msg = "mmap(NULL)",
 88		.low_addr_required = 1,
 89	},
 90	{
 91		.addr = LOW_ADDR,
 92		.size = 2 * PAGE_SIZE,
 93		.flags = MAP_PRIVATE | MAP_ANONYMOUS,
 94		.msg = "mmap(LOW_ADDR)",
 95		.low_addr_required = 1,
 96	},
 97	{
 98		.addr = HIGH_ADDR,
 99		.size = 2 * PAGE_SIZE,
100		.flags = MAP_PRIVATE | MAP_ANONYMOUS,
101		.msg = "mmap(HIGH_ADDR)",
102		.keep_mapped = 1,
103	},
104	{
105		.addr = HIGH_ADDR,
106		.size = 2 * PAGE_SIZE,
107		.flags = MAP_PRIVATE | MAP_ANONYMOUS,
108		.msg = "mmap(HIGH_ADDR) again",
109		.keep_mapped = 1,
110	},
111	{
112		.addr = HIGH_ADDR,
113		.size = 2 * PAGE_SIZE,
114		.flags = MAP_PRIVATE | MAP_ANONYMOUS | MAP_FIXED,
115		.msg = "mmap(HIGH_ADDR, MAP_FIXED)",
116	},
117	{
118		.addr = (void *) -1,
119		.size = 2 * PAGE_SIZE,
120		.flags = MAP_PRIVATE | MAP_ANONYMOUS,
121		.msg = "mmap(-1)",
122		.keep_mapped = 1,
123	},
124	{
125		.addr = (void *) -1,
126		.size = 2 * PAGE_SIZE,
127		.flags = MAP_PRIVATE | MAP_ANONYMOUS,
128		.msg = "mmap(-1) again",
129	},
130	{
131		.addr = ((void *)(ADDR_SWITCH_HINT - PAGE_SIZE)),
132		.size = PAGE_SIZE,
133		.flags = MAP_PRIVATE | MAP_ANONYMOUS,
134		.msg = "mmap(ADDR_SWITCH_HINT - PAGE_SIZE, PAGE_SIZE)",
135		.low_addr_required = 1,
136	},
137	{
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,
143		.keep_mapped = 1,
144	},
145	{
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,
151		.keep_mapped = 1,
152	},
153	{
154		.addr = ((void *)(ADDR_SWITCH_HINT)),
155		.size = PAGE_SIZE,
156		.flags = MAP_PRIVATE | MAP_ANONYMOUS,
157		.msg = "mmap(ADDR_SWITCH_HINT, PAGE_SIZE)",
158	},
159	{
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)",
164	},
165};
166
167static struct testcase hugetlb_testcases[] = {
168	{
169		.addr = NULL,
170		.size = HUGETLB_SIZE,
171		.flags = MAP_HUGETLB | MAP_PRIVATE | MAP_ANONYMOUS,
172		.msg = "mmap(NULL, MAP_HUGETLB)",
173		.low_addr_required = 1,
174	},
175	{
176		.addr = LOW_ADDR,
177		.size = HUGETLB_SIZE,
178		.flags = MAP_HUGETLB | MAP_PRIVATE | MAP_ANONYMOUS,
179		.msg = "mmap(LOW_ADDR, MAP_HUGETLB)",
180		.low_addr_required = 1,
181	},
182	{
183		.addr = HIGH_ADDR,
184		.size = HUGETLB_SIZE,
185		.flags = MAP_HUGETLB | MAP_PRIVATE | MAP_ANONYMOUS,
186		.msg = "mmap(HIGH_ADDR, MAP_HUGETLB)",
187		.keep_mapped = 1,
188	},
189	{
190		.addr = HIGH_ADDR,
191		.size = HUGETLB_SIZE,
192		.flags = MAP_HUGETLB | MAP_PRIVATE | MAP_ANONYMOUS,
193		.msg = "mmap(HIGH_ADDR, MAP_HUGETLB) again",
194		.keep_mapped = 1,
195	},
196	{
197		.addr = HIGH_ADDR,
198		.size = HUGETLB_SIZE,
199		.flags = MAP_HUGETLB | MAP_PRIVATE | MAP_ANONYMOUS | MAP_FIXED,
200		.msg = "mmap(HIGH_ADDR, MAP_FIXED | MAP_HUGETLB)",
201	},
202	{
203		.addr = (void *) -1,
204		.size = HUGETLB_SIZE,
205		.flags = MAP_HUGETLB | MAP_PRIVATE | MAP_ANONYMOUS,
206		.msg = "mmap(-1, MAP_HUGETLB)",
207		.keep_mapped = 1,
208	},
209	{
210		.addr = (void *) -1,
211		.size = HUGETLB_SIZE,
212		.flags = MAP_HUGETLB | MAP_PRIVATE | MAP_ANONYMOUS,
213		.msg = "mmap(-1, MAP_HUGETLB) again",
214	},
215	{
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,
221		.keep_mapped = 1,
222	},
223	{
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)",
228	},
229};
230
231static int run_test(struct testcase *test, int count)
232{
233	void *p;
234	int i, ret = 0;
235
236	for (i = 0; i < count; i++) {
237		struct testcase *t = test + i;
238
239		p = mmap(t->addr, t->size, PROT_READ | PROT_WRITE, t->flags, -1, 0);
240
241		printf("%s: %p - ", t->msg, p);
242
243		if (p == MAP_FAILED) {
244			printf("FAILED\n");
245			ret = 1;
246			continue;
247		}
248
249		if (t->low_addr_required && p >= (void *)(ADDR_SWITCH_HINT)) {
250			printf("FAILED\n");
251			ret = 1;
252		} else {
253			/*
254			 * Do a dereference of the address returned so that we catch
255			 * bugs in page fault handling
256			 */
257			memset(p, 0, t->size);
258			printf("OK\n");
259		}
260		if (!t->keep_mapped)
261			munmap(p, t->size);
262	}
263
264	return ret;
265}
266
267static int supported_arch(void)
268{
269#if defined(__powerpc64__)
270	return 1;
271#elif defined(__x86_64__)
272	return 1;
273#else
274	return 0;
275#endif
276}
277
278int main(int argc, char **argv)
279{
280	int ret;
281
282	if (!supported_arch())
283		return 0;
284
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));
288	return ret;
289}