xref: /openbmc/qemu/tests/tcg/multiarch/test-mmap.c (revision 709395f8)
1 /*
2  * Small test program to verify simulated mmap behaviour.
3  *
4  * When running qemu-linux-user with the -p flag, you may need to tell
5  * this test program about the pagesize because getpagesize() will not reflect
6  * the -p choice. Simply pass one argument being the pagesize.
7  *
8  * Copyright (c) 2007 AXIS Communications AB
9  * Written by Edgar E. Iglesias.
10  *
11  * This program is free software; you can redistribute it and/or modify
12  * it under the terms of the GNU General Public License as published by
13  * the Free Software Foundation; either version 2 of the License, or
14  * (at your option) any later version.
15  *
16  * This program is distributed in the hope that it will be useful,
17  * but WITHOUT ANY WARRANTY; without even the implied warranty of
18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19  * GNU General Public License for more details.
20  *
21  * You should have received a copy of the GNU General Public License
22  * along with this program; if not, see <http://www.gnu.org/licenses/>.
23  */
24 
25 #include <stdio.h>
26 #include <stdlib.h>
27 #include <stdint.h>
28 #include <string.h>
29 #include <unistd.h>
30 #include <errno.h>
31 #include <sys/mman.h>
32 
33 #define D(x)
34 
35 #define fail_unless(x)                                         \
36 do                                                             \
37 {                                                              \
38   if (!(x)) {                                                  \
39     fprintf(stderr, "FAILED at %s:%d\n", __FILE__, __LINE__); \
40     exit (EXIT_FAILURE);                                       \
41   }                                                            \
42 } while (0)
43 
44 unsigned char *dummybuf;
45 static unsigned int pagesize;
46 static unsigned int pagemask;
47 int test_fd;
48 size_t test_fsize;
49 
50 void check_aligned_anonymous_unfixed_mmaps(void)
51 {
52 	void *p1;
53 	void *p2;
54 	void *p3;
55 	void *p4;
56 	void *p5;
57 	uintptr_t p;
58 	int i;
59 
60 	fprintf(stdout, "%s", __func__);
61 	for (i = 0; i < 0x1fff; i++)
62 	{
63 		size_t len;
64 
65 		len = pagesize + (pagesize * i & 7);
66 		p1 = mmap(NULL, len, PROT_READ,
67 			  MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
68 		p2 = mmap(NULL, len, PROT_READ,
69 			  MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
70 		p3 = mmap(NULL, len, PROT_READ,
71 			  MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
72 		p4 = mmap(NULL, len, PROT_READ,
73 			  MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
74 		p5 = mmap(NULL, len, PROT_READ,
75 			  MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
76 
77 		/* Make sure we get pages aligned with the pagesize. The
78 		   target expects this.  */
79 		fail_unless (p1 != MAP_FAILED);
80 		fail_unless (p2 != MAP_FAILED);
81 		fail_unless (p3 != MAP_FAILED);
82 		fail_unless (p4 != MAP_FAILED);
83 		fail_unless (p5 != MAP_FAILED);
84 		p = (uintptr_t) p1;
85 		D(printf ("p=%x\n", p));
86 		fail_unless ((p & pagemask) == 0);
87 		p = (uintptr_t) p2;
88 		fail_unless ((p & pagemask) == 0);
89 		p = (uintptr_t) p3;
90 		fail_unless ((p & pagemask) == 0);
91 		p = (uintptr_t) p4;
92 		fail_unless ((p & pagemask) == 0);
93 		p = (uintptr_t) p5;
94 		fail_unless ((p & pagemask) == 0);
95 
96 		/* Make sure we can read from the entire area.  */
97 		memcpy (dummybuf, p1, pagesize);
98 		memcpy (dummybuf, p2, pagesize);
99 		memcpy (dummybuf, p3, pagesize);
100 		memcpy (dummybuf, p4, pagesize);
101 		memcpy (dummybuf, p5, pagesize);
102 
103 		munmap (p1, len);
104 		munmap (p2, len);
105 		munmap (p3, len);
106 		munmap (p4, len);
107 		munmap (p5, len);
108 	}
109 	fprintf(stdout, " passed\n");
110 }
111 
112 void check_large_anonymous_unfixed_mmap(void)
113 {
114 	void *p1;
115 	uintptr_t p;
116 	size_t len;
117 
118 	fprintf(stdout, "%s", __func__);
119 
120 	len = 0x02000000;
121 	p1 = mmap(NULL, len, PROT_READ,
122 		  MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
123 
124 	/* Make sure we get pages aligned with the pagesize. The
125 	   target expects this.  */
126 	fail_unless (p1 != MAP_FAILED);
127 	p = (uintptr_t) p1;
128 	fail_unless ((p & pagemask) == 0);
129 
130 	/* Make sure we can read from the entire area.  */
131 	memcpy (dummybuf, p1, pagesize);
132 	munmap (p1, len);
133 	fprintf(stdout, " passed\n");
134 }
135 
136 void check_aligned_anonymous_unfixed_colliding_mmaps(void)
137 {
138 	char *p1;
139 	char *p2;
140 	char *p3;
141 	uintptr_t p;
142 	int i;
143 
144 	fprintf(stdout, "%s", __func__);
145 	for (i = 0; i < 0x2fff; i++)
146 	{
147 		int nlen;
148 		p1 = mmap(NULL, pagesize, PROT_READ,
149 			  MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
150 		fail_unless (p1 != MAP_FAILED);
151 		p = (uintptr_t) p1;
152 		fail_unless ((p & pagemask) == 0);
153 		memcpy (dummybuf, p1, pagesize);
154 
155 		p2 = mmap(NULL, pagesize, PROT_READ,
156 			  MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
157 		fail_unless (p2 != MAP_FAILED);
158 		p = (uintptr_t) p2;
159 		fail_unless ((p & pagemask) == 0);
160 		memcpy (dummybuf, p2, pagesize);
161 
162 
163 		munmap (p1, pagesize);
164 		nlen = pagesize * 8;
165 		p3 = mmap(NULL, nlen, PROT_READ,
166 			  MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
167 		fail_unless (p3 != MAP_FAILED);
168 
169 		/* Check if the mmaped areas collide.  */
170 		if (p3 < p2
171 		    && (p3 + nlen) > p2)
172 			fail_unless (0);
173 
174 		memcpy (dummybuf, p3, pagesize);
175 
176 		/* Make sure we get pages aligned with the pagesize. The
177 		   target expects this.  */
178 		p = (uintptr_t) p3;
179 		fail_unless ((p & pagemask) == 0);
180 		munmap (p2, pagesize);
181 		munmap (p3, nlen);
182 	}
183 	fprintf(stdout, " passed\n");
184 }
185 
186 void check_aligned_anonymous_fixed_mmaps(void)
187 {
188 	char *addr;
189 	void *p1;
190 	uintptr_t p;
191 	int i;
192 
193 	/* Find a suitable address to start with.  */
194 	addr = mmap(NULL, pagesize * 40, PROT_READ | PROT_WRITE,
195 		    MAP_PRIVATE | MAP_ANONYMOUS,
196 		    -1, 0);
197 	fprintf(stdout, "%s addr=%p", __func__, addr);
198 	fail_unless (addr != MAP_FAILED);
199 
200 	for (i = 0; i < 40; i++)
201 	{
202 		/* Create submaps within our unfixed map.  */
203 		p1 = mmap(addr, pagesize, PROT_READ,
204 			  MAP_PRIVATE | MAP_ANONYMOUS | MAP_FIXED,
205 			  -1, 0);
206 		/* Make sure we get pages aligned with the pagesize.
207 		   The target expects this.  */
208 		p = (uintptr_t) p1;
209 		fail_unless (p1 == addr);
210 		fail_unless ((p & pagemask) == 0);
211 		memcpy (dummybuf, p1, pagesize);
212 		munmap (p1, pagesize);
213 		addr += pagesize;
214 	}
215 	fprintf(stdout, " passed\n");
216 }
217 
218 void check_aligned_anonymous_fixed_mmaps_collide_with_host(void)
219 {
220 	char *addr;
221 	void *p1;
222 	uintptr_t p;
223 	int i;
224 
225 	/* Find a suitable address to start with.  Right were the x86 hosts
226 	 stack is.  */
227 	addr = ((void *)0x80000000);
228 	fprintf(stdout, "%s addr=%p", __func__, addr);
229 	fprintf(stdout, "FIXME: QEMU fails to track pages used by the host.");
230 
231 	for (i = 0; i < 20; i++)
232 	{
233 		/* Create submaps within our unfixed map.  */
234 		p1 = mmap(addr, pagesize, PROT_READ | PROT_WRITE,
235 			  MAP_PRIVATE | MAP_ANONYMOUS | MAP_FIXED,
236 			  -1, 0);
237 		/* Make sure we get pages aligned with the pagesize.
238 		   The target expects this.  */
239 		p = (uintptr_t) p1;
240 		fail_unless (p1 == addr);
241 		fail_unless ((p & pagemask) == 0);
242 		memcpy (p1, dummybuf, pagesize);
243 		munmap (p1, pagesize);
244 		addr += pagesize;
245 	}
246 	fprintf(stdout, " passed\n");
247 }
248 
249 void check_file_unfixed_mmaps(void)
250 {
251 	unsigned int *p1, *p2, *p3;
252 	uintptr_t p;
253 	int i;
254 
255 	fprintf(stdout, "%s", __func__);
256 	for (i = 0; i < 0x10; i++)
257 	{
258 		size_t len;
259 
260 		len = pagesize;
261 		p1 = mmap(NULL, len, PROT_READ,
262 			  MAP_PRIVATE,
263 			  test_fd, 0);
264 		p2 = mmap(NULL, len, PROT_READ,
265 			  MAP_PRIVATE,
266 			  test_fd, pagesize);
267 		p3 = mmap(NULL, len, PROT_READ,
268 			  MAP_PRIVATE,
269 			  test_fd, pagesize * 2);
270 
271 		fail_unless (p1 != MAP_FAILED);
272 		fail_unless (p2 != MAP_FAILED);
273 		fail_unless (p3 != MAP_FAILED);
274 
275 		/* Make sure we get pages aligned with the pagesize. The
276 		   target expects this.  */
277 		p = (uintptr_t) p1;
278 		fail_unless ((p & pagemask) == 0);
279 		p = (uintptr_t) p2;
280 		fail_unless ((p & pagemask) == 0);
281 		p = (uintptr_t) p3;
282 		fail_unless ((p & pagemask) == 0);
283 
284 		/* Verify that the file maps was made correctly.  */
285 		D(printf ("p1=%d p2=%d p3=%d\n", *p1, *p2, *p3));
286 		fail_unless (*p1 == 0);
287 		fail_unless (*p2 == (pagesize / sizeof *p2));
288 		fail_unless (*p3 == ((pagesize * 2) / sizeof *p3));
289 
290 		memcpy (dummybuf, p1, pagesize);
291 		memcpy (dummybuf, p2, pagesize);
292 		memcpy (dummybuf, p3, pagesize);
293 		munmap (p1, len);
294 		munmap (p2, len);
295 		munmap (p3, len);
296 	}
297 	fprintf(stdout, " passed\n");
298 }
299 
300 void check_file_unfixed_eof_mmaps(void)
301 {
302 	char *cp;
303 	unsigned int *p1;
304 	uintptr_t p;
305 	int i;
306 
307 	fprintf(stdout, "%s", __func__);
308 	for (i = 0; i < 0x10; i++)
309 	{
310 		p1 = mmap(NULL, pagesize, PROT_READ,
311 			  MAP_PRIVATE,
312 			  test_fd,
313 			  (test_fsize - sizeof *p1) & ~pagemask);
314 
315 		fail_unless (p1 != MAP_FAILED);
316 
317 		/* Make sure we get pages aligned with the pagesize. The
318 		   target expects this.  */
319 		p = (uintptr_t) p1;
320 		fail_unless ((p & pagemask) == 0);
321 		/* Verify that the file maps was made correctly.  */
322 		fail_unless (p1[(test_fsize & pagemask) / sizeof *p1 - 1]
323 			     == ((test_fsize - sizeof *p1) / sizeof *p1));
324 
325 		/* Verify that the end of page is accessible and zeroed.  */
326 		cp = (void *) p1;
327 		fail_unless (cp[pagesize - 4] == 0);
328 		munmap (p1, pagesize);
329 	}
330 	fprintf(stdout, " passed\n");
331 }
332 
333 void check_file_fixed_eof_mmaps(void)
334 {
335 	char *addr;
336 	char *cp;
337 	unsigned int *p1;
338 	uintptr_t p;
339 	int i;
340 
341 	/* Find a suitable address to start with.  */
342 	addr = mmap(NULL, pagesize * 44, PROT_READ,
343 		    MAP_PRIVATE | MAP_ANONYMOUS,
344 		    -1, 0);
345 
346 	fprintf(stdout, "%s addr=%p", __func__, (void *)addr);
347 	fail_unless (addr != MAP_FAILED);
348 
349 	for (i = 0; i < 0x10; i++)
350 	{
351 		/* Create submaps within our unfixed map.  */
352 		p1 = mmap(addr, pagesize, PROT_READ,
353 			  MAP_PRIVATE | MAP_FIXED,
354 			  test_fd,
355 			  (test_fsize - sizeof *p1) & ~pagemask);
356 
357 		fail_unless (p1 != MAP_FAILED);
358 
359 		/* Make sure we get pages aligned with the pagesize. The
360 		   target expects this.  */
361 		p = (uintptr_t) p1;
362 		fail_unless ((p & pagemask) == 0);
363 
364 		/* Verify that the file maps was made correctly.  */
365 		fail_unless (p1[(test_fsize & pagemask) / sizeof *p1 - 1]
366 			     == ((test_fsize - sizeof *p1) / sizeof *p1));
367 
368 		/* Verify that the end of page is accessible and zeroed.  */
369 		cp = (void *)p1;
370 		fail_unless (cp[pagesize - 4] == 0);
371 		munmap (p1, pagesize);
372 		addr += pagesize;
373 	}
374 	fprintf(stdout, " passed\n");
375 }
376 
377 void check_file_fixed_mmaps(void)
378 {
379 	unsigned char *addr;
380 	unsigned int *p1, *p2, *p3, *p4;
381 	int i;
382 
383 	/* Find a suitable address to start with.  */
384 	addr = mmap(NULL, pagesize * 40 * 4, PROT_READ,
385 		    MAP_PRIVATE | MAP_ANONYMOUS,
386 		    -1, 0);
387 	fprintf(stdout, "%s addr=%p", __func__, (void *)addr);
388 	fail_unless (addr != MAP_FAILED);
389 
390 	for (i = 0; i < 40; i++)
391 	{
392 		p1 = mmap(addr, pagesize, PROT_READ,
393 			  MAP_PRIVATE | MAP_FIXED,
394 			  test_fd, 0);
395 		p2 = mmap(addr + pagesize, pagesize, PROT_READ,
396 			  MAP_PRIVATE | MAP_FIXED,
397 			  test_fd, pagesize);
398 		p3 = mmap(addr + pagesize * 2, pagesize, PROT_READ,
399 			  MAP_PRIVATE | MAP_FIXED,
400 			  test_fd, pagesize * 2);
401 		p4 = mmap(addr + pagesize * 3, pagesize, PROT_READ,
402 			  MAP_PRIVATE | MAP_FIXED,
403 			  test_fd, pagesize * 3);
404 
405 		/* Make sure we get pages aligned with the pagesize.
406 		   The target expects this.  */
407 		fail_unless (p1 == (void *)addr);
408 		fail_unless (p2 == (void *)addr + pagesize);
409 		fail_unless (p3 == (void *)addr + pagesize * 2);
410 		fail_unless (p4 == (void *)addr + pagesize * 3);
411 
412 		/* Verify that the file maps was made correctly.  */
413 		fail_unless (*p1 == 0);
414 		fail_unless (*p2 == (pagesize / sizeof *p2));
415 		fail_unless (*p3 == ((pagesize * 2) / sizeof *p3));
416 		fail_unless (*p4 == ((pagesize * 3) / sizeof *p4));
417 
418 		memcpy (dummybuf, p1, pagesize);
419 		memcpy (dummybuf, p2, pagesize);
420 		memcpy (dummybuf, p3, pagesize);
421 		memcpy (dummybuf, p4, pagesize);
422 
423 		munmap (p1, pagesize);
424 		munmap (p2, pagesize);
425 		munmap (p3, pagesize);
426 		munmap (p4, pagesize);
427 		addr += pagesize * 4;
428 	}
429 	fprintf(stdout, " passed\n");
430 }
431 
432 void checked_write(int fd, const void *buf, size_t count)
433 {
434     ssize_t rc = write(fd, buf, count);
435     fail_unless(rc == count);
436 }
437 
438 void check_invalid_mmaps(void)
439 {
440     unsigned char *addr;
441 
442     /* Attempt to map a zero length page.  */
443     addr = mmap(NULL, 0, PROT_READ, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
444     fprintf(stdout, "%s addr=%p", __func__, (void *)addr);
445     fail_unless(addr == MAP_FAILED);
446     fail_unless(errno == EINVAL);
447 
448     /* Attempt to map a over length page.  */
449     addr = mmap(NULL, -4, PROT_READ, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
450     fprintf(stdout, "%s addr=%p", __func__, (void *)addr);
451     fail_unless(addr == MAP_FAILED);
452     fail_unless(errno == ENOMEM);
453 
454     fprintf(stdout, " passed\n");
455 }
456 
457 int main(int argc, char **argv)
458 {
459 	char tempname[] = "/tmp/.cmmapXXXXXX";
460 	unsigned int i;
461 
462 	/* Trust the first argument, otherwise probe the system for our
463 	   pagesize.  */
464 	if (argc > 1)
465 		pagesize = strtoul(argv[1], NULL, 0);
466 	else
467 		pagesize = sysconf(_SC_PAGESIZE);
468 
469 	/* Assume pagesize is a power of two.  */
470 	pagemask = pagesize - 1;
471 	dummybuf = malloc (pagesize);
472 	printf ("pagesize=%u pagemask=%x\n", pagesize, pagemask);
473 
474 	test_fd = mkstemp(tempname);
475 	unlink(tempname);
476 
477 	/* Fill the file with int's counting from zero and up.  */
478     for (i = 0; i < (pagesize * 4) / sizeof i; i++) {
479         checked_write(test_fd, &i, sizeof i);
480     }
481 
482 	/* Append a few extra writes to make the file end at non
483 	   page boundary.  */
484     checked_write(test_fd, &i, sizeof i); i++;
485     checked_write(test_fd, &i, sizeof i); i++;
486     checked_write(test_fd, &i, sizeof i); i++;
487 
488 	test_fsize = lseek(test_fd, 0, SEEK_CUR);
489 
490 	/* Run the tests.  */
491 	check_aligned_anonymous_unfixed_mmaps();
492 	check_aligned_anonymous_unfixed_colliding_mmaps();
493 	check_aligned_anonymous_fixed_mmaps();
494 	check_file_unfixed_mmaps();
495 	check_file_fixed_mmaps();
496 	check_file_fixed_eof_mmaps();
497 	check_file_unfixed_eof_mmaps();
498 	check_invalid_mmaps();
499 
500 	/* Fails at the moment.  */
501 	/* check_aligned_anonymous_fixed_mmaps_collide_with_host(); */
502 
503 	return EXIT_SUCCESS;
504 }
505