target-i386: Rewrite gen_enter inline

Use gen_lea_v_seg for centralized segment base knowledge. Unify
code across 32- and 64-bit. Fix note about "must save state"
before using the out-of-line helpers.

Backports commit 743e398e2fbf2f7183bf7a53c9d011fabcaa1770 from qemu
This commit is contained in:
Richard Henderson 2018-02-20 10:10:05 -05:00 committed by Lioncash
parent 302752df8b
commit 7dd4fcc621
No known key found for this signature in database
GPG Key ID: 4E3C3CC1031BA9C7
3 changed files with 34 additions and 142 deletions

View File

@ -46,10 +46,6 @@ DEF_HELPER_FLAGS_3(set_dr, TCG_CALL_NO_WG, void, env, int, tl)
DEF_HELPER_FLAGS_2(get_dr, TCG_CALL_NO_WG, tl, env, int)
DEF_HELPER_2(invlpg, void, env, tl)
DEF_HELPER_4(enter_level, void, env, int, int, tl)
#ifdef TARGET_X86_64
DEF_HELPER_4(enter64_level, void, env, int, int, tl)
#endif
DEF_HELPER_2(sysenter, void, env, int)
DEF_HELPER_2(sysexit, void, env, int)
#ifdef TARGET_X86_64

View File

