diff options
author | Paul Brook <paul@codesourcery.com> | 2009-07-17 12:48:08 +0100 |
---|---|---|
committer | Paul Brook <paul@codesourcery.com> | 2009-07-17 13:12:41 +0100 |
commit | 379f6698d73f476de38682b3ff96ecb226728c43 (patch) | |
tree | 35ec0c77416322f16fa27d646af50c60363168e3 /linux-user | |
parent | a9ff9df188615d653a5a904bafbe724d40143e35 (diff) |
Userspace guest address offsetting
Re-implement GUEST_BASE support.
Offset guest ddress space by default if the guest binary contains
regions below the host mmap_min_addr.
Implement support for i386, x86-64 and arm hosts.
Signed-off-by: Riku Voipio <riku.voipio@iki.fi>
Signed-off-by: Paul Brook <paul@codesourcery.com>
Diffstat (limited to 'linux-user')
-rw-r--r-- | linux-user/elfload.c | 23 | ||||
-rw-r--r-- | linux-user/main.c | 45 | ||||
-rw-r--r-- | linux-user/qemu.h | 3 |
3 files changed, 71 insertions, 0 deletions
diff --git a/linux-user/elfload.c b/linux-user/elfload.c index d31cca71d1..d4c9274206 100644 --- a/linux-user/elfload.c +++ b/linux-user/elfload.c @@ -1545,6 +1545,29 @@ int load_elf_binary(struct linux_binprm * bprm, struct target_pt_regs * regs, info->mmap = 0; elf_entry = (abi_ulong) elf_ex.e_entry; +#if defined(CONFIG_USE_GUEST_BASE) + /* + * In case where user has not explicitly set the guest_base, we + * probe here that should we set it automatically. + */ + if (!have_guest_base) { + /* + * Go through ELF program header table and find out whether + * any of the segments drop below our current mmap_min_addr and + * in that case set guest_base to corresponding address. + */ + for (i = 0, elf_ppnt = elf_phdata; i < elf_ex.e_phnum; + i++, elf_ppnt++) { + if (elf_ppnt->p_type != PT_LOAD) + continue; + if (HOST_PAGE_ALIGN(elf_ppnt->p_vaddr) < mmap_min_addr) { + guest_base = HOST_PAGE_ALIGN(mmap_min_addr); + break; + } + } + } +#endif /* CONFIG_USE_GUEST_BASE */ + /* Do this so that we can load the interpreter, if need be. We will change some of these later */ info->rss = 0; diff --git a/linux-user/main.c b/linux-user/main.c index 9038b58e7e..4388c04c9a 100644 --- a/linux-user/main.c +++ b/linux-user/main.c @@ -39,6 +39,11 @@ char *exec_path; int singlestep; +#if defined(CONFIG_USE_GUEST_BASE) +unsigned long mmap_min_addr; +unsigned long guest_base; +int have_guest_base; +#endif static const char *interp_prefix = CONFIG_QEMU_PREFIX; const char *qemu_uname_release = CONFIG_UNAME_RELEASE; @@ -2320,6 +2325,9 @@ static void usage(void) "-E var=value sets/modifies targets environment variable(s)\n" "-U var unsets targets environment variable(s)\n" "-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" +#endif "\n" "Debug options:\n" "-d options activate log (logfile=%s)\n" @@ -2495,6 +2503,11 @@ int main(int argc, char **argv, char **envp) #endif exit(1); } +#if defined(CONFIG_USE_GUEST_BASE) + } else if (!strcmp(r, "B")) { + guest_base = strtol(argv[optind++], NULL, 0); + have_guest_base = 1; +#endif } else if (!strcmp(r, "drop-ld-preload")) { (void) envlist_unsetenv(envlist, "LD_PRELOAD"); } else if (!strcmp(r, "singlestep")) { @@ -2572,6 +2585,35 @@ int main(int argc, char **argv, char **envp) target_environ = envlist_to_environ(envlist, NULL); envlist_free(envlist); +#if defined(CONFIG_USE_GUEST_BASE) + /* + * Now that page sizes are configured in cpu_init() we can do + * proper page alignment for guest_base. + */ + guest_base = HOST_PAGE_ALIGN(guest_base); + + /* + * Read in mmap_min_addr kernel parameter. This value is used + * When loading the ELF image to determine whether guest_base + * is needed. + * + * When user has explicitly set the quest base, we skip this + * test. + */ + if (!have_guest_base) { + FILE *fp; + + if ((fp = fopen("/proc/sys/vm/mmap_min_addr", "r")) != NULL) { + unsigned long tmp; + if (fscanf(fp, "%lu", &tmp) == 1) { + mmap_min_addr = tmp; + qemu_log("host mmap_min_addr=0x%lx\n", mmap_min_addr); + } + fclose(fp); + } + } +#endif /* CONFIG_USE_GUEST_BASE */ + /* * Prepare copy of argv vector for target. */ @@ -2622,6 +2664,9 @@ int main(int argc, char **argv, char **envp) free(target_environ); if (qemu_log_enabled()) { +#if defined(CONFIG_USE_GUEST_BASE) + qemu_log("guest_base 0x%lx\n", guest_base); +#endif log_page_dump(); qemu_log("start_brk 0x" TARGET_ABI_FMT_lx "\n", info->start_brk); diff --git a/linux-user/qemu.h b/linux-user/qemu.h index 83ad443c23..8e728a3d28 100644 --- a/linux-user/qemu.h +++ b/linux-user/qemu.h @@ -133,6 +133,9 @@ void init_task_state(TaskState *ts); void task_settid(TaskState *); void stop_all_tasks(void); extern const char *qemu_uname_release; +#if defined(CONFIG_USE_GUEST_BASE) +extern unsigned long mmap_min_addr; +#endif /* ??? See if we can avoid exposing so much of the loader internals. */ /* |