diff -uNrp qemu.orig/target-i386/exec.h qemu/target-i386/exec.h --- qemu.orig/target-i386/exec.h 2004-11-14 13:43:20.000000000 +0100 +++ qemu/target-i386/exec.h 2004-11-14 13:47:31.000000000 +0100 @@ -167,6 +167,7 @@ void helper_divl_EAX_T0(uint32_t eip); void helper_idivl_EAX_T0(uint32_t eip); void helper_cmpxchg8b(void); void helper_cpuid(void); +void helper_enter_level(uint8_t *dst_ptr, int level, int data32); void helper_sysenter(void); void helper_sysexit(void); void helper_rdtsc(void); diff -uNrp qemu.orig/target-i386/helper.c qemu/target-i386/helper.c --- qemu.orig/target-i386/helper.c 2004-11-14 13:43:20.000000000 +0100 +++ qemu/target-i386/helper.c 2004-11-14 13:47:31.000000000 +0100 @@ -1068,6 +1068,27 @@ void helper_cpuid(void) } } +void helper_enter_level( uint8_t *dst_ptr, int level, int data32 ) +{ + int ofs = 0; + uint8_t *src_ptr = env->segs[R_SS].base + EBP; + + if (data32) { + /* 32 bit */ + while (--level) { + ofs -= 4; + stl( dst_ptr + ofs, ldl( src_ptr + ofs ) ); + } + } + else { + /* 16 bit */ + while (--level) { + ofs -= 2; + stw( dst_ptr + ofs, lduw( src_ptr + ofs ) ); + } + } +} + void helper_lldt_T0(void) { int selector; diff -uNrp qemu.orig/target-i386/op.c qemu/target-i386/op.c --- qemu.orig/target-i386/op.c 2004-11-14 13:43:20.000000000 +0100 +++ qemu/target-i386/op.c 2004-11-14 13:47:31.000000000 +0100 @@ -695,6 +695,11 @@ void OPPROTO op_cpuid(void) helper_cpuid(); } +void OPPROTO op_enter_level(void) +{ + helper_enter_level((uint8_t *)A0, PARAM1, PARAM2); +} + void OPPROTO op_sysenter(void) { helper_sysenter(); diff -uNrp qemu.orig/target-i386/translate.c qemu/target-i386/translate.c --- qemu.orig/target-i386/translate.c 2004-11-14 13:43:20.000000000 +0100 +++ qemu/target-i386/translate.c 2004-11-14 13:51:57.000000000 +0100 @@ -1694,11 +1694,10 @@ static void gen_popa(DisasContext *s) /* XXX: check this */ static void gen_enter(DisasContext *s, int esp_addend, int level) { - int ot, level1, addend, opsize; + int ot, opsize; ot = s->dflag + OT_WORD; level &= 0x1f; - level1 = level; opsize = 2 << s->dflag; gen_op_movl_A0_ESP(); @@ -1712,19 +1711,13 @@ static void gen_enter(DisasContext *s, i gen_op_mov_TN_reg[OT_LONG][0][R_EBP](); gen_op_st_T0_A0[ot + s->mem_index](); if (level) { - while (level--) { - gen_op_addl_A0_im(-opsize); - gen_op_addl_T0_im(-opsize); - gen_op_st_T0_A0[ot + s->mem_index](); - } - gen_op_addl_A0_im(-opsize); + if (level > 1) + gen_op_enter_level( level, s->dflag ); + gen_op_addl_A0_im(-opsize * level); gen_op_st_T1_A0[ot + s->mem_index](); } gen_op_mov_reg_T1[ot][R_EBP](); - addend = -esp_addend; - if (level1) - addend -= opsize * (level1 + 1); - gen_op_addl_T1_im(addend); + gen_op_addl_T1_im( -esp_addend + (-opsize * level) ); gen_op_mov_reg_T1[ot][R_ESP](); }