Merge tag 'trace-3.16' of git://git.kernel.org/pub/scm/linux/kernel/git/rostedt/linux...
[firefly-linux-kernel-4.4.55.git] / arch / x86 / kernel / entry_64.S
index 3db806de57a0f6734b9f66186a93da005d6a553d..48a2644a082a4ccb25ede707403d1aa3fd212286 100644 (file)
@@ -36,7 +36,7 @@
  * - FIXUP_TOP_OF_STACK/RESTORE_TOP_OF_STACK - Fix up the hardware stack
  * frame that is otherwise undefined after a SYSCALL
  * - TRACE_IRQ_* - Trace hard interrupt state for lock debugging.
- * - errorentry/paranoidentry/zeroentry - Define exception entry points.
+ * - idtentry - Define exception entry points.
  */
 
 #include <linux/linkage.h>
@@ -57,6 +57,7 @@
 #include <asm/asm.h>
 #include <asm/context_tracking.h>
 #include <asm/smap.h>
+#include <asm/pgtable_types.h>
 #include <linux/err.h>
 
 /* Avoid __ASSEMBLER__'ifying <linux/audit.h> just for this.  */
@@ -836,8 +837,18 @@ restore_args:
        RESTORE_ARGS 1,8,1
 
 irq_return:
+       /*
+        * Are we returning to a stack segment from the LDT?  Note: in
+        * 64-bit mode SS:RSP on the exception stack is always valid.
+        */
+#ifdef CONFIG_X86_ESPFIX64
+       testb $4,(SS-RIP)(%rsp)
+       jnz irq_return_ldt
+#endif
+
+irq_return_iret:
        INTERRUPT_RETURN
-       _ASM_EXTABLE(irq_return, bad_iret)
+       _ASM_EXTABLE(irq_return_iret, bad_iret)
 
 #ifdef CONFIG_PARAVIRT
 ENTRY(native_iret)
@@ -845,6 +856,32 @@ ENTRY(native_iret)
        _ASM_EXTABLE(native_iret, bad_iret)
 #endif
 
+#ifdef CONFIG_X86_ESPFIX64
+irq_return_ldt:
+       pushq_cfi %rax
+       pushq_cfi %rdi
+       SWAPGS
+       movq PER_CPU_VAR(espfix_waddr),%rdi
+       movq %rax,(0*8)(%rdi)   /* RAX */
+       movq (2*8)(%rsp),%rax   /* RIP */
+       movq %rax,(1*8)(%rdi)
+       movq (3*8)(%rsp),%rax   /* CS */
+       movq %rax,(2*8)(%rdi)
+       movq (4*8)(%rsp),%rax   /* RFLAGS */
+       movq %rax,(3*8)(%rdi)
+       movq (6*8)(%rsp),%rax   /* SS */
+       movq %rax,(5*8)(%rdi)
+       movq (5*8)(%rsp),%rax   /* RSP */
+       movq %rax,(4*8)(%rdi)
+       andl $0xffff0000,%eax
+       popq_cfi %rdi
+       orq PER_CPU_VAR(espfix_stack),%rax
+       SWAPGS
+       movq %rax,%rsp
+       popq_cfi %rax
+       jmp irq_return_iret
+#endif
+
        .section .fixup,"ax"
 bad_iret:
        /*
@@ -906,9 +943,45 @@ ENTRY(retint_kernel)
        call preempt_schedule_irq
        jmp exit_intr
 #endif
-
        CFI_ENDPROC
 END(common_interrupt)
+
+       /*
+        * If IRET takes a fault on the espfix stack, then we
+        * end up promoting it to a doublefault.  In that case,
+        * modify the stack to make it look like we just entered
+        * the #GP handler from user space, similar to bad_iret.
+        */
+#ifdef CONFIG_X86_ESPFIX64
+       ALIGN
+__do_double_fault:
+       XCPT_FRAME 1 RDI+8
+       movq RSP(%rdi),%rax             /* Trap on the espfix stack? */
+       sarq $PGDIR_SHIFT,%rax
+       cmpl $ESPFIX_PGD_ENTRY,%eax
+       jne do_double_fault             /* No, just deliver the fault */
+       cmpl $__KERNEL_CS,CS(%rdi)
+       jne do_double_fault
+       movq RIP(%rdi),%rax
+       cmpq $irq_return_iret,%rax
+#ifdef CONFIG_PARAVIRT
+       je 1f
+       cmpq $native_iret,%rax
+#endif
+       jne do_double_fault             /* This shouldn't happen... */
+1:
+       movq PER_CPU_VAR(kernel_stack),%rax
+       subq $(6*8-KERNEL_STACK_OFFSET),%rax    /* Reset to original stack */
+       movq %rax,RSP(%rdi)
+       movq $0,(%rax)                  /* Missing (lost) #GP error code */
+       movq $general_protection,RIP(%rdi)
+       retq
+       CFI_ENDPROC
+END(__do_double_fault)
+#else
+# define __do_double_fault do_double_fault
+#endif
+
 /*
  * End of kprobes section
  */
