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