Revision 68a1c816

b/cpu-all.h
627 627
#if defined(CONFIG_USE_GUEST_BASE)
628 628
extern unsigned long guest_base;
629 629
extern int have_guest_base;
630
extern unsigned long reserved_va;
630 631
#define GUEST_BASE guest_base
631 632
#else
632 633
#define GUEST_BASE 0ul
b/linux-user/elfload.c
1682 1682
     * In case where user has not explicitly set the guest_base, we
1683 1683
     * probe here that should we set it automatically.
1684 1684
     */
1685
    if (!have_guest_base) {
1685
    if (!(have_guest_base || reserved_va)) {
1686 1686
        /*
1687 1687
         * Go through ELF program header table and find the address
1688 1688
         * range used by loadable segments.  Check that this is available on
b/linux-user/main.c
44 44
#if defined(CONFIG_USE_GUEST_BASE)
45 45
unsigned long guest_base;
46 46
int have_guest_base;
47
unsigned long reserved_va;
47 48
#endif
48 49

  
49 50
static const char *interp_prefix = CONFIG_QEMU_PREFIX;
......
2610 2611
           "-0 argv0          forces target process argv[0] to be argv0\n"
2611 2612
#if defined(CONFIG_USE_GUEST_BASE)
2612 2613
           "-B address        set guest_base address to address\n"
2614
           "-R size           reserve size bytes for guest virtual address space\n"
2613 2615
#endif
2614 2616
           "\n"
2615 2617
           "Debug options:\n"
......
2805 2807
        } else if (!strcmp(r, "B")) {
2806 2808
           guest_base = strtol(argv[optind++], NULL, 0);
2807 2809
           have_guest_base = 1;
2810
        } else if (!strcmp(r, "R")) {
2811
            char *p;
2812
            int shift = 0;
2813
            reserved_va = strtoul(argv[optind++], &p, 0);
2814
            switch (*p) {
2815
            case 'k':
2816
            case 'K':
2817
                shift = 10;
2818
                break;
2819
            case 'M':
2820
                shift = 20;
2821
                break;
2822
            case 'G':
2823
                shift = 30;
2824
                break;
2825
            }
2826
            if (shift) {
2827
                unsigned long unshifted = reserved_va;
2828
                p++;
2829
                reserved_va <<= shift;
2830
                if (((reserved_va >> shift) != unshifted)
2831
#if HOST_LONG_BITS > TARGET_VIRT_ADDR_SPACE_BITS
2832
                    || (reserved_va > (1ul << TARGET_VIRT_ADDR_SPACE_BITS))
2833
#endif
2834
                    ) {
2835
                    fprintf(stderr, "Reserved virtual address too big\n");
2836
                    exit(1);
2837
                }
2838
            }
2839
            if (*p) {
2840
                fprintf(stderr, "Unrecognised -R size suffix '%s'\n", p);
2841
                exit(1);
2842
            }
2808 2843
#endif
2809 2844
        } else if (!strcmp(r, "drop-ld-preload")) {
2810 2845
            (void) envlist_unsetenv(envlist, "LD_PRELOAD");
......
2893 2928
     * proper page alignment for guest_base.
2894 2929
     */
2895 2930
    guest_base = HOST_PAGE_ALIGN(guest_base);
2931

  
2932
    if (reserved_va) {
2933
        void *p;
2934
        int flags;
2935

  
2936
        flags = MAP_ANONYMOUS | MAP_PRIVATE | MAP_NORESERVE;
2937
        if (have_guest_base) {
2938
            flags |= MAP_FIXED;
2939
        }
2940
        p = mmap((void *)guest_base, reserved_va, PROT_NONE, flags, -1, 0);
2941
        if (p == MAP_FAILED) {
2942
            fprintf(stderr, "Unable to reserve guest address space\n");
2943
            exit(1);
2944
        }
2945
        guest_base = (unsigned long)p;
2946
        /* Make sure the address is properly aligned.  */
2947
        if (guest_base & ~qemu_host_page_mask) {
2948
            munmap(p, reserved_va);
2949
            p = mmap((void *)guest_base, reserved_va + qemu_host_page_size,
2950
                     PROT_NONE, flags, -1, 0);
2951
            if (p == MAP_FAILED) {
2952
                fprintf(stderr, "Unable to reserve guest address space\n");
2953
                exit(1);
2954
            }
2955
            guest_base = HOST_PAGE_ALIGN((unsigned long)p);
2956
        }
2957
        qemu_log("Reserved 0x%lx bytes of guest address space\n", reserved_va);
2958
    }
2896 2959
#endif /* CONFIG_USE_GUEST_BASE */
2897 2960

  
2898 2961
    /*
b/linux-user/mmap.c
216 216

  
217 217
unsigned long last_brk;
218 218

  
219
/* Subroutine of mmap_find_vma, used when we have pre-allocated a chunk
220
   of guest address space.  */
221
static abi_ulong mmap_find_vma_reserved(abi_ulong start, abi_ulong size)
222
{
223
    abi_ulong addr;
224
    abi_ulong last_addr;
225
    int prot;
226
    int looped = 0;
227

  
228
    if (size > reserved_va) {
229
        return (abi_ulong)-1;
230
    }
231

  
232
    last_addr = start;
233
    for (addr = start; last_addr + size != addr; addr += qemu_host_page_size) {
234
        if (last_addr + size >= reserved_va
235
            || (abi_ulong)(last_addr + size) < last_addr) {
236
            if (looped) {
237
                return (abi_ulong)-1;
238
            }
239
            last_addr = qemu_host_page_size;
240
            addr = 0;
241
            looped = 1;
242
            continue;
243
        }
244
        prot = page_get_flags(addr);
245
        if (prot) {
246
            last_addr = addr + qemu_host_page_size;
247
        }
248
    }
249
    mmap_next_start = addr;
250
    return last_addr;
251
}
252

  
219 253
/*
220 254
 * Find and reserve a free memory area of size 'size'. The search
221 255
 * starts at 'start'.
......
237 271

  
238 272
    size = HOST_PAGE_ALIGN(size);
239 273

  
274
    if (reserved_va) {
275
        return mmap_find_vma_reserved(start, size);
276
    }
277

  
240 278
    addr = start;
241 279
    wrapped = repeat = 0;
242 280
    prev = 0;
......
525 563
    return -1;
526 564
}
527 565

  
566
static void mmap_reserve(abi_ulong start, abi_ulong size)
567
{
568
    abi_ulong real_start;
569
    abi_ulong real_end;
570
    abi_ulong addr;
571
    abi_ulong end;
572
    int prot;
573

  
574
    real_start = start & qemu_host_page_mask;
575
    real_end = HOST_PAGE_ALIGN(start + size);
576
    end = start + size;
577
    if (start > real_start) {
578
        /* handle host page containing start */
579
        prot = 0;
580
        for (addr = real_start; addr < start; addr += TARGET_PAGE_SIZE) {
581
            prot |= page_get_flags(addr);
582
        }
583
        if (real_end == real_start + qemu_host_page_size) {
584
            for (addr = end; addr < real_end; addr += TARGET_PAGE_SIZE) {
585
                prot |= page_get_flags(addr);
586
            }
587
            end = real_end;
588
        }
589
        if (prot != 0)
590
            real_start += qemu_host_page_size;
591
    }
592
    if (end < real_end) {
593
        prot = 0;
594
        for (addr = end; addr < real_end; addr += TARGET_PAGE_SIZE) {
595
            prot |= page_get_flags(addr);
596
        }
597
        if (prot != 0)
598
            real_end -= qemu_host_page_size;
599
    }
600
    if (real_start != real_end) {
601
        mmap(g2h(real_start), real_end - real_start, PROT_NONE,
602
                 MAP_FIXED | MAP_ANONYMOUS | MAP_PRIVATE | MAP_NORESERVE,
603
                 -1, 0);
604
    }
605
}
606

  
528 607
int target_munmap(abi_ulong start, abi_ulong len)
529 608
{
530 609
    abi_ulong end, real_start, real_end, addr;
......
572 651
    ret = 0;
573 652
    /* unmap what we can */
574 653
    if (real_start < real_end) {
575
        ret = munmap(g2h(real_start), real_end - real_start);
654
        if (reserved_va) {
655
            mmap_reserve(real_start, real_end - real_start);
656
        } else {
657
            ret = munmap(g2h(real_start), real_end - real_start);
658
        }
576 659
    }
577 660

  
578 661
    if (ret == 0)
......
590 673

  
591 674
    mmap_lock();
592 675

  
593
    if (flags & MREMAP_FIXED)
676
    if (flags & MREMAP_FIXED) {
594 677
        host_addr = (void *) syscall(__NR_mremap, g2h(old_addr),
595 678
                                     old_size, new_size,
596 679
                                     flags,
597
                                     new_addr);
598
    else if (flags & MREMAP_MAYMOVE) {
680
                                     g2h(new_addr));
681

  
682
        if (reserved_va && host_addr != MAP_FAILED) {
683
            /* If new and old addresses overlap then the above mremap will
684
               already have failed with EINVAL.  */
685
            mmap_reserve(old_addr, old_size);
686
        }
687
    } else if (flags & MREMAP_MAYMOVE) {
599 688
        abi_ulong mmap_start;
600 689

  
601 690
        mmap_start = mmap_find_vma(0, new_size);
......
603 692
        if (mmap_start == -1) {
604 693
            errno = ENOMEM;
605 694
            host_addr = MAP_FAILED;
606
        } else
695
        } else {
607 696
            host_addr = (void *) syscall(__NR_mremap, g2h(old_addr),
608 697
                                         old_size, new_size,
609 698
                                         flags | MREMAP_FIXED,
610 699
                                         g2h(mmap_start));
700
            mmap_reserve(old_addr, old_size);
701
        }
611 702
    } else {
612
        host_addr = mremap(g2h(old_addr), old_size, new_size, flags);
703
        int prot = 0;
704
        if (reserved_va && old_size < new_size) {
705
            abi_ulong addr;
706
            for (addr = old_addr + old_size;
707
                 addr < old_addr + new_size;
708
                 addr++) {
709
                prot |= page_get_flags(addr);
710
            }
711
        }
712
        if (prot == 0) {
713
            host_addr = mremap(g2h(old_addr), old_size, new_size, flags);
714
            if (host_addr != MAP_FAILED && reserved_va && old_size > new_size) {
715
                mmap_reserve(old_addr + old_size, new_size - old_size);
716
            }
717
        } else {
718
            errno = ENOMEM;
719
            host_addr = MAP_FAILED;
720
        }
613 721
        /* Check if address fits target address space */
614 722
        if ((unsigned long)host_addr + new_size > (abi_ulong)-1) {
615 723
            /* Revert mremap() changes */
b/qemu-doc.texi
2124 2124
@subsection Command line options
2125 2125

  
2126 2126
@example
2127
usage: qemu-i386 [-h] [-d] [-L path] [-s size] [-cpu model] [-g port] [-B offset] program [arguments...]
2127
usage: qemu-i386 [-h] [-d] [-L path] [-s size] [-cpu model] [-g port] [-B offset] [-R size] program [arguments...]
2128 2128
@end example
2129 2129

  
2130 2130
@table @option
......
2140 2140
Offset guest address by the specified number of bytes.  This is useful when
2141 2141
the address region rewuired by guest applications is reserved on the host.
2142 2142
Ths option is currently only supported on some hosts.
2143
@item -R size
2144
Pre-allocate a guest virtual address space of the given size (in bytes).
2145
"G", "M", and "k" suffixes may be used when specifying the size.  
2143 2146
@end table
2144 2147

  
2145 2148
Debug options:

Also available in: Unified diff