All of lore.kernel.org
 help / color / mirror / Atom feed
* [Qemu-devel] Patch: generate a DBF when a GPF could not be delivered on x86
@ 2007-03-27 11:40 Bernhard Kauer
  2007-03-28  8:13 ` Sebastian Kaliszewski
  0 siblings, 1 reply; 4+ messages in thread
From: Bernhard Kauer @ 2007-03-27 11:40 UTC (permalink / raw)
  To: qemu-devel

[-- Attachment #1: Type: text/plain, Size: 236 bytes --]

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
 

[-- Attachment #2: qemu_dbf.diff --]
[-- Type: text/plain, Size: 6286 bytes --]

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);

^ permalink raw reply	[flat|nested] 4+ messages in thread

* Re: [Qemu-devel] Patch: generate a DBF when a GPF could not be delivered on x86
  2007-03-27 11:40 [Qemu-devel] Patch: generate a DBF when a GPF could not be delivered on x86 Bernhard Kauer
@ 2007-03-28  8:13 ` Sebastian Kaliszewski
  2007-03-28 12:39   ` Bernhard Kauer
  0 siblings, 1 reply; 4+ messages in thread
From: Sebastian Kaliszewski @ 2007-03-28  8:13 UTC (permalink / raw)
  To: qemu-devel

Bernhard Kauer wrote:
> 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.

If you're at it, maybe add triple fault handling (ie exception if DBF 
handler) -- it should reset CPU.


rgds
-- 
Sebastian Kaliszewski

^ permalink raw reply	[flat|nested] 4+ messages in thread

* Re: [Qemu-devel] Patch: generate a DBF when a GPF could not be delivered on x86
  2007-03-28  8:13 ` Sebastian Kaliszewski
@ 2007-03-28 12:39   ` Bernhard Kauer
  2007-03-31 12:14     ` [Qemu-devel] Patch: generate double and triple faults Bernhard Kauer
  0 siblings, 1 reply; 4+ messages in thread
From: Bernhard Kauer @ 2007-03-28 12:39 UTC (permalink / raw)
  To: qemu-devel

On Wed, Mar 28, 2007 at 10:13:49AM +0200, Sebastian Kaliszewski wrote:
> Bernhard Kauer wrote:
> >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.
> 
> If you're at it, maybe add triple fault handling (ie exception if DBF 
> handler) -- it should reset CPU.

There are many things missing in the x86 exception handling. For example
the case PF -> PF is also not handled.


    Bernhard Kauer

^ permalink raw reply	[flat|nested] 4+ messages in thread

* [Qemu-devel] Patch: generate double and triple faults
  2007-03-28 12:39   ` Bernhard Kauer
@ 2007-03-31 12:14     ` Bernhard Kauer
  0 siblings, 0 replies; 4+ messages in thread
From: Bernhard Kauer @ 2007-03-31 12:14 UTC (permalink / raw)
  To: qemu-devel

[-- Attachment #1: Type: text/plain, Size: 885 bytes --]

On Wed, Mar 28, 2007 at 02:39:31PM +0200, Bernhard Kauer wrote:
> On Wed, Mar 28, 2007 at 10:13:49AM +0200, Sebastian Kaliszewski wrote:
> > Bernhard Kauer wrote:
> > >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.
> > 
> > If you're at it, maybe add triple fault handling (ie exception if DBF 
> > handler) -- it should reset CPU.
> 
> There are many things missing in the x86 exception handling. For example
> the case PF -> PF is also not handled.

The attached patch implements double andd triple fault handling and makes
the last patch obsolete. It does not generate a reset on triple fault, but
it aborts qemu. The same happen currently if the TSS is bogous.


Greetings,

    Bernhard Kauer

