call gate fix - verr and verw fix


git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@459 c046a42c-6fe2-441c-8c8c-71466251a162
diff --git a/target-i386/helper.c b/target-i386/helper.c
index 0706515..7fd9a9a 100644
--- a/target-i386/helper.c
+++ b/target-i386/helper.c
@@ -19,6 +19,8 @@
  */
 #include "exec.h"
 
+//#define DEBUG_PCALL
+
 const uint8_t parity_table[256] = {
     CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0,
     0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P,
@@ -540,6 +542,27 @@
     uint32_t e1, e2, offset, ss, esp, ss_e1, ss_e2, push_size;
     uint32_t old_cs, old_ss, old_esp, old_eip;
 
+#ifdef DEBUG_PCALL
+    if (loglevel) {
+        static int count;
+        fprintf(logfile, "%d: interrupt: vector=%02x error_code=%04x int=%d CS:IP=%04x:%08x CPL=%d\n",
+                count, intno, error_code, is_int, env->segs[R_CS].selector, env->eip, env->hflags & 3);
+#if 0
+        {
+            int i;
+            uint8_t *ptr;
+            printf("       code=");
+            ptr = env->segs[R_CS].base + env->eip;
+            for(i = 0; i < 16; i++) {
+                printf(" %02x", ldub(ptr + i));
+            }
+            printf("\n");
+        }
+#endif
+        count++;
+    }
+#endif
+
     has_error_code = 0;
     if (!is_int && !is_hw) {
         switch(intno) {
@@ -1260,11 +1283,22 @@
     
     new_cs = T0;
     new_eip = T1;
+#ifdef DEBUG_PCALL
+    if (loglevel) {
+        fprintf(logfile, "lcall %04x:%08x\n",
+                new_cs, new_eip);
+    }
+#endif
     if ((new_cs & 0xfffc) == 0)
         raise_exception_err(EXCP0D_GPF, 0);
     if (load_segment(&e1, &e2, new_cs) != 0)
         raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc);
     cpl = env->hflags & HF_CPL_MASK;
+#ifdef DEBUG_PCALL
+    if (loglevel) {
+        fprintf(logfile, "desc=%08x:%08x\n", e1, e2);
+    }
+#endif
     if (e2 & DESC_S_MASK) {
         if (!(e2 & DESC_CS_MASK))
             raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc);
@@ -1341,6 +1375,7 @@
             raise_exception_err(EXCP0B_NOSEG,  new_cs & 0xfffc);
         selector = e1 >> 16;
         offset = (e2 & 0xffff0000) | (e1 & 0x0000ffff);
+        param_count = e2 & 0x1f;
         if ((selector & 0xfffc) == 0)
             raise_exception_err(EXCP0D_GPF, 0);
 
@@ -1357,6 +1392,11 @@
         if (!(e2 & DESC_C_MASK) && dpl < cpl) {
             /* to inner priviledge */
             get_ss_esp_from_tss(&ss, &sp, dpl);
+#ifdef DEBUG_PCALL
+            if (loglevel)
+                fprintf(logfile, "ss=%04x sp=%04x param_count=%d ESP=%x\n", 
+                        ss, sp, param_count, ESP);
+#endif
             if ((ss & 0xfffc) == 0)
                 raise_exception_err(EXCP0A_TSS, ss & 0xfffc);
             if ((ss & 3) != dpl)
@@ -1373,7 +1413,6 @@
             if (!(ss_e2 & DESC_P_MASK))
                 raise_exception_err(EXCP0A_TSS, ss & 0xfffc);
             
-            param_count = e2 & 0x1f;
             push_size = ((param_count * 2) + 8) << shift;
 
             old_esp = ESP;
@@ -1389,7 +1428,7 @@
                            get_seg_limit(ss_e1, ss_e2),
                            ss_e2);
 
-            if (!(env->segs[R_SS].flags & DESC_B_MASK))
+            if (!(ss_e2 & DESC_B_MASK))
                 sp &= 0xffff;
             ssp = env->segs[R_SS].base + sp;
             if (shift) {
@@ -1441,7 +1480,6 @@
                        e2);
         cpu_x86_set_cpl(env, dpl);
         
-        /* from this point, not restartable if same priviledge */
         if (!(env->segs[R_SS].flags & DESC_B_MASK))
             ESP = (ESP & 0xffff0000) | (sp & 0xffff);
         else
@@ -1838,7 +1876,7 @@
         if (dpl < cpl || dpl < rpl)
             return;
     }
-    /* ok */
+    CC_SRC |= CC_Z;
 }
 
 void helper_verw(void)
@@ -1866,7 +1904,7 @@
         if (!(e2 & DESC_W_MASK))
             return;
     }
-    /* ok */
+    CC_SRC |= CC_Z;
 }
 
 /* FPU helpers */