summaryrefslogtreecommitdiff
path: root/tcg
diff options
context:
space:
mode:
authorPaul Brook <paul@codesourcery.com>2009-07-17 12:48:08 +0100
committerPaul Brook <paul@codesourcery.com>2009-07-17 13:12:41 +0100
commit379f6698d73f476de38682b3ff96ecb226728c43 (patch)
tree35ec0c77416322f16fa27d646af50c60363168e3 /tcg
parenta9ff9df188615d653a5a904bafbe724d40143e35 (diff)
downloadqemu-379f6698d73f476de38682b3ff96ecb226728c43.tar.gz
qemu-379f6698d73f476de38682b3ff96ecb226728c43.tar.bz2
qemu-379f6698d73f476de38682b3ff96ecb226728c43.zip
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 'tcg')
-rw-r--r--tcg/arm/tcg-target.c34
-rw-r--r--tcg/arm/tcg-target.h2
-rw-r--r--tcg/i386/tcg-target.c36
-rw-r--r--tcg/i386/tcg-target.h2
-rw-r--r--tcg/tcg.c4
-rw-r--r--tcg/x86_64/tcg-target.c56
-rw-r--r--tcg/x86_64/tcg-target.h2
7 files changed, 103 insertions, 33 deletions
diff --git a/tcg/arm/tcg-target.c b/tcg/arm/tcg-target.c
index 1edcd103f3..6cfe1d6670 100644
--- a/tcg/arm/tcg-target.c
+++ b/tcg/arm/tcg-target.c
@@ -990,7 +990,22 @@ static inline void tcg_out_qemu_ld(TCGContext *s, int cond,
# endif
*label_ptr += ((void *) s->code_ptr - (void *) label_ptr - 8) >> 2;
-#else
+#else /* !CONFIG_SOFTMMU */
+ if (GUEST_BASE) {
+ uint32_t offset = GUEST_BASE;
+ int i;
+ int rot;
+
+ while (offset) {
+ i = ctz32(offset) & ~1;
+ rot = ((32 - i) << 7) & 0xf00;
+
+ tcg_out_dat_imm(s, COND_AL, ARITH_ADD, 8, addr_reg,
+ ((offset >> i) & 0xff) | rot);
+ addr_reg = 8;
+ offset &= ~(0xff << i);
+ }
+ }
switch (opc) {
case 0:
tcg_out_ld8_12(s, COND_AL, data_reg, addr_reg, 0);
@@ -1200,7 +1215,22 @@ static inline void tcg_out_qemu_st(TCGContext *s, int cond,
# endif
*label_ptr += ((void *) s->code_ptr - (void *) label_ptr - 8) >> 2;
-#else
+#else /* !CONFIG_SOFTMMU */
+ if (GUEST_BASE) {
+ uint32_t offset = GUEST_BASE;
+ int i;
+ int rot;
+
+ while (offset) {
+ i = ctz32(offset) & ~1;
+ rot = ((32 - i) << 7) & 0xf00;
+
+ tcg_out_dat_imm(s, COND_AL, ARITH_ADD, 8, addr_reg,
+ ((offset >> i) & 0xff) | rot);
+ addr_reg = 8;
+ offset &= ~(0xff << i);
+ }
+ }
switch (opc) {
case 0:
tcg_out_st8_12(s, COND_AL, data_reg, addr_reg, 0);
diff --git a/tcg/arm/tcg-target.h b/tcg/arm/tcg-target.h
index 78ab8fd3e5..ffa9ceeca0 100644
--- a/tcg/arm/tcg-target.h
+++ b/tcg/arm/tcg-target.h
@@ -60,6 +60,8 @@ enum {
#define TCG_TARGET_STACK_ALIGN 8
#define TCG_TARGET_CALL_STACK_OFFSET 0
+#define TCG_TARGET_HAS_GUEST_BASE
+
enum {
/* Note: must be synced with dyngen-exec.h */
TCG_AREG0 = TCG_REG_R7,
diff --git a/tcg/i386/tcg-target.c b/tcg/i386/tcg-target.c
index e0fd434620..ed61780e67 100644
--- a/tcg/i386/tcg-target.c
+++ b/tcg/i386/tcg-target.c
@@ -427,6 +427,10 @@ static void *qemu_st_helpers[4] = {
};
#endif
+#ifndef CONFIG_USER_ONLY
+#define GUEST_BASE 0
+#endif
+
/* XXX: qemu_ld and qemu_st could be modified to clobber only EDX and
EAX. It will be useful once fixed registers globals are less
common. */
@@ -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/i386/tcg-target.h b/tcg/i386/tcg-target.h
index 301a5bf142..461ef315c6 100644
--- a/tcg/i386/tcg-target.h
+++ b/tcg/i386/tcg-target.h
@@ -53,6 +53,8 @@ enum {
#define TCG_TARGET_HAS_ext16s_i32
#define TCG_TARGET_HAS_rot_i32
+#define TCG_TARGET_HAS_GUEST_BASE
+
/* Note: must be synced with dyngen-exec.h */
#define TCG_AREG0 TCG_REG_EBP
#define TCG_AREG1 TCG_REG_EBX
diff --git a/tcg/tcg.c b/tcg/tcg.c
index 299bff6f03..4cb5934f53 100644
--- a/tcg/tcg.c
+++ b/tcg/tcg.c
@@ -46,6 +46,7 @@
#include "qemu-common.h"
#include "cache-utils.h"
+#include "host-utils.h"
/* Note: the long term plan is to reduce the dependancies on the QEMU
CPU definitions. Currently they are used for qemu_ld/st
@@ -57,6 +58,9 @@
#include "tcg-op.h"
#include "elf.h"
+#if defined(CONFIG_USE_GUEST_BASE) && !defined(TCG_TARGET_HAS_GUEST_BASE)
+#error GUEST_BASE not supported on this host.
+#endif
static void patch_reloc(uint8_t *code_ptr, int type,
tcg_target_long value, tcg_target_long addend);
diff --git a/tcg/x86_64/tcg-target.c b/tcg/x86_64/tcg-target.c
index 5378e8510b..9facb01e41 100644
--- a/tcg/x86_64/tcg-target.c
+++ b/tcg/x86_64/tcg-target.c
@@ -508,6 +508,7 @@ static void tcg_out_qemu_ld(TCGContext *s, const TCGArg *args,
int opc)
{
int addr_reg, data_reg, r0, r1, mem_index, s_bits, bswap, rexw;
+ int32_t offset;
#if defined(CONFIG_SOFTMMU)
uint8_t *label1_ptr, *label2_ptr;
#endif
@@ -604,8 +605,20 @@ static void tcg_out_qemu_ld(TCGContext *s, const TCGArg *args,
/* add x(r1), r0 */
tcg_out_modrm_offset(s, 0x03 | P_REXW, r0, r1, offsetof(CPUTLBEntry, addend) -
offsetof(CPUTLBEntry, addr_read));
+ offset = 0;
#else
- r0 = addr_reg;
+ if (GUEST_BASE == (int32_t)GUEST_BASE) {
+ r0 = addr_reg;
+ offset = GUEST_BASE;
+ } else {
+ offset = 0;
+ /* movq $GUEST_BASE, r0 */
+ tcg_out_opc(s, (0xb8 + (r0 & 7)) | P_REXW, 0, r0, 0);
+ tcg_out32(s, GUEST_BASE);
+ tcg_out32(s, GUEST_BASE >> 32);
+ /* addq addr_reg, r0 */
+ tcg_out_modrm(s, 0x01 | P_REXW, addr_reg, r0);
+ }
#endif
#ifdef TARGET_WORDS_BIGENDIAN
@@ -616,15 +629,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, offset);
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, offset);
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, offset);
if (bswap) {
/* rolw $8, data_reg */
tcg_out8(s, 0x66);
@@ -635,7 +648,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, offset);
/* rolw $8, data_reg */
tcg_out8(s, 0x66);
tcg_out_modrm(s, 0xc1, 0, data_reg);
@@ -645,12 +658,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, offset);
}
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, offset);
if (bswap) {
/* bswap */
tcg_out_opc(s, (0xc8 + (data_reg & 7)) | P_EXT, 0, data_reg, 0);
@@ -659,19 +672,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, offset);
/* 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, offset);
}
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, offset);
if (bswap) {
/* bswap */
tcg_out_opc(s, (0xc8 + (data_reg & 7)) | P_EXT | P_REXW, 0, data_reg, 0);
@@ -691,6 +704,7 @@ static void tcg_out_qemu_st(TCGContext *s, const TCGArg *args,
int opc)
{
int addr_reg, data_reg, r0, r1, mem_index, s_bits, bswap, rexw;
+ int32_t offset;
#if defined(CONFIG_SOFTMMU)
uint8_t *label1_ptr, *label2_ptr;
#endif
@@ -775,8 +789,20 @@ static void tcg_out_qemu_st(TCGContext *s, const TCGArg *args,
/* add x(r1), r0 */
tcg_out_modrm_offset(s, 0x03 | P_REXW, r0, r1, offsetof(CPUTLBEntry, addend) -
offsetof(CPUTLBEntry, addr_write));
+ offset = 0;
#else
- r0 = addr_reg;
+ if (GUEST_BASE == (int32_t)GUEST_BASE) {
+ r0 = addr_reg;
+ offset = GUEST_BASE;
+ } else {
+ offset = 0;
+ /* movq $GUEST_BASE, r0 */
+ tcg_out_opc(s, (0xb8 + (r0 & 7)) | P_REXW, 0, r0, 0);
+ tcg_out32(s, GUEST_BASE);
+ tcg_out32(s, GUEST_BASE >> 32);
+ /* addq addr_reg, r0 */
+ tcg_out_modrm(s, 0x01 | P_REXW, addr_reg, r0);
+ }
#endif
#ifdef TARGET_WORDS_BIGENDIAN
@@ -787,7 +813,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, offset);
break;
case 1:
if (bswap) {
@@ -799,7 +825,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, offset);
break;
case 2:
if (bswap) {
@@ -809,7 +835,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, offset);
break;
case 3:
if (bswap) {
@@ -819,7 +845,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, offset);
break;
default:
tcg_abort();
diff --git a/tcg/x86_64/tcg-target.h b/tcg/x86_64/tcg-target.h
index 8cb05c6328..8d47e78738 100644
--- a/tcg/x86_64/tcg-target.h
+++ b/tcg/x86_64/tcg-target.h
@@ -73,6 +73,8 @@ enum {
#define TCG_TARGET_HAS_rot_i32
#define TCG_TARGET_HAS_rot_i64
+#define TCG_TARGET_HAS_GUEST_BASE
+
/* Note: must be synced with dyngen-exec.h */
#define TCG_AREG0 TCG_REG_R14
#define TCG_AREG1 TCG_REG_R15