@ -1376,80 +1376,6 @@ bool x86_cpu_exec_interrupt(CPUState *cs, int interrupt_request)
return ret;
}
void helper_enter_level(CPUX86State *env, int level, int data32,
target_ulong t1)
{
target_ulong ssp;
uint32_t esp_mask, esp, ebp;
esp_mask = get_sp_mask(env->segs[R_SS].flags);
ssp = env->segs[R_SS].base;
ebp = env->regs[R_EBP];
esp = env->regs[R_ESP];
if (data32) {
/* 32 bit */
esp -= 4;
while (--level) {
esp -= 4;
ebp -= 4;
cpu_stl_data_ra(env, ssp + (esp & esp_mask),
cpu_ldl_data_ra(env, ssp + (ebp & esp_mask),
GETPC()),
GETPC());
}
esp -= 4;
cpu_stl_data_ra(env, ssp + (esp & esp_mask), t1, GETPC());
} else {
/* 16 bit */
esp -= 2;
while (--level) {
esp -= 2;
ebp -= 2;
cpu_stw_data_ra(env, ssp + (esp & esp_mask),
cpu_lduw_data_ra(env, ssp + (ebp & esp_mask),
GETPC()),
GETPC());
}
esp -= 2;
cpu_stw_data_ra(env, ssp + (esp & esp_mask), t1, GETPC());
}
}
#ifdef TARGET_X86_64
void helper_enter64_level(CPUX86State *env, int level, int data64,
target_ulong t1)
{
target_ulong esp, ebp;
ebp = env->regs[R_EBP];
esp = env->regs[R_ESP];
if (data64) {
/* 64 bit */
esp -= 8;
while (--level) {
esp -= 8;
ebp -= 8;
cpu_stq_data_ra(env, esp, cpu_ldq_data_ra(env, ebp, GETPC()),
GETPC());
}
esp -= 8;
cpu_stq_data_ra(env, esp, t1, GETPC());
} else {
/* 16 bit */
esp -= 2;
while (--level) {
esp -= 2;
ebp -= 2;
cpu_stw_data_ra(env, esp, cpu_lduw_data_ra(env, ebp, GETPC()),
GETPC());
}
esp -= 2;
cpu_stw_data_ra(env, esp, t1, GETPC());
}
}
#endif
void helper_lldt(CPUX86State *env, int selector)
{
SegmentCache *dt;

View File

@ -441,14 +441,6 @@ static inline void gen_op_mov_v_reg(TCGContext *s, TCGMemOp ot, TCGv t0, int reg
}
}
static inline void gen_op_movl_A0_reg(TCGContext *s, int reg)
{
TCGv cpu_A0 = *(TCGv *)s->cpu_A0;
TCGv **cpu_regs = (TCGv **)s->cpu_regs;
tcg_gen_mov_tl(s, cpu_A0, *cpu_regs[reg]);
}
static inline void gen_op_addl_A0_im(TCGContext *s, int32_t val)
{
TCGv cpu_A0 = *(TCGv *)s->cpu_A0;
@ -503,21 +495,6 @@ static inline void gen_op_add_reg_T0(TCGContext *s, TCGMemOp size, int reg)
gen_op_mov_reg_v(s, size, reg, cpu_tmp0);
}
static inline void gen_op_addl_A0_seg(DisasContext *s, int reg)
{
TCGContext *tcg_ctx = s->uc->tcg_ctx;
TCGv cpu_A0 = *(TCGv *)tcg_ctx->cpu_A0;
TCGv **cpu_seg_base = (TCGv **)tcg_ctx->cpu_seg_base;
if (CODE64(s)) {
tcg_gen_ext32u_tl(tcg_ctx, cpu_A0, cpu_A0);
tcg_gen_add_tl(tcg_ctx, cpu_A0, cpu_A0, *cpu_seg_base[reg]);
} else {
tcg_gen_add_tl(tcg_ctx, cpu_A0, cpu_A0, *cpu_seg_base[reg]);
tcg_gen_ext32u_tl(tcg_ctx, cpu_A0, cpu_A0);
}
}
static inline void gen_op_ld_v(DisasContext *s, int idx, TCGv t0, TCGv a0)
{
if (HOOK_EXISTS(s->uc, UC_HOOK_MEM_READ))
@ -2644,54 +2621,47 @@ static void gen_popa(DisasContext *s)
static void gen_enter(DisasContext *s, int esp_addend, int level)
{
TCGMemOp ot = mo_pushpop(s, s->dflag);
int opsize = 1 << ot;
TCGMemOp d_ot = mo_pushpop(s, s->dflag);
TCGMemOp a_ot = CODE64(s) ? MO_64 : s->ss32 ? MO_32 : MO_16;
int size = 1 << d_ot;
TCGContext *tcg_ctx = s->uc->tcg_ctx;
TCGv cpu_A0 = *(TCGv *)tcg_ctx->cpu_A0;
TCGv cpu_tmp0 = *(TCGv *)tcg_ctx->cpu_tmp0;
TCGv **cpu_T = (TCGv **)tcg_ctx->cpu_T;
TCGv **cpu_regs = (TCGv **)tcg_ctx->cpu_regs;
level &= 0x1f;
#ifdef TARGET_X86_64
if (CODE64(s)) {
gen_op_movl_A0_reg(tcg_ctx, R_ESP);
gen_op_addq_A0_im(tcg_ctx, -opsize);
tcg_gen_mov_tl(tcg_ctx, *cpu_T[1], cpu_A0);
/* Push BP; compute FrameTemp into T1. */
tcg_gen_subi_tl(tcg_ctx, *cpu_T[1], *cpu_regs[R_ESP], size);
gen_lea_v_seg(s, a_ot, *cpu_T[1], R_SS, -1);
gen_op_st_v(s, d_ot, *cpu_regs[R_EBP], cpu_A0);
/* push bp */
gen_op_mov_v_reg(tcg_ctx, MO_32, *cpu_T[0], R_EBP);
gen_op_st_v(s, ot, *cpu_T[0], cpu_A0);
if (level) {
/* XXX: must save state */
gen_helper_enter64_level(tcg_ctx, tcg_ctx->cpu_env, tcg_const_i32(tcg_ctx, level),
tcg_const_i32(tcg_ctx, (ot == MO_64)),
*cpu_T[1]);
level &= 31;
if (level != 0) {
int i;
/* Copy level-1 pointers from the previous frame. */
for (i = 1; i < level; ++i) {
tcg_gen_subi_tl(tcg_ctx, cpu_A0, *cpu_regs[R_EBP], size * i);
gen_lea_v_seg(s, a_ot, cpu_A0, R_SS, -1);
gen_op_ld_v(s, d_ot, cpu_tmp0, cpu_A0);
tcg_gen_subi_tl(tcg_ctx, cpu_A0, *cpu_T[1], size * i);
gen_lea_v_seg(s, a_ot, cpu_A0, R_SS, -1);
gen_op_st_v(s, d_ot, cpu_tmp0, cpu_A0);
}
gen_op_mov_reg_v(tcg_ctx, ot, R_EBP, *cpu_T[1]);
tcg_gen_addi_tl(tcg_ctx, *cpu_T[1], *cpu_T[1], -esp_addend + (-opsize * level));
gen_op_mov_reg_v(tcg_ctx, MO_64, R_ESP, *cpu_T[1]);
} else
#endif
{
gen_op_movl_A0_reg(tcg_ctx, R_ESP);
gen_op_addl_A0_im(tcg_ctx, -opsize);
if (!s->ss32)
tcg_gen_ext16u_tl(tcg_ctx, cpu_A0, cpu_A0);
tcg_gen_mov_tl(tcg_ctx, *cpu_T[1], cpu_A0);
if (s->addseg)
gen_op_addl_A0_seg(s, R_SS);
/* push bp */
gen_op_mov_v_reg(tcg_ctx, MO_32, *cpu_T[0], R_EBP);
gen_op_st_v(s, ot, *cpu_T[0], cpu_A0);
if (level) {
/* XXX: must save state */
gen_helper_enter_level(tcg_ctx, tcg_ctx->cpu_env, tcg_const_i32(tcg_ctx, level),
tcg_const_i32(tcg_ctx, s->dflag - 1),
*cpu_T[1]);
}
gen_op_mov_reg_v(tcg_ctx, ot, R_EBP, *cpu_T[1]);
tcg_gen_addi_tl(tcg_ctx, *cpu_T[1], *cpu_T[1], -esp_addend + (-opsize * level));
gen_op_mov_reg_v(tcg_ctx, MO_16 + s->ss32, R_ESP, *cpu_T[1]);
/* Push the current FrameTemp as the last level. */
tcg_gen_subi_tl(tcg_ctx, cpu_A0, *cpu_T[1], size * level);
gen_lea_v_seg(s, a_ot, cpu_A0, R_SS, -1);
gen_op_st_v(s, d_ot, *cpu_T[1], cpu_A0);
}
/* Copy the FrameTemp value to EBP. */
gen_op_mov_reg_v(tcg_ctx, a_ot, R_EBP, *cpu_T[1]);
/* Compute the final value of ESP. */
tcg_gen_subi_tl(tcg_ctx, *cpu_T[1], *cpu_T[1], esp_addend + size * level);
gen_op_mov_reg_v(tcg_ctx, a_ot, R_ESP, *cpu_T[1]);
}
static void gen_exception(DisasContext *s, int trapno, target_ulong cur_eip)