diff options
-rw-r--r-- | Changelog | 1 | ||||
-rw-r--r-- | target-i386/exec.h | 1 | ||||
-rw-r--r-- | target-i386/helper.c | 32 | ||||
-rw-r--r-- | target-i386/op.c | 5 | ||||
-rw-r--r-- | target-i386/translate.c | 18 | ||||
-rw-r--r-- | tests/test-i386.c | 51 |
6 files changed, 92 insertions, 16 deletions
@@ -27,6 +27,7 @@ version 0.6.1: - Floppy fixes for NT4 and NT5 (Mike Nordell) - NT4 IDE fixes (Ben Pfaf, Mike Nordell) - SDL Audio support and SB16 fixes (malc) + - ENTER instruction bug fix (initial patch by Stefan Kisdaroczi) version 0.6.0: diff --git a/target-i386/exec.h b/target-i386/exec.h index 61af5468e7..c0c8ca0db7 100644 --- a/target-i386/exec.h +++ b/target-i386/exec.h @@ -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(int level, int data32); void helper_sysenter(void); void helper_sysexit(void); void helper_rdtsc(void); diff --git a/target-i386/helper.c b/target-i386/helper.c index 41ebaf221e..e6686da722 100644 --- a/target-i386/helper.c +++ b/target-i386/helper.c @@ -1068,6 +1068,38 @@ void helper_cpuid(void) } } +void helper_enter_level(int level, int data32) +{ + uint8_t *ssp; + uint32_t esp_mask, esp, ebp; + + esp_mask = get_sp_mask(env->segs[R_SS].flags); + ssp = env->segs[R_SS].base; + ebp = EBP; + esp = ESP; + if (data32) { + /* 32 bit */ + esp -= 4; + while (--level) { + esp -= 4; + ebp -= 4; + stl(ssp + (esp & esp_mask), ldl(ssp + (ebp & esp_mask))); + } + esp -= 4; + stl(ssp + (esp & esp_mask), T1); + } else { + /* 16 bit */ + esp -= 2; + while (--level) { + esp -= 2; + ebp -= 2; + stw(ssp + (esp & esp_mask), lduw(ssp + (ebp & esp_mask))); + } + esp -= 2; + stw(ssp + (esp & esp_mask), T1); + } +} + void helper_lldt_T0(void) { int selector; diff --git a/target-i386/op.c b/target-i386/op.c index 9ea00a7571..21d4d82991 100644 --- a/target-i386/op.c +++ b/target-i386/op.c @@ -695,6 +695,11 @@ void OPPROTO op_cpuid(void) helper_cpuid(); } +void OPPROTO op_enter_level(void) +{ + helper_enter_level(PARAM1, PARAM2); +} + void OPPROTO op_sysenter(void) { helper_sysenter(); diff --git a/target-i386/translate.c b/target-i386/translate.c index bd2a61b0e5..5b8f213123 100644 --- a/target-i386/translate.c +++ b/target-i386/translate.c @@ -1690,15 +1690,12 @@ static void gen_popa(DisasContext *s) gen_op_mov_reg_T1[OT_WORD + s->dflag][R_ESP](); } -/* NOTE: wrap around in 16 bit not fully handled */ -/* 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 +1709,10 @@ static void gen_enter(DisasContext *s, int esp_addend, int level) 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); - gen_op_st_T1_A0[ot + s->mem_index](); + gen_op_enter_level(level, s->dflag); } 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](); } diff --git a/tests/test-i386.c b/tests/test-i386.c index 29f0dfa1fa..a4bfa34dee 100644 --- a/tests/test-i386.c +++ b/tests/test-i386.c @@ -1625,7 +1625,55 @@ void test_self_modifying_code(void) printf("smc_code2(%d) = %d\n", i, smc_code2(i)); } } - + +int enter_stack[4096]; + +#define TEST_ENTER(size, stack_type, level)\ +{\ + int esp_save, esp_val, ebp_val, ebp_save, i;\ + stack_type *ptr, *stack_end, *stack_ptr;\ + memset(enter_stack, 0, sizeof(enter_stack));\ + stack_end = stack_ptr = (stack_type *)(enter_stack + 4096);\ + ebp_val = (long)stack_ptr;\ + for(i=1;i<=32;i++)\ + *--stack_ptr = i;\ + esp_val = (long)stack_ptr;\ + asm("movl %%esp, %[esp_save]\n"\ + "movl %%ebp, %[ebp_save]\n"\ + "movl %[esp_val], %%esp\n"\ + "movl %[ebp_val], %%ebp\n"\ + "enter" size " $12, $" #level "\n"\ + "movl %%esp, %[esp_val]\n"\ + "movl %%ebp, %[ebp_val]\n"\ + "movl %[esp_save], %%esp\n"\ + "movl %[ebp_save], %%ebp\n"\ + : [esp_save] "=r" (esp_save),\ + [ebp_save] "=r" (ebp_save),\ + [esp_val] "=r" (esp_val),\ + [ebp_val] "=r" (ebp_val)\ + : "[esp_val]" (esp_val),\ + "[ebp_val]" (ebp_val));\ + printf("level=%d:\n", level);\ + printf("esp_val=0x%08lx\n", esp_val - (long)stack_end);\ + printf("ebp_val=0x%08lx\n", ebp_val - (long)stack_end);\ + for(ptr = (stack_type *)esp_val; ptr < stack_end; ptr++)\ + printf("%08x\n", ptr[0]);\ +} + +static void test_enter(void) +{ + TEST_ENTER("l", uint32_t, 0); + TEST_ENTER("l", uint32_t, 1); + TEST_ENTER("l", uint32_t, 2); + TEST_ENTER("l", uint32_t, 31); + + TEST_ENTER("w", uint16_t, 0); + TEST_ENTER("w", uint16_t, 1); + TEST_ENTER("w", uint16_t, 2); + TEST_ENTER("w", uint16_t, 31); +} + + static void *call_end __init_call = NULL; int main(int argc, char **argv) @@ -1653,5 +1701,6 @@ int main(int argc, char **argv) test_exceptions(); test_self_modifying_code(); test_single_step(); + test_enter(); return 0; } |