Revision fe3b4152

b/linux-user/mmap.c
273 273

  
274 274
unsigned long last_brk;
275 275

  
276
/* find a free memory area of size 'size'. The search starts at
277
   'start'. If 'start' == 0, then a default start address is used.
278
   Return -1 if error.
279
*/
280
/* page_init() marks pages used by the host as reserved to be sure not
281
   to use them. */
276
/*
277
 * Find and reserve a free memory area of size 'size'. The search
278
 * starts at 'start'.
279
 * It must be called with mmap_lock() held.
280
 * Return -1 if error.
281
 */
282 282
abi_ulong mmap_find_vma(abi_ulong start, abi_ulong size)
283 283
{
284
    abi_ulong addr, addr1, addr_start;
285
    int prot;
286
    unsigned long new_brk;
287

  
288
    new_brk = (unsigned long)sbrk(0);
289
    if (last_brk && last_brk < new_brk && last_brk == (target_ulong)last_brk) {
290
        /* This is a hack to catch the host allocating memory with brk().
291
           If it uses mmap then we loose.
292
           FIXME: We really want to avoid the host allocating memory in
293
           the first place, and maybe leave some slack to avoid switching
294
           to mmap.  */
295
        page_set_flags(last_brk & TARGET_PAGE_MASK,
296
                       TARGET_PAGE_ALIGN(new_brk),
297
                       PAGE_RESERVED); 
298
    }
299
    last_brk = new_brk;
284
    void *ptr;
285
    abi_ulong addr;
300 286

  
301 287
    size = HOST_PAGE_ALIGN(size);
302
    start = start & qemu_host_page_mask;
288
    start &= qemu_host_page_mask;
289

  
290
    /* If 'start' == 0, then a default start address is used. */
291
    if (start == 0)
292
        start = mmap_next_start;
293

  
303 294
    addr = start;
304
    if (addr == 0)
305
        addr = mmap_next_start;
306
    addr_start = addr;
295

  
307 296
    for(;;) {
308
        prot = 0;
309
        for(addr1 = addr; addr1 < (addr + size); addr1 += TARGET_PAGE_SIZE) {
310
            prot |= page_get_flags(addr1);
311
        }
312
        if (prot == 0)
297
        /*
298
         * Reserve needed memory area to avoid a race.
299
         * It should be discarded using:
300
         *  - mmap() with MAP_FIXED flag
301
         *  - mremap() with MREMAP_FIXED flag
302
         *  - shmat() with SHM_REMAP flag
303
         */
304
        ptr = mmap((void *)(unsigned long)addr, size, PROT_NONE,
305
                   MAP_ANONYMOUS|MAP_PRIVATE|MAP_NORESERVE, -1, 0);
306

  
307
        /* ENOMEM, if host address space has no memory */
308
        if (ptr == MAP_FAILED)
309
            return (abi_ulong)-1;
310

  
311
        /* If address fits target address space we've found what we need */
312
        if ((unsigned long)ptr + size - 1 <= (abi_ulong)-1)
313 313
            break;
314

  
315
        /* Unmap and try again with new page */
316
        munmap(ptr, size);
314 317
        addr += qemu_host_page_size;
315
        /* we found nothing */
316
        if (addr == addr_start)
318

  
319
        /* ENOMEM if we check whole of target address space */
320
        if (addr == start)
317 321
            return (abi_ulong)-1;
318 322
    }
319
    if (start == 0)
320
        mmap_next_start = addr + size;
321
    return addr;
323

  
324
    /* Update default start address */
325
    if (start == mmap_next_start)
326
        mmap_next_start = (unsigned long)ptr + size;
327

  
328
    return h2g(ptr);
322 329
}
323 330

  
324 331
/* NOTE: all the constants are the HOST ones */

Also available in: Unified diff