qemu-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Qemu-devel] [PATCH 06/21] Revived GUEST_BASE support for usermode emula


From: riku . voipio
Subject: [Qemu-devel] [PATCH 06/21] Revived GUEST_BASE support for usermode emulation targets [v5]
Date: Fri, 12 Jun 2009 16:50:16 +0300

From: Mika Westerberg <address@hidden>

From: Mika Westerberg <address@hidden>

- Now GUEST_BASE is dynamic and can be set from command line.
- Qemu checks /proc/sys/vm/mmap_min_addr and sets GUEST_BASE
  if needed.
- Code generation supports GUEST_BASE for i386 and x86_64 hosts.

[v3]: implemented GUEST_BASE with offset mods

Using malc's advice, instead of a mov or lea, just adjust
the offset parameter of tcg_out_modrm_offset(). - Riku

[v5]: set a GUEST_BASE_MAX instead of supporting moving
to arbitary ranges

From: Mika Westerberg <address@hidden>
Signed-off-by: Riku Voipio <address@hidden>
---
 configure               |    9 +++++++
 cpu-all.h               |    7 ++++-
 linux-user/elfload.c    |   24 +++++++++++++++++++
 linux-user/main.c       |   59 +++++++++++++++++++++++++++++++++++++++++++++++
 linux-user/qemu.h       |    3 ++
 tcg/i386/tcg-target.c   |   36 ++++++++++++++++------------
 tcg/x86_64/tcg-target.c |   30 +++++++++++++----------
 7 files changed, 138 insertions(+), 30 deletions(-)

diff --git a/configure b/configure
index 89e7f53..11501c6 100755
--- a/configure
+++ b/configure
@@ -181,6 +181,7 @@ linux_user="no"
 darwin_user="no"
 bsd_user="no"
 build_docs="yes"
+guest_base="no"
 uname_release=""
 curses="yes"
 curl="yes"
@@ -465,6 +466,8 @@ for opt do
   ;;
   --enable-bsd-user) bsd_user="yes"
   ;;
+  --enable-guest-base) guest_base="yes"
+  ;;
   --enable-uname-release=*) uname_release="$optarg"
   ;;
   --sparc_cpu=*)
@@ -628,6 +631,8 @@ echo "  --enable-darwin-user     enable all darwin usermode 
emulation targets"
 echo "  --disable-darwin-user    disable all darwin usermode emulation targets"
 echo "  --enable-bsd-user        enable all BSD usermode emulation targets"
 echo "  --disable-bsd-user       disable all BSD usermode emulation targets"
+echo "  --enable-guest-base      enable GUEST_BASE support for usermode"
+echo "                           emulation targets"
 echo "  --fmod-lib               path to FMOD library"
 echo "  --fmod-inc               path to FMOD includes"
 echo "  --oss-lib                path to OSS library"
@@ -1375,6 +1380,7 @@ echo "Documentation     $build_docs"
 [ ! -z "$uname_release" ] && \
 echo "uname -r          $uname_release"
 echo "NPTL support      $nptl"
+echo "GUEST_BASE        $guest_base"
 echo "vde support       $vde"
 echo "AIO support       $aio"
 echo "IO thread         $io_thread"
@@ -2127,6 +2133,9 @@ if test "$target_user_only" = "yes" -a "$elfload32" = 
"yes"; then
   echo "TARGET_HAS_ELFLOAD32=yes" >> $config_mak
   echo "#define TARGET_HAS_ELFLOAD32 1" >> $config_h
 fi
+if test "$target_user_only" = "yes" -a "$guest_base" = "yes"; then
+  echo "#define CONFIG_USE_GUEST_BASE 1" >> $config_h
+fi
 if test "$target_bsd_user" = "yes" ; then
   echo "CONFIG_BSD_USER=yes" >> $config_mak
   echo "#define CONFIG_BSD_USER 1" >> $config_h
