]> xenbits.xensource.com Git - people/royger/xen-test-framework.git/commitdiff
Modify entry points to be able to return from exceptions
authorAndrew Cooper <andrew.cooper3@citrix.com>
Tue, 15 Dec 2015 09:33:45 +0000 (09:33 +0000)
committerAndrew Cooper <andrew.cooper3@citrix.com>
Fri, 18 Dec 2015 18:31:11 +0000 (18:31 +0000)
Trap and Interrupt exceptions will now return, while Fault and Abort
exceptions are still fatal.

Signed-off-by: Andrew Cooper <andrew.cooper3@citrix.com>
arch/x86/entry_32.S
arch/x86/entry_64.S
arch/x86/traps.c
include/arch/x86/lib.h
include/arch/x86/processor.h

index e46057eefca0ba0cc4c2431d7259159552356451..7d3a1ad4538add9d0e6417e4aaaf4123579887a6 100644 (file)
@@ -65,4 +65,14 @@ handle_exception:
         push %esp               /* struct cpu_regs * */
         call do_exception
         add $4, %esp
-        ud2a
+
+        RESTORE_ALL
+        add $8, %esp            /* Pop error_code/entry_vector. */
+
+#if defined(CONFIG_ENV_pv)
+
+        jmp HYPERCALL_iret      /* PV guests use the 'iret' hypercall. */
+
+#else
+        iret                    /* HVM guests use a real 'iret' instruction. */
+#endif
index 826bfd7780cdf0834e1611388ce227dd86a4d351..dbfbb96b8d5f108f165f05ef9b6210880d90cff0 100644 (file)
@@ -75,4 +75,15 @@ handle_exception:
 
         mov %rsp, %rdi          /* struct cpu_regs * */
         call do_exception
-        ud2a
+
+        RESTORE_ALL
+        add $8, %rsp            /* Pop error_code/entry_vector. */
+
+#if defined(CONFIG_ENV_pv)
+
+        push $0                 /* Indicate that this isn't a SYSRET'able   */
+        jmp HYPERCALL_iret      /* situation, and use the 'iret' hypercall. */
+
+#else
+        iretq                   /* HVM guests use a real 'iret' instruction. */
+#endif
index f46190e7738f75126acca6705aaa61339879fc0b..61a2cd2308f9833d264d17d8b21171a07feb31fa 100644 (file)
@@ -1,14 +1,66 @@
 #include <xtf/lib.h>
 #include <xtf/traps.h>
 
+#include <arch/x86/processor.h>
+
+/*
+ * Evaluate whether this exception is a trap or an interrupt.  i.e. whether it
+ * save to just return at the current %eip, or whether further action is
+ * required to resolve the source of the exception.
+ */
+static bool is_trap_or_interrupt(const struct cpu_regs *regs)
+{
+    /* All non-reserved vectors are interrupts. */
+    if ( regs->entry_vector >= X86_NR_RESERVED_VECTORS )
+        return true;
+
+    uint32_t vec_bit = 1u << regs->entry_vector;
+
+    if ( vec_bit & (X86_EXC_TRAPS | X86_EXC_INTERRUPTS) )
+        return true;
+
+    /* Architectural faults and aborts all need further action. */
+    if ( vec_bit & (X86_EXC_FAULTS | X86_EXC_ABORTS) )
+        return false;
+
+    /*
+     * The Debug Exception is awkward, and either a trap or a fault depending
+     * on other conditions.
+     */
+    unsigned long dr6 = read_dr6();
+
+    /* General Detect is a fault. */
+    if ( dr6 & X86_DR6_BD )
+        return false;
+
+    /* Instruction breakpoints are faults. */
+    if ( dr6 & (X86_DR6_B0 | X86_DR6_B1 | X86_DR6_B2 | X86_DR6_B3) )
+    {
+        unsigned long dr7 = read_dr7(), bp;
+
+        for ( bp = 0; bp < 4; ++bp )
+        {
+            if ( (dr6 & (1u << bp)) &&              /* Breakpoint triggered? */
+                 ((dr7 & (3u << (bp + 16))) == 0) ) /* Instruction breakpoint? */
+                return false;
+        }
+    }
+
+    /* All other debug conditions are traps. */
+    return true;
+}
+
 /*
  * C entry-point for exceptions, after the per-environment stubs have suitably
  * adjusted the stack.
  */
 void do_exception(struct cpu_regs *regs)
 {
-    panic("Unhandled exception: vec %u at %04x:%p\n",
-          regs->entry_vector, regs->cs, _p(regs->ip));
+    bool safe = is_trap_or_interrupt(regs);
+
+    if ( !safe )
+        panic("Unhandled exception: vec %u at %04x:%p\n",
+              regs->entry_vector, regs->cs, _p(regs->ip));
 }
 
 /*
index e8faa95dad164a026ba50139475766a3c8a4e33e..458e25f7c05287da7a59295dd72545def709938d 100644 (file)
@@ -79,6 +79,24 @@ static inline void outl(uint32_t val, uint16_t port)
     asm volatile("outl %k0, %w1": : "a" (val), "Nd" (port));
 }
 
+static inline unsigned long read_dr6(void)
+{
+    unsigned long val;
+
+    asm volatile ("mov %%dr6, %0" : "=r" (val));
+
+    return val;
+}
+
+static inline unsigned long read_dr7(void)
+{
+    unsigned long val;
+
+    asm volatile ("mov %%dr7, %0" : "=r" (val));
+
+    return val;
+}
+
 #endif /* XTF_X86_LIB_H */
 
 /*
index 7e359b5f011a94d3870a1d20dbbeebb243820270..d1346f6f5bbaad959595115e988f3e3fb4693a9e 100644 (file)
 #define X86_CR4_SMEP            0x00100000  /* SMEP                           */
 #define X86_CR4_SMAP            0x00200000  /* SMAP                           */
 
+/*
+ * DR6 status bits.
+ */
+#define X86_DR6_B0              (1u <<  0)  /* Breakpoint 0 triggered  */
+#define X86_DR6_B1              (1u <<  1)  /* Breakpoint 1 triggered  */
+#define X86_DR6_B2              (1u <<  2)  /* Breakpoint 2 triggered  */
+#define X86_DR6_B3              (1u <<  3)  /* Breakpoint 3 triggered  */
+#define X86_DR6_BD              (1u << 13)  /* Debug register accessed */
+#define X86_DR6_BS              (1u << 14)  /* Single step             */
+#define X86_DR6_BT              (1u << 15)  /* Task switch             */
+
 /*
  * Exception mnemonics.
  */