enter insn fix
authorbellard <bellard@c046a42c-6fe2-441c-8c8c-71466251a162>
Sun, 14 Nov 2004 15:39:16 +0000 (15:39 +0000)
committerbellard <bellard@c046a42c-6fe2-441c-8c8c-71466251a162>
Sun, 14 Nov 2004 15:39:16 +0000 (15:39 +0000)
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1135 c046a42c-6fe2-441c-8c8c-71466251a162

Changelog
target-i386/exec.h
target-i386/helper.c
target-i386/op.c
target-i386/translate.c
tests/test-i386.c

index 73b85e5..5b2073a 100644 (file)
--- a/Changelog
+++ b/Changelog
@@ -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:
 
index 61af546..c0c8ca0 100644 (file)
@@ -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);
index 41ebaf2..e6686da 100644 (file)
@@ -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;
index 9ea00a7..21d4d82 100644 (file)
@@ -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();
index bd2a61b..5b8f213 100644 (file)
@@ -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]();
 }
 
index 29f0dfa..a4bfa34 100644 (file)
@@ -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;
 }