tcg/i386: Extend addresses for 32-bit guests

Removing the ??? comment explaining why it (mostly) worked.

Backports commit ee8ba9e4d8458b8bba5455a7ae704620c4f2ef4b from qemu
This commit is contained in:
Richard Henderson 2018-02-10 20:42:12 -05:00 committed by Lioncash
parent 17c1f027c1
commit 95e666c547
No known key found for this signature in database
GPG key ID: 4E3C3CC1031BA9C7

View file

@ -1537,8 +1537,8 @@ static inline void setup_guest_base_seg(TCGContext *s) { }
#endif /* SOFTMMU */ #endif /* SOFTMMU */
static void tcg_out_qemu_ld_direct(TCGContext *s, TCGReg datalo, TCGReg datahi, static void tcg_out_qemu_ld_direct(TCGContext *s, TCGReg datalo, TCGReg datahi,
TCGReg base, intptr_t ofs, int seg, TCGReg base, int index, intptr_t ofs,
TCGMemOp memop) int seg, TCGMemOp memop)
{ {
const TCGMemOp real_bswap = memop & MO_BSWAP; const TCGMemOp real_bswap = memop & MO_BSWAP;
TCGMemOp bswap = real_bswap; TCGMemOp bswap = real_bswap;
@ -1551,13 +1551,16 @@ static void tcg_out_qemu_ld_direct(TCGContext *s, TCGReg datalo, TCGReg datahi,
switch (memop & MO_SSIZE) { switch (memop & MO_SSIZE) {
case MO_UB: case MO_UB:
tcg_out_modrm_offset(s, OPC_MOVZBL + seg, datalo, base, ofs); tcg_out_modrm_sib_offset(s, OPC_MOVZBL + seg, datalo,
base, index, 0, ofs);
break; break;
case MO_SB: case MO_SB:
tcg_out_modrm_offset(s, OPC_MOVSBL + P_REXW + seg, datalo, base, ofs); tcg_out_modrm_sib_offset(s, OPC_MOVSBL + P_REXW + seg, datalo,
base, index, 0, ofs);
break; break;
case MO_UW: case MO_UW:
tcg_out_modrm_offset(s, OPC_MOVZWL + seg, datalo, base, ofs); tcg_out_modrm_sib_offset(s, OPC_MOVZWL + seg, datalo,
base, index, 0, ofs);
if (real_bswap) { if (real_bswap) {
tcg_out_rolw_8(s, datalo); tcg_out_rolw_8(s, datalo);
} }
@ -1565,20 +1568,22 @@ static void tcg_out_qemu_ld_direct(TCGContext *s, TCGReg datalo, TCGReg datahi,
case MO_SW: case MO_SW:
if (real_bswap) { if (real_bswap) {
if (s->have_movbe) { if (s->have_movbe) {
tcg_out_modrm_offset(s, OPC_MOVBE_GyMy + P_DATA16 + seg, tcg_out_modrm_sib_offset(s, OPC_MOVBE_GyMy + P_DATA16 + seg,
datalo, base, ofs); datalo, base, index, 0, ofs);
} else { } else {
tcg_out_modrm_offset(s, OPC_MOVZWL + seg, datalo, base, ofs); tcg_out_modrm_sib_offset(s, OPC_MOVZWL + seg, datalo,
base, index, 0, ofs);
tcg_out_rolw_8(s, datalo); tcg_out_rolw_8(s, datalo);
} }
tcg_out_modrm(s, OPC_MOVSWL + P_REXW, datalo, datalo); tcg_out_modrm_sib_offset(s, OPC_MOVSWL + P_REXW + seg,
datalo, base, index, 0, ofs);
} else { } else {
tcg_out_modrm_offset(s, OPC_MOVSWL + P_REXW + seg, tcg_out_modrm_offset(s, OPC_MOVSWL + P_REXW + seg,
datalo, base, ofs); datalo, base, ofs);
} }
break; break;
case MO_UL: case MO_UL:
tcg_out_modrm_offset(s, movop + seg, datalo, base, ofs); tcg_out_modrm_sib_offset(s, movop + seg, datalo, base, index, 0, ofs);
if (bswap) { if (bswap) {
tcg_out_bswap32(s, datalo); tcg_out_bswap32(s, datalo);
} }
@ -1586,19 +1591,22 @@ static void tcg_out_qemu_ld_direct(TCGContext *s, TCGReg datalo, TCGReg datahi,
#if TCG_TARGET_REG_BITS == 64 #if TCG_TARGET_REG_BITS == 64
case MO_SL: case MO_SL:
if (real_bswap) { if (real_bswap) {
tcg_out_modrm_offset(s, movop + seg, datalo, base, ofs); tcg_out_modrm_sib_offset(s, movop + seg, datalo,
base, index, 0, ofs);
if (bswap) { if (bswap) {
tcg_out_bswap32(s, datalo); tcg_out_bswap32(s, datalo);
} }
tcg_out_ext32s(s, datalo, datalo); tcg_out_ext32s(s, datalo, datalo);
} else { } else {
tcg_out_modrm_offset(s, OPC_MOVSLQ + seg, datalo, base, ofs); tcg_out_modrm_sib_offset(s, OPC_MOVSLQ + seg, datalo,
base, index, 0, ofs);
} }
break; break;
#endif #endif
case MO_Q: case MO_Q:
if (TCG_TARGET_REG_BITS == 64) { if (TCG_TARGET_REG_BITS == 64) {
tcg_out_modrm_offset(s, movop + P_REXW + seg, datalo, base, ofs); tcg_out_modrm_sib_offset(s, movop + P_REXW + seg, datalo,
base, index, 0, ofs);
if (bswap) { if (bswap) {
tcg_out_bswap64(s, datalo); tcg_out_bswap64(s, datalo);
} }
@ -1609,11 +1617,15 @@ static void tcg_out_qemu_ld_direct(TCGContext *s, TCGReg datalo, TCGReg datahi,
datahi = t; datahi = t;
} }
if (base != datalo) { if (base != datalo) {
tcg_out_modrm_offset(s, movop + seg, datalo, base, ofs); tcg_out_modrm_sib_offset(s, movop + seg, datalo,
tcg_out_modrm_offset(s, movop + seg, datahi, base, ofs + 4); base, index, 0, ofs);
tcg_out_modrm_sib_offset(s, movop + seg, datahi,
base, index, 0, ofs + 4);
} else { } else {
tcg_out_modrm_offset(s, movop + seg, datahi, base, ofs + 4); tcg_out_modrm_sib_offset(s, movop + seg, datahi,
tcg_out_modrm_offset(s, movop + seg, datalo, base, ofs); base, index, 0, ofs + 4);
tcg_out_modrm_sib_offset(s, movop + seg, datalo,
base, index, 0, ofs);
} }
if (bswap) { if (bswap) {
tcg_out_bswap32(s, datalo); tcg_out_bswap32(s, datalo);
@ -1656,7 +1668,7 @@ static void tcg_out_qemu_ld(TCGContext *s, const TCGArg *args, bool is64)
label_ptr, offsetof(CPUTLBEntry, addr_read)); label_ptr, offsetof(CPUTLBEntry, addr_read));
/* TLB Hit. */ /* TLB Hit. */
tcg_out_qemu_ld_direct(s, datalo, datahi, TCG_REG_L1, 0, 0, opc); tcg_out_qemu_ld_direct(s, datalo, datahi, TCG_REG_L1, -1, 0, 0, opc);
/* Record the current context of a load into ldst label */ /* Record the current context of a load into ldst label */
add_qemu_ldst_label(s, true, oi, datalo, datahi, addrlo, addrhi, add_qemu_ldst_label(s, true, oi, datalo, datahi, addrlo, addrhi,
@ -1665,24 +1677,33 @@ static void tcg_out_qemu_ld(TCGContext *s, const TCGArg *args, bool is64)
{ {
int32_t offset = GUEST_BASE; int32_t offset = GUEST_BASE;
TCGReg base = addrlo; TCGReg base = addrlo;
int index = -1;
int seg = 0; int seg = 0;
/* ??? We assume all operations have left us with register contents /* For a 32-bit guest, the high 32 bits may contain garbage.
that are zero extended. So far this appears to be true. If we We can do this with the ADDR32 prefix if we're not using
want to enforce this, we can either do an explicit zero-extension a guest base, or when using segmentation. Otherwise we
here, or (if GUEST_BASE == 0, or a segment register is in use) need to zero-extend manually. */
use the ADDR32 prefix. For now, do nothing. */ if (GUEST_BASE == 0 || guest_base_flags) {
if (GUEST_BASE && s->guest_base_flags) {
seg = s->guest_base_flags; seg = s->guest_base_flags;
offset = 0; offset = 0;
} else if (TCG_TARGET_REG_BITS == 64 && offset != GUEST_BASE) { if (TCG_TARGET_REG_BITS > TARGET_LONG_BITS) {
tcg_out_movi(s, TCG_TYPE_I64, TCG_REG_L1, GUEST_BASE); seg |= P_ADDR32;
tgen_arithr(s, ARITH_ADD + P_REXW, TCG_REG_L1, base); }
base = TCG_REG_L1; } else if (TCG_TARGET_REG_BITS == 64) {
offset = 0; if (TARGET_LONG_BITS == 32) {
tcg_out_ext32u(s, TCG_REG_L0, base);
base = TCG_REG_L0;
}
if (offset != GUEST_BASE) {
tcg_out_movi(s, TCG_TYPE_I64, TCG_REG_L1, GUEST_BASE);
index = TCG_REG_L1;
offset = 0;
}
} }
tcg_out_qemu_ld_direct(s, datalo, datahi, base, offset, seg, opc); tcg_out_qemu_ld_direct(s, datalo, datahi,
base, index, offset, seg, opc);
} }
#endif #endif
} }
@ -1800,19 +1821,29 @@ static void tcg_out_qemu_st(TCGContext *s, const TCGArg *args, bool is64)
TCGReg base = addrlo; TCGReg base = addrlo;
int seg = 0; int seg = 0;
/* ??? We assume all operations have left us with register contents /* See comment in tcg_out_qemu_ld re zero-extension of addrlo. */
that are zero extended. So far this appears to be true. If we if (GUEST_BASE == 0 || guest_base_flags) {
want to enforce this, we can either do an explicit zero-extension
here, or (if GUEST_BASE == 0, or a segment register is in use)
use the ADDR32 prefix. For now, do nothing. */
if (GUEST_BASE && s->guest_base_flags) {
seg = s->guest_base_flags; seg = s->guest_base_flags;
offset = 0; offset = 0;
} else if (TCG_TARGET_REG_BITS == 64 && offset != GUEST_BASE) { if (TCG_TARGET_REG_BITS > TARGET_LONG_BITS) {
tcg_out_movi(s, TCG_TYPE_I64, TCG_REG_L1, GUEST_BASE); seg |= P_ADDR32;
tgen_arithr(s, ARITH_ADD + P_REXW, TCG_REG_L1, base); }
} else if (TCG_TARGET_REG_BITS == 64) {
/* ??? Note that we can't use the same SIB addressing scheme
as for loads, since we require L0 free for bswap. */
if (offset != GUEST_BASE) {
if (TARGET_LONG_BITS == 32) {
tcg_out_ext32u(s, TCG_REG_L0, base);
base = TCG_REG_L0;
}
tcg_out_movi(s, TCG_TYPE_I64, TCG_REG_L1, GUEST_BASE);
tgen_arithr(s, ARITH_ADD + P_REXW, TCG_REG_L1, base);
base = TCG_REG_L1;
offset = 0;
}
} else if (TARGET_LONG_BITS == 32) {
tcg_out_ext32u(s, TCG_REG_L1, base);
base = TCG_REG_L1; base = TCG_REG_L1;
offset = 0;
} }
tcg_out_qemu_st_direct(s, datalo, datahi, base, offset, seg, opc); tcg_out_qemu_st_direct(s, datalo, datahi, base, offset, seg, opc);