Annotation of qemu/linux-user/mmap.c, revision 1.1.1.5

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

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.