aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBlue Swirl <blauwirbel@gmail.com>2009-09-27 19:30:51 +0000
committerBlue Swirl <blauwirbel@gmail.com>2009-09-27 19:30:51 +0000
commit2fa5d9ba56e93dd80b71127025d8467fc1bafff5 (patch)
tree5945a1ca60fb8662d92b6687e1b989ad67bd8df9
parent17cf428f2e1f6970296b4c0ddcb054e4bc3f2355 (diff)
BSD user: implement GUEST_BASE
Based on 379f6698d73f476de38682b3ff96ecb226728c43. Signed-off-by: Blue Swirl <blauwirbel@gmail.com>
-rw-r--r--bsd-user/elfload.c23
-rw-r--r--bsd-user/main.c44
-rw-r--r--bsd-user/qemu.h3
3 files changed, 70 insertions, 0 deletions
diff --git a/bsd-user/elfload.c b/bsd-user/elfload.c
index 48ec4ac150..06e6c63efb 100644
--- a/bsd-user/elfload.c
+++ b/bsd-user/elfload.c
@@ -1337,6 +1337,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/bsd-user/main.c b/bsd-user/main.c
index 56710ec79d..1bba2b5055 100644
--- a/bsd-user/main.c
+++ b/bsd-user/main.c
@@ -37,6 +37,11 @@
#define DEBUG_LOGFILE "/tmp/qemu.log"
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;
@@ -607,6 +612,9 @@ static void usage(void)
"-drop-ld-preload drop LD_PRELOAD for target process\n"
"-E var=value sets/modifies targets environment variable(s)\n"
"-U var unsets targets environment variable(s)\n"
+#if defined(CONFIG_USE_GUEST_BASE)
+ "-B address set guest_base address to address\n"
+#endif
"-bsd type select emulated BSD type FreeBSD/NetBSD/OpenBSD (default)\n"
"\n"
"Debug options:\n"
@@ -746,6 +754,11 @@ int main(int argc, char **argv)
#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, "bsd")) {
@@ -815,6 +828,34 @@ int main(int argc, char **argv)
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 */
if (loader_exec(filename, argv+optind, target_environ, regs, info) != 0) {
printf("Error loading %s\n", filename);
@@ -828,6 +869,9 @@ int main(int argc, char **argv)
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/bsd-user/qemu.h b/bsd-user/qemu.h
index cbee3e72fe..9f4cd1ba01 100644
--- a/bsd-user/qemu.h
+++ b/bsd-user/qemu.h
@@ -84,6 +84,9 @@ typedef struct TaskState {
void init_task_state(TaskState *ts);
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. */
/*