symbian-qemu-0.9.1-12/qemu-symbian-svp/linux-user/mmap.c
changeset 1 2fb8b9db1c86
equal deleted inserted replaced
0:ffa851df0825 1:2fb8b9db1c86
       
     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, write to the Free Software
       
    18  *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
       
    19  */
       
    20 #include <stdlib.h>
       
    21 #include <stdio.h>
       
    22 #include <stdarg.h>
       
    23 #include <string.h>
       
    24 #include <unistd.h>
       
    25 #include <errno.h>
       
    26 #include <sys/mman.h>
       
    27 #include <linux/mman.h>
       
    28 #include <linux/unistd.h>
       
    29 
       
    30 #include "qemu.h"
       
    31 #include "qemu-common.h"
       
    32 
       
    33 //#define DEBUG_MMAP
       
    34 
       
    35 #if defined(USE_NPTL)
       
    36 pthread_mutex_t mmap_mutex;
       
    37 static int __thread mmap_lock_count;
       
    38 
       
    39 void mmap_lock(void)
       
    40 {
       
    41     if (mmap_lock_count++ == 0) {
       
    42         pthread_mutex_lock(&mmap_mutex);
       
    43     }
       
    44 }
       
    45 
       
    46 void mmap_unlock(void)
       
    47 {
       
    48     if (--mmap_lock_count == 0) {
       
    49         pthread_mutex_unlock(&mmap_mutex);
       
    50     }
       
    51 }
       
    52 
       
    53 /* Grab lock to make sure things are in a consistent state after fork().  */
       
    54 void mmap_fork_start(void)
       
    55 {
       
    56     if (mmap_lock_count)
       
    57         abort();
       
    58     pthread_mutex_lock(&mmap_mutex);
       
    59 }
       
    60 
       
    61 void mmap_fork_end(int child)
       
    62 {
       
    63     if (child)
       
    64         pthread_mutex_init(&mmap_mutex, NULL);
       
    65     else
       
    66         pthread_mutex_unlock(&mmap_mutex);
       
    67 }
       
    68 #else
       
    69 /* We aren't threadsafe to start with, so no need to worry about locking.  */
       
    70 void mmap_lock(void)
       
    71 {
       
    72 }
       
    73 
       
    74 void mmap_unlock(void)
       
    75 {
       
    76 }
       
    77 #endif
       
    78 
       
    79 void *qemu_vmalloc(size_t size)
       
    80 {
       
    81     void *p;
       
    82     unsigned long addr;
       
    83     mmap_lock();
       
    84     /* Use map and mark the pages as used.  */
       
    85     p = mmap(NULL, size, PROT_READ | PROT_WRITE,
       
    86              MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
       
    87 
       
    88     addr = (unsigned long)p;
       
    89     if (addr == (target_ulong) addr) {
       
    90         /* Allocated region overlaps guest address space.
       
    91            This may recurse.  */
       
    92         page_set_flags(addr & TARGET_PAGE_MASK, TARGET_PAGE_ALIGN(addr + size),
       
    93                        PAGE_RESERVED);
       
    94     }
       
    95 
       
    96     mmap_unlock();
       
    97     return p;
       
    98 }
       
    99 
       
   100 void *qemu_malloc(size_t size)
       
   101 {
       
   102     char * p;
       
   103     size += 16;
       
   104     p = qemu_vmalloc(size);
       
   105     *(size_t *)p = size;
       
   106     return p + 16;
       
   107 }
       
   108 
       
   109 /* We use map, which is always zero initialized.  */
       
   110 void * qemu_mallocz(size_t size)
       
   111 {
       
   112     return qemu_malloc(size);
       
   113 }
       
   114 
       
   115 void qemu_free(void *ptr)
       
   116 {
       
   117     /* FIXME: We should unmark the reserved pages here.  However this gets
       
   118        complicated when one target page spans multiple host pages, so we
       
   119        don't bother.  */
       
   120     size_t *p;
       
   121     p = (size_t *)((char *)ptr - 16);
       
   122     munmap(p, *p);
       
   123 }
       
   124 
       
   125 /* NOTE: all the constants are the HOST ones, but addresses are target. */
       
   126 int target_mprotect(abi_ulong start, abi_ulong len, int prot)
       
   127 {
       
   128     abi_ulong end, host_start, host_end, addr;
       
   129     int prot1, ret;
       
   130 
       
   131 #ifdef DEBUG_MMAP
       
   132     printf("mprotect: start=0x" TARGET_FMT_lx
       
   133            "len=0x" TARGET_FMT_lx " prot=%c%c%c\n", start, len,
       
   134            prot & PROT_READ ? 'r' : '-',
       
   135            prot & PROT_WRITE ? 'w' : '-',
       
   136            prot & PROT_EXEC ? 'x' : '-');
       
   137 #endif
       
   138 
       
   139     if ((start & ~TARGET_PAGE_MASK) != 0)
       
   140         return -EINVAL;
       
   141     len = TARGET_PAGE_ALIGN(len);
       
   142     end = start + len;
       
   143     if (end < start)
       
   144         return -EINVAL;
       
   145     prot &= PROT_READ | PROT_WRITE | PROT_EXEC;
       
   146     if (len == 0)
       
   147         return 0;
       
   148 
       
   149     mmap_lock();
       
   150     host_start = start & qemu_host_page_mask;
       
   151     host_end = HOST_PAGE_ALIGN(end);
       
   152     if (start > host_start) {
       
   153         /* handle host page containing start */
       
   154         prot1 = prot;
       
   155         for(addr = host_start; addr < start; addr += TARGET_PAGE_SIZE) {
       
   156             prot1 |= page_get_flags(addr);
       
   157         }
       
   158         if (host_end == host_start + qemu_host_page_size) {
       
   159             for(addr = end; addr < host_end; addr += TARGET_PAGE_SIZE) {
       
   160                 prot1 |= page_get_flags(addr);
       
   161             }
       
   162             end = host_end;
       
   163         }
       
   164         ret = mprotect(g2h(host_start), qemu_host_page_size, prot1 & PAGE_BITS);
       
   165         if (ret != 0)
       
   166             goto error;
       
   167         host_start += qemu_host_page_size;
       
   168     }
       
   169     if (end < host_end) {
       
   170         prot1 = prot;
       
   171         for(addr = end; addr < host_end; addr += TARGET_PAGE_SIZE) {
       
   172             prot1 |= page_get_flags(addr);
       
   173         }
       
   174         ret = mprotect(g2h(host_end - qemu_host_page_size), qemu_host_page_size,
       
   175                        prot1 & PAGE_BITS);
       
   176         if (ret != 0)
       
   177             goto error;
       
   178         host_end -= qemu_host_page_size;
       
   179     }
       
   180 
       
   181     /* handle the pages in the middle */
       
   182     if (host_start < host_end) {
       
   183         ret = mprotect(g2h(host_start), host_end - host_start, prot);
       
   184         if (ret != 0)
       
   185             goto error;
       
   186     }
       
   187     page_set_flags(start, start + len, prot | PAGE_VALID);
       
   188     mmap_unlock();
       
   189     return 0;
       
   190 error:
       
   191     mmap_unlock();
       
   192     return ret;
       
   193 }
       
   194 
       
   195 /* map an incomplete host page */
       
   196 static int mmap_frag(abi_ulong real_start,
       
   197                      abi_ulong start, abi_ulong end,
       
   198                      int prot, int flags, int fd, abi_ulong offset)
       
   199 {
       
   200     abi_ulong real_end, addr;
       
   201     void *host_start;
       
   202     int prot1, prot_new;
       
   203 
       
   204     real_end = real_start + qemu_host_page_size;
       
   205     host_start = g2h(real_start);
       
   206 
       
   207     /* get the protection of the target pages outside the mapping */
       
   208     prot1 = 0;
       
   209     for(addr = real_start; addr < real_end; addr++) {
       
   210         if (addr < start || addr >= end)
       
   211             prot1 |= page_get_flags(addr);
       
   212     }
       
   213 
       
   214     if (prot1 == 0) {
       
   215         /* no page was there, so we allocate one */
       
   216         void *p = mmap(host_start, qemu_host_page_size, prot,
       
   217                        flags | MAP_ANONYMOUS, -1, 0);
       
   218         if (p == MAP_FAILED)
       
   219             return -1;
       
   220         prot1 = prot;
       
   221     }
       
   222     prot1 &= PAGE_BITS;
       
   223 
       
   224     prot_new = prot | prot1;
       
   225     if (!(flags & MAP_ANONYMOUS)) {
       
   226         /* msync() won't work here, so we return an error if write is
       
   227            possible while it is a shared mapping */
       
   228         if ((flags & MAP_TYPE) == MAP_SHARED &&
       
   229             (prot & PROT_WRITE))
       
   230             return -EINVAL;
       
   231 
       
   232         /* adjust protection to be able to read */
       
   233         if (!(prot1 & PROT_WRITE))
       
   234             mprotect(host_start, qemu_host_page_size, prot1 | PROT_WRITE);
       
   235 
       
   236         /* read the corresponding file data */
       
   237         pread(fd, g2h(start), end - start, offset);
       
   238 
       
   239         /* put final protection */
       
   240         if (prot_new != (prot1 | PROT_WRITE))
       
   241             mprotect(host_start, qemu_host_page_size, prot_new);
       
   242     } else {
       
   243         /* just update the protection */
       
   244         if (prot_new != prot1) {
       
   245             mprotect(host_start, qemu_host_page_size, prot_new);
       
   246         }
       
   247     }
       
   248     return 0;
       
   249 }
       
   250 
       
   251 #if defined(__CYGWIN__)
       
   252 /* Cygwin doesn't have a whole lot of address space.  */
       
   253 static abi_ulong mmap_next_start = 0x18000000;
       
   254 #else
       
   255 static abi_ulong mmap_next_start = 0x40000000;
       
   256 #endif
       
   257 
       
   258 unsigned long last_brk;
       
   259 
       
   260 /* find a free memory area of size 'size'. The search starts at
       
   261    'start'. If 'start' == 0, then a default start address is used.
       
   262    Return -1 if error.
       
   263 */
       
   264 /* page_init() marks pages used by the host as reserved to be sure not
       
   265    to use them. */
       
   266 static abi_ulong mmap_find_vma(abi_ulong start, abi_ulong size)
       
   267 {
       
   268     abi_ulong addr, addr1, addr_start;
       
   269     int prot;
       
   270     unsigned long new_brk;
       
   271 
       
   272     new_brk = (unsigned long)sbrk(0);
       
   273     if (last_brk && last_brk < new_brk && last_brk == (target_ulong)last_brk) {
       
   274         /* This is a hack to catch the host allocating memory with brk().
       
   275            If it uses mmap then we loose.
       
   276            FIXME: We really want to avoid the host allocating memory in
       
   277            the first place, and maybe leave some slack to avoid switching
       
   278            to mmap.  */
       
   279         page_set_flags(last_brk & TARGET_PAGE_MASK,
       
   280                        TARGET_PAGE_ALIGN(new_brk),
       
   281                        PAGE_RESERVED); 
       
   282     }
       
   283     last_brk = new_brk;
       
   284 
       
   285     size = HOST_PAGE_ALIGN(size);
       
   286     start = start & qemu_host_page_mask;
       
   287     addr = start;
       
   288     if (addr == 0)
       
   289         addr = mmap_next_start;
       
   290     addr_start = addr;
       
   291     for(;;) {
       
   292         prot = 0;
       
   293         for(addr1 = addr; addr1 < (addr + size); addr1 += TARGET_PAGE_SIZE) {
       
   294             prot |= page_get_flags(addr1);
       
   295         }
       
   296         if (prot == 0)
       
   297             break;
       
   298         addr += qemu_host_page_size;
       
   299         /* we found nothing */
       
   300         if (addr == addr_start)
       
   301             return (abi_ulong)-1;
       
   302     }
       
   303     if (start == 0)
       
   304         mmap_next_start = addr + size;
       
   305     return addr;
       
   306 }
       
   307 
       
   308 /* NOTE: all the constants are the HOST ones */
       
   309 abi_long target_mmap(abi_ulong start, abi_ulong len, int prot,
       
   310                      int flags, int fd, abi_ulong offset)
       
   311 {
       
   312     abi_ulong ret, end, real_start, real_end, retaddr, host_offset, host_len;
       
   313     unsigned long host_start;
       
   314 
       
   315     mmap_lock();
       
   316 #ifdef DEBUG_MMAP
       
   317     {
       
   318         printf("mmap: start=0x" TARGET_FMT_lx
       
   319                " len=0x" TARGET_FMT_lx " prot=%c%c%c flags=",
       
   320                start, len,
       
   321                prot & PROT_READ ? 'r' : '-',
       
   322                prot & PROT_WRITE ? 'w' : '-',
       
   323                prot & PROT_EXEC ? 'x' : '-');
       
   324         if (flags & MAP_FIXED)
       
   325             printf("MAP_FIXED ");
       
   326         if (flags & MAP_ANONYMOUS)
       
   327             printf("MAP_ANON ");
       
   328         switch(flags & MAP_TYPE) {
       
   329         case MAP_PRIVATE:
       
   330             printf("MAP_PRIVATE ");
       
   331             break;
       
   332         case MAP_SHARED:
       
   333             printf("MAP_SHARED ");
       
   334             break;
       
   335         default:
       
   336             printf("[MAP_TYPE=0x%x] ", flags & MAP_TYPE);
       
   337             break;
       
   338         }
       
   339         printf("fd=%d offset=" TARGET_FMT_lx "\n", fd, offset);
       
   340     }
       
   341 #endif
       
   342 
       
   343     if (offset & ~TARGET_PAGE_MASK) {
       
   344         errno = EINVAL;
       
   345         goto fail;
       
   346     }
       
   347 
       
   348     len = TARGET_PAGE_ALIGN(len);
       
   349     if (len == 0)
       
   350         goto the_end;
       
   351     real_start = start & qemu_host_page_mask;
       
   352 
       
   353     if (!(flags & MAP_FIXED)) {
       
   354         abi_ulong mmap_start;
       
   355         void *p;
       
   356         host_offset = offset & qemu_host_page_mask;
       
   357         host_len = len + offset - host_offset;
       
   358         host_len = HOST_PAGE_ALIGN(host_len);
       
   359         mmap_start = mmap_find_vma(real_start, host_len);
       
   360         if (mmap_start == (abi_ulong)-1) {
       
   361             errno = ENOMEM;
       
   362             goto fail;
       
   363         }
       
   364         /* Note: we prefer to control the mapping address. It is
       
   365            especially important if qemu_host_page_size >
       
   366            qemu_real_host_page_size */
       
   367         p = mmap(g2h(mmap_start),
       
   368                  host_len, prot, flags | MAP_FIXED, fd, host_offset);
       
   369         if (p == MAP_FAILED)
       
   370             goto fail;
       
   371         /* update start so that it points to the file position at 'offset' */
       
   372         host_start = (unsigned long)p;
       
   373         if (!(flags & MAP_ANONYMOUS))
       
   374             host_start += offset - host_offset;
       
   375         start = h2g(host_start);
       
   376     } else {
       
   377         int flg;
       
   378         target_ulong addr;
       
   379 
       
   380         if (start & ~TARGET_PAGE_MASK) {
       
   381             errno = EINVAL;
       
   382             goto fail;
       
   383         }
       
   384         end = start + len;
       
   385         real_end = HOST_PAGE_ALIGN(end);
       
   386 
       
   387 	/*
       
   388 	 * Test if requested memory area fits target address space
       
   389 	 * It can fail only on 64-bit host with 32-bit target.
       
   390 	 * On any other target/host host mmap() handles this error correctly.
       
   391 	 */
       
   392         if ((unsigned long)start + len - 1 > (abi_ulong) -1) {
       
   393             errno = EINVAL;
       
   394             goto fail;
       
   395         }
       
   396 
       
   397         for(addr = real_start; addr < real_end; addr += TARGET_PAGE_SIZE) {
       
   398             flg = page_get_flags(addr);
       
   399             if (flg & PAGE_RESERVED) {
       
   400                 errno = ENXIO;
       
   401                 goto fail;
       
   402             }
       
   403         }
       
   404 
       
   405         /* worst case: we cannot map the file because the offset is not
       
   406            aligned, so we read it */
       
   407         if (!(flags & MAP_ANONYMOUS) &&
       
   408             (offset & ~qemu_host_page_mask) != (start & ~qemu_host_page_mask)) {
       
   409             /* msync() won't work here, so we return an error if write is
       
   410                possible while it is a shared mapping */
       
   411             if ((flags & MAP_TYPE) == MAP_SHARED &&
       
   412                 (prot & PROT_WRITE)) {
       
   413                 errno = EINVAL;
       
   414                 goto fail;
       
   415             }
       
   416             retaddr = target_mmap(start, len, prot | PROT_WRITE,
       
   417                                   MAP_FIXED | MAP_PRIVATE | MAP_ANONYMOUS,
       
   418                                   -1, 0);
       
   419             if (retaddr == -1)
       
   420                 goto fail;
       
   421             pread(fd, g2h(start), len, offset);
       
   422             if (!(prot & PROT_WRITE)) {
       
   423                 ret = target_mprotect(start, len, prot);
       
   424                 if (ret != 0) {
       
   425                     start = ret;
       
   426                     goto the_end;
       
   427                 }
       
   428             }
       
   429             goto the_end;
       
   430         }
       
   431         
       
   432         /* handle the start of the mapping */
       
   433         if (start > real_start) {
       
   434             if (real_end == real_start + qemu_host_page_size) {
       
   435                 /* one single host page */
       
   436                 ret = mmap_frag(real_start, start, end,
       
   437                                 prot, flags, fd, offset);
       
   438                 if (ret == -1)
       
   439                     goto fail;
       
   440                 goto the_end1;
       
   441             }
       
   442             ret = mmap_frag(real_start, start, real_start + qemu_host_page_size,
       
   443                             prot, flags, fd, offset);
       
   444             if (ret == -1)
       
   445                 goto fail;
       
   446             real_start += qemu_host_page_size;
       
   447         }
       
   448         /* handle the end of the mapping */
       
   449         if (end < real_end) {
       
   450             ret = mmap_frag(real_end - qemu_host_page_size,
       
   451                             real_end - qemu_host_page_size, real_end,
       
   452                             prot, flags, fd,
       
   453                             offset + real_end - qemu_host_page_size - start);
       
   454             if (ret == -1)
       
   455                 goto fail;
       
   456             real_end -= qemu_host_page_size;
       
   457         }
       
   458 
       
   459         /* map the middle (easier) */
       
   460         if (real_start < real_end) {
       
   461             void *p;
       
   462             unsigned long offset1;
       
   463             if (flags & MAP_ANONYMOUS)
       
   464                 offset1 = 0;
       
   465             else
       
   466                 offset1 = offset + real_start - start;
       
   467             p = mmap(g2h(real_start), real_end - real_start,
       
   468                      prot, flags, fd, offset1);
       
   469             if (p == MAP_FAILED)
       
   470                 goto fail;
       
   471         }
       
   472     }
       
   473  the_end1:
       
   474     page_set_flags(start, start + len, prot | PAGE_VALID);
       
   475  the_end:
       
   476 #ifdef DEBUG_MMAP
       
   477     printf("ret=0x" TARGET_FMT_lx "\n", start);
       
   478     page_dump(stdout);
       
   479     printf("\n");
       
   480 #endif
       
   481     mmap_unlock();
       
   482     return start;
       
   483 fail:
       
   484     mmap_unlock();
       
   485     return -1;
       
   486 }
       
   487 
       
   488 int target_munmap(abi_ulong start, abi_ulong len)
       
   489 {
       
   490     abi_ulong end, real_start, real_end, addr;
       
   491     int prot, ret;
       
   492 
       
   493 #ifdef DEBUG_MMAP
       
   494     printf("munmap: start=0x%lx len=0x%lx\n", start, len);
       
   495 #endif
       
   496     if (start & ~TARGET_PAGE_MASK)
       
   497         return -EINVAL;
       
   498     len = TARGET_PAGE_ALIGN(len);
       
   499     if (len == 0)
       
   500         return -EINVAL;
       
   501     mmap_lock();
       
   502     end = start + len;
       
   503     real_start = start & qemu_host_page_mask;
       
   504     real_end = HOST_PAGE_ALIGN(end);
       
   505 
       
   506     if (start > real_start) {
       
   507         /* handle host page containing start */
       
   508         prot = 0;
       
   509         for(addr = real_start; addr < start; addr += TARGET_PAGE_SIZE) {
       
   510             prot |= page_get_flags(addr);
       
   511         }
       
   512         if (real_end == real_start + qemu_host_page_size) {
       
   513             for(addr = end; addr < real_end; addr += TARGET_PAGE_SIZE) {
       
   514                 prot |= page_get_flags(addr);
       
   515             }
       
   516             end = real_end;
       
   517         }
       
   518         if (prot != 0)
       
   519             real_start += qemu_host_page_size;
       
   520     }
       
   521     if (end < real_end) {
       
   522         prot = 0;
       
   523         for(addr = end; addr < real_end; addr += TARGET_PAGE_SIZE) {
       
   524             prot |= page_get_flags(addr);
       
   525         }
       
   526         if (prot != 0)
       
   527             real_end -= qemu_host_page_size;
       
   528     }
       
   529 
       
   530     ret = 0;
       
   531     /* unmap what we can */
       
   532     if (real_start < real_end) {
       
   533         ret = munmap(g2h(real_start), real_end - real_start);
       
   534     }
       
   535 
       
   536     if (ret == 0)
       
   537         page_set_flags(start, start + len, 0);
       
   538     mmap_unlock();
       
   539     return ret;
       
   540 }
       
   541 
       
   542 abi_long target_mremap(abi_ulong old_addr, abi_ulong old_size,
       
   543                        abi_ulong new_size, unsigned long flags,
       
   544                        abi_ulong new_addr)
       
   545 {
       
   546     int prot;
       
   547     void *host_addr;
       
   548 
       
   549     mmap_lock();
       
   550 
       
   551     if (flags & MREMAP_FIXED)
       
   552         host_addr = (void *) syscall(__NR_mremap, g2h(old_addr),
       
   553                                      old_size, new_size,
       
   554                                      flags,
       
   555                                      new_addr);
       
   556     else if (flags & MREMAP_MAYMOVE) {
       
   557         abi_ulong mmap_start;
       
   558 
       
   559         mmap_start = mmap_find_vma(0, new_size);
       
   560 
       
   561         if (mmap_start == -1) {
       
   562             errno = ENOMEM;
       
   563             host_addr = MAP_FAILED;
       
   564         } else
       
   565             host_addr = (void *) syscall(__NR_mremap, g2h(old_addr),
       
   566                                          old_size, new_size,
       
   567                                          flags | MREMAP_FIXED,
       
   568                                          g2h(mmap_start));
       
   569     } else {
       
   570         host_addr = mremap(g2h(old_addr), old_size, new_size, flags);
       
   571         /* Check if address fits target address space */
       
   572         if ((unsigned long)host_addr + new_size > (abi_ulong)-1) {
       
   573             /* Revert mremap() changes */
       
   574             host_addr = mremap(g2h(old_addr), new_size, old_size, flags);
       
   575             errno = ENOMEM;
       
   576             host_addr = MAP_FAILED;
       
   577         }
       
   578     }
       
   579 
       
   580     if (host_addr == MAP_FAILED) {
       
   581         new_addr = -1;
       
   582     } else {
       
   583         new_addr = h2g(host_addr);
       
   584         prot = page_get_flags(old_addr);
       
   585         page_set_flags(old_addr, old_addr + old_size, 0);
       
   586         page_set_flags(new_addr, new_addr + new_size, prot | PAGE_VALID);
       
   587     }
       
   588     mmap_unlock();
       
   589     return new_addr;
       
   590 }
       
   591 
       
   592 int target_msync(abi_ulong start, abi_ulong len, int flags)
       
   593 {
       
   594     abi_ulong end;
       
   595 
       
   596     if (start & ~TARGET_PAGE_MASK)
       
   597         return -EINVAL;
       
   598     len = TARGET_PAGE_ALIGN(len);
       
   599     end = start + len;
       
   600     if (end < start)
       
   601         return -EINVAL;
       
   602     if (end == start)
       
   603         return 0;
       
   604 
       
   605     start &= qemu_host_page_mask;
       
   606     return msync(g2h(start), end - start, flags);
       
   607 }