|
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 beeing 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, write to the Free Software |
|
23 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. |
|
24 */ |
|
25 |
|
26 #include <stdio.h> |
|
27 #include <stdlib.h> |
|
28 #include <stdint.h> |
|
29 #include <string.h> |
|
30 #include <unistd.h> |
|
31 |
|
32 #include <sys/mman.h> |
|
33 |
|
34 #define D(x) |
|
35 |
|
36 #define fail_unless(x) \ |
|
37 do \ |
|
38 { \ |
|
39 if (!(x)) { \ |
|
40 fprintf (stderr, "FAILED at %s:%d\n", __FILE__, __LINE__); \ |
|
41 exit (EXIT_FAILURE); \ |
|
42 } \ |
|
43 } while (0); |
|
44 |
|
45 unsigned char *dummybuf; |
|
46 static unsigned int pagesize; |
|
47 static unsigned int pagemask; |
|
48 int test_fd; |
|
49 size_t test_fsize; |
|
50 |
|
51 void check_aligned_anonymous_unfixed_mmaps(void) |
|
52 { |
|
53 void *p1; |
|
54 void *p2; |
|
55 void *p3; |
|
56 void *p4; |
|
57 void *p5; |
|
58 uintptr_t p; |
|
59 int i; |
|
60 |
|
61 fprintf (stderr, "%s", __func__); |
|
62 for (i = 0; i < 0x1fff; i++) |
|
63 { |
|
64 size_t len; |
|
65 |
|
66 len = pagesize + (pagesize * i & 7); |
|
67 p1 = mmap(NULL, len, PROT_READ, |
|
68 MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); |
|
69 p2 = mmap(NULL, len, PROT_READ, |
|
70 MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); |
|
71 p3 = mmap(NULL, len, PROT_READ, |
|
72 MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); |
|
73 p4 = mmap(NULL, len, PROT_READ, |
|
74 MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); |
|
75 p5 = mmap(NULL, len, PROT_READ, |
|
76 MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); |
|
77 |
|
78 /* Make sure we get pages aligned with the pagesize. The |
|
79 target expects this. */ |
|
80 fail_unless (p1 != MAP_FAILED); |
|
81 fail_unless (p2 != MAP_FAILED); |
|
82 fail_unless (p3 != MAP_FAILED); |
|
83 fail_unless (p4 != MAP_FAILED); |
|
84 fail_unless (p5 != MAP_FAILED); |
|
85 p = (uintptr_t) p1; |
|
86 D(printf ("p=%x\n", p)); |
|
87 fail_unless ((p & pagemask) == 0); |
|
88 p = (uintptr_t) p2; |
|
89 fail_unless ((p & pagemask) == 0); |
|
90 p = (uintptr_t) p3; |
|
91 fail_unless ((p & pagemask) == 0); |
|
92 p = (uintptr_t) p4; |
|
93 fail_unless ((p & pagemask) == 0); |
|
94 p = (uintptr_t) p5; |
|
95 fail_unless ((p & pagemask) == 0); |
|
96 |
|
97 /* Make sure we can read from the entire area. */ |
|
98 memcpy (dummybuf, p1, pagesize); |
|
99 memcpy (dummybuf, p2, pagesize); |
|
100 memcpy (dummybuf, p3, pagesize); |
|
101 memcpy (dummybuf, p4, pagesize); |
|
102 memcpy (dummybuf, p5, pagesize); |
|
103 |
|
104 munmap (p1, len); |
|
105 munmap (p2, len); |
|
106 munmap (p3, len); |
|
107 munmap (p4, len); |
|
108 munmap (p5, len); |
|
109 } |
|
110 fprintf (stderr, " passed\n"); |
|
111 } |
|
112 |
|
113 void check_large_anonymous_unfixed_mmap(void) |
|
114 { |
|
115 void *p1; |
|
116 uintptr_t p; |
|
117 size_t len; |
|
118 |
|
119 fprintf (stderr, "%s", __func__); |
|
120 |
|
121 len = 0x02000000; |
|
122 p1 = mmap(NULL, len, PROT_READ, |
|
123 MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); |
|
124 |
|
125 /* Make sure we get pages aligned with the pagesize. The |
|
126 target expects this. */ |
|
127 fail_unless (p1 != MAP_FAILED); |
|
128 p = (uintptr_t) p1; |
|
129 fail_unless ((p & pagemask) == 0); |
|
130 |
|
131 /* Make sure we can read from the entire area. */ |
|
132 memcpy (dummybuf, p1, pagesize); |
|
133 munmap (p1, len); |
|
134 fprintf (stderr, " passed\n"); |
|
135 } |
|
136 |
|
137 void check_aligned_anonymous_unfixed_colliding_mmaps(void) |
|
138 { |
|
139 char *p1; |
|
140 char *p2; |
|
141 char *p3; |
|
142 uintptr_t p; |
|
143 int i; |
|
144 |
|
145 fprintf (stderr, "%s", __func__); |
|
146 for (i = 0; i < 0x2fff; i++) |
|
147 { |
|
148 int nlen; |
|
149 p1 = mmap(NULL, pagesize, PROT_READ, |
|
150 MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); |
|
151 fail_unless (p1 != MAP_FAILED); |
|
152 p = (uintptr_t) p1; |
|
153 fail_unless ((p & pagemask) == 0); |
|
154 memcpy (dummybuf, p1, pagesize); |
|
155 |
|
156 p2 = mmap(NULL, pagesize, PROT_READ, |
|
157 MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); |
|
158 fail_unless (p2 != MAP_FAILED); |
|
159 p = (uintptr_t) p2; |
|
160 fail_unless ((p & pagemask) == 0); |
|
161 memcpy (dummybuf, p2, pagesize); |
|
162 |
|
163 |
|
164 munmap (p1, pagesize); |
|
165 nlen = pagesize * 8; |
|
166 p3 = mmap(NULL, nlen, PROT_READ, |
|
167 MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); |
|
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 fail_unless (p3 != MAP_FAILED); |
|
179 p = (uintptr_t) p3; |
|
180 fail_unless ((p & pagemask) == 0); |
|
181 munmap (p2, pagesize); |
|
182 munmap (p3, nlen); |
|
183 } |
|
184 fprintf (stderr, " passed\n"); |
|
185 } |
|
186 |
|
187 void check_aligned_anonymous_fixed_mmaps(void) |
|
188 { |
|
189 char *addr; |
|
190 void *p1; |
|
191 uintptr_t p; |
|
192 int i; |
|
193 |
|
194 /* Find a suitable address to start with. */ |
|
195 addr = mmap(NULL, pagesize * 40, PROT_READ | PROT_WRITE, |
|
196 MAP_PRIVATE | MAP_ANONYMOUS, |
|
197 -1, 0); |
|
198 fprintf (stderr, "%s addr=%p", __func__, addr); |
|
199 fail_unless (addr != MAP_FAILED); |
|
200 |
|
201 for (i = 0; i < 40; i++) |
|
202 { |
|
203 /* Create submaps within our unfixed map. */ |
|
204 p1 = mmap(addr, pagesize, PROT_READ, |
|
205 MAP_PRIVATE | MAP_ANONYMOUS | MAP_FIXED, |
|
206 -1, 0); |
|
207 /* Make sure we get pages aligned with the pagesize. |
|
208 The target expects this. */ |
|
209 p = (uintptr_t) p1; |
|
210 fail_unless (p1 == addr); |
|
211 fail_unless ((p & pagemask) == 0); |
|
212 memcpy (dummybuf, p1, pagesize); |
|
213 munmap (p1, pagesize); |
|
214 addr += pagesize; |
|
215 } |
|
216 fprintf (stderr, " passed\n"); |
|
217 } |
|
218 |
|
219 void check_aligned_anonymous_fixed_mmaps_collide_with_host(void) |
|
220 { |
|
221 char *addr; |
|
222 void *p1; |
|
223 uintptr_t p; |
|
224 int i; |
|
225 |
|
226 /* Find a suitable address to start with. Right were the x86 hosts |
|
227 stack is. */ |
|
228 addr = ((void *)0x80000000); |
|
229 fprintf (stderr, "%s addr=%p", __func__, addr); |
|
230 fprintf (stderr, "FIXME: QEMU fails to track pages used by the host."); |
|
231 |
|
232 for (i = 0; i < 20; i++) |
|
233 { |
|
234 /* Create submaps within our unfixed map. */ |
|
235 p1 = mmap(addr, pagesize, PROT_READ | PROT_WRITE, |
|
236 MAP_PRIVATE | MAP_ANONYMOUS | MAP_FIXED, |
|
237 -1, 0); |
|
238 /* Make sure we get pages aligned with the pagesize. |
|
239 The target expects this. */ |
|
240 p = (uintptr_t) p1; |
|
241 fail_unless (p1 == addr); |
|
242 fail_unless ((p & pagemask) == 0); |
|
243 memcpy (p1, dummybuf, pagesize); |
|
244 munmap (p1, pagesize); |
|
245 addr += pagesize; |
|
246 } |
|
247 fprintf (stderr, " passed\n"); |
|
248 } |
|
249 |
|
250 void check_file_unfixed_mmaps(void) |
|
251 { |
|
252 unsigned int *p1, *p2, *p3; |
|
253 uintptr_t p; |
|
254 int i; |
|
255 |
|
256 fprintf (stderr, "%s", __func__); |
|
257 for (i = 0; i < 0x10; i++) |
|
258 { |
|
259 size_t len; |
|
260 |
|
261 len = pagesize; |
|
262 p1 = mmap(NULL, len, PROT_READ, |
|
263 MAP_PRIVATE, |
|
264 test_fd, 0); |
|
265 p2 = mmap(NULL, len, PROT_READ, |
|
266 MAP_PRIVATE, |
|
267 test_fd, pagesize); |
|
268 p3 = mmap(NULL, len, PROT_READ, |
|
269 MAP_PRIVATE, |
|
270 test_fd, pagesize * 2); |
|
271 |
|
272 fail_unless (p1 != MAP_FAILED); |
|
273 fail_unless (p2 != MAP_FAILED); |
|
274 fail_unless (p3 != MAP_FAILED); |
|
275 |
|
276 /* Make sure we get pages aligned with the pagesize. The |
|
277 target expects this. */ |
|
278 p = (uintptr_t) p1; |
|
279 fail_unless ((p & pagemask) == 0); |
|
280 p = (uintptr_t) p2; |
|
281 fail_unless ((p & pagemask) == 0); |
|
282 p = (uintptr_t) p3; |
|
283 fail_unless ((p & pagemask) == 0); |
|
284 |
|
285 /* Verify that the file maps was made correctly. */ |
|
286 D(printf ("p1=%d p2=%d p3=%d\n", *p1, *p2, *p3)); |
|
287 fail_unless (*p1 == 0); |
|
288 fail_unless (*p2 == (pagesize / sizeof *p2)); |
|
289 fail_unless (*p3 == ((pagesize * 2) / sizeof *p3)); |
|
290 |
|
291 memcpy (dummybuf, p1, pagesize); |
|
292 memcpy (dummybuf, p2, pagesize); |
|
293 memcpy (dummybuf, p3, pagesize); |
|
294 munmap (p1, len); |
|
295 munmap (p2, len); |
|
296 munmap (p3, len); |
|
297 } |
|
298 fprintf (stderr, " passed\n"); |
|
299 } |
|
300 |
|
301 void check_file_unfixed_eof_mmaps(void) |
|
302 { |
|
303 char *cp; |
|
304 unsigned int *p1; |
|
305 uintptr_t p; |
|
306 int i; |
|
307 |
|
308 fprintf (stderr, "%s", __func__); |
|
309 for (i = 0; i < 0x10; i++) |
|
310 { |
|
311 p1 = mmap(NULL, pagesize, PROT_READ, |
|
312 MAP_PRIVATE, |
|
313 test_fd, |
|
314 (test_fsize - sizeof *p1) & ~pagemask); |
|
315 |
|
316 fail_unless (p1 != MAP_FAILED); |
|
317 |
|
318 /* Make sure we get pages aligned with the pagesize. The |
|
319 target expects this. */ |
|
320 p = (uintptr_t) p1; |
|
321 fail_unless ((p & pagemask) == 0); |
|
322 /* Verify that the file maps was made correctly. */ |
|
323 fail_unless (p1[(test_fsize & pagemask) / sizeof *p1 - 1] |
|
324 == ((test_fsize - sizeof *p1) / sizeof *p1)); |
|
325 |
|
326 /* Verify that the end of page is accessable and zeroed. */ |
|
327 cp = (void *) p1; |
|
328 fail_unless (cp[pagesize - 4] == 0); |
|
329 munmap (p1, pagesize); |
|
330 } |
|
331 fprintf (stderr, " passed\n"); |
|
332 } |
|
333 |
|
334 void check_file_fixed_eof_mmaps(void) |
|
335 { |
|
336 char *addr; |
|
337 char *cp; |
|
338 unsigned int *p1; |
|
339 uintptr_t p; |
|
340 int i; |
|
341 |
|
342 /* Find a suitable address to start with. */ |
|
343 addr = mmap(NULL, pagesize * 44, PROT_READ, |
|
344 MAP_PRIVATE | MAP_ANONYMOUS, |
|
345 -1, 0); |
|
346 |
|
347 fprintf (stderr, "%s addr=%p", __func__, (void *)addr); |
|
348 fail_unless (addr != MAP_FAILED); |
|
349 |
|
350 for (i = 0; i < 0x10; i++) |
|
351 { |
|
352 /* Create submaps within our unfixed map. */ |
|
353 p1 = mmap(addr, pagesize, PROT_READ, |
|
354 MAP_PRIVATE | MAP_FIXED, |
|
355 test_fd, |
|
356 (test_fsize - sizeof *p1) & ~pagemask); |
|
357 |
|
358 fail_unless (p1 != MAP_FAILED); |
|
359 |
|
360 /* Make sure we get pages aligned with the pagesize. The |
|
361 target expects this. */ |
|
362 p = (uintptr_t) p1; |
|
363 fail_unless ((p & pagemask) == 0); |
|
364 |
|
365 /* Verify that the file maps was made correctly. */ |
|
366 fail_unless (p1[(test_fsize & pagemask) / sizeof *p1 - 1] |
|
367 == ((test_fsize - sizeof *p1) / sizeof *p1)); |
|
368 |
|
369 /* Verify that the end of page is accessable and zeroed. */ |
|
370 cp = (void *)p1; |
|
371 fail_unless (cp[pagesize - 4] == 0); |
|
372 munmap (p1, pagesize); |
|
373 addr += pagesize; |
|
374 } |
|
375 fprintf (stderr, " passed\n"); |
|
376 } |
|
377 |
|
378 void check_file_fixed_mmaps(void) |
|
379 { |
|
380 unsigned char *addr; |
|
381 unsigned int *p1, *p2, *p3, *p4; |
|
382 int i; |
|
383 |
|
384 /* Find a suitable address to start with. */ |
|
385 addr = mmap(NULL, pagesize * 40 * 4, PROT_READ, |
|
386 MAP_PRIVATE | MAP_ANONYMOUS, |
|
387 -1, 0); |
|
388 fprintf (stderr, "%s addr=%p", __func__, (void *)addr); |
|
389 fail_unless (addr != MAP_FAILED); |
|
390 |
|
391 for (i = 0; i < 40; i++) |
|
392 { |
|
393 p1 = mmap(addr, pagesize, PROT_READ, |
|
394 MAP_PRIVATE | MAP_FIXED, |
|
395 test_fd, 0); |
|
396 p2 = mmap(addr + pagesize, pagesize, PROT_READ, |
|
397 MAP_PRIVATE | MAP_FIXED, |
|
398 test_fd, pagesize); |
|
399 p3 = mmap(addr + pagesize * 2, pagesize, PROT_READ, |
|
400 MAP_PRIVATE | MAP_FIXED, |
|
401 test_fd, pagesize * 2); |
|
402 p4 = mmap(addr + pagesize * 3, pagesize, PROT_READ, |
|
403 MAP_PRIVATE | MAP_FIXED, |
|
404 test_fd, pagesize * 3); |
|
405 |
|
406 /* Make sure we get pages aligned with the pagesize. |
|
407 The target expects this. */ |
|
408 fail_unless (p1 == (void *)addr); |
|
409 fail_unless (p2 == (void *)addr + pagesize); |
|
410 fail_unless (p3 == (void *)addr + pagesize * 2); |
|
411 fail_unless (p4 == (void *)addr + pagesize * 3); |
|
412 |
|
413 /* Verify that the file maps was made correctly. */ |
|
414 fail_unless (*p1 == 0); |
|
415 fail_unless (*p2 == (pagesize / sizeof *p2)); |
|
416 fail_unless (*p3 == ((pagesize * 2) / sizeof *p3)); |
|
417 fail_unless (*p4 == ((pagesize * 3) / sizeof *p4)); |
|
418 |
|
419 memcpy (dummybuf, p1, pagesize); |
|
420 memcpy (dummybuf, p2, pagesize); |
|
421 memcpy (dummybuf, p3, pagesize); |
|
422 memcpy (dummybuf, p4, pagesize); |
|
423 |
|
424 munmap (p1, pagesize); |
|
425 munmap (p2, pagesize); |
|
426 munmap (p3, pagesize); |
|
427 munmap (p4, pagesize); |
|
428 addr += pagesize * 4; |
|
429 } |
|
430 fprintf (stderr, " passed\n"); |
|
431 } |
|
432 |
|
433 int main(int argc, char **argv) |
|
434 { |
|
435 char tempname[] = "/tmp/.cmmapXXXXXX"; |
|
436 unsigned int i; |
|
437 |
|
438 /* Trust the first argument, otherwise probe the system for our |
|
439 pagesize. */ |
|
440 if (argc > 1) |
|
441 pagesize = strtoul(argv[1], NULL, 0); |
|
442 else |
|
443 pagesize = sysconf(_SC_PAGESIZE); |
|
444 |
|
445 /* Assume pagesize is a power of two. */ |
|
446 pagemask = pagesize - 1; |
|
447 dummybuf = malloc (pagesize); |
|
448 printf ("pagesize=%u pagemask=%x\n", pagesize, pagemask); |
|
449 |
|
450 test_fd = mkstemp(tempname); |
|
451 unlink(tempname); |
|
452 |
|
453 /* Fill the file with int's counting from zero and up. */ |
|
454 for (i = 0; i < (pagesize * 4) / sizeof i; i++) |
|
455 write (test_fd, &i, sizeof i); |
|
456 /* Append a few extra writes to make the file end at non |
|
457 page boundary. */ |
|
458 write (test_fd, &i, sizeof i); i++; |
|
459 write (test_fd, &i, sizeof i); i++; |
|
460 write (test_fd, &i, sizeof i); i++; |
|
461 |
|
462 test_fsize = lseek(test_fd, 0, SEEK_CUR); |
|
463 |
|
464 /* Run the tests. */ |
|
465 check_aligned_anonymous_unfixed_mmaps(); |
|
466 check_aligned_anonymous_unfixed_colliding_mmaps(); |
|
467 check_aligned_anonymous_fixed_mmaps(); |
|
468 check_file_unfixed_mmaps(); |
|
469 check_file_fixed_mmaps(); |
|
470 check_file_fixed_eof_mmaps(); |
|
471 check_file_unfixed_eof_mmaps(); |
|
472 |
|
473 /* Fails at the moment. */ |
|
474 /* check_aligned_anonymous_fixed_mmaps_collide_with_host(); */ |
|
475 |
|
476 return EXIT_SUCCESS; |
|
477 } |