jmp     restore_all_switch_stack
 SYM_CODE_END(handle_exception)
 
-SYM_CODE_START(double_fault)
+SYM_CODE_START(asm_exc_double_fault)
 1:
        /*
         * This is a task gate handler, not an interrupt gate handler.
 1:
        hlt
        jmp 1b
-SYM_CODE_END(double_fault)
+SYM_CODE_END(asm_exc_double_fault)
 
 /*
  * NMI is doubly nasty.  It can happen on the first instruction of
 
        call    paranoid_entry
        UNWIND_HINT_REGS
 
-       /* Read CR2 early */
-       GET_CR2_INTO(%r12);
-
-       TRACE_IRQS_OFF
-
        movq    %rsp, %rdi              /* pt_regs pointer into first argument */
        movq    ORIG_RAX(%rsp), %rsi    /* get error code into 2nd argument*/
        movq    $-1, ORIG_RAX(%rsp)     /* no syscall to restart */
-       movq    %r12, %rdx              /* Move CR2 into 3rd argument */
        call    \cfunc
 
        jmp     paranoid_exit
        /*
         * This may fault.  Non-paranoid faults on return to userspace are
         * handled by fixup_bad_iret.  These include #SS, #GP, and #NP.
-        * Double-faults due to espfix64 are handled in do_double_fault.
+        * Double-faults due to espfix64 are handled in exc_double_fault.
         * Other faults here are fatal.
         */
        iretq
 
 idtentry       X86_TRAP_PF             page_fault              do_page_fault                   has_error_code=1
 
-idtentry_df    X86_TRAP_DF             double_fault            do_double_fault
-
 #ifdef CONFIG_XEN_PV
 idtentry       512 /* dummy */         hypervisor_callback     xen_do_hypervisor_callback      has_error_code=0
 #endif
 
 DECLARE_IDTENTRY_DEBUG(X86_TRAP_DB,    exc_debug);
 DECLARE_IDTENTRY_XEN(X86_TRAP_DB,      debug);
 
+/* #DF */
+DECLARE_IDTENTRY_DF(X86_TRAP_DF,       exc_double_fault);
+
 #endif
 
 
 #define dotraplinkage __visible
 
-#ifdef CONFIG_X86_64
-asmlinkage void double_fault(void);
-#endif
 asmlinkage void page_fault(void);
 asmlinkage void async_page_fault(void);
 
 #if defined(CONFIG_X86_64) && defined(CONFIG_XEN_PV)
-asmlinkage void xen_double_fault(void);
 asmlinkage void xen_page_fault(void);
 #endif
 
-dotraplinkage void do_double_fault(struct pt_regs *regs, long error_code, unsigned long cr2);
 dotraplinkage void do_page_fault(struct pt_regs *regs, unsigned long error_code, unsigned long address);
 
 #ifdef CONFIG_X86_64
 
 #include <asm/desc.h>
 #include <asm/traps.h>
 
-extern void double_fault(void);
 #define ptr_ok(x) ((x) > PAGE_OFFSET && (x) < PAGE_OFFSET + MAXMEM)
 
 #define TSS(x) this_cpu_read(cpu_tss_rw.x86_tss.x)
  * Called by double_fault with CR0.TS and EFLAGS.NT cleared.  The CPU thinks
  * we're running the doublefault task.  Cannot return.
  */
-asmlinkage notrace void __noreturn doublefault_shim(void)
+asmlinkage noinstr void __noreturn doublefault_shim(void)
 {
        unsigned long cr2;
        struct pt_regs regs;
         * Fill in pt_regs.  A downside of doing this in C is that the unwinder
         * won't see it (no ENCODE_FRAME_POINTER), so a nested stack dump
         * won't successfully unwind to the source of the double fault.
-        * The main dump from do_double_fault() is fine, though, since it
+        * The main dump from exc_double_fault() is fine, though, since it
         * uses these regs directly.
         *
         * If anyone ever cares, this could be moved to asm.
        regs.cx         = TSS(cx);
        regs.bx         = TSS(bx);
 
-       do_double_fault(®s, 0, cr2);
+       exc_double_fault(®s, 0, cr2);
 
        /*
         * x86_32 does not save the original CR3 anywhere on a task switch.
         */
        panic("cannot return from double fault\n");
 }
