.endif
 
        ASM_CLAC
-       PARAVIRT_ADJUST_EXCEPTION_FRAME
 
        .ifeq \has_error_code
        pushq   $-1                             /* ORIG_RAX: no syscall to restart */
 ENDPROC(do_softirq_own_stack)
 
 #ifdef CONFIG_XEN
-idtentry xen_hypervisor_callback xen_do_hypervisor_callback has_error_code=0
+idtentry hypervisor_callback xen_do_hypervisor_callback has_error_code=0
 
 /*
  * A note on the "critical region" in our callback handler.
        movq    8(%rsp), %r11
        addq    $0x30, %rsp
        pushq   $0                              /* RIP */
-       pushq   %r11
-       pushq   %rcx
        UNWIND_HINT_IRET_REGS offset=8
        jmp     general_protection
 1:     /* Segment mismatch => Category 1 (Bad segment). Retry the IRET. */
 idtentry stack_segment         do_stack_segment        has_error_code=1
 
 #ifdef CONFIG_XEN
-idtentry xen_debug             do_debug                has_error_code=0
-idtentry xen_int3              do_int3                 has_error_code=0
-idtentry xen_stack_segment     do_stack_segment        has_error_code=1
+idtentry xendebug              do_debug                has_error_code=0
+idtentry xenint3               do_int3                 has_error_code=0
 #endif
 
 idtentry general_protection    do_general_protection   has_error_code=1
 END(error_exit)
 
 /* Runs on exception stack */
+/* XXX: broken on Xen PV */
 ENTRY(nmi)
        UNWIND_HINT_IRET_REGS
-       /*
-        * Fix up the exception frame if we're on Xen.
-        * PARAVIRT_ADJUST_EXCEPTION_FRAME is guaranteed to push at most
-        * one value to the stack on native, so it may clobber the rdx
-        * scratch slot, but it won't clobber any of the important
-        * slots past it.
-        *
-        * Xen is a different story, because the Xen frame itself overlaps
-        * the "NMI executing" variable.
-        */
-       PARAVIRT_ADJUST_EXCEPTION_FRAME
-
        /*
         * We allow breakpoints in NMIs. If a breakpoint occurs, then
         * the iretq it performs will take us out of NMI context.
 
        /*
         * Interrupts are off on entry.
         */
-       PARAVIRT_ADJUST_EXCEPTION_FRAME
        ASM_CLAC                        /* Do this early to minimize exposure */
        SWAPGS
 
 
 #define GET_CR2_INTO_RAX                               \
        call PARA_INDIRECT(pv_mmu_ops+PV_MMU_read_cr2)
 
