Qemu does not generate a double fault (DBF) on x86, if a general protection
fault could not be delivered. Instead it hangs in a loop.

The patch fix this bug by checking whether we are already in a GPF exception.


    Bernhard Kauer
 
Index: helper.c
===================================================================
RCS file: /sources/qemu/qemu/target-i386/helper.c,v
retrieving revision 1.74
diff -u -r1.74 helper.c
--- helper.c    1 Feb 2007 22:12:19 -0000       1.74
+++ helper.c    27 Mar 2007 11:33:34 -0000
@@ -592,6 +592,16 @@
     sp += 4;\
 }
 
+void
+raise_gpf(int intno, int is_int, int is_hw, int error)
+{
+  if (!is_int && !is_hw && intno == EXCP0D_GPF)
+    raise_exception_err(EXCP08_DBLE, 0);
+  else
+    raise_exception_err(EXCP0D_GPF, error >= 0 ? error : intno * 
TARGET_LONG_SIZE + 2);
+}
+
+
 /* protected mode interrupt */
 static void do_interrupt_protected(int intno, int is_int, int error_code,
                                    unsigned int next_eip, int is_hw)
@@ -624,7 +634,7 @@
 
     dt = &env->idt;
     if (intno * 8 + 7 > dt->limit)
-        raise_exception_err(EXCP0D_GPF, intno * 8 + 2);
+        raise_gpf(intno, is_int, is_hw, -1);
     ptr = dt->base + intno * 8;
     e1 = ldl_kernel(ptr);
     e2 = ldl_kernel(ptr + 4);
@@ -661,29 +671,30 @@
     case 15: /* 386 trap gate */
         break;
     default:
-        raise_exception_err(EXCP0D_GPF, intno * 8 + 2);
+        raise_gpf(intno, is_int, is_hw, -1);
         break;
     }
     dpl = (e2 >> DESC_DPL_SHIFT) & 3;
     cpl = env->hflags & HF_CPL_MASK;
     /* check privledge if software int */
     if (is_int && dpl < cpl)
-        raise_exception_err(EXCP0D_GPF, intno * 8 + 2);
+        raise_gpf(intno, is_int, is_hw, -1);
+
     /* check valid bit */
     if (!(e2 & DESC_P_MASK))
         raise_exception_err(EXCP0B_NOSEG, intno * 8 + 2);
     selector = e1 >> 16;
     offset = (e2 & 0xffff0000) | (e1 & 0x0000ffff);
     if ((selector & 0xfffc) == 0)
-        raise_exception_err(EXCP0D_GPF, 0);
+        raise_gpf(intno, is_int, is_hw, 0);
 
     if (load_segment(&e1, &e2, selector) != 0)
-        raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
+        raise_gpf(intno, is_int, is_hw, selector & 0xfffc);
     if (!(e2 & DESC_S_MASK) || !(e2 & (DESC_CS_MASK)))
-        raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
+        raise_gpf(intno, is_int, is_hw, selector & 0xfffc);
     dpl = (e2 >> DESC_DPL_SHIFT) & 3;
     if (dpl > cpl)