@@ -999,125 +1072,100 @@ apicinterrupt IRQ_WORK_VECTOR \
 /*
  * Exception entry points.
  */
-.macro zeroentry sym do_sym
-ENTRY(\sym)
-       INTR_FRAME
-       ASM_CLAC
-       PARAVIRT_ADJUST_EXCEPTION_FRAME
-       pushq_cfi $-1           /* ORIG_RAX: no syscall to restart */
-       subq $ORIG_RAX-R15, %rsp
-       CFI_ADJUST_CFA_OFFSET ORIG_RAX-R15
-       call error_entry
-       DEFAULT_FRAME 0
-       movq %rsp,%rdi          /* pt_regs pointer */
-       xorl %esi,%esi          /* no error code */
-       call \do_sym
-       jmp error_exit          /* %ebx: no swapgs flag */
-       CFI_ENDPROC
-END(\sym)
-.endm
+#define INIT_TSS_IST(x) PER_CPU_VAR(init_tss) + (TSS_ist + ((x) - 1) * 8)
 
-.macro paranoidzeroentry sym do_sym
+.macro idtentry sym do_sym has_error_code:req paranoid=0 shift_ist=-1
 ENTRY(\sym)
-       INTR_FRAME
-       ASM_CLAC
-       PARAVIRT_ADJUST_EXCEPTION_FRAME
-       pushq_cfi $-1           /* ORIG_RAX: no syscall to restart */
-       subq $ORIG_RAX-R15, %rsp
-       CFI_ADJUST_CFA_OFFSET ORIG_RAX-R15
-       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
+       /* Sanity check */
+       .if \shift_ist != -1 && \paranoid == 0
+       .error "using shift_ist requires paranoid=1"
+       .endif
 
-#define INIT_TSS_IST(x) PER_CPU_VAR(init_tss) + (TSS_ist + ((x) - 1) * 8)
-.macro paranoidzeroentry_ist sym do_sym ist
-ENTRY(\sym)
+       .if \has_error_code
+       XCPT_FRAME
+       .else
        INTR_FRAME
-       ASM_CLAC
-       PARAVIRT_ADJUST_EXCEPTION_FRAME
-       pushq_cfi $-1           /* ORIG_RAX: no syscall to restart */
-       subq $ORIG_RAX-R15, %rsp
-       CFI_ADJUST_CFA_OFFSET ORIG_RAX-R15
-       call save_paranoid
-       TRACE_IRQS_OFF_DEBUG
-       movq %rsp,%rdi          /* pt_regs pointer */
-       xorl %esi,%esi          /* no error code */
-       subq $EXCEPTION_STKSZ, INIT_TSS_IST(\ist)
-       call \do_sym
-       addq $EXCEPTION_STKSZ, INIT_TSS_IST(\ist)
-       jmp paranoid_exit       /* %ebx: no swapgs flag */
-       CFI_ENDPROC
-END(\sym)
-.endm
+       .endif
 
-.macro errorentry sym do_sym
-ENTRY(\sym)
-       XCPT_FRAME
        ASM_CLAC
        PARAVIRT_ADJUST_EXCEPTION_FRAME
+
+       .ifeq \has_error_code
+       pushq_cfi $-1                   /* ORIG_RAX: no syscall to restart */
+       .endif
+
        subq $ORIG_RAX-R15, %rsp
        CFI_ADJUST_CFA_OFFSET ORIG_RAX-R15
+
+       .if \paranoid
+       call save_paranoid
+       .else
        call error_entry
+       .endif
+
        DEFAULT_FRAME 0
+
+       .if \paranoid
+       .if \shift_ist != -1
+       TRACE_IRQS_OFF_DEBUG            /* reload IDT in case of recursion */
+       .else
+       TRACE_IRQS_OFF
+       .endif
+       .endif
+
        movq %rsp,%rdi                  /* pt_regs pointer */
+
+       .if \has_error_code
        movq ORIG_RAX(%rsp),%rsi        /* get error code */
        movq $-1,ORIG_RAX(%rsp)         /* no syscall to restart */
+       .else
+       xorl %esi,%esi                  /* no error code */
+       .endif
+
+       .if \shift_ist != -1
+       subq $EXCEPTION_STKSZ, INIT_TSS_IST(\shift_ist)
+       .endif
+
        call \do_sym
