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) \ 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 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 110void 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 134void 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 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}