]> git.proxmox.com Git - mirror_ubuntu-jammy-kernel.git/blobdiff - arch/x86/kernel/entry_64.S
performance counters: x86 support
[mirror_ubuntu-jammy-kernel.git] / arch / x86 / kernel / entry_64.S
index fad777b113662f15d9f9e401b15fb1a8ee4d2cc6..fc013cfde3071fe3672164dd8083829a5b9aa9eb 100644 (file)
 #define __AUDIT_ARCH_LE           0x40000000
 
        .code64
-/*
- * Some macro's to hide the most frequently occuring CFI annotations.
- */
-       .macro pushq_cfi reg
-       pushq \reg
-       CFI_ADJUST_CFA_OFFSET 8
-       .endm
-
-       .macro popq_cfi reg
-       popq \reg
-       CFI_ADJUST_CFA_OFFSET -8
-       .endm
-
-       .macro movq_cfi reg offset=0
-       movq %\reg, \offset(%rsp)
-       CFI_REL_OFFSET \reg, \offset
-       .endm
-
-       .macro movq_cfi_restore offset reg
-       movq \offset(%rsp), %\reg
-       CFI_RESTORE \reg
-       .endm
-
 #ifdef CONFIG_FUNCTION_TRACER
 #ifdef CONFIG_DYNAMIC_FTRACE
 ENTRY(mcount)
@@ -217,7 +194,7 @@ ENTRY(native_usergs_sysret64)
        pushq %rax /* rsp */
        CFI_ADJUST_CFA_OFFSET   8
        CFI_REL_OFFSET  rsp,0
-       pushq $(1<<9) /* eflags - interrupts on */
+       pushq $X86_EFLAGS_IF /* eflags - interrupts on */
        CFI_ADJUST_CFA_OFFSET   8
        /*CFI_REL_OFFSET        rflags,0*/
        pushq $__KERNEL_CS /* cs */
@@ -384,32 +361,35 @@ ENTRY(save_paranoid)
 END(save_paranoid)
 
 /*
- * A newly forked process directly context switches into this.
+ * A newly forked process directly context switches into this address.
+ *
+ * rdi: prev task we switched from
  */
-/* rdi:        prev */
 ENTRY(ret_from_fork)
        DEFAULT_FRAME
+
        push kernel_eflags(%rip)
        CFI_ADJUST_CFA_OFFSET 8
-       popf                            # reset kernel eflags
+       popf                                    # reset kernel eflags
        CFI_ADJUST_CFA_OFFSET -8
-       call schedule_tail
+
+       call schedule_tail                      # rdi: 'prev' task parameter
+
        GET_THREAD_INFO(%rcx)
-       testl $(_TIF_SYSCALL_TRACE|_TIF_SYSCALL_AUDIT),TI_flags(%rcx)
-       jnz rff_trace
-rff_action:
+
+       CFI_REMEMBER_STATE
        RESTORE_REST
-       testl $3,CS-ARGOFFSET(%rsp)     # from kernel_thread?
+
+       testl $3, CS-ARGOFFSET(%rsp)            # from kernel_thread?
        je   int_ret_from_sys_call
-       testl $_TIF_IA32,TI_flags(%rcx)
+
+       testl $_TIF_IA32, TI_flags(%rcx)        # 32-bit compat task needs IRET
        jnz  int_ret_from_sys_call
+
        RESTORE_TOP_OF_STACK %rdi, -ARGOFFSET
-       jmp ret_from_sys_call
-rff_trace:
-       movq %rsp,%rdi
-       call syscall_trace_leave
-       GET_THREAD_INFO(%rcx)
-       jmp rff_action
+       jmp ret_from_sys_call                   # go to the SYSRET fastpath
+
+       CFI_RESTORE_STATE
        CFI_ENDPROC
 END(ret_from_fork)
 
@@ -529,10 +509,13 @@ sysret_signal:
        jc sysret_audit
 #endif
        /* edx: work flags (arg3) */
-       leaq do_notify_resume(%rip),%rax
        leaq -ARGOFFSET(%rsp),%rdi # &pt_regs -> arg1
        xorl %esi,%esi # oldset -> arg2
-       call ptregscall_common
+       SAVE_REST
+       FIXUP_TOP_OF_STACK %r11
+       call do_notify_resume
+       RESTORE_TOP_OF_STACK %r11
+       RESTORE_REST
        movl $_TIF_WORK_MASK,%edi
        /* Use IRET because user could have changed frame. This
           works because ptregscall_common has called FIXUP_TOP_OF_STACK. */
@@ -942,76 +925,75 @@ END(common_interrupt)
 /*
  * APIC interrupts.
  */
-       .p2align 5
-
-       .macro apicinterrupt num,func
+.macro apicinterrupt num sym do_sym
+ENTRY(\sym)
        INTR_FRAME
        pushq $~(\num)
        CFI_ADJUST_CFA_OFFSET 8
-       interrupt \func
+       interrupt \do_sym
        jmp ret_from_intr
        CFI_ENDPROC
-       .endm
+END(\sym)
+.endm
 
-ENTRY(thermal_interrupt)
-       apicinterrupt THERMAL_APIC_VECTOR,smp_thermal_interrupt
-END(thermal_interrupt)
+#ifdef CONFIG_SMP
+apicinterrupt IRQ_MOVE_CLEANUP_VECTOR \
+       irq_move_cleanup_interrupt smp_irq_move_cleanup_interrupt
+#endif
 
