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