diff --git a/cpu-all.h b/cpu-all.h
index 8f078c4..d8603ae 100644
--- a/cpu-all.h
+++ b/cpu-all.h
@@ -625,8 +625,13 @@ static inline void stfq_be_p(void *ptr, float64 v)
 /* On some host systems the guest address space is reserved on the host.
  * This allows the guest address space to be offset to a convenient location.
  */
-//#define GUEST_BASE 0x20000000
+#if defined(CONFIG_USE_GUEST_BASE)
+#define GUEST_BASE_MAX 0x38000000
+extern unsigned long guest_base;
+#define GUEST_BASE guest_base
+#else
 #define GUEST_BASE 0
+#endif
 
 /* All direct uses of g2h and h2g need to go away for usermode softmmu.  */
 #define g2h(x) ((void *)((unsigned long)(x) + GUEST_BASE))
diff --git a/linux-user/elfload.c b/linux-user/elfload.c
index 1839337..1a22042 100644
--- a/linux-user/elfload.c
+++ b/linux-user/elfload.c
@@ -1545,6 +1545,30 @@ 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 (guest_base == 0) {
+        /*
+         * 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);
+                qemu_log("setting guest_base=0x%lx\n", guest_base);
+                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 7eabd0c..0395549 100644
--- a/linux-user/main.c
+++ b/linux-user/main.c
@@ -41,6 +41,10 @@
 char *exec_path;
 
 int singlestep;
+#if defined(CONFIG_USE_GUEST_BASE)
+unsigned long mmap_min_addr = 0;
+unsigned long guest_base = 0;
+#endif
 
 static const char *interp_prefix = CONFIG_QEMU_PREFIX;
 const char *qemu_uname_release = CONFIG_UNAME_RELEASE;
@@ -2294,6 +2298,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"
@@ -2468,6 +2475,10 @@ 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);
+#endif
         } else if (!strcmp(r, "drop-ld-preload")) {
             (void) envlist_unsetenv(envlist, "LD_PRELOAD");
         } else if (!strcmp(r, "singlestep")) {
@@ -2545,6 +2556,41 @@ 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 and check
+     * whether it is set to some value > 0.  This value is used
+     * later on when doing mmap(2)s to calculate where guest_base
+     * is to set, if needed.
+     *
+     * When user has explicitly set the quest base, we skip this
+     * test.
+     */
+    if (guest_base == 0) {
+        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("kernel mmap_min_addr=%lu\n", mmap_min_addr);
+            }
+            fclose(fp);
+        }
+    }
+    if (guest_base >= GUEST_BASE_MAX) {
+        fprintf(stderr, "guest base %lu is larger than GUEST_BASE_MAX: %d \n",
+                guest_base, GUEST_BASE_MAX);
+        exit(1);
+    }
+#endif /* CONFIG_USE_GUEST_BASE */
+
     /*
      * Prepare copy of argv vector for target.
      */