-ENTRY(threshold_interrupt)
-       apicinterrupt THRESHOLD_APIC_VECTOR,mce_threshold_interrupt
-END(threshold_interrupt)
+apicinterrupt UV_BAU_MESSAGE \
+       uv_bau_message_intr1 uv_bau_message_interrupt
+apicinterrupt LOCAL_TIMER_VECTOR \
+       apic_timer_interrupt smp_apic_timer_interrupt
 
 #ifdef CONFIG_SMP
-ENTRY(reschedule_interrupt)
-       apicinterrupt RESCHEDULE_VECTOR,smp_reschedule_interrupt
-END(reschedule_interrupt)
-
-       .macro INVALIDATE_ENTRY num
-ENTRY(invalidate_interrupt\num)
-       apicinterrupt INVALIDATE_TLB_VECTOR_START+\num,smp_invalidate_interrupt
-END(invalidate_interrupt\num)
-       .endm
-
-       INVALIDATE_ENTRY 0
-       INVALIDATE_ENTRY 1
-       INVALIDATE_ENTRY 2
-       INVALIDATE_ENTRY 3
-       INVALIDATE_ENTRY 4
-       INVALIDATE_ENTRY 5
-       INVALIDATE_ENTRY 6
-       INVALIDATE_ENTRY 7
-
-ENTRY(call_function_interrupt)
-       apicinterrupt CALL_FUNCTION_VECTOR,smp_call_function_interrupt
-END(call_function_interrupt)
-ENTRY(call_function_single_interrupt)
-       apicinterrupt CALL_FUNCTION_SINGLE_VECTOR,smp_call_function_single_interrupt
-END(call_function_single_interrupt)
-ENTRY(irq_move_cleanup_interrupt)
-       apicinterrupt IRQ_MOVE_CLEANUP_VECTOR,smp_irq_move_cleanup_interrupt
-END(irq_move_cleanup_interrupt)
+apicinterrupt INVALIDATE_TLB_VECTOR_START+0 \
+       invalidate_interrupt0 smp_invalidate_interrupt
+apicinterrupt INVALIDATE_TLB_VECTOR_START+1 \
+       invalidate_interrupt1 smp_invalidate_interrupt
+apicinterrupt INVALIDATE_TLB_VECTOR_START+2 \
+       invalidate_interrupt2 smp_invalidate_interrupt
+apicinterrupt INVALIDATE_TLB_VECTOR_START+3 \
+       invalidate_interrupt3 smp_invalidate_interrupt
+apicinterrupt INVALIDATE_TLB_VECTOR_START+4 \
+       invalidate_interrupt4 smp_invalidate_interrupt
+apicinterrupt INVALIDATE_TLB_VECTOR_START+5 \
+       invalidate_interrupt5 smp_invalidate_interrupt
+apicinterrupt INVALIDATE_TLB_VECTOR_START+6 \
+       invalidate_interrupt6 smp_invalidate_interrupt
+apicinterrupt INVALIDATE_TLB_VECTOR_START+7 \
+       invalidate_interrupt7 smp_invalidate_interrupt
 #endif
 
-ENTRY(apic_timer_interrupt)
-       apicinterrupt LOCAL_TIMER_VECTOR,smp_apic_timer_interrupt
-END(apic_timer_interrupt)
+apicinterrupt THRESHOLD_APIC_VECTOR \
+       threshold_interrupt mce_threshold_interrupt
+apicinterrupt THERMAL_APIC_VECTOR \
+       thermal_interrupt smp_thermal_interrupt
 
-ENTRY(uv_bau_message_intr1)
-       apicinterrupt 220,uv_bau_message_interrupt
-END(uv_bau_message_intr1)
+#ifdef CONFIG_SMP
+apicinterrupt CALL_FUNCTION_SINGLE_VECTOR \
+       call_function_single_interrupt smp_call_function_single_interrupt
+apicinterrupt CALL_FUNCTION_VECTOR \
+       call_function_interrupt smp_call_function_interrupt
+apicinterrupt RESCHEDULE_VECTOR \
+       reschedule_interrupt smp_reschedule_interrupt
+#endif
 
-ENTRY(error_interrupt)
-       apicinterrupt ERROR_APIC_VECTOR,smp_error_interrupt
-END(error_interrupt)
+apicinterrupt ERROR_APIC_VECTOR \
+       error_interrupt smp_error_interrupt
+apicinterrupt SPURIOUS_APIC_VECTOR \
+       spurious_interrupt smp_spurious_interrupt
 
-ENTRY(spurious_interrupt)
-       apicinterrupt SPURIOUS_APIC_VECTOR,smp_spurious_interrupt
-END(spurious_interrupt)
+#ifdef CONFIG_PERF_COUNTERS
+apicinterrupt LOCAL_PERF_VECTOR \
+       perf_counter_interrupt smp_perf_counter_interrupt
+#endif
 
 /*
  * Exception entry points.
  */
-       .macro zeroentry sym
+.macro zeroentry sym do_sym
+ENTRY(\sym)
        INTR_FRAME
        PARAVIRT_ADJUST_EXCEPTION_FRAME
        pushq_cfi $-1           /* ORIG_RAX: no syscall to restart */
