From 68a1c816868b3e35a1da698af412b29e61b1948a Mon Sep 17 00:00:00 2001 From: Paul Brook Date: Sat, 29 May 2010 02:27:35 +0100 Subject: Pre-allocate guest address space Allow pre-allocation of the guest virtual address space in usermode emulation. Signed-off-by: Paul Brook --- linux-user/main.c | 63 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 63 insertions(+) (limited to 'linux-user/main.c') diff --git a/linux-user/main.c b/linux-user/main.c index de1076b..0f23fc9 100644 --- a/linux-user/main.c +++ b/linux-user/main.c @@ -44,6 +44,7 @@ unsigned long mmap_min_addr; #if defined(CONFIG_USE_GUEST_BASE) unsigned long guest_base; int have_guest_base; +unsigned long reserved_va; #endif static const char *interp_prefix = CONFIG_QEMU_PREFIX; @@ -2610,6 +2611,7 @@ static void usage(void) "-0 argv0 forces target process argv[0] to be argv0\n" #if defined(CONFIG_USE_GUEST_BASE) "-B address set guest_base address to address\n" + "-R size reserve size bytes for guest virtual address space\n" #endif "\n" "Debug options:\n" @@ -2805,6 +2807,39 @@ int main(int argc, char **argv, char **envp) } else if (!strcmp(r, "B")) { guest_base = strtol(argv[optind++], NULL, 0); have_guest_base = 1; + } else if (!strcmp(r, "R")) { + char *p; + int shift = 0; + reserved_va = strtoul(argv[optind++], &p, 0); + switch (*p) { + case 'k': + case 'K': + shift = 10; + break; + case 'M': + shift = 20; + break; + case 'G': + shift = 30; + break; + } + if (shift) { + unsigned long unshifted = reserved_va; + p++; + reserved_va <<= shift; + if (((reserved_va >> shift) != unshifted) +#if HOST_LONG_BITS > TARGET_VIRT_ADDR_SPACE_BITS + || (reserved_va > (1ul << TARGET_VIRT_ADDR_SPACE_BITS)) +#endif + ) { + fprintf(stderr, "Reserved virtual address too big\n"); + exit(1); + } + } + if (*p) { + fprintf(stderr, "Unrecognised -R size suffix '%s'\n", p); + exit(1); + } #endif } else if (!strcmp(r, "drop-ld-preload")) { (void) envlist_unsetenv(envlist, "LD_PRELOAD"); @@ -2893,6 +2928,34 @@ int main(int argc, char **argv, char **envp) * proper page alignment for guest_base. */ guest_base = HOST_PAGE_ALIGN(guest_base); + + if (reserved_va) { + void *p; + int flags; + + flags = MAP_ANONYMOUS | MAP_PRIVATE | MAP_NORESERVE; + if (have_guest_base) { + flags |= MAP_FIXED; + } + p = mmap((void *)guest_base, reserved_va, PROT_NONE, flags, -1, 0); + if (p == MAP_FAILED) { + fprintf(stderr, "Unable to reserve guest address space\n"); + exit(1); + } + guest_base = (unsigned long)p; + /* Make sure the address is properly aligned. */ + if (guest_base & ~qemu_host_page_mask) { + munmap(p, reserved_va); + p = mmap((void *)guest_base, reserved_va + qemu_host_page_size, + PROT_NONE, flags, -1, 0); + if (p == MAP_FAILED) { + fprintf(stderr, "Unable to reserve guest address space\n"); + exit(1); + } + guest_base = HOST_PAGE_ALIGN((unsigned long)p); + } + qemu_log("Reserved 0x%lx bytes of guest address space\n", reserved_va); + } #endif /* CONFIG_USE_GUEST_BASE */ /* -- cgit v1.1