Statistics
| Branch: | Revision:

root / tests / test-mmap.c @ 530e7615

History | View | Annotate | Download (12.5 kB)

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
}