@@ -2594,6 +2640,19 @@ int main(int argc, char **argv, char **envp)
     free(target_environ);
 
     if (qemu_log_enabled()) {
+#if defined(CONFIG_USE_GUEST_BASE)
+        if (guest_base > 0) {
+            qemu_log("guest_base is set to 0x%lx\n", guest_base);
+            qemu_log(
+                "==========================================================\n"
+                "Note that all target addresses below are given in target\n"
+                "address space which is different from host by guest_base.\n"
+                "For example: target address 0x" TARGET_ABI_FMT_lx " becomes\n"
+               "%p and so on.\n"
+                "==========================================================\n",
+                (abi_ulong)0x8000, g2h(0x8000));
+        }
+#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 e04a31c..4028953 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.  */
 /*
diff --git a/tcg/i386/tcg-target.c b/tcg/i386/tcg-target.c
index e0fd434..aaec3c7 100644
--- a/tcg/i386/tcg-target.c
+++ b/tcg/i386/tcg-target.c
@@ -22,6 +22,10 @@
  * THE SOFTWARE.
  */
 
+#ifndef CONFIG_USE_GUEST_BASE
+#define GUEST_BASE 0
+#endif
+
 #ifndef NDEBUG
 static const char * const tcg_target_reg_names[TCG_TARGET_NB_REGS] = {
     "%eax",
@@ -572,15 +576,15 @@ static void tcg_out_qemu_ld(TCGContext *s, const TCGArg 
*args,
     switch(opc) {
     case 0:
         /* movzbl */
-        tcg_out_modrm_offset(s, 0xb6 | P_EXT, data_reg, r0, 0);
+        tcg_out_modrm_offset(s, 0xb6 | P_EXT, data_reg, r0, GUEST_BASE);
         break;
     case 0 | 4:
         /* movsbl */
-        tcg_out_modrm_offset(s, 0xbe | P_EXT, data_reg, r0, 0);
+        tcg_out_modrm_offset(s, 0xbe | P_EXT, data_reg, r0, GUEST_BASE);
         break;
     case 1:
         /* movzwl */
-        tcg_out_modrm_offset(s, 0xb7 | P_EXT, data_reg, r0, 0);
+        tcg_out_modrm_offset(s, 0xb7 | P_EXT, data_reg, r0, GUEST_BASE);
         if (bswap) {
             /* rolw $8, data_reg */
             tcg_out8(s, 0x66); 
@@ -590,7 +594,7 @@ static void tcg_out_qemu_ld(TCGContext *s, const TCGArg 
*args,
         break;
     case 1 | 4:
         /* movswl */
-        tcg_out_modrm_offset(s, 0xbf | P_EXT, data_reg, r0, 0);
+        tcg_out_modrm_offset(s, 0xbf | P_EXT, data_reg, r0, GUEST_BASE);
         if (bswap) {
             /* rolw $8, data_reg */
             tcg_out8(s, 0x66); 
@@ -603,7 +607,7 @@ static void tcg_out_qemu_ld(TCGContext *s, const TCGArg 
*args,
         break;
     case 2:
         /* movl (r0), data_reg */
-        tcg_out_modrm_offset(s, 0x8b, data_reg, r0, 0);
+        tcg_out_modrm_offset(s, 0x8b, data_reg, r0, GUEST_BASE);
         if (bswap) {
             /* bswap */
             tcg_out_opc(s, (0xc8 + data_reg) | P_EXT);
@@ -619,13 +623,13 @@ static void tcg_out_qemu_ld(TCGContext *s, const TCGArg 
*args,
             r0 = r1;
         }
         if (!bswap) {
-            tcg_out_modrm_offset(s, 0x8b, data_reg, r0, 0);
-            tcg_out_modrm_offset(s, 0x8b, data_reg2, r0, 4);
+            tcg_out_modrm_offset(s, 0x8b, data_reg, r0, GUEST_BASE);
+            tcg_out_modrm_offset(s, 0x8b, data_reg2, r0, GUEST_BASE + 4);
         } else {
-            tcg_out_modrm_offset(s, 0x8b, data_reg, r0, 4);
+            tcg_out_modrm_offset(s, 0x8b, data_reg, r0, GUEST_BASE + 4);
             tcg_out_opc(s, (0xc8 + data_reg) | P_EXT);
 
-            tcg_out_modrm_offset(s, 0x8b, data_reg2, r0, 0);
+            tcg_out_modrm_offset(s, 0x8b, data_reg2, r0, GUEST_BASE);
             /* bswap */
             tcg_out_opc(s, (0xc8 + data_reg2) | P_EXT);
         }
@@ -806,7 +810,7 @@ static void tcg_out_qemu_st(TCGContext *s, const TCGArg 
*args,
     switch(opc) {
     case 0:
         /* movb */
-        tcg_out_modrm_offset(s, 0x88, data_reg, r0, 0);
+        tcg_out_modrm_offset(s, 0x88, data_reg, r0, GUEST_BASE);
         break;
     case 1:
         if (bswap) {
@@ -818,7 +822,7 @@ static void tcg_out_qemu_st(TCGContext *s, const TCGArg 
*args,
         }
         /* movw */
         tcg_out8(s, 0x66);
-        tcg_out_modrm_offset(s, 0x89, data_reg, r0, 0);
+        tcg_out_modrm_offset(s, 0x89, data_reg, r0, GUEST_BASE);
         break;
     case 2:
         if (bswap) {
@@ -828,21 +832,21 @@ static void tcg_out_qemu_st(TCGContext *s, const TCGArg 
*args,
             data_reg = r1;
         }
         /* movl */
-        tcg_out_modrm_offset(s, 0x89, data_reg, r0, 0);
+        tcg_out_modrm_offset(s, 0x89, data_reg, r0, GUEST_BASE);
         break;
     case 3:
         if (bswap) {
             tcg_out_mov(s, r1, data_reg2);
             /* bswap data_reg */
             tcg_out_opc(s, (0xc8 + r1) | P_EXT);
-            tcg_out_modrm_offset(s, 0x89, r1, r0, 0);
+            tcg_out_modrm_offset(s, 0x89, r1, r0, GUEST_BASE);
             tcg_out_mov(s, r1, data_reg);
             /* bswap data_reg */
             tcg_out_opc(s, (0xc8 + r1) | P_EXT);
-            tcg_out_modrm_offset(s, 0x89, r1, r0, 4);
+            tcg_out_modrm_offset(s, 0x89, r1, r0, GUEST_BASE + 4);
         } else {
-            tcg_out_modrm_offset(s, 0x89, data_reg, r0, 0);
-            tcg_out_modrm_offset(s, 0x89, data_reg2, r0, 4);
+            tcg_out_modrm_offset(s, 0x89, data_reg, r0, GUEST_BASE);
+            tcg_out_modrm_offset(s, 0x89, data_reg2, r0, GUEST_BASE + 4);
         }
         break;
     default:
diff --git a/tcg/x86_64/tcg-target.c b/tcg/x86_64/tcg-target.c
index 5378e85..6015bb5 100644
--- a/tcg/x86_64/tcg-target.c
+++ b/tcg/x86_64/tcg-target.c
@@ -22,6 +22,10 @@
  * THE SOFTWARE.
  */
 
+#ifndef CONFIG_USE_GUEST_BASE
+#define GUEST_BASE 0
+#endif
+
 #ifndef NDEBUG
 static const char * const tcg_target_reg_names[TCG_TARGET_NB_REGS] = {
     "%rax",
@@ -616,15 +620,15 @@ static void tcg_out_qemu_ld(TCGContext *s, const TCGArg 
*args,
     switch(opc) {
     case 0:
         /* movzbl */
-        tcg_out_modrm_offset(s, 0xb6 | P_EXT, data_reg, r0, 0);
+        tcg_out_modrm_offset(s, 0xb6 | P_EXT, data_reg, r0, GUEST_BASE);
         break;
     case 0 | 4:
         /* movsbX */
-        tcg_out_modrm_offset(s, 0xbe | P_EXT | rexw, data_reg, r0, 0);
+        tcg_out_modrm_offset(s, 0xbe | P_EXT | rexw, data_reg, r0, GUEST_BASE);
         break;
     case 1:
         /* movzwl */
-        tcg_out_modrm_offset(s, 0xb7 | P_EXT, data_reg, r0, 0);
+        tcg_out_modrm_offset(s, 0xb7 | P_EXT, data_reg, r0, GUEST_BASE);
         if (bswap) {
             /* rolw $8, data_reg */
             tcg_out8(s, 0x66); 
@@ -635,7 +639,7 @@ static void tcg_out_qemu_ld(TCGContext *s, const TCGArg 
*args,
     case 1 | 4:
         if (bswap) {
             /* movzwl */
-            tcg_out_modrm_offset(s, 0xb7 | P_EXT, data_reg, r0, 0);
+            tcg_out_modrm_offset(s, 0xb7 | P_EXT, data_reg, r0, GUEST_BASE);
             /* rolw $8, data_reg */
             tcg_out8(s, 0x66); 
             tcg_out_modrm(s, 0xc1, 0, data_reg);
@@ -645,12 +649,12 @@ static void tcg_out_qemu_ld(TCGContext *s, const TCGArg 
*args,
             tcg_out_modrm(s, 0xbf | P_EXT | rexw, data_reg, data_reg);
         } else {
             /* movswX */
-            tcg_out_modrm_offset(s, 0xbf | P_EXT | rexw, data_reg, r0, 0);
+            tcg_out_modrm_offset(s, 0xbf | P_EXT | rexw, data_reg, r0, 
GUEST_BASE);
         }
         break;
     case 2:
         /* movl (r0), data_reg */
-        tcg_out_modrm_offset(s, 0x8b, data_reg, r0, 0);
+        tcg_out_modrm_offset(s, 0x8b, data_reg, r0, GUEST_BASE);
         if (bswap) {
             /* bswap */
             tcg_out_opc(s, (0xc8 + (data_reg & 7)) | P_EXT, 0, data_reg, 0);
@@ -659,19 +663,19 @@ static void tcg_out_qemu_ld(TCGContext *s, const TCGArg 
*args,
     case 2 | 4:
         if (bswap) {
             /* movl (r0), data_reg */
-            tcg_out_modrm_offset(s, 0x8b, data_reg, r0, 0);
+            tcg_out_modrm_offset(s, 0x8b, data_reg, r0, GUEST_BASE);
             /* bswap */
             tcg_out_opc(s, (0xc8 + (data_reg & 7)) | P_EXT, 0, data_reg, 0);
             /* movslq */
             tcg_out_modrm(s, 0x63 | P_REXW, data_reg, data_reg);
         } else {
             /* movslq */
-            tcg_out_modrm_offset(s, 0x63 | P_REXW, data_reg, r0, 0);
+            tcg_out_modrm_offset(s, 0x63 | P_REXW, data_reg, r0, GUEST_BASE);
         }
         break;
     case 3:
         /* movq (r0), data_reg */
-        tcg_out_modrm_offset(s, 0x8b | P_REXW, data_reg, r0, 0);
+        tcg_out_modrm_offset(s, 0x8b | P_REXW, data_reg, r0, GUEST_BASE);
         if (bswap) {
             /* bswap */
             tcg_out_opc(s, (0xc8 + (data_reg & 7)) | P_EXT | P_REXW, 0, 
data_reg, 0);
@@ -787,7 +791,7 @@ static void tcg_out_qemu_st(TCGContext *s, const TCGArg 
*args,
     switch(opc) {
     case 0:
         /* movb */
-        tcg_out_modrm_offset(s, 0x88 | P_REXB, data_reg, r0, 0);
+        tcg_out_modrm_offset(s, 0x88 | P_REXB, data_reg, r0, GUEST_BASE);
         break;
     case 1:
         if (bswap) {
@@ -799,7 +803,7 @@ static void tcg_out_qemu_st(TCGContext *s, const TCGArg 
*args,
         }
         /* movw */
         tcg_out8(s, 0x66);
-        tcg_out_modrm_offset(s, 0x89, data_reg, r0, 0);
+        tcg_out_modrm_offset(s, 0x89, data_reg, r0, GUEST_BASE);
         break;
     case 2:
         if (bswap) {
@@ -809,7 +813,7 @@ static void tcg_out_qemu_st(TCGContext *s, const TCGArg 
*args,
             data_reg = r1;
         }
         /* movl */
-        tcg_out_modrm_offset(s, 0x89, data_reg, r0, 0);
+        tcg_out_modrm_offset(s, 0x89, data_reg, r0, GUEST_BASE);
         break;
     case 3:
         if (bswap) {
@@ -819,7 +823,7 @@ static void tcg_out_qemu_st(TCGContext *s, const TCGArg 
*args,
             data_reg = r1;
         }
         /* movq */
-        tcg_out_modrm_offset(s, 0x89 | P_REXW, data_reg, r0, 0);
+        tcg_out_modrm_offset(s, 0x89 | P_REXW, data_reg, r0, GUEST_BASE);
         break;
     default:
         tcg_abort();
-- 
1.6.2.1





reply via email to

[Prev in Thread] Current Thread [Next in Thread]