-NOKPROBE_SYMBOL(doublefault_shim);
 
 DEFINE_PER_CPU_PAGE_ALIGNED(struct doublefault_stack, doublefault_stack) = {
        .tss = {
                .ldt            = 0,
        .io_bitmap_base = IO_BITMAP_OFFSET_INVALID,
 
-               .ip             = (unsigned long) double_fault,
+               .ip             = (unsigned long) asm_exc_double_fault,
                .flags          = X86_EFLAGS_FIXED,
                .es             = __USER_DS,
                .cs             = __KERNEL_CS,
 
 #ifdef CONFIG_X86_32
        TSKG(X86_TRAP_DF,               GDT_ENTRY_DOUBLEFAULT_TSS),
 #else
-       INTG(X86_TRAP_DF,               double_fault),
+       INTG(X86_TRAP_DF,               asm_exc_double_fault),
 #endif
        INTG(X86_TRAP_DB,               asm_exc_debug),
 
 static const __initconst struct idt_data ist_idts[] = {
        ISTG(X86_TRAP_DB,       asm_exc_debug,          IST_INDEX_DB),
        ISTG(X86_TRAP_NMI,      asm_exc_nmi,            IST_INDEX_NMI),
-       ISTG(X86_TRAP_DF,       double_fault,           IST_INDEX_DF),
+       ISTG(X86_TRAP_DF,       asm_exc_double_fault,   IST_INDEX_DF),
 #ifdef CONFIG_X86_MCE
        ISTG(X86_TRAP_MC,       asm_exc_machine_check,  IST_INDEX_MCE),
 #endif
 
  * from the TSS.  Returning is, in principle, okay, but changes to regs will
  * be lost.  If, for some reason, we need to return to a context with modified
  * regs, the shim code could be adjusted to synchronize the registers.
+ *
+ * The 32bit #DF shim provides CR2 already as an argument. On 64bit it needs
+ * to be read before doing anything else.
  */
-dotraplinkage void do_double_fault(struct pt_regs *regs, long error_code, unsigned long cr2)
+DEFINE_IDTENTRY_DF(exc_double_fault)
 {
        static const char str[] = "double fault";
        struct task_struct *tsk = current;
 
+#ifdef CONFIG_X86_64
+       unsigned long address = read_cr2();
+#endif
+
 #ifdef CONFIG_X86_ESPFIX64
        extern unsigned char native_irq_return_iret[];
 
 #endif
 
        nmi_enter();
+       instrumentation_begin();
        notify_die(DIE_TRAP, str, regs, error_code, X86_TRAP_DF, SIGSEGV);
 
        tsk->thread.error_code = error_code;
         * stack even if the actual trigger for the double fault was
         * something else.
         */
-       if ((unsigned long)task_stack_page(tsk) - 1 - cr2 < PAGE_SIZE)
-               handle_stack_overflow("kernel stack overflow (double-fault)", regs, cr2);
+       if ((unsigned long)task_stack_page(tsk) - 1 - address < PAGE_SIZE) {
+               handle_stack_overflow("kernel stack overflow (double-fault)",
+                                     regs, address);
+       }
 #endif
 
        pr_emerg("PANIC: double fault, error_code: 0x%lx\n", error_code);
        die("double fault", regs, error_code);
        panic("Machine halted.");
+       instrumentation_end();
 }
 
 DEFINE_IDTENTRY(exc_bounds)
 
 
 static struct trap_array_entry trap_array[] = {
        TRAP_ENTRY_REDIR(exc_debug, exc_xendebug,       true  ),
-       { double_fault,                xen_double_fault,                true },
+       TRAP_ENTRY(exc_double_fault,                    true  ),
 #ifdef CONFIG_X86_MCE
        TRAP_ENTRY(exc_machine_check,                   true  ),
 #endif
         * 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
+        * 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++) {
 
 xen_pv_trap asm_exc_bounds
 xen_pv_trap asm_exc_invalid_op
 xen_pv_trap asm_exc_device_not_available
-xen_pv_trap double_fault
+xen_pv_trap asm_exc_double_fault
 xen_pv_trap asm_exc_coproc_segment_overrun
 xen_pv_trap asm_exc_invalid_tss
 xen_pv_trap asm_exc_segment_not_present