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>
This commit is contained in:
Paul Brook 2009-07-17 12:48:08 +01:00
parent a9ff9df188
commit 379f6698d7
13 changed files with 206 additions and 36 deletions

View file

@ -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;

View file

@ -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);

View file

@ -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. */
/*