@@ -1021,12 +1003,51 @@ END(spurious_interrupt)
        DEFAULT_FRAME 0
        movq %rsp,%rdi          /* pt_regs pointer */
        xorl %esi,%esi          /* no error code */
-       call \sym
+       call \do_sym
        jmp error_exit          /* %ebx: no swapgs flag */
        CFI_ENDPROC
-       .endm
+END(\sym)
+.endm
+
+.macro paranoidzeroentry sym do_sym
+ENTRY(\sym)
+       INTR_FRAME
+       PARAVIRT_ADJUST_EXCEPTION_FRAME
+       pushq $-1               /* ORIG_RAX: no syscall to restart */
+       CFI_ADJUST_CFA_OFFSET 8
+       subq $15*8, %rsp
+       call save_paranoid
+       TRACE_IRQS_OFF
+       movq %rsp,%rdi          /* pt_regs pointer */
+       xorl %esi,%esi          /* no error code */
+       call \do_sym
+       jmp paranoid_exit       /* %ebx: no swapgs flag */
+       CFI_ENDPROC
+END(\sym)
+.endm
 
-       .macro errorentry sym
+.macro paranoidzeroentry_ist sym do_sym ist
+ENTRY(\sym)
+       INTR_FRAME
+       PARAVIRT_ADJUST_EXCEPTION_FRAME
+       pushq $-1               /* ORIG_RAX: no syscall to restart */
+       CFI_ADJUST_CFA_OFFSET 8
+       subq $15*8, %rsp
+       call save_paranoid
+       TRACE_IRQS_OFF
+       movq %rsp,%rdi          /* pt_regs pointer */
+       xorl %esi,%esi          /* no error code */
+       movq %gs:pda_data_offset, %rbp
+       subq $EXCEPTION_STKSZ, per_cpu__init_tss + TSS_ist + (\ist - 1) * 8(%rbp)
+       call \do_sym
+       addq $EXCEPTION_STKSZ, per_cpu__init_tss + TSS_ist + (\ist - 1) * 8(%rbp)
+       jmp paranoid_exit       /* %ebx: no swapgs flag */
+       CFI_ENDPROC
+END(\sym)
+.endm
+
+.macro errorentry sym do_sym
+ENTRY(\sym)
        XCPT_FRAME
        PARAVIRT_ADJUST_EXCEPTION_FRAME
        subq $15*8,%rsp
@@ -1036,194 +1057,75 @@ END(spurious_interrupt)
        movq %rsp,%rdi                  /* pt_regs pointer */
        movq ORIG_RAX(%rsp),%rsi        /* get error code */
        movq $-1,ORIG_RAX(%rsp)         /* no syscall to restart */
-       call \sym
+       call \do_sym
        jmp error_exit                  /* %ebx: no swapgs flag */
        CFI_ENDPROC
-       .endm
+END(\sym)
+.endm
 
        /* error code is on the stack already */
-       .macro paranoidentry sym ist=0
-       subq $15*8, %rsp
+.macro paranoiderrorentry sym do_sym
+ENTRY(\sym)
+       XCPT_FRAME
+       PARAVIRT_ADJUST_EXCEPTION_FRAME
+       subq $15*8,%rsp
        CFI_ADJUST_CFA_OFFSET 15*8
        call save_paranoid
        DEFAULT_FRAME 0