-        raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
+        raise_gpf(intno, is_int, is_hw, selector & 0xfffc);
     if (!(e2 & DESC_P_MASK))
         raise_exception_err(EXCP0B_NOSEG, selector & 0xfffc);
     if (!(e2 & DESC_C_MASK) && dpl < cpl) {
@@ -710,14 +721,14 @@
     } else if ((e2 & DESC_C_MASK) || dpl == cpl) {
         /* to same priviledge */
         if (env->eflags & VM_MASK)
-            raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
+           raise_gpf(intno, is_int, is_hw, selector & 0xfffc);
         new_stack = 0;
         sp_mask = get_sp_mask(env->segs[R_SS].flags);
         ssp = env->segs[R_SS].base;
         esp = ESP;
         dpl = cpl;
     } else {
-        raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
+        raise_gpf(intno, is_int, is_hw, selector & 0xfffc);
         new_stack = 0; /* avoid warning */
         sp_mask = 0; /* avoid warning */
         ssp = 0; /* avoid warning */
@@ -860,7 +871,7 @@
 
     dt = &env->idt;
     if (intno * 16 + 15 > dt->limit)
-        raise_exception_err(EXCP0D_GPF, intno * 16 + 2);
+        raise_gpf(intno, is_int, is_hw, -1);
     ptr = dt->base + intno * 16;
     e1 = ldl_kernel(ptr);
     e2 = ldl_kernel(ptr + 4);
@@ -872,14 +883,13 @@
     case 15: /* 386 trap gate */
         break;
     default:
-        raise_exception_err(EXCP0D_GPF, intno * 16 + 2);
-        break;
+        raise_gpf(intno, is_int, is_hw, -1);
     }
     dpl = (e2 >> DESC_DPL_SHIFT) & 3;
     cpl = env->hflags & HF_CPL_MASK;
     /* check privledge if software int */
     if (is_int && dpl < cpl)
-        raise_exception_err(EXCP0D_GPF, intno * 16 + 2);
+        raise_gpf(intno, is_int, is_hw, -1);
     /* check valid bit */
     if (!(e2 & DESC_P_MASK))
         raise_exception_err(EXCP0B_NOSEG, intno * 16 + 2);
@@ -887,19 +897,19 @@
     offset = ((target_ulong)e3 << 32) | (e2 & 0xffff0000) | (e1 & 0x0000ffff);
     ist = e2 & 7;
     if ((selector & 0xfffc) == 0)
-        raise_exception_err(EXCP0D_GPF, 0);
+        raise_gpf(intno, is_int, is_hw, 0);
 
     if (load_segment(&e1, &e2, selector) != 0)
-        raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
+        raise_gpf(intno, is_int, is_hw, selector & 0xfffc);
     if (!(e2 & DESC_S_MASK) || !(e2 & (DESC_CS_MASK)))
-        raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
+        raise_gpf(intno, is_int, is_hw, selector & 0xfffc);
     dpl = (e2 >> DESC_DPL_SHIFT) & 3;
     if (dpl > cpl)
-        raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
+        raise_gpf(intno, is_int, is_hw, selector & 0xfffc);
     if (!(e2 & DESC_P_MASK))
         raise_exception_err(EXCP0B_NOSEG, selector & 0xfffc);
     if (!(e2 & DESC_L_MASK) || (e2 & DESC_B_MASK))
-        raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
+        raise_gpf(intno, is_int, is_hw, selector & 0xfffc);
     if ((!(e2 & DESC_C_MASK) && dpl < cpl) || ist != 0) {
         /* to inner priviledge */
         if (ist != 0)
@@ -912,7 +922,7 @@
     } else if ((e2 & DESC_C_MASK) || dpl == cpl) {
         /* to same priviledge */
         if (env->eflags & VM_MASK)
-            raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
+           raise_gpf(intno, is_int, is_hw, selector & 0xfffc);
         new_stack = 0;
         if (ist != 0)
             esp = get_rsp_from_tss(ist + 3);
@@ -921,7 +931,7 @@
         esp &= ~0xfLL; /* align stack */
         dpl = cpl;
     } else {
-        raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
+        raise_gpf(intno, is_int, is_hw, selector & 0xfffc);
         new_stack = 0; /* avoid warning */
         esp = 0; /* avoid warning */
     }
@@ -1089,7 +1099,12 @@
     /* real mode (simpler !) */
     dt = &env->idt;
     if (intno * 4 + 3 > dt->limit)
-        raise_exception_err(EXCP0D_GPF, intno * 8 + 2);
+      {
+        if (!is_int && intno == EXCP0D_GPF)
+           raise_exception_err(EXCP08_DBLE, 0);
+       else
+           raise_exception_err(EXCP0D_GPF, intno * 4 + 2);
+      }
     ptr = dt->base + intno * 4;
     offset = lduw_kernel(ptr);
     selector = lduw_kernel(ptr + 2);

Reply via email to