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 } 479