-       .if \ist
-       movq    %gs:pda_data_offset, %rbp
-       .endif
-       TRACE_IRQS_OFF
-       movq %rsp,%rdi
-       movq ORIG_RAX(%rsp),%rsi
-       movq $-1,ORIG_RAX(%rsp)
-       .if \ist
-       subq    $EXCEPTION_STKSZ, per_cpu__init_tss + TSS_ist + (\ist - 1) * 8(%rbp)
-       .endif
-       call \sym
-       .if \ist
-       addq    $EXCEPTION_STKSZ, per_cpu__init_tss + TSS_ist + (\ist - 1) * 8(%rbp)
-       .endif
-       DISABLE_INTERRUPTS(CLBR_NONE)
-       TRACE_IRQS_OFF
-       .endm
-
-       /*
-        * "Paranoid" exit path from exception stack.
-        * Paranoid because this is used by NMIs and cannot take
-        * any kernel state for granted.
-        * We don't do kernel preemption checks here, because only
-        * NMI should be common and it does not enable IRQs and
-        * cannot get reschedule ticks.
-        *
-        * "trace" is 0 for the NMI handler only, because irq-tracing
-        * is fundamentally NMI-unsafe. (we cannot change the soft and
-        * hard flags at once, atomically)
-        */
-
-       /* ebx: no swapgs flag */
-KPROBE_ENTRY(paranoid_exit)
-       INTR_FRAME
-       testl %ebx,%ebx                         /* swapgs needed? */
-       jnz paranoid_restore
-       testl $3,CS(%rsp)
-       jnz   paranoid_userspace
-paranoid_swapgs:
-       TRACE_IRQS_IRETQ 0
-       SWAPGS_UNSAFE_STACK
-paranoid_restore:
-       RESTORE_ALL 8
-       jmp irq_return
-paranoid_userspace:
-       GET_THREAD_INFO(%rcx)
-       movl TI_flags(%rcx),%ebx
-       andl $_TIF_WORK_MASK,%ebx
-       jz paranoid_swapgs
-       movq %rsp,%rdi                  /* &pt_regs */
-       call sync_regs
-       movq %rax,%rsp                  /* switch stack for scheduling */
-       testl $_TIF_NEED_RESCHED,%ebx
-       jnz paranoid_schedule
-       movl %ebx,%edx                  /* arg3: thread flags */
-       TRACE_IRQS_ON
-       ENABLE_INTERRUPTS(CLBR_NONE)
-       xorl %esi,%esi                  /* arg2: oldset */
-       movq %rsp,%rdi                  /* arg1: &pt_regs */
-       call do_notify_resume
-       DISABLE_INTERRUPTS(CLBR_NONE)
-       TRACE_IRQS_OFF
-       jmp paranoid_userspace
-paranoid_schedule:
-       TRACE_IRQS_ON
-       ENABLE_INTERRUPTS(CLBR_ANY)
-       call schedule
-       DISABLE_INTERRUPTS(CLBR_ANY)
-       TRACE_IRQS_OFF
-       jmp paranoid_userspace
-       CFI_ENDPROC
-END(paranoid_exit)
-
-/*
- * Exception entry point. This expects an error code/orig_rax on the stack.
- * returns in "no swapgs flag" in %ebx.
- */
-KPROBE_ENTRY(error_entry)
-       XCPT_FRAME
-       CFI_ADJUST_CFA_OFFSET 15*8
-       /* oldrax contains error code */
-       cld
-       movq_cfi rdi, RDI+8
-       movq_cfi rsi, RSI+8
-       movq_cfi rdx, RDX+8
-       movq_cfi rcx, RCX+8
-       movq_cfi rax, RAX+8
-       movq_cfi  r8,  R8+8
-       movq_cfi  r9,  R9+8
-       movq_cfi r10, R10+8
-       movq_cfi r11, R11+8
-       movq_cfi rbx, RBX+8
-       movq_cfi rbp, RBP+8
-       movq_cfi r12, R12+8
-       movq_cfi r13, R13+8
-       movq_cfi r14, R14+8
-       movq_cfi r15, R15+8
-       xorl %ebx,%ebx
-       testl $3,CS+8(%rsp)
-       je error_kernelspace
-error_swapgs:
-       SWAPGS
-error_sti:
        TRACE_IRQS_OFF
-       ret
-       CFI_ENDPROC
-
-/*
- * There are two places in the kernel that can potentially fault with
- * usergs. Handle them here. The exception handlers after iret run with
- * kernel gs again, so don't set the user space flag. B stepping K8s
- * sometimes report an truncated RIP for IRET exceptions returning to
- * compat mode. Check for these here too.
- */
-error_kernelspace:
-       incl %ebx
-       leaq irq_return(%rip),%rcx
-       cmpq %rcx,RIP+8(%rsp)
-       je error_swapgs
-       movl %ecx,%ecx  /* zero extend */
-       cmpq %rcx,RIP+8(%rsp)
-       je error_swapgs
-       cmpq $gs_change,RIP+8(%rsp)
-        je error_swapgs
-       jmp error_sti
-KPROBE_END(error_entry)
-
-
-/* ebx:        no swapgs flag (1: don't need swapgs, 0: need it) */
-KPROBE_ENTRY(error_exit)
-       DEFAULT_FRAME
-       movl %ebx,%eax
-       RESTORE_REST
-       DISABLE_INTERRUPTS(CLBR_NONE)
-       TRACE_IRQS_OFF
-       GET_THREAD_INFO(%rcx)
-       testl %eax,%eax
-       jne retint_kernel
-       LOCKDEP_SYS_EXIT_IRQ
-       movl TI_flags(%rcx),%edx
-       movl $_TIF_WORK_MASK,%edi
-       andl %edi,%edx
-       jnz retint_careful
-       jmp retint_swapgs
+       movq %rsp,%rdi                  /* pt_regs pointer */
+       movq ORIG_RAX(%rsp),%rsi        /* get error code */
+       movq $-1,ORIG_RAX(%rsp)         /* no syscall to restart */
+       call \do_sym
+       jmp paranoid_exit               /* %ebx: no swapgs flag */
        CFI_ENDPROC
-KPROBE_END(error_exit)
+END(\sym)
+.endm
 
-       /* Reload gs selector with exception handling */
-       /* edi:  new selector */
+zeroentry divide_error do_divide_error
+zeroentry overflow do_overflow
+zeroentry bounds do_bounds
+zeroentry invalid_op do_invalid_op
+zeroentry device_not_available do_device_not_available
+paranoiderrorentry double_fault do_double_fault
+zeroentry coprocessor_segment_overrun do_coprocessor_segment_overrun
+errorentry invalid_TSS do_invalid_TSS
+errorentry segment_not_present do_segment_not_present
+zeroentry spurious_interrupt_bug do_spurious_interrupt_bug
+zeroentry coprocessor_error do_coprocessor_error
+errorentry alignment_check do_alignment_check
+zeroentry simd_coprocessor_error do_simd_coprocessor_error
+
+       /* Reload gs selector with exception handling */
+       /* edi:  new selector */
 ENTRY(native_load_gs_index)
        CFI_STARTPROC
        pushf
        CFI_ADJUST_CFA_OFFSET 8
        DISABLE_INTERRUPTS(CLBR_ANY | ~(CLBR_RDI))
