qemu

FORK: QEMU emulator
git clone https://git.neptards.moe/neptards/qemu.git
Log | Files | Refs | Submodules | LICENSE

test-mmap.c (14026B)


      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     fprintf(stdout, "%s", __func__);
     60     for (i = 0; i < 8; i++) {
     61         size_t len;
     62         len = pagesize + (pagesize * i);
     63         p1 = mmap(NULL, len, PROT_READ,
     64                   MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
     65         p2 = mmap(NULL, len, PROT_READ,
     66                   MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
     67         p3 = mmap(NULL, len, PROT_READ,
     68                   MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
     69         p4 = mmap(NULL, len, PROT_READ,
     70                   MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
     71         p5 = mmap(NULL, len, PROT_READ,
     72                   MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
     73 
     74         /*
     75          * Make sure we get pages aligned with the pagesize. The
     76          * target expects this.
     77          */
     78         fail_unless(p1 != MAP_FAILED);
     79         fail_unless(p2 != MAP_FAILED);
     80         fail_unless(p3 != MAP_FAILED);
     81         fail_unless(p4 != MAP_FAILED);
     82         fail_unless(p5 != MAP_FAILED);
     83         p = (uintptr_t) p1;
     84         D(printf("p=%x\n", p));
     85         fail_unless((p & pagemask) == 0);
     86         p = (uintptr_t) p2;
     87         fail_unless((p & pagemask) == 0);
     88         p = (uintptr_t) p3;
     89         fail_unless((p & pagemask) == 0);
     90         p = (uintptr_t) p4;
     91         fail_unless((p & pagemask) == 0);
     92         p = (uintptr_t) p5;
     93         fail_unless((p & pagemask) == 0);
     94 
     95         /* Make sure we can read from the entire area.  */
     96         memcpy(dummybuf, p1, pagesize);
     97         memcpy(dummybuf, p2, pagesize);
     98         memcpy(dummybuf, p3, pagesize);
     99         memcpy(dummybuf, p4, pagesize);
    100         memcpy(dummybuf, p5, pagesize);
    101         munmap(p1, len);
    102         munmap(p2, len);
    103         munmap(p3, len);
    104         munmap(p4, len);
    105         munmap(p5, len);
    106     }
    107     fprintf(stdout, " passed\n");
    108 }
    109 
    110 void check_large_anonymous_unfixed_mmap(void)
    111 {
    112 	void *p1;
    113 	uintptr_t p;
    114 	size_t len;
    115 
    116 	fprintf(stdout, "%s", __func__);
    117 
    118 	len = 0x02000000;
    119 	p1 = mmap(NULL, len, PROT_READ, 
    120 		  MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
    121 
    122 	/* Make sure we get pages aligned with the pagesize. The
    123 	   target expects this.  */
    124 	fail_unless (p1 != MAP_FAILED);
    125 	p = (uintptr_t) p1;
    126 	fail_unless ((p & pagemask) == 0);
    127 	
    128 	/* Make sure we can read from the entire area.  */
    129 	memcpy (dummybuf, p1, pagesize);
    130 	munmap (p1, len);
    131 	fprintf(stdout, " passed\n");
    132 }
    133 
    134 void check_aligned_anonymous_unfixed_colliding_mmaps(void)
    135 {
    136     char *p1;
    137     char *p2;
    138     char *p3;
    139     uintptr_t p;
    140     int i;
    141 
    142     fprintf(stdout, "%s", __func__);
    143     for (i = 0; i < 2; i++) {
    144         int nlen;
    145         p1 = mmap(NULL, pagesize, PROT_READ,
    146                   MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
    147         fail_unless(p1 != MAP_FAILED);
    148         p = (uintptr_t) p1;
    149         fail_unless((p & pagemask) == 0);
    150         memcpy(dummybuf, p1, pagesize);
    151 
    152         p2 = mmap(NULL, pagesize, PROT_READ,
    153                   MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
    154         fail_unless(p2 != MAP_FAILED);
    155         p = (uintptr_t) p2;
    156         fail_unless((p & pagemask) == 0);
    157         memcpy(dummybuf, p2, pagesize);
    158 
    159 
    160         munmap(p1, pagesize);
    161         nlen = pagesize * 8;
    162         p3 = mmap(NULL, nlen, PROT_READ,
    163                   MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
    164         fail_unless(p3 != MAP_FAILED);
    165 
    166         /* Check if the mmaped areas collide.  */
    167         if (p3 < p2
    168             && (p3 + nlen) > p2) {
    169             fail_unless(0);
    170         }
    171 
    172         memcpy(dummybuf, p3, pagesize);
    173 
    174         /*
    175          * Make sure we get pages aligned with the pagesize. The
    176          * target expects this.
    177          */
    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 }