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
#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));
}
/*
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 */
/*
#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.
*/