From: Andrew Cooper Date: Tue, 15 Dec 2015 09:33:45 +0000 (+0000) Subject: Modify entry points to be able to return from exceptions X-Git-Url: http://xenbits.xensource.com/gitweb?a=commitdiff_plain;h=9f52b8e4b40fce3343c0e818ae8759c98400e053;p=people%2Froyger%2Fxen-test-framework.git Modify entry points to be able to return from exceptions Trap and Interrupt exceptions will now return, while Fault and Abort exceptions are still fatal. Signed-off-by: Andrew Cooper --- diff --git a/arch/x86/entry_32.S b/arch/x86/entry_32.S index e46057e..7d3a1ad 100644 --- a/arch/x86/entry_32.S +++ b/arch/x86/entry_32.S @@ -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 diff --git a/arch/x86/entry_64.S b/arch/x86/entry_64.S index 826bfd7..dbfbb96 100644 --- a/arch/x86/entry_64.S +++ b/arch/x86/entry_64.S @@ -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 diff --git a/arch/x86/traps.c b/arch/x86/traps.c index f46190e..61a2cd2 100644 --- a/arch/x86/traps.c +++ b/arch/x86/traps.c @@ -1,14 +1,66 @@ #include #include +#include + +/* + * 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)); } /* diff --git a/include/arch/x86/lib.h b/include/arch/x86/lib.h index e8faa95..458e25f 100644 --- a/include/arch/x86/lib.h +++ b/include/arch/x86/lib.h @@ -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 */ /* diff --git a/include/arch/x86/processor.h b/include/arch/x86/processor.h index 7e359b5..d1346f6 100644 --- a/include/arch/x86/processor.h +++ b/include/arch/x86/processor.h @@ -60,6 +60,17 @@ #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. */