+
+       .if \shift_ist != -1
+       addq $EXCEPTION_STKSZ, INIT_TSS_IST(\shift_ist)
+       .endif
+
+       .if \paranoid
+       jmp paranoid_exit               /* %ebx: no swapgs flag */
+       .else
        jmp error_exit                  /* %ebx: no swapgs flag */
+       .endif
+
        CFI_ENDPROC
 END(\sym)
 .endm
 
 #ifdef CONFIG_TRACING
-.macro trace_errorentry sym do_sym
-errorentry trace(\sym) trace(\do_sym)
-errorentry \sym \do_sym
+.macro trace_idtentry sym do_sym has_error_code:req
+idtentry trace(\sym) trace(\do_sym) has_error_code=\has_error_code
+idtentry \sym \do_sym has_error_code=\has_error_code
 .endm
 #else
-.macro trace_errorentry sym do_sym
-errorentry \sym \do_sym
+.macro trace_idtentry sym do_sym has_error_code:req
+idtentry \sym \do_sym has_error_code=\has_error_code
 .endm
 #endif
 
-       /* error code is on the stack already */
-.macro paranoiderrorentry sym do_sym
-ENTRY(\sym)
-       XCPT_FRAME
-       ASM_CLAC
-       PARAVIRT_ADJUST_EXCEPTION_FRAME
-       subq $ORIG_RAX-R15, %rsp
-       CFI_ADJUST_CFA_OFFSET ORIG_RAX-R15
-       call save_paranoid
-       DEFAULT_FRAME 0
-       TRACE_IRQS_OFF
-       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
-END(\sym)
-.endm
-
-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
+idtentry divide_error do_divide_error has_error_code=0
+idtentry overflow do_overflow has_error_code=0
+idtentry bounds do_bounds has_error_code=0
+idtentry invalid_op do_invalid_op has_error_code=0
+idtentry device_not_available do_device_not_available has_error_code=0
+idtentry double_fault __do_double_fault has_error_code=1 paranoid=1
+idtentry coprocessor_segment_overrun do_coprocessor_segment_overrun has_error_code=0
+idtentry invalid_TSS do_invalid_TSS has_error_code=1
+idtentry segment_not_present do_segment_not_present has_error_code=1
+idtentry spurious_interrupt_bug do_spurious_interrupt_bug has_error_code=0
+idtentry coprocessor_error do_coprocessor_error has_error_code=0
+idtentry alignment_check do_alignment_check has_error_code=1
+idtentry simd_coprocessor_error do_simd_coprocessor_error has_error_code=0
 
 
        /* Reload gs selector with exception handling */
@@ -1167,7 +1215,7 @@ ENTRY(do_softirq_own_stack)
 END(do_softirq_own_stack)
 
 #ifdef CONFIG_XEN
-zeroentry xen_hypervisor_callback xen_do_hypervisor_callback
+idtentry xen_hypervisor_callback xen_do_hypervisor_callback has_error_code=0
 
 /*
  * A note on the "critical region" in our callback handler.
@@ -1278,21 +1326,21 @@ apicinterrupt3 HYPERVISOR_CALLBACK_VECTOR \
  */
        .pushsection .kprobes.text, "ax"
 
-paranoidzeroentry_ist debug do_debug DEBUG_STACK
-paranoidzeroentry_ist int3 do_int3 DEBUG_STACK
-paranoiderrorentry stack_segment do_stack_segment
+idtentry debug do_debug has_error_code=0 paranoid=1 shift_ist=DEBUG_STACK
+idtentry int3 do_int3 has_error_code=0 paranoid=1 shift_ist=DEBUG_STACK
+idtentry stack_segment do_stack_segment has_error_code=1 paranoid=1
 #ifdef CONFIG_XEN
-zeroentry xen_debug do_debug
-zeroentry xen_int3 do_int3
-errorentry xen_stack_segment do_stack_segment
+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
 #endif
-errorentry general_protection do_general_protection
-trace_errorentry page_fault do_page_fault
+idtentry general_protection do_general_protection has_error_code=1
+trace_idtentry page_fault do_page_fault has_error_code=1
 #ifdef CONFIG_KVM_GUEST
-errorentry async_page_fault do_async_page_fault
+idtentry async_page_fault do_async_page_fault has_error_code=1
 #endif
 #ifdef CONFIG_X86_MCE
-paranoidzeroentry machine_check *machine_check_vector(%rip)
+idtentry machine_check has_error_code=0 paranoid=1 do_sym=*machine_check_vector(%rip)
 #endif
 
        /*
@@ -1397,7 +1445,7 @@ error_sti:
  */
 error_kernelspace:
        incl %ebx
-       leaq irq_return(%rip),%rcx
+       leaq irq_return_iret(%rip),%rcx
        cmpq %rcx,RIP+8(%rsp)
        je error_swapgs
        movl %ecx,%eax  /* zero extend */