[-- Attachment #2: qemu_exceptions.diff --]
[-- Type: text/plain, Size: 3227 bytes --]

Index: cpu-exec.c
===================================================================
RCS file: /sources/qemu/qemu/cpu-exec.c,v
retrieving revision 1.97
diff -u -r1.97 cpu-exec.c
--- cpu-exec.c	30 Mar 2007 16:44:53 -0000	1.97
+++ cpu-exec.c	31 Mar 2007 11:59:52 -0000
@@ -360,6 +360,7 @@
                                  env->exception_is_int, 
                                  env->error_code, 
                                  env->exception_next_eip, 0);
+		    env->old_exception = -1;  // successful delivered
 #elif defined(TARGET_PPC)
                     do_interrupt(env);
 #elif defined(TARGET_MIPS)
Index: target-i386/helper.c
===================================================================
RCS file: /sources/qemu/qemu/target-i386/helper.c,v
retrieving revision 1.74
diff -u -r1.74 helper.c
--- target-i386/helper.c	1 Feb 2007 22:12:19 -0000	1.74
+++ target-i386/helper.c	31 Mar 2007 11:59:58 -0000
@@ -1192,6 +1193,37 @@
     }
 }
 
+
+/**
+ * Check nested exceptions and change to double or triple fault if
+ * needed. It should only be called, if this is not an
+ * interrrupt. Returns the new exception number.
+ */
+int check_exception(int intno, int *error_code)
+{
+  if (loglevel & CPU_LOG_INT)
+    fprintf(logfile, "%s()  old: %x new %x\n",__func__,  env->old_exception, intno);
+
+
+ if (env->old_exception == EXCP08_DBLE)
+   cpu_abort(env, "triple fault");
+
+ char  first_contributory  = env->old_exception == 0 || (env->old_exception >= 10 && env->old_exception <= 13);
+ char second_contributory  = intno == 0 || (intno >= 10 && intno <= 13);
+
+ if ((first_contributory && second_contributory) 
+     || (env->old_exception == EXCP0E_PAGE && (second_contributory || (intno == EXCP0E_PAGE))))
+   {
+     intno = EXCP08_DBLE;
+     *error_code = 0;
+   }
+
+ if (second_contributory || (intno == EXCP0E_PAGE) || (intno == EXCP08_DBLE))
+   env->old_exception = intno;
+ return intno;
+}
+
+
 /*
  * Signal an interruption. It is executed in the main CPU loop.
  * is_int is TRUE if coming from the int instruction. next_eip is the
@@ -1201,6 +1233,9 @@
 void raise_interrupt(int intno, int is_int, int error_code, 
                      int next_eip_addend)
 {
+    if (!is_int)
+        intno = check_exception(intno, &error_code);
+
     env->exception_index = intno;
     env->error_code = error_code;
     env->exception_is_int = is_int;
@@ -1211,6 +1246,8 @@
 /* same as raise_exception_err, but do not restore global registers */
 static void raise_exception_err_norestore(int exception_index, int error_code)
 {
+    exception_index = check_exception(exception_index, &error_code);
+
     env->exception_index = exception_index;
     env->error_code = error_code;
     env->exception_is_int = 0;
Index: target-i386/cpu.h
===================================================================
RCS file: /sources/qemu/qemu/target-i386/cpu.h,v
retrieving revision 1.41
diff -u -r1.41 cpu.h
--- target-i386/cpu.h	5 Feb 2007 22:06:27 -0000	1.41
+++ target-i386/cpu.h	31 Mar 2007 11:59:56 -0000
@@ -515,6 +515,7 @@
     uint32_t smbase;
     int interrupt_request; 
     int user_mode_only; /* user mode only simulation */
+    int old_exception;  /* exception in flight */
 
     CPU_COMMON
 

^ permalink raw reply	[flat|nested] 4+ messages in thread

end of thread, other threads:[~2007-03-31 12:17 UTC | newest]

Thread overview: 4+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2007-03-27 11:40 [Qemu-devel] Patch: generate a DBF when a GPF could not be delivered on x86 Bernhard Kauer
2007-03-28  8:13 ` Sebastian Kaliszewski
2007-03-28 12:39   ` Bernhard Kauer
2007-03-31 12:14     ` [Qemu-devel] Patch: generate double and triple faults Bernhard Kauer

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.