-#define PARAVIRT_ADJUST_EXCEPTION_FRAME                                        \
-       PARA_SITE(PARA_PATCH(pv_irq_ops, PV_IRQ_adjust_exception_frame), \
-                 CLBR_NONE,                                            \
-                 call PARA_INDIRECT(pv_irq_ops+PV_IRQ_adjust_exception_frame))
-
 #define USERGS_SYSRET64                                                        \
        PARA_SITE(PARA_PATCH(pv_cpu_ops, PV_CPU_usergs_sysret64),       \
                  CLBR_NONE,                                            \
 
        void (*safe_halt)(void);
        void (*halt)(void);
 
-#ifdef CONFIG_X86_64
-       void (*adjust_exception_frame)(void);
-#endif
 } __no_randomize_layout;
 
 struct pv_mmu_ops {
 
 void __end_entry_SYSENTER_compat(void);
 void entry_SYSCALL_compat(void);
 void entry_INT80_compat(void);
+#if defined(CONFIG_X86_64) && defined(CONFIG_XEN_PV)
+void xen_entry_INT80_compat(void);
+#endif
 #endif
 
 void x86_configure_nx(void);
 
 asmlinkage void debug(void);
 asmlinkage void nmi(void);
 asmlinkage void int3(void);
-asmlinkage void xen_debug(void);
-asmlinkage void xen_int3(void);
-asmlinkage void xen_stack_segment(void);
 asmlinkage void overflow(void);
 asmlinkage void bounds(void);
 asmlinkage void invalid_op(void);
 #endif /* CONFIG_X86_MCE */
 asmlinkage void simd_coprocessor_error(void);
 
+#if defined(CONFIG_X86_64) && defined(CONFIG_XEN_PV)
+asmlinkage void xen_divide_error(void);
+asmlinkage void xen_xendebug(void);
+asmlinkage void xen_xenint3(void);
+asmlinkage void xen_nmi(void);
+asmlinkage void xen_overflow(void);
+asmlinkage void xen_bounds(void);
+asmlinkage void xen_invalid_op(void);
+asmlinkage void xen_device_not_available(void);
+asmlinkage void xen_double_fault(void);
+asmlinkage void xen_coprocessor_segment_overrun(void);
+asmlinkage void xen_invalid_TSS(void);
+asmlinkage void xen_segment_not_present(void);
+asmlinkage void xen_stack_segment(void);
+asmlinkage void xen_general_protection(void);
+asmlinkage void xen_page_fault(void);
+asmlinkage void xen_spurious_interrupt_bug(void);
+asmlinkage void xen_coprocessor_error(void);
+asmlinkage void xen_alignment_check(void);
+#ifdef CONFIG_X86_MCE
+asmlinkage void xen_machine_check(void);
+#endif /* CONFIG_X86_MCE */
+asmlinkage void xen_simd_coprocessor_error(void);
+#endif
+
 dotraplinkage void do_divide_error(struct pt_regs *, long);
 dotraplinkage void do_debug(struct pt_regs *, long);
 dotraplinkage void do_nmi(struct pt_regs *, long);
 
 int main(void)
 {
 #ifdef CONFIG_PARAVIRT
-       OFFSET(PV_IRQ_adjust_exception_frame, pv_irq_ops, adjust_exception_frame);
        OFFSET(PV_CPU_usergs_sysret64, pv_cpu_ops, usergs_sysret64);
        OFFSET(PV_CPU_swapgs, pv_cpu_ops, swapgs);
        BLANK();
 
        .irq_enable = __PV_IS_CALLEE_SAVE(native_irq_enable),
        .safe_halt = native_safe_halt,
        .halt = native_halt,
-#ifdef CONFIG_X86_64
-       .adjust_exception_frame = paravirt_nop,
-#endif
 };
 
 __visible struct pv_cpu_ops pv_cpu_ops = {
 
        preempt_enable();
 }
 
+#ifdef CONFIG_X86_64
+struct trap_array_entry {
+       void (*orig)(void);
+       void (*xen)(void);
+       bool ist_okay;
+};
+
+static struct trap_array_entry trap_array[] = {
+       { debug,                       xen_xendebug,                    true },
+       { int3,                        xen_xenint3,                     true },
+       { double_fault,                xen_double_fault,                true },
+#ifdef CONFIG_X86_MCE
+       { machine_check,               xen_machine_check,               true },
+#endif
+       { nmi,                         xen_nmi,                         true },
+       { overflow,                    xen_overflow,                    false },
+#ifdef CONFIG_IA32_EMULATION
+       { entry_INT80_compat,          xen_entry_INT80_compat,          false },
+#endif
+       { page_fault,                  xen_page_fault,                  false },
+       { divide_error,                xen_divide_error,                false },
+       { bounds,                      xen_bounds,                      false },
+       { invalid_op,                  xen_invalid_op,                  false },
+       { device_not_available,        xen_device_not_available,        false },
+       { coprocessor_segment_overrun, xen_coprocessor_segment_overrun, false },
+       { invalid_TSS,                 xen_invalid_TSS,                 false },
+       { segment_not_present,         xen_segment_not_present,         false },
+       { stack_segment,               xen_stack_segment,               false },
+       { general_protection,          xen_general_protection,          false },
+       { spurious_interrupt_bug,      xen_spurious_interrupt_bug,      false },
+       { coprocessor_error,           xen_coprocessor_error,           false },
+       { alignment_check,             xen_alignment_check,             false },
+       { simd_coprocessor_error,      xen_simd_coprocessor_error,      false },
+};
+
+static bool get_trap_addr(void **addr, unsigned int ist)
+{
+       unsigned int nr;
+       bool ist_okay = false;
+
+       /*
+        * Replace trap handler addresses by Xen specific ones.
+        * Check for known traps using IST and whitelist them.
+        * The debugger ones are the only ones we care about.
+        * Xen will handle faults like double_fault, * so we should never see
+        * them.  Warn if there's an unexpected IST-using fault handler.
+        */
+       for (nr = 0; nr < ARRAY_SIZE(trap_array); nr++) {
+               struct trap_array_entry *entry = trap_array + nr;
+
+               if (*addr == entry->orig) {
+                       *addr = entry->xen;
+                       ist_okay = entry->ist_okay;
+                       break;
+               }
+       }
+
+       if (WARN_ON(ist != 0 && !ist_okay))
+               return false;
+
+       return true;
+}
+#endif
+
 static int cvt_gate_to_trap(int vector, const gate_desc *val,
                            struct trap_info *info)
 {
 
        addr = gate_offset(val);
 #ifdef CONFIG_X86_64
-       /*
-        * Look for known traps using IST, and substitute them
-        * appropriately.  The debugger ones are the only ones we care
-        * about.  Xen will handle faults like double_fault,
-        * so we should never see them.  Warn if
-        * there's an unexpected IST-using fault handler.
-        */
-       if (addr == (unsigned long)debug)
-               addr = (unsigned long)xen_debug;
-       else if (addr == (unsigned long)int3)
-               addr = (unsigned long)xen_int3;
-       else if (addr == (unsigned long)stack_segment)
-               addr = (unsigned long)xen_stack_segment;
-       else if (addr == (unsigned long)double_fault) {
-               /* Don't need to handle these */
+       if (!get_trap_addr((void **)&addr, val->bits.ist))
                return 0;
-#ifdef CONFIG_X86_MCE
-       } else if (addr == (unsigned long)machine_check) {
-               /*
-                * when xen hypervisor inject vMCE to guest,
-                * use native mce handler to handle it
-                */
-               ;
-#endif
-       } else if (addr == (unsigned long)nmi)
-               /*
-                * Use the native version as well.
-                */
-               ;
-       else {
-               /* Some other trap using IST? */
-               if (WARN_ON(val->bits.ist != 0))
-                       return 0;
-       }
 #endif /* CONFIG_X86_64 */
        info->address = addr;
 
 
 
        .safe_halt = xen_safe_halt,
        .halt = xen_halt,
-#ifdef CONFIG_X86_64
-       .adjust_exception_frame = xen_adjust_exception_frame,
-#endif
 };
 
 void __init xen_init_irq_ops(void)
 
 
 #include <linux/linkage.h>
 
-ENTRY(xen_adjust_exception_frame)
-       mov 8+0(%rsp), %rcx
-       mov 8+8(%rsp), %r11
-       ret $16
-ENDPROC(xen_adjust_exception_frame)
+.macro xen_pv_trap name
+ENTRY(xen_\name)
+       pop %rcx
+       pop %r11
+       jmp  \name
+END(xen_\name)
+.endm
+
+xen_pv_trap divide_error
+xen_pv_trap debug
+xen_pv_trap xendebug
+xen_pv_trap int3
+xen_pv_trap xenint3
+xen_pv_trap nmi
+xen_pv_trap overflow
+xen_pv_trap bounds
+xen_pv_trap invalid_op
+xen_pv_trap device_not_available
+xen_pv_trap double_fault
+xen_pv_trap coprocessor_segment_overrun
+xen_pv_trap invalid_TSS
+xen_pv_trap segment_not_present
+xen_pv_trap stack_segment
+xen_pv_trap general_protection
+xen_pv_trap page_fault
+xen_pv_trap spurious_interrupt_bug
+xen_pv_trap coprocessor_error
+xen_pv_trap alignment_check
+#ifdef CONFIG_X86_MCE
+xen_pv_trap machine_check
+#endif /* CONFIG_X86_MCE */
+xen_pv_trap simd_coprocessor_error
+#ifdef CONFIG_IA32_EMULATION
+xen_pv_trap entry_INT80_compat
+#endif
+xen_pv_trap hypervisor_callback
 
 hypercall_iret = hypercall_page + __HYPERVISOR_iret * 32
 /*
 
 __visible void xen_iret(void);
 __visible void xen_sysret32(void);
 __visible void xen_sysret64(void);
-__visible void xen_adjust_exception_frame(void);
 
 extern int xen_panic_handler_init(void);