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