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 /tcg | |
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 'tcg')
-rw-r--r-- | tcg/arm/tcg-target.c | 34 | ||||
-rw-r--r-- | tcg/arm/tcg-target.h | 2 | ||||
-rw-r--r-- | tcg/i386/tcg-target.c | 36 | ||||
-rw-r--r-- | tcg/i386/tcg-target.h | 2 | ||||
-rw-r--r-- | tcg/tcg.c | 4 | ||||
-rw-r--r-- | tcg/x86_64/tcg-target.c | 56 | ||||
-rw-r--r-- | tcg/x86_64/tcg-target.h | 2 |
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 @@ -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 |