qemu/tests/tcg/multiarch/test-mmap.c
<<
>>
Prefs
   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)                                         \
  36do                                                             \
  37{                                                              \
  38  if (!(x)) {                                                  \
  39    fprintf(stderr, "FAILED at %s:%d\n", __FILE__, __LINE__); \
  40    exit (EXIT_FAILURE);                                       \
  41  }                                                            \
  42} while (0)
  43
  44unsigned char *dummybuf;
  45static unsigned int pagesize;
  46static unsigned int pagemask;
  47int test_fd;
  48size_t test_fsize;
  49
  50void 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
 112void 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
 136void 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
 186void 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
 218void 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
 249void 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
 300void 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
 333void 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
 377void 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
 432void 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
 438void 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
 457int 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