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