-        SWAPGS
+       SWAPGS
 gs_change:
-        movl %edi,%gs
+       movl %edi,%gs
 2:     mfence          /* workaround */
        SWAPGS
-        popf
+       popf
        CFI_ADJUST_CFA_OFFSET -8
-        ret
+       ret
        CFI_ENDPROC
-ENDPROC(native_load_gs_index)
+END(native_load_gs_index)
 
-        .section __ex_table,"a"
-        .align 8
-        .quad gs_change,bad_gs
-        .previous
-        .section .fixup,"ax"
+       .section __ex_table,"a"
+       .align 8
+       .quad gs_change,bad_gs
+       .previous
+       .section .fixup,"ax"
        /* running with kernelgs */
 bad_gs:
        SWAPGS                  /* switch back to user gs */
        xorl %eax,%eax
-        movl %eax,%gs
-        jmp  2b
-        .previous
+       movl %eax,%gs
+       jmp  2b
+       .previous
 
 /*
  * Create a kernel thread.
@@ -1258,15 +1160,15 @@ ENTRY(kernel_thread)
         * so internally to the x86_64 port you can rely on kernel_thread()
         * not to reschedule the child before returning, this avoids the need
         * of hacks for example to fork off the per-CPU idle tasks.
-         * [Hopefully no generic code relies on the reschedule -AK]
+        * [Hopefully no generic code relies on the reschedule -AK]
         */
        RESTORE_ALL
        UNFAKE_STACK_FRAME
        ret
        CFI_ENDPROC
-ENDPROC(kernel_thread)
+END(kernel_thread)
 
-child_rip:
+ENTRY(child_rip)
        pushq $0                # fake return address
        CFI_STARTPROC
        /*
@@ -1279,8 +1181,9 @@ child_rip:
        # exit
        mov %eax, %edi
        call do_exit
+       ud2                     # padding for call trace
        CFI_ENDPROC
-ENDPROC(child_rip)
+END(child_rip)
 
 /*
  * execve(). This function needs to use IRET, not SYSRET, to set up all state properly.
@@ -1311,172 +1214,7 @@ ENTRY(kernel_execve)
        UNFAKE_STACK_FRAME
        ret
        CFI_ENDPROC
-ENDPROC(kernel_execve)
-
-KPROBE_ENTRY(page_fault)
-       errorentry do_page_fault
-KPROBE_END(page_fault)
-
-ENTRY(coprocessor_error)
-       zeroentry do_coprocessor_error
-END(coprocessor_error)
-
-ENTRY(simd_coprocessor_error)
-       zeroentry do_simd_coprocessor_error
-END(simd_coprocessor_error)
-
-ENTRY(device_not_available)
-       zeroentry do_device_not_available
-END(device_not_available)
-
-       /* runs on exception stack */
-KPROBE_ENTRY(debug)
-       INTR_FRAME
-       PARAVIRT_ADJUST_EXCEPTION_FRAME
-       pushq $0
-       CFI_ADJUST_CFA_OFFSET 8
-       paranoidentry do_debug, DEBUG_STACK
-       jmp paranoid_exit
-       CFI_ENDPROC
-KPROBE_END(debug)
-
-       /* runs on exception stack */
-KPROBE_ENTRY(nmi)
-       INTR_FRAME
-       PARAVIRT_ADJUST_EXCEPTION_FRAME
-       pushq_cfi $-1
-       subq $15*8, %rsp
-       CFI_ADJUST_CFA_OFFSET 15*8
-       call save_paranoid
-       DEFAULT_FRAME 0
-       /* paranoidentry do_nmi, 0; without TRACE_IRQS_OFF */
-       movq %rsp,%rdi
-       movq ORIG_RAX(%rsp),%rsi
-       movq $-1,ORIG_RAX(%rsp)
-       call do_nmi
-       DISABLE_INTERRUPTS(CLBR_NONE)
-#ifdef CONFIG_TRACE_IRQFLAGS
-       /* paranoidexit; without TRACE_IRQS_OFF */
-       /* ebx: no swapgs flag */
-nmi_exit:
-       testl %ebx,%ebx                         /* swapgs needed? */
-       jnz nmi_restore
-       testl $3,CS(%rsp)
-       jnz nmi_userspace
-nmi_swapgs:
-       SWAPGS_UNSAFE_STACK
-nmi_restore:
-       RESTORE_ALL 8
-       jmp irq_return
-nmi_userspace:
-       GET_THREAD_INFO(%rcx)
-       movl TI_flags(%rcx),%ebx
-       andl $_TIF_WORK_MASK,%ebx
-       jz nmi_swapgs
-       movq %rsp,%rdi                  /* &pt_regs */
-       call sync_regs
-       movq %rax,%rsp                  /* switch stack for scheduling */
-       testl $_TIF_NEED_RESCHED,%ebx
-       jnz nmi_schedule
-       movl %ebx,%edx                  /* arg3: thread flags */
-       ENABLE_INTERRUPTS(CLBR_NONE)
-       xorl %esi,%esi                  /* arg2: oldset */
-       movq %rsp,%rdi                  /* arg1: &pt_regs */
-       call do_notify_resume
-       DISABLE_INTERRUPTS(CLBR_NONE)
-       jmp nmi_userspace
-nmi_schedule:
-       ENABLE_INTERRUPTS(CLBR_ANY)
-       call schedule
-       DISABLE_INTERRUPTS(CLBR_ANY)
-       jmp nmi_userspace
-       CFI_ENDPROC
-#else
-       jmp paranoid_exit
-       CFI_ENDPROC
-#endif
-KPROBE_END(nmi)
-
-KPROBE_ENTRY(int3)
-       INTR_FRAME
-       PARAVIRT_ADJUST_EXCEPTION_FRAME
-       pushq $0
-       CFI_ADJUST_CFA_OFFSET 8
-       paranoidentry do_int3, DEBUG_STACK
-       jmp paranoid_exit
-       CFI_ENDPROC
-KPROBE_END(int3)
-
-ENTRY(overflow)
-       zeroentry do_overflow
-END(overflow)
-
-ENTRY(bounds)
-       zeroentry do_bounds
-END(bounds)
-
-ENTRY(invalid_op)
-       zeroentry do_invalid_op
-END(invalid_op)
-
-ENTRY(coprocessor_segment_overrun)
-       zeroentry do_coprocessor_segment_overrun
-END(coprocessor_segment_overrun)
-
-       /* runs on exception stack */
-ENTRY(double_fault)
-       XCPT_FRAME
-       PARAVIRT_ADJUST_EXCEPTION_FRAME
-       paranoidentry do_double_fault
-       jmp paranoid_exit
-       CFI_ENDPROC
-END(double_fault)
-
-ENTRY(invalid_TSS)
-       errorentry do_invalid_TSS
-END(invalid_TSS)
-
-ENTRY(segment_not_present)
-       errorentry do_segment_not_present
-END(segment_not_present)
-
-       /* runs on exception stack */
-ENTRY(stack_segment)
-       XCPT_FRAME
-       PARAVIRT_ADJUST_EXCEPTION_FRAME
-       paranoidentry do_stack_segment
-       jmp paranoid_exit
-       CFI_ENDPROC
-END(stack_segment)
-
-KPROBE_ENTRY(general_protection)
-       errorentry do_general_protection
-KPROBE_END(general_protection)
-
-ENTRY(alignment_check)
-       errorentry do_alignment_check
-END(alignment_check)
-
-ENTRY(divide_error)
-       zeroentry do_divide_error
-END(divide_error)
-
-ENTRY(spurious_interrupt_bug)
-       zeroentry do_spurious_interrupt_bug
-END(spurious_interrupt_bug)
-
-#ifdef CONFIG_X86_MCE
-       /* runs on exception stack */
-ENTRY(machine_check)
-       INTR_FRAME
-       PARAVIRT_ADJUST_EXCEPTION_FRAME
-       pushq $0
-       CFI_ADJUST_CFA_OFFSET 8
-       paranoidentry do_machine_check
-       jmp paranoid_exit
-       CFI_ENDPROC
-END(machine_check)
-#endif
+END(kernel_execve)
 
 /* Call softirq on interrupt stack. Interrupts are off. */
 ENTRY(call_softirq)
