summaryrefslogtreecommitdiff
path: root/linux-user/main.c
diff options
context:
space:
mode:
authorPaul Brook <paul@codesourcery.com>2010-05-29 02:27:35 +0100
committerPaul Brook <paul@codesourcery.com>2010-05-29 02:27:35 +0100
commit68a1c816868b3e35a1da698af412b29e61b1948a (patch)
tree2f8ae184dd481d3a0e74d1de76fc7b53189fd97c /linux-user/main.c
parent0be1d07c0e4fa7395aca5129cfc5bb9a0a94a78c (diff)
Pre-allocate guest address space
Allow pre-allocation of the guest virtual address space in usermode emulation. Signed-off-by: Paul Brook <paul@codesourcery.com>
Diffstat (limited to 'linux-user/main.c')
-rw-r--r--linux-user/main.c63
1 files changed, 63 insertions, 0 deletions
diff --git a/linux-user/main.c b/linux-user/main.c
index de1076b0af..0f23fc9cd9 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 */
/*