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 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 112 void 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 136 void 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 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 } 505