1 /* 2 * mmap support for qemu 3 * 4 * Copyright (c) 2003 - 2008 Fabrice Bellard 5 * 6 * This program is free software; you can redistribute it and/or modify 7 * it under the terms of the GNU General Public License as published by 8 * the Free Software Foundation; either version 2 of the License, or 9 * (at your option) any later version. 10 * 11 * This program is distributed in the hope that it will be useful, 12 * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 * GNU General Public License for more details. 15 * 16 * You should have received a copy of the GNU General Public License 17 * along with this program; if not, see <http://www.gnu.org/licenses/>. 18 */ 19 #include "qemu/osdep.h" 20 21 #include "qemu.h" 22 23 static pthread_mutex_t mmap_mutex = PTHREAD_MUTEX_INITIALIZER; 24 static __thread int mmap_lock_count; 25 26 void mmap_lock(void) 27 { 28 if (mmap_lock_count++ == 0) { 29 pthread_mutex_lock(&mmap_mutex); 30 } 31 } 32 33 void mmap_unlock(void) 34 { 35 assert(mmap_lock_count > 0); 36 if (--mmap_lock_count == 0) { 37 pthread_mutex_unlock(&mmap_mutex); 38 } 39 } 40 41 bool have_mmap_lock(void) 42 { 43 return mmap_lock_count > 0 ? true : false; 44 } 45 46 /* Grab lock to make sure things are in a consistent state after fork(). */ 47 void mmap_fork_start(void) 48 { 49 if (mmap_lock_count) 50 abort(); 51 pthread_mutex_lock(&mmap_mutex); 52 } 53 54 void mmap_fork_end(int child) 55 { 56 if (child) 57 pthread_mutex_init(&mmap_mutex, NULL); 58 else 59 pthread_mutex_unlock(&mmap_mutex); 60 } 61 62 /* NOTE: all the constants are the HOST ones, but addresses are target. */ 63 int target_mprotect(abi_ulong start, abi_ulong len, int prot) 64 { 65 abi_ulong end, host_start, host_end, addr; 66 int prot1, ret; 67 68 qemu_log_mask(CPU_LOG_PAGE, "mprotect: start=0x" TARGET_ABI_FMT_lx 69 " len=0x" TARGET_ABI_FMT_lx " prot=%c%c%c\n", start, len, 70 prot & PROT_READ ? 'r' : '-', 71 prot & PROT_WRITE ? 'w' : '-', 72 prot & PROT_EXEC ? 'x' : '-'); 73 if ((start & ~TARGET_PAGE_MASK) != 0) 74 return -EINVAL; 75 len = TARGET_PAGE_ALIGN(len); 76 end = start + len; 77 if (end < start) 78 return -EINVAL; 79 prot &= PROT_READ | PROT_WRITE | PROT_EXEC; 80 if (len == 0) 81 return 0; 82 83 mmap_lock(); 84 host_start = start & qemu_host_page_mask; 85 host_end = HOST_PAGE_ALIGN(end); 86 if (start > host_start) { 87 /* handle host page containing start */ 88 prot1 = prot; 89 for (addr = host_start; addr < start; addr += TARGET_PAGE_SIZE) { 90 prot1 |= page_get_flags(addr); 91 } 92 if (host_end == host_start + qemu_host_page_size) { 93 for (addr = end; addr < host_end; addr += TARGET_PAGE_SIZE) { 94 prot1 |= page_get_flags(addr); 95 } 96 end = host_end; 97 } 98 ret = mprotect(g2h_untagged(host_start), 99 qemu_host_page_size, prot1 & PAGE_BITS); 100 if (ret != 0) 101 goto error; 102 host_start += qemu_host_page_size; 103 } 104 if (end < host_end) { 105 prot1 = prot; 106 for (addr = end; addr < host_end; addr += TARGET_PAGE_SIZE) { 107 prot1 |= page_get_flags(addr); 108 } 109 ret = mprotect(g2h_untagged(host_end - qemu_host_page_size), 110 qemu_host_page_size, prot1 & PAGE_BITS); 111 if (ret != 0) 112 goto error; 113 host_end -= qemu_host_page_size; 114 } 115 116 /* handle the pages in the middle */ 117 if (host_start < host_end) { 118 ret = mprotect(g2h_untagged(host_start), host_end - host_start, prot); 119 if (ret != 0) 120 goto error; 121 } 122 page_set_flags(start, start + len - 1, prot | PAGE_VALID); 123 mmap_unlock(); 124 return 0; 125 error: 126 mmap_unlock(); 127 return ret; 128 } 129 130 /* 131 * map an incomplete host page 132 * 133 * mmap_frag can be called with a valid fd, if flags doesn't contain one of 134 * MAP_ANON, MAP_STACK, MAP_GUARD. If we need to map a page in those cases, we 135 * pass fd == -1. However, if flags contains MAP_GUARD then MAP_ANON cannot be 136 * added. 137 * 138 * * If fd is valid (not -1) we want to map the pages with MAP_ANON. 139 * * If flags contains MAP_GUARD we don't want to add MAP_ANON because it 140 * will be rejected. See kern_mmap's enforcing of constraints for MAP_GUARD 141 * in sys/vm/vm_mmap.c. 142 * * If flags contains MAP_ANON it doesn't matter if we add it or not. 143 * * If flags contains MAP_STACK, mmap adds MAP_ANON when called so doesn't 144 * matter if we add it or not either. See enforcing of constraints for 145 * MAP_STACK in kern_mmap. 146 * 147 * Don't add MAP_ANON for the flags that use fd == -1 without specifying the 148 * flags directly, with the assumption that future flags that require fd == -1 149 * will also not require MAP_ANON. 150 */ 151 static int mmap_frag(abi_ulong real_start, 152 abi_ulong start, abi_ulong end, 153 int prot, int flags, int fd, abi_ulong offset) 154 { 155 abi_ulong real_end, addr; 156 void *host_start; 157 int prot1, prot_new; 158 159 real_end = real_start + qemu_host_page_size; 160 host_start = g2h_untagged(real_start); 161 162 /* get the protection of the target pages outside the mapping */ 163 prot1 = 0; 164 for (addr = real_start; addr < real_end; addr++) { 165 if (addr < start || addr >= end) 166 prot1 |= page_get_flags(addr); 167 } 168 169 if (prot1 == 0) { 170 /* no page was there, so we allocate one. See also above. */ 171 void *p = mmap(host_start, qemu_host_page_size, prot, 172 flags | ((fd != -1) ? MAP_ANON : 0), -1, 0); 173 if (p == MAP_FAILED) 174 return -1; 175 prot1 = prot; 176 } 177 prot1 &= PAGE_BITS; 178 179 prot_new = prot | prot1; 180 if (fd != -1) { 181 /* msync() won't work here, so we return an error if write is 182 possible while it is a shared mapping */ 183 if ((flags & TARGET_BSD_MAP_FLAGMASK) == MAP_SHARED && 184 (prot & PROT_WRITE)) 185 return -1; 186 187 /* adjust protection to be able to read */ 188 if (!(prot1 & PROT_WRITE)) 189 mprotect(host_start, qemu_host_page_size, prot1 | PROT_WRITE); 190 191 /* read the corresponding file data */ 192 if (pread(fd, g2h_untagged(start), end - start, offset) == -1) { 193 return -1; 194 } 195 196 /* put final protection */ 197 if (prot_new != (prot1 | PROT_WRITE)) 198 mprotect(host_start, qemu_host_page_size, prot_new); 199 } else { 200 if (prot_new != prot1) { 201 mprotect(host_start, qemu_host_page_size, prot_new); 202 } 203 if (prot_new & PROT_WRITE) { 204 memset(g2h_untagged(start), 0, end - start); 205 } 206 } 207 return 0; 208 } 209 210 #if HOST_LONG_BITS == 64 && TARGET_ABI_BITS == 64 211 # define TASK_UNMAPPED_BASE (1ul << 38) 212 #else 213 # define TASK_UNMAPPED_BASE 0x40000000 214 #endif 215 abi_ulong mmap_next_start = TASK_UNMAPPED_BASE; 216 217 unsigned long last_brk; 218 219 /* 220 * Subroutine of mmap_find_vma, used when we have pre-allocated a chunk of guest 221 * address space. 222 */ 223 static abi_ulong mmap_find_vma_reserved(abi_ulong start, abi_ulong size, 224 abi_ulong alignment) 225 { 226 abi_ulong ret; 227 228 ret = page_find_range_empty(start, reserved_va, size, alignment); 229 if (ret == -1 && start > TARGET_PAGE_SIZE) { 230 /* Restart at the beginning of the address space. */ 231 ret = page_find_range_empty(TARGET_PAGE_SIZE, start - 1, 232 size, alignment); 233 } 234 235 return ret; 236 } 237 238 /* 239 * Find and reserve a free memory area of size 'size'. The search 240 * starts at 'start'. 241 * It must be called with mmap_lock() held. 242 * Return -1 if error. 243 */ 244 static abi_ulong mmap_find_vma_aligned(abi_ulong start, abi_ulong size, 245 abi_ulong alignment) 246 { 247 void *ptr, *prev; 248 abi_ulong addr; 249 int flags; 250 int wrapped, repeat; 251 252 /* If 'start' == 0, then a default start address is used. */ 253 if (start == 0) { 254 start = mmap_next_start; 255 } else { 256 start &= qemu_host_page_mask; 257 } 258 259 size = HOST_PAGE_ALIGN(size); 260 261 if (reserved_va) { 262 return mmap_find_vma_reserved(start, size, 263 (alignment != 0 ? 1 << alignment : 264 MAX(qemu_host_page_size, TARGET_PAGE_SIZE))); 265 } 266 267 addr = start; 268 wrapped = repeat = 0; 269 prev = 0; 270 flags = MAP_ANON | MAP_PRIVATE; 271 if (alignment != 0) { 272 flags |= MAP_ALIGNED(alignment); 273 } 274 275 for (;; prev = ptr) { 276 /* 277 * Reserve needed memory area to avoid a race. 278 * It should be discarded using: 279 * - mmap() with MAP_FIXED flag 280 * - mremap() with MREMAP_FIXED flag 281 * - shmat() with SHM_REMAP flag 282 */ 283 ptr = mmap(g2h_untagged(addr), size, PROT_NONE, 284 flags, -1, 0); 285 286 /* ENOMEM, if host address space has no memory */ 287 if (ptr == MAP_FAILED) { 288 return (abi_ulong)-1; 289 } 290 291 /* 292 * Count the number of sequential returns of the same address. 293 * This is used to modify the search algorithm below. 294 */ 295 repeat = (ptr == prev ? repeat + 1 : 0); 296 297 if (h2g_valid(ptr + size - 1)) { 298 addr = h2g(ptr); 299 300 if ((addr & ~TARGET_PAGE_MASK) == 0) { 301 /* Success. */ 302 if (start == mmap_next_start && addr >= TASK_UNMAPPED_BASE) { 303 mmap_next_start = addr + size; 304 } 305 return addr; 306 } 307 308 /* The address is not properly aligned for the target. */ 309 switch (repeat) { 310 case 0: 311 /* 312 * Assume the result that the kernel gave us is the 313 * first with enough free space, so start again at the 314 * next higher target page. 315 */ 316 addr = TARGET_PAGE_ALIGN(addr); 317 break; 318 case 1: 319 /* 320 * Sometimes the kernel decides to perform the allocation 321 * at the top end of memory instead. 322 */ 323 addr &= TARGET_PAGE_MASK; 324 break; 325 case 2: 326 /* Start over at low memory. */ 327 addr = 0; 328 break; 329 default: 330 /* Fail. This unaligned block must the last. */ 331 addr = -1; 332 break; 333 } 334 } else { 335 /* 336 * Since the result the kernel gave didn't fit, start 337 * again at low memory. If any repetition, fail. 338 */ 339 addr = (repeat ? -1 : 0); 340 } 341 342 /* Unmap and try again. */ 343 munmap(ptr, size); 344 345 /* ENOMEM if we checked the whole of the target address space. */ 346 if (addr == (abi_ulong)-1) { 347 return (abi_ulong)-1; 348 } else if (addr == 0) { 349 if (wrapped) { 350 return (abi_ulong)-1; 351 } 352 wrapped = 1; 353 /* 354 * Don't actually use 0 when wrapping, instead indicate 355 * that we'd truly like an allocation in low memory. 356 */ 357 addr = TARGET_PAGE_SIZE; 358 } else if (wrapped && addr >= start) { 359 return (abi_ulong)-1; 360 } 361 } 362 } 363 364 abi_ulong mmap_find_vma(abi_ulong start, abi_ulong size) 365 { 366 return mmap_find_vma_aligned(start, size, 0); 367 } 368 369 /* NOTE: all the constants are the HOST ones */ 370 abi_long target_mmap(abi_ulong start, abi_ulong len, int prot, 371 int flags, int fd, off_t offset) 372 { 373 abi_ulong ret, end, real_start, real_end, retaddr, host_offset, host_len; 374 375 mmap_lock(); 376 if (qemu_loglevel_mask(CPU_LOG_PAGE)) { 377 qemu_log("mmap: start=0x" TARGET_ABI_FMT_lx 378 " len=0x" TARGET_ABI_FMT_lx " prot=%c%c%c flags=", 379 start, len, 380 prot & PROT_READ ? 'r' : '-', 381 prot & PROT_WRITE ? 'w' : '-', 382 prot & PROT_EXEC ? 'x' : '-'); 383 if (flags & MAP_ALIGNMENT_MASK) { 384 qemu_log("MAP_ALIGNED(%u) ", 385 (flags & MAP_ALIGNMENT_MASK) >> MAP_ALIGNMENT_SHIFT); 386 } 387 if (flags & MAP_GUARD) { 388 qemu_log("MAP_GUARD "); 389 } 390 if (flags & MAP_FIXED) { 391 qemu_log("MAP_FIXED "); 392 } 393 if (flags & MAP_ANON) { 394 qemu_log("MAP_ANON "); 395 } 396 if (flags & MAP_EXCL) { 397 qemu_log("MAP_EXCL "); 398 } 399 if (flags & MAP_PRIVATE) { 400 qemu_log("MAP_PRIVATE "); 401 } 402 if (flags & MAP_SHARED) { 403 qemu_log("MAP_SHARED "); 404 } 405 if (flags & MAP_NOCORE) { 406 qemu_log("MAP_NOCORE "); 407 } 408 if (flags & MAP_STACK) { 409 qemu_log("MAP_STACK "); 410 } 411 qemu_log("fd=%d offset=0x%lx\n", fd, offset); 412 } 413 414 if ((flags & MAP_ANON) && fd != -1) { 415 errno = EINVAL; 416 goto fail; 417 } 418 if (flags & MAP_STACK) { 419 if ((fd != -1) || ((prot & (PROT_READ | PROT_WRITE)) != 420 (PROT_READ | PROT_WRITE))) { 421 errno = EINVAL; 422 goto fail; 423 } 424 } 425 if ((flags & MAP_GUARD) && (prot != PROT_NONE || fd != -1 || 426 offset != 0 || (flags & (MAP_SHARED | MAP_PRIVATE | 427 /* MAP_PREFAULT | */ /* MAP_PREFAULT not in mman.h */ 428 MAP_PREFAULT_READ | MAP_ANON | MAP_STACK)) != 0)) { 429 errno = EINVAL; 430 goto fail; 431 } 432 433 if (offset & ~TARGET_PAGE_MASK) { 434 errno = EINVAL; 435 goto fail; 436 } 437 438 if (len == 0) { 439 errno = EINVAL; 440 goto fail; 441 } 442 443 /* Check for overflows */ 444 len = TARGET_PAGE_ALIGN(len); 445 if (len == 0) { 446 errno = ENOMEM; 447 goto fail; 448 } 449 450 real_start = start & qemu_host_page_mask; 451 host_offset = offset & qemu_host_page_mask; 452 453 /* 454 * If the user is asking for the kernel to find a location, do that 455 * before we truncate the length for mapping files below. 456 */ 457 if (!(flags & MAP_FIXED)) { 458 host_len = len + offset - host_offset; 459 host_len = HOST_PAGE_ALIGN(host_len); 460 if ((flags & MAP_ALIGNMENT_MASK) != 0) 461 start = mmap_find_vma_aligned(real_start, host_len, 462 (flags & MAP_ALIGNMENT_MASK) >> MAP_ALIGNMENT_SHIFT); 463 else 464 start = mmap_find_vma(real_start, host_len); 465 if (start == (abi_ulong)-1) { 466 errno = ENOMEM; 467 goto fail; 468 } 469 } 470 471 /* 472 * When mapping files into a memory area larger than the file, accesses 473 * to pages beyond the file size will cause a SIGBUS. 474 * 475 * For example, if mmaping a file of 100 bytes on a host with 4K pages 476 * emulating a target with 8K pages, the target expects to be able to 477 * access the first 8K. But the host will trap us on any access beyond 478 * 4K. 479 * 480 * When emulating a target with a larger page-size than the hosts, we 481 * may need to truncate file maps at EOF and add extra anonymous pages 482 * up to the targets page boundary. 483 */ 484 485 if ((qemu_real_host_page_size() < qemu_host_page_size) && fd != -1) { 486 struct stat sb; 487 488 if (fstat(fd, &sb) == -1) { 489 goto fail; 490 } 491 492 /* Are we trying to create a map beyond EOF?. */ 493 if (offset + len > sb.st_size) { 494 /* 495 * If so, truncate the file map at eof aligned with 496 * the hosts real pagesize. Additional anonymous maps 497 * will be created beyond EOF. 498 */ 499 len = REAL_HOST_PAGE_ALIGN(sb.st_size - offset); 500 } 501 } 502 503 if (!(flags & MAP_FIXED)) { 504 unsigned long host_start; 505 void *p; 506 507 host_len = len + offset - host_offset; 508 host_len = HOST_PAGE_ALIGN(host_len); 509 510 /* 511 * Note: we prefer to control the mapping address. It is 512 * especially important if qemu_host_page_size > 513 * qemu_real_host_page_size 514 */ 515 p = mmap(g2h_untagged(start), host_len, prot, 516 flags | MAP_FIXED | ((fd != -1) ? MAP_ANON : 0), -1, 0); 517 if (p == MAP_FAILED) 518 goto fail; 519 /* update start so that it points to the file position at 'offset' */ 520 host_start = (unsigned long)p; 521 if (fd != -1) { 522 p = mmap(g2h_untagged(start), len, prot, 523 flags | MAP_FIXED, fd, host_offset); 524 if (p == MAP_FAILED) { 525 munmap(g2h_untagged(start), host_len); 526 goto fail; 527 } 528 host_start += offset - host_offset; 529 } 530 start = h2g(host_start); 531 } else { 532 if (start & ~TARGET_PAGE_MASK) { 533 errno = EINVAL; 534 goto fail; 535 } 536 end = start + len; 537 real_end = HOST_PAGE_ALIGN(end); 538 539 /* 540 * Test if requested memory area fits target address space 541 * It can fail only on 64-bit host with 32-bit target. 542 * On any other target/host host mmap() handles this error correctly. 543 */ 544 if (!guest_range_valid_untagged(start, len)) { 545 errno = EINVAL; 546 goto fail; 547 } 548 549 /* 550 * worst case: we cannot map the file because the offset is not 551 * aligned, so we read it 552 */ 553 if (fd != -1 && 554 (offset & ~qemu_host_page_mask) != (start & ~qemu_host_page_mask)) { 555 /* 556 * msync() won't work here, so we return an error if write is 557 * possible while it is a shared mapping 558 */ 559 if ((flags & TARGET_BSD_MAP_FLAGMASK) == MAP_SHARED && 560 (prot & PROT_WRITE)) { 561 errno = EINVAL; 562 goto fail; 563 } 564 retaddr = target_mmap(start, len, prot | PROT_WRITE, 565 MAP_FIXED | MAP_PRIVATE | MAP_ANON, 566 -1, 0); 567 if (retaddr == -1) 568 goto fail; 569 if (pread(fd, g2h_untagged(start), len, offset) == -1) { 570 goto fail; 571 } 572 if (!(prot & PROT_WRITE)) { 573 ret = target_mprotect(start, len, prot); 574 assert(ret == 0); 575 } 576 goto the_end; 577 } 578 579 /* Reject the mapping if any page within the range is mapped */ 580 if ((flags & MAP_EXCL) && !page_check_range_empty(start, end - 1)) { 581 errno = EINVAL; 582 goto fail; 583 } 584 585 /* handle the start of the mapping */ 586 if (start > real_start) { 587 if (real_end == real_start + qemu_host_page_size) { 588 /* one single host page */ 589 ret = mmap_frag(real_start, start, end, 590 prot, flags, fd, offset); 591 if (ret == -1) 592 goto fail; 593 goto the_end1; 594 } 595 ret = mmap_frag(real_start, start, real_start + qemu_host_page_size, 596 prot, flags, fd, offset); 597 if (ret == -1) 598 goto fail; 599 real_start += qemu_host_page_size; 600 } 601 /* handle the end of the mapping */ 602 if (end < real_end) { 603 ret = mmap_frag(real_end - qemu_host_page_size, 604 real_end - qemu_host_page_size, end, 605 prot, flags, fd, 606 offset + real_end - qemu_host_page_size - start); 607 if (ret == -1) 608 goto fail; 609 real_end -= qemu_host_page_size; 610 } 611 612 /* map the middle (easier) */ 613 if (real_start < real_end) { 614 void *p; 615 unsigned long offset1; 616 if (flags & MAP_ANON) 617 offset1 = 0; 618 else 619 offset1 = offset + real_start - start; 620 p = mmap(g2h_untagged(real_start), real_end - real_start, 621 prot, flags, fd, offset1); 622 if (p == MAP_FAILED) 623 goto fail; 624 } 625 } 626 the_end1: 627 page_set_flags(start, start + len - 1, prot | PAGE_VALID); 628 the_end: 629 #ifdef DEBUG_MMAP 630 printf("ret=0x" TARGET_ABI_FMT_lx "\n", start); 631 page_dump(stdout); 632 printf("\n"); 633 #endif 634 mmap_unlock(); 635 return start; 636 fail: 637 mmap_unlock(); 638 return -1; 639 } 640 641 static void mmap_reserve(abi_ulong start, abi_ulong size) 642 { 643 abi_ulong real_start; 644 abi_ulong real_end; 645 abi_ulong addr; 646 abi_ulong end; 647 int prot; 648 649 real_start = start & qemu_host_page_mask; 650 real_end = HOST_PAGE_ALIGN(start + size); 651 end = start + size; 652 if (start > real_start) { 653 /* handle host page containing start */ 654 prot = 0; 655 for (addr = real_start; addr < start; addr += TARGET_PAGE_SIZE) { 656 prot |= page_get_flags(addr); 657 } 658 if (real_end == real_start + qemu_host_page_size) { 659 for (addr = end; addr < real_end; addr += TARGET_PAGE_SIZE) { 660 prot |= page_get_flags(addr); 661 } 662 end = real_end; 663 } 664 if (prot != 0) { 665 real_start += qemu_host_page_size; 666 } 667 } 668 if (end < real_end) { 669 prot = 0; 670 for (addr = end; addr < real_end; addr += TARGET_PAGE_SIZE) { 671 prot |= page_get_flags(addr); 672 } 673 if (prot != 0) { 674 real_end -= qemu_host_page_size; 675 } 676 } 677 if (real_start != real_end) { 678 mmap(g2h_untagged(real_start), real_end - real_start, PROT_NONE, 679 MAP_FIXED | MAP_ANON | MAP_PRIVATE, -1, 0); 680 } 681 } 682 683 int target_munmap(abi_ulong start, abi_ulong len) 684 { 685 abi_ulong end, real_start, real_end, addr; 686 int prot, ret; 687 688 #ifdef DEBUG_MMAP 689 printf("munmap: start=0x" TARGET_ABI_FMT_lx " len=0x" 690 TARGET_ABI_FMT_lx "\n", 691 start, len); 692 #endif 693 if (start & ~TARGET_PAGE_MASK) 694 return -EINVAL; 695 len = TARGET_PAGE_ALIGN(len); 696 if (len == 0) 697 return -EINVAL; 698 mmap_lock(); 699 end = start + len; 700 real_start = start & qemu_host_page_mask; 701 real_end = HOST_PAGE_ALIGN(end); 702 703 if (start > real_start) { 704 /* handle host page containing start */ 705 prot = 0; 706 for (addr = real_start; addr < start; addr += TARGET_PAGE_SIZE) { 707 prot |= page_get_flags(addr); 708 } 709 if (real_end == real_start + qemu_host_page_size) { 710 for (addr = end; addr < real_end; addr += TARGET_PAGE_SIZE) { 711 prot |= page_get_flags(addr); 712 } 713 end = real_end; 714 } 715 if (prot != 0) 716 real_start += qemu_host_page_size; 717 } 718 if (end < real_end) { 719 prot = 0; 720 for (addr = end; addr < real_end; addr += TARGET_PAGE_SIZE) { 721 prot |= page_get_flags(addr); 722 } 723 if (prot != 0) 724 real_end -= qemu_host_page_size; 725 } 726 727 ret = 0; 728 /* unmap what we can */ 729 if (real_start < real_end) { 730 if (reserved_va) { 731 mmap_reserve(real_start, real_end - real_start); 732 } else { 733 ret = munmap(g2h_untagged(real_start), real_end - real_start); 734 } 735 } 736 737 if (ret == 0) { 738 page_set_flags(start, start + len - 1, 0); 739 } 740 mmap_unlock(); 741 return ret; 742 } 743 744 int target_msync(abi_ulong start, abi_ulong len, int flags) 745 { 746 abi_ulong end; 747 748 if (start & ~TARGET_PAGE_MASK) 749 return -EINVAL; 750 len = TARGET_PAGE_ALIGN(len); 751 end = start + len; 752 if (end < start) 753 return -EINVAL; 754 if (end == start) 755 return 0; 756 757 start &= qemu_host_page_mask; 758 return msync(g2h_untagged(start), end - start, flags); 759 } 760