qemu

FORK: QEMU emulator
git clone https://git.neptards.moe/neptards/qemu.git
Log | Files | Refs | Submodules | LICENSE

mmap.c (29336B)


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