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