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 #include "trace.h" 21 #include "exec/log.h" 22 #include "qemu.h" 23 24 static pthread_mutex_t mmap_mutex = PTHREAD_MUTEX_INITIALIZER; 25 static __thread int mmap_lock_count; 26 27 void mmap_lock(void) 28 { 29 if (mmap_lock_count++ == 0) { 30 pthread_mutex_lock(&mmap_mutex); 31 } 32 } 33 34 void mmap_unlock(void) 35 { 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 /* 63 * Validate target prot bitmask. 64 * Return the prot bitmask for the host in *HOST_PROT. 65 * Return 0 if the target prot bitmask is invalid, otherwise 66 * the internal qemu page_flags (which will include PAGE_VALID). 67 */ 68 static int validate_prot_to_pageflags(int *host_prot, int prot) 69 { 70 int valid = PROT_READ | PROT_WRITE | PROT_EXEC | TARGET_PROT_SEM; 71 int page_flags = (prot & PAGE_BITS) | PAGE_VALID; 72 73 /* 74 * For the host, we need not pass anything except read/write/exec. 75 * While PROT_SEM is allowed by all hosts, it is also ignored, so 76 * don't bother transforming guest bit to host bit. Any other 77 * target-specific prot bits will not be understood by the host 78 * and will need to be encoded into page_flags for qemu emulation. 79 * 80 * Pages that are executable by the guest will never be executed 81 * by the host, but the host will need to be able to read them. 82 */ 83 *host_prot = (prot & (PROT_READ | PROT_WRITE)) 84 | (prot & PROT_EXEC ? PROT_READ : 0); 85 86 #ifdef TARGET_AARCH64 87 { 88 ARMCPU *cpu = ARM_CPU(thread_cpu); 89 90 /* 91 * The PROT_BTI bit is only accepted if the cpu supports the feature. 92 * Since this is the unusual case, don't bother checking unless 93 * the bit has been requested. If set and valid, record the bit 94 * within QEMU's page_flags. 95 */ 96 if ((prot & TARGET_PROT_BTI) && cpu_isar_feature(aa64_bti, cpu)) { 97 valid |= TARGET_PROT_BTI; 98 page_flags |= PAGE_BTI; 99 } 100 /* Similarly for the PROT_MTE bit. */ 101 if ((prot & TARGET_PROT_MTE) && cpu_isar_feature(aa64_mte, cpu)) { 102 valid |= TARGET_PROT_MTE; 103 page_flags |= PAGE_MTE; 104 } 105 } 106 #endif 107 108 return prot & ~valid ? 0 : page_flags; 109 } 110 111 /* NOTE: all the constants are the HOST ones, but addresses are target. */ 112 int target_mprotect(abi_ulong start, abi_ulong len, int target_prot) 113 { 114 abi_ulong end, host_start, host_end, addr; 115 int prot1, ret, page_flags, host_prot; 116 117 trace_target_mprotect(start, len, target_prot); 118 119 if ((start & ~TARGET_PAGE_MASK) != 0) { 120 return -TARGET_EINVAL; 121 } 122 page_flags = validate_prot_to_pageflags(&host_prot, target_prot); 123 if (!page_flags) { 124 return -TARGET_EINVAL; 125 } 126 len = TARGET_PAGE_ALIGN(len); 127 end = start + len; 128 if (!guest_range_valid_untagged(start, len)) { 129 return -TARGET_ENOMEM; 130 } 131 if (len == 0) { 132 return 0; 133 } 134 135 mmap_lock(); 136 host_start = start & qemu_host_page_mask; 137 host_end = HOST_PAGE_ALIGN(end); 138 if (start > host_start) { 139 /* handle host page containing start */ 140 prot1 = host_prot; 141 for (addr = host_start; addr < start; addr += TARGET_PAGE_SIZE) { 142 prot1 |= page_get_flags(addr); 143 } 144 if (host_end == host_start + qemu_host_page_size) { 145 for (addr = end; addr < host_end; addr += TARGET_PAGE_SIZE) { 146 prot1 |= page_get_flags(addr); 147 } 148 end = host_end; 149 } 150 ret = mprotect(g2h_untagged(host_start), qemu_host_page_size, 151 prot1 & PAGE_BITS); 152 if (ret != 0) { 153 goto error; 154 } 155 host_start += qemu_host_page_size; 156 } 157 if (end < host_end) { 158 prot1 = host_prot; 159 for (addr = end; addr < host_end; addr += TARGET_PAGE_SIZE) { 160 prot1 |= page_get_flags(addr); 161 } 162 ret = mprotect(g2h_untagged(host_end - qemu_host_page_size), 163 qemu_host_page_size, prot1 & PAGE_BITS); 164 if (ret != 0) { 165 goto error; 166 } 167 host_end -= qemu_host_page_size; 168 } 169 170 /* handle the pages in the middle */ 171 if (host_start < host_end) { 172 ret = mprotect(g2h_untagged(host_start), 173 host_end - host_start, host_prot); 174 if (ret != 0) { 175 goto error; 176 } 177 } 178 page_set_flags(start, start + len, page_flags); 179 mmap_unlock(); 180 return 0; 181 error: 182 mmap_unlock(); 183 return ret; 184 } 185 186 /* map an incomplete host page */ 187 static int mmap_frag(abi_ulong real_start, 188 abi_ulong start, abi_ulong end, 189 int prot, int flags, int fd, abi_ulong offset) 190 { 191 abi_ulong real_end, addr; 192 void *host_start; 193 int prot1, prot_new; 194 195 real_end = real_start + qemu_host_page_size; 196 host_start = g2h_untagged(real_start); 197 198 /* get the protection of the target pages outside the mapping */ 199 prot1 = 0; 200 for(addr = real_start; addr < real_end; addr++) { 201 if (addr < start || addr >= end) 202 prot1 |= page_get_flags(addr); 203 } 204 205 if (prot1 == 0) { 206 /* no page was there, so we allocate one */ 207 void *p = mmap(host_start, qemu_host_page_size, prot, 208 flags | MAP_ANONYMOUS, -1, 0); 209 if (p == MAP_FAILED) 210 return -1; 211 prot1 = prot; 212 } 213 prot1 &= PAGE_BITS; 214 215 prot_new = prot | prot1; 216 if (!(flags & MAP_ANONYMOUS)) { 217 /* msync() won't work here, so we return an error if write is 218 possible while it is a shared mapping */ 219 if ((flags & MAP_TYPE) == MAP_SHARED && 220 (prot & PROT_WRITE)) 221 return -1; 222 223 /* adjust protection to be able to read */ 224 if (!(prot1 & PROT_WRITE)) 225 mprotect(host_start, qemu_host_page_size, prot1 | PROT_WRITE); 226 227 /* read the corresponding file data */ 228 if (pread(fd, g2h_untagged(start), end - start, offset) == -1) 229 return -1; 230 231 /* put final protection */ 232 if (prot_new != (prot1 | PROT_WRITE)) 233 mprotect(host_start, qemu_host_page_size, prot_new); 234 } else { 235 if (prot_new != prot1) { 236 mprotect(host_start, qemu_host_page_size, prot_new); 237 } 238 if (prot_new & PROT_WRITE) { 239 memset(g2h_untagged(start), 0, end - start); 240 } 241 } 242 return 0; 243 } 244 245 #if HOST_LONG_BITS == 64 && TARGET_ABI_BITS == 64 246 #ifdef TARGET_AARCH64 247 # define TASK_UNMAPPED_BASE 0x5500000000 248 #else 249 # define TASK_UNMAPPED_BASE (1ul << 38) 250 #endif 251 #else 252 # define TASK_UNMAPPED_BASE 0x40000000 253 #endif 254 abi_ulong mmap_next_start = TASK_UNMAPPED_BASE; 255 256 unsigned long last_brk; 257 258 /* Subroutine of mmap_find_vma, used when we have pre-allocated a chunk 259 of guest address space. */ 260 static abi_ulong mmap_find_vma_reserved(abi_ulong start, abi_ulong size, 261 abi_ulong align) 262 { 263 abi_ulong addr, end_addr, incr = qemu_host_page_size; 264 int prot; 265 bool looped = false; 266 267 if (size > reserved_va) { 268 return (abi_ulong)-1; 269 } 270 271 /* Note that start and size have already been aligned by mmap_find_vma. */ 272 273 end_addr = start + size; 274 if (start > reserved_va - size) { 275 /* Start at the top of the address space. */ 276 end_addr = ((reserved_va - size) & -align) + size; 277 looped = true; 278 } 279 280 /* Search downward from END_ADDR, checking to see if a page is in use. */ 281 addr = end_addr; 282 while (1) { 283 addr -= incr; 284 if (addr > end_addr) { 285 if (looped) { 286 /* Failure. The entire address space has been searched. */ 287 return (abi_ulong)-1; 288 } 289 /* Re-start at the top of the address space. */ 290 addr = end_addr = ((reserved_va - size) & -align) + size; 291 looped = true; 292 } else { 293 prot = page_get_flags(addr); 294 if (prot) { 295 /* Page in use. Restart below this page. */ 296 addr = end_addr = ((addr - size) & -align) + size; 297 } else if (addr && addr + size == end_addr) { 298 /* Success! All pages between ADDR and END_ADDR are free. */ 299 if (start == mmap_next_start) { 300 mmap_next_start = addr; 301 } 302 return addr; 303 } 304 } 305 } 306 } 307 308 /* 309 * Find and reserve a free memory area of size 'size'. The search 310 * starts at 'start'. 311 * It must be called with mmap_lock() held. 312 * Return -1 if error. 313 */ 314 abi_ulong mmap_find_vma(abi_ulong start, abi_ulong size, abi_ulong align) 315 { 316 void *ptr, *prev; 317 abi_ulong addr; 318 int wrapped, repeat; 319 320 align = MAX(align, qemu_host_page_size); 321 322 /* If 'start' == 0, then a default start address is used. */ 323 if (start == 0) { 324 start = mmap_next_start; 325 } else { 326 start &= qemu_host_page_mask; 327 } 328 start = ROUND_UP(start, align); 329 330 size = HOST_PAGE_ALIGN(size); 331 332 if (reserved_va) { 333 return mmap_find_vma_reserved(start, size, align); 334 } 335 336 addr = start; 337 wrapped = repeat = 0; 338 prev = 0; 339 340 for (;; prev = ptr) { 341 /* 342 * Reserve needed memory area to avoid a race. 343 * It should be discarded using: 344 * - mmap() with MAP_FIXED flag 345 * - mremap() with MREMAP_FIXED flag 346 * - shmat() with SHM_REMAP flag 347 */ 348 ptr = mmap(g2h_untagged(addr), size, PROT_NONE, 349 MAP_ANONYMOUS|MAP_PRIVATE|MAP_NORESERVE, -1, 0); 350 351 /* ENOMEM, if host address space has no memory */ 352 if (ptr == MAP_FAILED) { 353 return (abi_ulong)-1; 354 } 355 356 /* Count the number of sequential returns of the same address. 357 This is used to modify the search algorithm below. */ 358 repeat = (ptr == prev ? repeat + 1 : 0); 359 360 if (h2g_valid(ptr + size - 1)) { 361 addr = h2g(ptr); 362 363 if ((addr & (align - 1)) == 0) { 364 /* Success. */ 365 if (start == mmap_next_start && addr >= TASK_UNMAPPED_BASE) { 366 mmap_next_start = addr + size; 367 } 368 return addr; 369 } 370 371 /* The address is not properly aligned for the target. */ 372 switch (repeat) { 373 case 0: 374 /* Assume the result that the kernel gave us is the 375 first with enough free space, so start again at the 376 next higher target page. */ 377 addr = ROUND_UP(addr, align); 378 break; 379 case 1: 380 /* Sometimes the kernel decides to perform the allocation 381 at the top end of memory instead. */ 382 addr &= -align; 383 break; 384 case 2: 385 /* Start over at low memory. */ 386 addr = 0; 387 break; 388 default: 389 /* Fail. This unaligned block must the last. */ 390 addr = -1; 391 break; 392 } 393 } else { 394 /* Since the result the kernel gave didn't fit, start 395 again at low memory. If any repetition, fail. */ 396 addr = (repeat ? -1 : 0); 397 } 398 399 /* Unmap and try again. */ 400 munmap(ptr, size); 401 402 /* ENOMEM if we checked the whole of the target address space. */ 403 if (addr == (abi_ulong)-1) { 404 return (abi_ulong)-1; 405 } else if (addr == 0) { 406 if (wrapped) { 407 return (abi_ulong)-1; 408 } 409 wrapped = 1; 410 /* Don't actually use 0 when wrapping, instead indicate 411 that we'd truly like an allocation in low memory. */ 412 addr = (mmap_min_addr > TARGET_PAGE_SIZE 413 ? TARGET_PAGE_ALIGN(mmap_min_addr) 414 : TARGET_PAGE_SIZE); 415 } else if (wrapped && addr >= start) { 416 return (abi_ulong)-1; 417 } 418 } 419 } 420 421 /* NOTE: all the constants are the HOST ones */ 422 abi_long target_mmap(abi_ulong start, abi_ulong len, int target_prot, 423 int flags, int fd, abi_ulong offset) 424 { 425 abi_ulong ret, end, real_start, real_end, retaddr, host_offset, host_len; 426 int page_flags, host_prot; 427 428 mmap_lock(); 429 trace_target_mmap(start, len, target_prot, flags, fd, offset); 430 431 if (!len) { 432 errno = EINVAL; 433 goto fail; 434 } 435 436 page_flags = validate_prot_to_pageflags(&host_prot, target_prot); 437 if (!page_flags) { 438 errno = EINVAL; 439 goto fail; 440 } 441 442 /* Also check for overflows... */ 443 len = TARGET_PAGE_ALIGN(len); 444 if (!len) { 445 errno = ENOMEM; 446 goto fail; 447 } 448 449 if (offset & ~TARGET_PAGE_MASK) { 450 errno = EINVAL; 451 goto fail; 452 } 453 454 /* 455 * If we're mapping shared memory, ensure we generate code for parallel 456 * execution and flush old translations. This will work up to the level 457 * supported by the host -- anything that requires EXCP_ATOMIC will not 458 * be atomic with respect to an external process. 459 */ 460 if (flags & MAP_SHARED) { 461 CPUState *cpu = thread_cpu; 462 if (!(cpu->tcg_cflags & CF_PARALLEL)) { 463 cpu->tcg_cflags |= CF_PARALLEL; 464 tb_flush(cpu); 465 } 466 } 467 468 real_start = start & qemu_host_page_mask; 469 host_offset = offset & qemu_host_page_mask; 470 471 /* If the user is asking for the kernel to find a location, do that 472 before we truncate the length for mapping files below. */ 473 if (!(flags & MAP_FIXED)) { 474 host_len = len + offset - host_offset; 475 host_len = HOST_PAGE_ALIGN(host_len); 476 start = mmap_find_vma(real_start, host_len, TARGET_PAGE_SIZE); 477 if (start == (abi_ulong)-1) { 478 errno = ENOMEM; 479 goto fail; 480 } 481 } 482 483 /* When mapping files into a memory area larger than the file, accesses 484 to pages beyond the file size will cause a SIGBUS. 485 486 For example, if mmaping a file of 100 bytes on a host with 4K pages 487 emulating a target with 8K pages, the target expects to be able to 488 access the first 8K. But the host will trap us on any access beyond 489 4K. 490 491 When emulating a target with a larger page-size than the hosts, we 492 may need to truncate file maps at EOF and add extra anonymous pages 493 up to the targets page boundary. */ 494 495 if ((qemu_real_host_page_size < qemu_host_page_size) && 496 !(flags & MAP_ANONYMOUS)) { 497 struct stat sb; 498 499 if (fstat (fd, &sb) == -1) 500 goto fail; 501 502 /* Are we trying to create a map beyond EOF?. */ 503 if (offset + len > sb.st_size) { 504 /* If so, truncate the file map at eof aligned with 505 the hosts real pagesize. Additional anonymous maps 506 will be created beyond EOF. */ 507 len = REAL_HOST_PAGE_ALIGN(sb.st_size - offset); 508 } 509 } 510 511 if (!(flags & MAP_FIXED)) { 512 unsigned long host_start; 513 void *p; 514 515 host_len = len + offset - host_offset; 516 host_len = HOST_PAGE_ALIGN(host_len); 517 518 /* Note: we prefer to control the mapping address. It is 519 especially important if qemu_host_page_size > 520 qemu_real_host_page_size */ 521 p = mmap(g2h_untagged(start), host_len, host_prot, 522 flags | MAP_FIXED | MAP_ANONYMOUS, -1, 0); 523 if (p == MAP_FAILED) { 524 goto fail; 525 } 526 /* update start so that it points to the file position at 'offset' */ 527 host_start = (unsigned long)p; 528 if (!(flags & MAP_ANONYMOUS)) { 529 p = mmap(g2h_untagged(start), len, host_prot, 530 flags | MAP_FIXED, fd, host_offset); 531 if (p == MAP_FAILED) { 532 munmap(g2h_untagged(start), host_len); 533 goto fail; 534 } 535 host_start += offset - host_offset; 536 } 537 start = h2g(host_start); 538 } else { 539 if (start & ~TARGET_PAGE_MASK) { 540 errno = EINVAL; 541 goto fail; 542 } 543 end = start + len; 544 real_end = HOST_PAGE_ALIGN(end); 545 546 /* 547 * Test if requested memory area fits target address space 548 * It can fail only on 64-bit host with 32-bit target. 549 * On any other target/host host mmap() handles this error correctly. 550 */ 551 if (end < start || !guest_range_valid_untagged(start, len)) { 552 errno = ENOMEM; 553 goto fail; 554 } 555 556 /* worst case: we cannot map the file because the offset is not 557 aligned, so we read it */ 558 if (!(flags & MAP_ANONYMOUS) && 559 (offset & ~qemu_host_page_mask) != (start & ~qemu_host_page_mask)) { 560 /* msync() won't work here, so we return an error if write is 561 possible while it is a shared mapping */ 562 if ((flags & MAP_TYPE) == MAP_SHARED && 563 (host_prot & PROT_WRITE)) { 564 errno = EINVAL; 565 goto fail; 566 } 567 retaddr = target_mmap(start, len, target_prot | PROT_WRITE, 568 MAP_FIXED | MAP_PRIVATE | MAP_ANONYMOUS, 569 -1, 0); 570 if (retaddr == -1) 571 goto fail; 572 if (pread(fd, g2h_untagged(start), len, offset) == -1) 573 goto fail; 574 if (!(host_prot & PROT_WRITE)) { 575 ret = target_mprotect(start, len, target_prot); 576 assert(ret == 0); 577 } 578 goto the_end; 579 } 580 581 /* handle the start of the mapping */ 582 if (start > real_start) { 583 if (real_end == real_start + qemu_host_page_size) { 584 /* one single host page */ 585 ret = mmap_frag(real_start, start, end, 586 host_prot, flags, fd, offset); 587 if (ret == -1) 588 goto fail; 589 goto the_end1; 590 } 591 ret = mmap_frag(real_start, start, real_start + qemu_host_page_size, 592 host_prot, flags, fd, offset); 593 if (ret == -1) 594 goto fail; 595 real_start += qemu_host_page_size; 596 } 597 /* handle the end of the mapping */ 598 if (end < real_end) { 599 ret = mmap_frag(real_end - qemu_host_page_size, 600 real_end - qemu_host_page_size, end, 601 host_prot, flags, fd, 602 offset + real_end - qemu_host_page_size - start); 603 if (ret == -1) 604 goto fail; 605 real_end -= qemu_host_page_size; 606 } 607 608 /* map the middle (easier) */ 609 if (real_start < real_end) { 610 void *p; 611 unsigned long offset1; 612 if (flags & MAP_ANONYMOUS) 613 offset1 = 0; 614 else 615 offset1 = offset + real_start - start; 616 p = mmap(g2h_untagged(real_start), real_end - real_start, 617 host_prot, flags, fd, offset1); 618 if (p == MAP_FAILED) 619 goto fail; 620 } 621 } 622 the_end1: 623 if (flags & MAP_ANONYMOUS) { 624 page_flags |= PAGE_ANON; 625 } 626 page_flags |= PAGE_RESET; 627 page_set_flags(start, start + len, page_flags); 628 the_end: 629 trace_target_mmap_complete(start); 630 if (qemu_loglevel_mask(CPU_LOG_PAGE)) { 631 log_page_dump(__func__); 632 } 633 tb_invalidate_phys_range(start, start + len); 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 if (end < real_end) { 668 prot = 0; 669 for (addr = end; addr < real_end; addr += TARGET_PAGE_SIZE) { 670 prot |= page_get_flags(addr); 671 } 672 if (prot != 0) 673 real_end -= qemu_host_page_size; 674 } 675 if (real_start != real_end) { 676 mmap(g2h_untagged(real_start), real_end - real_start, PROT_NONE, 677 MAP_FIXED | MAP_ANONYMOUS | MAP_PRIVATE | MAP_NORESERVE, 678 -1, 0); 679 } 680 } 681 682 int target_munmap(abi_ulong start, abi_ulong len) 683 { 684 abi_ulong end, real_start, real_end, addr; 685 int prot, ret; 686 687 trace_target_munmap(start, len); 688 689 if (start & ~TARGET_PAGE_MASK) 690 return -TARGET_EINVAL; 691 len = TARGET_PAGE_ALIGN(len); 692 if (len == 0 || !guest_range_valid_untagged(start, len)) { 693 return -TARGET_EINVAL; 694 } 695 696 mmap_lock(); 697 end = start + len; 698 real_start = start & qemu_host_page_mask; 699 real_end = HOST_PAGE_ALIGN(end); 700 701 if (start > real_start) { 702 /* handle host page containing start */ 703 prot = 0; 704 for(addr = real_start; addr < start; addr += TARGET_PAGE_SIZE) { 705 prot |= page_get_flags(addr); 706 } 707 if (real_end == real_start + qemu_host_page_size) { 708 for(addr = end; addr < real_end; addr += TARGET_PAGE_SIZE) { 709 prot |= page_get_flags(addr); 710 } 711 end = real_end; 712 } 713 if (prot != 0) 714 real_start += qemu_host_page_size; 715 } 716 if (end < real_end) { 717 prot = 0; 718 for(addr = end; addr < real_end; addr += TARGET_PAGE_SIZE) { 719 prot |= page_get_flags(addr); 720 } 721 if (prot != 0) 722 real_end -= qemu_host_page_size; 723 } 724 725 ret = 0; 726 /* unmap what we can */ 727 if (real_start < real_end) { 728 if (reserved_va) { 729 mmap_reserve(real_start, real_end - real_start); 730 } else { 731 ret = munmap(g2h_untagged(real_start), real_end - real_start); 732 } 733 } 734 735 if (ret == 0) { 736 page_set_flags(start, start + len, 0); 737 tb_invalidate_phys_range(start, start + len); 738 } 739 mmap_unlock(); 740 return ret; 741 } 742 743 abi_long target_mremap(abi_ulong old_addr, abi_ulong old_size, 744 abi_ulong new_size, unsigned long flags, 745 abi_ulong new_addr) 746 { 747 int prot; 748 void *host_addr; 749 750 if (!guest_range_valid_untagged(old_addr, old_size) || 751 ((flags & MREMAP_FIXED) && 752 !guest_range_valid_untagged(new_addr, new_size)) || 753 ((flags & MREMAP_MAYMOVE) == 0 && 754 !guest_range_valid_untagged(old_addr, new_size))) { 755 errno = ENOMEM; 756 return -1; 757 } 758 759 mmap_lock(); 760 761 if (flags & MREMAP_FIXED) { 762 host_addr = mremap(g2h_untagged(old_addr), old_size, new_size, 763 flags, g2h_untagged(new_addr)); 764 765 if (reserved_va && host_addr != MAP_FAILED) { 766 /* If new and old addresses overlap then the above mremap will 767 already have failed with EINVAL. */ 768 mmap_reserve(old_addr, old_size); 769 } 770 } else if (flags & MREMAP_MAYMOVE) { 771 abi_ulong mmap_start; 772 773 mmap_start = mmap_find_vma(0, new_size, TARGET_PAGE_SIZE); 774 775 if (mmap_start == -1) { 776 errno = ENOMEM; 777 host_addr = MAP_FAILED; 778 } else { 779 host_addr = mremap(g2h_untagged(old_addr), old_size, new_size, 780 flags | MREMAP_FIXED, 781 g2h_untagged(mmap_start)); 782 if (reserved_va) { 783 mmap_reserve(old_addr, old_size); 784 } 785 } 786 } else { 787 int prot = 0; 788 if (reserved_va && old_size < new_size) { 789 abi_ulong addr; 790 for (addr = old_addr + old_size; 791 addr < old_addr + new_size; 792 addr++) { 793 prot |= page_get_flags(addr); 794 } 795 } 796 if (prot == 0) { 797 host_addr = mremap(g2h_untagged(old_addr), 798 old_size, new_size, flags); 799 800 if (host_addr != MAP_FAILED) { 801 /* Check if address fits target address space */ 802 if (!guest_range_valid_untagged(h2g(host_addr), new_size)) { 803 /* Revert mremap() changes */ 804 host_addr = mremap(g2h_untagged(old_addr), 805 new_size, old_size, flags); 806 errno = ENOMEM; 807 host_addr = MAP_FAILED; 808 } else if (reserved_va && old_size > new_size) { 809 mmap_reserve(old_addr + old_size, old_size - new_size); 810 } 811 } 812 } else { 813 errno = ENOMEM; 814 host_addr = MAP_FAILED; 815 } 816 } 817 818 if (host_addr == MAP_FAILED) { 819 new_addr = -1; 820 } else { 821 new_addr = h2g(host_addr); 822 prot = page_get_flags(old_addr); 823 page_set_flags(old_addr, old_addr + old_size, 0); 824 page_set_flags(new_addr, new_addr + new_size, 825 prot | PAGE_VALID | PAGE_RESET); 826 } 827 tb_invalidate_phys_range(new_addr, new_addr + new_size); 828 mmap_unlock(); 829 return new_addr; 830 } 831