@@ -1496,37 +1234,30 @@ ENTRY(call_softirq)
        decl %gs:pda_irqcount
        ret
        CFI_ENDPROC
-ENDPROC(call_softirq)
-
-KPROBE_ENTRY(ignore_sysret)
-       CFI_STARTPROC
-       mov $-ENOSYS,%eax
-       sysret
-       CFI_ENDPROC
-ENDPROC(ignore_sysret)
+END(call_softirq)
 
 #ifdef CONFIG_XEN
-ENTRY(xen_hypervisor_callback)
-       zeroentry xen_do_hypervisor_callback
-END(xen_hypervisor_callback)
+zeroentry xen_hypervisor_callback xen_do_hypervisor_callback
 
 /*
-# A note on the "critical region" in our callback handler.
-# We want to avoid stacking callback handlers due to events occurring
-# during handling of the last event. To do this, we keep events disabled
-# until we've done all processing. HOWEVER, we must enable events before
-# popping the stack frame (can't be done atomically) and so it would still
-# be possible to get enough handler activations to overflow the stack.
-# Although unlikely, bugs of that kind are hard to track down, so we'd
-# like to avoid the possibility.
-# So, on entry to the handler we detect whether we interrupted an
-# existing activation in its critical region -- if so, we pop the current
-# activation and restart the handler using the previous one.
-*/
+ * A note on the "critical region" in our callback handler.
+ * We want to avoid stacking callback handlers due to events occurring
+ * during handling of the last event. To do this, we keep events disabled
+ * until we've done all processing. HOWEVER, we must enable events before
+ * popping the stack frame (can't be done atomically) and so it would still
+ * be possible to get enough handler activations to overflow the stack.
+ * Although unlikely, bugs of that kind are hard to track down, so we'd
+ * like to avoid the possibility.
+ * So, on entry to the handler we detect whether we interrupted an
+ * existing activation in its critical region -- if so, we pop the current
+ * activation and restart the handler using the previous one.
+ */
 ENTRY(xen_do_hypervisor_callback)   # do_hypervisor_callback(struct *pt_regs)
        CFI_STARTPROC
-/* Since we don't modify %rdi, evtchn_do_upall(struct *pt_regs) will
-   see the correct pointer to the pt_regs */
+/*
+ * Since we don't modify %rdi, evtchn_do_upall(struct *pt_regs) will
+ * see the correct pointer to the pt_regs
+ */
        movq %rdi, %rsp            # we don't return, adjust the stack frame
        CFI_ENDPROC
        DEFAULT_FRAME
@@ -1544,18 +1275,18 @@ ENTRY(xen_do_hypervisor_callback)   # do_hypervisor_callback(struct *pt_regs)
 END(do_hypervisor_callback)
 
 /*
-# Hypervisor uses this for application faults while it executes.
-# We get here for two reasons:
-#  1. Fault while reloading DS, ES, FS or GS
-#  2. Fault while executing IRET
-# Category 1 we do not need to fix up as Xen has already reloaded all segment
-# registers that could be reloaded and zeroed the others.
-# Category 2 we fix up by killing the current process. We cannot use the
-# normal Linux return path in this case because if we use the IRET hypercall
-# to pop the stack frame we end up in an infinite loop of failsafe callbacks.
-# We distinguish between categories by comparing each saved segment register
-# with its current contents: any discrepancy means we in category 1.
-*/
+ * Hypervisor uses this for application faults while it executes.
+ * We get here for two reasons:
+ *  1. Fault while reloading DS, ES, FS or GS
+ *  2. Fault while executing IRET
+ * Category 1 we do not need to fix up as Xen has already reloaded all segment
+ * registers that could be reloaded and zeroed the others.
+ * Category 2 we fix up by killing the current process. We cannot use the
+ * normal Linux return path in this case because if we use the IRET hypercall
+ * to pop the stack frame we end up in an infinite loop of failsafe callbacks.
+ * We distinguish between categories by comparing each saved segment register
+ * with its current contents: any discrepancy means we in category 1.
+ */
 ENTRY(xen_failsafe_callback)
        INTR_FRAME 1 (6*8)
        /*CFI_REL_OFFSET gs,GS*/
@@ -1603,3 +1334,216 @@ ENTRY(xen_failsafe_callback)
 END(xen_failsafe_callback)
 
 #endif /* CONFIG_XEN */
+
+/*
+ * Some functions should be protected against kprobes
+ */
+       .pushsection .kprobes.text, "ax"
+
+paranoidzeroentry_ist debug do_debug DEBUG_STACK
+paranoidzeroentry_ist int3 do_int3 DEBUG_STACK
+paranoiderrorentry stack_segment do_stack_segment
+errorentry general_protection do_general_protection
+errorentry page_fault do_page_fault
+#ifdef CONFIG_X86_MCE
+paranoidzeroentry machine_check do_machine_check
+#endif
+
+       /*
+        * "Paranoid" exit path from exception stack.
+        * Paranoid because this is used by NMIs and cannot take
+        * any kernel state for granted.
+        * We don't do kernel preemption checks here, because only
+        * NMI should be common and it does not enable IRQs and
+        * cannot get reschedule ticks.
+        *
+        * "trace" is 0 for the NMI handler only, because irq-tracing
+        * is fundamentally NMI-unsafe. (we cannot change the soft and
+        * hard flags at once, atomically)
+        */
+
+       /* ebx: no swapgs flag */
+ENTRY(paranoid_exit)
+       INTR_FRAME
+       DISABLE_INTERRUPTS(CLBR_NONE)
+       TRACE_IRQS_OFF
+       testl %ebx,%ebx                         /* swapgs needed? */
+       jnz paranoid_restore
+       testl $3,CS(%rsp)
+       jnz   paranoid_userspace
+paranoid_swapgs:
+       TRACE_IRQS_IRETQ 0
+       SWAPGS_UNSAFE_STACK
+paranoid_restore:
+       RESTORE_ALL 8
+       jmp irq_return
+paranoid_userspace:
+       GET_THREAD_INFO(%rcx)
+       movl TI_flags(%rcx),%ebx
+       andl $_TIF_WORK_MASK,%ebx
+       jz paranoid_swapgs
+       movq %rsp,%rdi                  /* &pt_regs */
+       call sync_regs
+       movq %rax,%rsp                  /* switch stack for scheduling */
+       testl $_TIF_NEED_RESCHED,%ebx
+       jnz paranoid_schedule
+       movl %ebx,%edx                  /* arg3: thread flags */
+       TRACE_IRQS_ON
+       ENABLE_INTERRUPTS(CLBR_NONE)
+       xorl %esi,%esi                  /* arg2: oldset */
+       movq %rsp,%rdi                  /* arg1: &pt_regs */
+       call do_notify_resume
+       DISABLE_INTERRUPTS(CLBR_NONE)
+       TRACE_IRQS_OFF
+       jmp paranoid_userspace
+paranoid_schedule:
+       TRACE_IRQS_ON
+       ENABLE_INTERRUPTS(CLBR_ANY)
+       call schedule
+       DISABLE_INTERRUPTS(CLBR_ANY)
+       TRACE_IRQS_OFF
+       jmp paranoid_userspace
+       CFI_ENDPROC
+END(paranoid_exit)
+
+/*
+ * Exception entry point. This expects an error code/orig_rax on the stack.
+ * returns in "no swapgs flag" in %ebx.
+ */
+ENTRY(error_entry)
+       XCPT_FRAME
+       CFI_ADJUST_CFA_OFFSET 15*8
+       /* oldrax contains error code */
+       cld
+       movq_cfi rdi, RDI+8
+       movq_cfi rsi, RSI+8
+       movq_cfi rdx, RDX+8
+       movq_cfi rcx, RCX+8
+       movq_cfi rax, RAX+8
+       movq_cfi  r8,  R8+8
+       movq_cfi  r9,  R9+8
+       movq_cfi r10, R10+8
+       movq_cfi r11, R11+8
+       movq_cfi rbx, RBX+8
+       movq_cfi rbp, RBP+8
+       movq_cfi r12, R12+8
+       movq_cfi r13, R13+8
+       movq_cfi r14, R14+8
+       movq_cfi r15, R15+8
+       xorl %ebx,%ebx
+       testl $3,CS+8(%rsp)
+       je error_kernelspace
+error_swapgs:
+       SWAPGS
+error_sti:
+       TRACE_IRQS_OFF
+       ret
+       CFI_ENDPROC
+
+/*
+ * There are two places in the kernel that can potentially fault with
+ * usergs. Handle them here. The exception handlers after iret run with
+ * kernel gs again, so don't set the user space flag. B stepping K8s
+ * sometimes report an truncated RIP for IRET exceptions returning to
+ * compat mode. Check for these here too.
+ */
+error_kernelspace:
+       incl %ebx
+       leaq irq_return(%rip),%rcx
+       cmpq %rcx,RIP+8(%rsp)
+       je error_swapgs
+       movl %ecx,%ecx  /* zero extend */
+       cmpq %rcx,RIP+8(%rsp)
+       je error_swapgs
+       cmpq $gs_change,RIP+8(%rsp)
+       je error_swapgs
+       jmp error_sti
+END(error_entry)
+
+
+/* ebx:        no swapgs flag (1: don't need swapgs, 0: need it) */
+ENTRY(error_exit)
+       DEFAULT_FRAME
+       movl %ebx,%eax
+       RESTORE_REST
+       DISABLE_INTERRUPTS(CLBR_NONE)
+       TRACE_IRQS_OFF
+       GET_THREAD_INFO(%rcx)
+       testl %eax,%eax
+       jne retint_kernel
+       LOCKDEP_SYS_EXIT_IRQ
+       movl TI_flags(%rcx),%edx
+       movl $_TIF_WORK_MASK,%edi
+       andl %edi,%edx
+       jnz retint_careful
+       jmp retint_swapgs
+       CFI_ENDPROC
+END(error_exit)
+
+
+       /* runs on exception stack */
+ENTRY(nmi)
+       INTR_FRAME
+       PARAVIRT_ADJUST_EXCEPTION_FRAME
+       pushq_cfi $-1
+       subq $15*8, %rsp
+       CFI_ADJUST_CFA_OFFSET 15*8
+       call save_paranoid
+       DEFAULT_FRAME 0
+       /* paranoidentry do_nmi, 0; without TRACE_IRQS_OFF */
+       movq %rsp,%rdi
+       movq $-1,%rsi
+       call do_nmi
+#ifdef CONFIG_TRACE_IRQFLAGS
+       /* paranoidexit; without TRACE_IRQS_OFF */
+       /* ebx: no swapgs flag */
+       DISABLE_INTERRUPTS(CLBR_NONE)
+       testl %ebx,%ebx                         /* swapgs needed? */
+       jnz nmi_restore
+       testl $3,CS(%rsp)
+       jnz nmi_userspace
+nmi_swapgs:
+       SWAPGS_UNSAFE_STACK
+nmi_restore:
+       RESTORE_ALL 8
+       jmp irq_return
+nmi_userspace:
+       GET_THREAD_INFO(%rcx)
+       movl TI_flags(%rcx),%ebx
+       andl $_TIF_WORK_MASK,%ebx
+       jz nmi_swapgs
+       movq %rsp,%rdi                  /* &pt_regs */
+       call sync_regs
+       movq %rax,%rsp                  /* switch stack for scheduling */
+       testl $_TIF_NEED_RESCHED,%ebx
+       jnz nmi_schedule
+       movl %ebx,%edx                  /* arg3: thread flags */
+       ENABLE_INTERRUPTS(CLBR_NONE)
+       xorl %esi,%esi                  /* arg2: oldset */
+       movq %rsp,%rdi                  /* arg1: &pt_regs */
+       call do_notify_resume
+       DISABLE_INTERRUPTS(CLBR_NONE)
+       jmp nmi_userspace
+nmi_schedule:
+       ENABLE_INTERRUPTS(CLBR_ANY)
+       call schedule
+       DISABLE_INTERRUPTS(CLBR_ANY)
+       jmp nmi_userspace
+       CFI_ENDPROC
+#else
+       jmp paranoid_exit
+       CFI_ENDPROC
+#endif
+END(nmi)
+
+ENTRY(ignore_sysret)
+       CFI_STARTPROC
+       mov $-ENOSYS,%eax
+       sysret
+       CFI_ENDPROC
+END(ignore_sysret)
+
+/*
+ * End of kprobes section
+ */
+       .popsection