[PATCH] x86-64: Fix ENOSYS in system call tracing
[powerpc.git] / arch / x86_64 / kernel / entry.S
index 6f81042..038dcf7 100644 (file)
@@ -4,8 +4,6 @@
  *  Copyright (C) 1991, 1992  Linus Torvalds
  *  Copyright (C) 2000, 2001, 2002  Andi Kleen SuSE Labs
  *  Copyright (C) 2000  Pavel Machek <pavel@suse.cz>
- * 
- *  $Id$
  */
 
 /*
  * at the top of the kernel process stack.     
  * - partial stack frame: partially saved registers upto R11.
  * - full stack frame: Like partial stack frame, but all register saved. 
- *     
- * TODO:        
- * - schedule it carefully for the final hardware.
+ *
+ * Some macro usage:
+ * - CFI macros are used to generate dwarf2 unwind information for better
+ * backtraces. They don't change any code.
+ * - SAVE_ALL/RESTORE_ALL - Save/restore all registers
+ * - SAVE_ARGS/RESTORE_ARGS - Save/restore registers that C functions modify.
+ * There are unfortunately lots of special cases where some registers
+ * not touched. The macro is a big mess that should be cleaned up.
+ * - SAVE_REST/RESTORE_REST - Handle the registers not saved by SAVE_ARGS.
+ * Gives a full stack frame.
+ * - ENTRY/END Define functions in the symbol table.
+ * - 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.
  */
 
-#define ASSEMBLY 1
 #include <linux/linkage.h>
 #include <asm/segment.h>
-#include <asm/smp.h>
 #include <asm/cache.h>
 #include <asm/errno.h>
 #include <asm/dwarf2.h>
        .macro  CFI_DEFAULT_STACK start=1
        .if \start
        CFI_STARTPROC   simple
+       CFI_SIGNAL_FRAME
        CFI_DEF_CFA     rsp,SS+8
        .else
        CFI_DEF_CFA_OFFSET SS+8
 /* rdi:        prev */ 
 ENTRY(ret_from_fork)
        CFI_DEFAULT_STACK
+       push kernel_eflags(%rip)
+       CFI_ADJUST_CFA_OFFSET 4
+       popf                            # reset kernel eflags
+       CFI_ADJUST_CFA_OFFSET -4
        call schedule_tail
        GET_THREAD_INFO(%rcx)
        testl $(_TIF_SYSCALL_TRACE|_TIF_SYSCALL_AUDIT),threadinfo_flags(%rcx)
@@ -199,6 +212,7 @@ END(ret_from_fork)
 
 ENTRY(system_call)
        CFI_STARTPROC   simple
+       CFI_SIGNAL_FRAME
        CFI_DEF_CFA     rsp,PDA_STACKOFFSET
        CFI_REGISTER    rip,rcx
        /*CFI_REGISTER  rflags,r11*/
@@ -301,6 +315,8 @@ tracesys:
        LOAD_ARGS ARGOFFSET  /* reload args from stack in case ptrace changed it */
        RESTORE_REST
        cmpq $__NR_syscall_max,%rax
+       movq $-ENOSYS,%rcx
+       cmova %rcx,%rax
        ja  1f
        movq %r10,%rcx  /* fixup for C */
        call *sys_call_table(,%rax,8)
@@ -316,6 +332,7 @@ END(system_call)
  */    
 ENTRY(int_ret_from_sys_call)
        CFI_STARTPROC   simple
+       CFI_SIGNAL_FRAME
        CFI_DEF_CFA     rsp,SS+8-ARGOFFSET
        /*CFI_REL_OFFSET        ss,SS-ARGOFFSET*/
        CFI_REL_OFFSET  rsp,RSP-ARGOFFSET
@@ -476,6 +493,7 @@ END(stub_rt_sigreturn)
  */
        .macro _frame ref
        CFI_STARTPROC simple
+       CFI_SIGNAL_FRAME
        CFI_DEF_CFA rsp,SS+8-\ref
        /*CFI_REL_OFFSET ss,SS-\ref*/
        CFI_REL_OFFSET rsp,RSP-\ref
@@ -511,9 +529,16 @@ END(stub_rt_sigreturn)
        testl $3,CS(%rdi)
        je 1f
        swapgs  
-1:     incl    %gs:pda_irqcount        # RED-PEN should check preempt count
+       /* irqcount is used to check if a CPU is already on an interrupt
+          stack or not. While this is essentially redundant with preempt_count
+          it is a little cheaper to use a separate counter in the PDA
+          (short of moving irq_enter into assembly, which would be too
+           much work) */
+1:     incl    %gs:pda_irqcount
        cmoveq %gs:pda_irqstackptr,%rsp
        push    %rbp                    # backlink for old unwinder
+       CFI_ADJUST_CFA_OFFSET 8
+       CFI_REL_OFFSET rbp,0
        /*
         * We entered an interrupt context - irqs are off:
         */
@@ -619,8 +644,7 @@ retint_signal:
 #ifdef CONFIG_PREEMPT
        /* Returning to kernel space. Check if we need preemption */
        /* rcx:  threadinfo. interrupts off. */
-       .p2align
-retint_kernel: 
+ENTRY(retint_kernel)
        cmpl $0,threadinfo_preempt_count(%rcx)
        jnz  retint_restore_args
        bt  $TIF_NEED_RESCHED,threadinfo_flags(%rcx)
@@ -679,7 +703,6 @@ ENTRY(call_function_interrupt)
 END(call_function_interrupt)
 #endif
 
-#ifdef CONFIG_X86_LOCAL_APIC   
 ENTRY(apic_timer_interrupt)
        apicinterrupt LOCAL_TIMER_VECTOR,smp_apic_timer_interrupt
 END(apic_timer_interrupt)
@@ -691,7 +714,6 @@ END(error_interrupt)
 ENTRY(spurious_interrupt)
        apicinterrupt SPURIOUS_APIC_VECTOR,smp_spurious_interrupt
 END(spurious_interrupt)
-#endif
                                
 /*
  * Exception entry points.
@@ -768,7 +790,9 @@ paranoid_exit\trace:
        testl $3,CS(%rsp)
        jnz   paranoid_userspace\trace
 paranoid_swapgs\trace:
+       .if \trace
        TRACE_IRQS_IRETQ 0
+       .endif
        swapgs
 paranoid_restore\trace:
        RESTORE_ALL 8
@@ -814,7 +838,7 @@ paranoid_schedule\trace:
  * Exception entry point. This expects an error code/orig_rax on the stack
  * and the exception handler in %rax.  
  */                                            
-ENTRY(error_entry)
+KPROBE_ENTRY(error_entry)
        _frame RDI
        /* rdi slot contains rax, oldrax contains error code */
        cld     
@@ -898,7 +922,7 @@ error_kernelspace:
        cmpq $gs_change,RIP(%rsp)
         je   error_swapgs
        jmp  error_sti
-END(error_entry)
+KPROBE_END(error_entry)
        
        /* Reload gs selector with exception handling */
        /* edi:  new selector */ 
@@ -958,6 +982,11 @@ ENTRY(kernel_thread)
        call do_fork
        movq %rax,RAX(%rsp)
        xorl %edi,%edi
+       test %rax,%rax
+       jnz  1f
+       /* terminate stack in child */
+       movq %rdi,RIP(%rsp)
+1:
 
        /*
         * It isn't worth to check for reschedule here,
@@ -973,6 +1002,8 @@ ENTRY(kernel_thread)
 ENDPROC(kernel_thread)
        
 child_rip:
+       pushq $0                # fake return address
+       CFI_STARTPROC
        /*
         * Here we are in the child and the registers are set as they were
         * at kernel_thread() invocation in the parent.
@@ -983,6 +1014,7 @@ child_rip:
        # exit
        xorl %edi, %edi
        call do_exit
+       CFI_ENDPROC
 ENDPROC(child_rip)
 
 /*
@@ -1000,7 +1032,7 @@ ENDPROC(child_rip)
  * do_sys_execve asm fallback arguments:
  *     rdi: name, rsi: argv, rdx: envp, fake frame on the stack
  */
-ENTRY(execve)
+ENTRY(kernel_execve)
        CFI_STARTPROC
        FAKE_STACK_FRAME $0
        SAVE_ALL        
@@ -1013,12 +1045,11 @@ ENTRY(execve)
        UNFAKE_STACK_FRAME
        ret
        CFI_ENDPROC
-ENDPROC(execve)
+ENDPROC(kernel_execve)
 
 KPROBE_ENTRY(page_fault)
        errorentry do_page_fault
-END(page_fault)
-       .previous .text
+KPROBE_END(page_fault)
 
 ENTRY(coprocessor_error)
        zeroentry do_coprocessor_error
@@ -1039,8 +1070,7 @@ KPROBE_ENTRY(debug)
        CFI_ADJUST_CFA_OFFSET 8         
        paranoidentry do_debug, DEBUG_STACK
        paranoidexit
-END(debug)
-       .previous .text
+KPROBE_END(debug)
 
        /* runs on exception stack */   
 KPROBE_ENTRY(nmi)
@@ -1054,8 +1084,7 @@ KPROBE_ENTRY(nmi)
        jmp paranoid_exit1
        CFI_ENDPROC
 #endif
-END(nmi)
-       .previous .text
+KPROBE_END(nmi)
 
 KPROBE_ENTRY(int3)
        INTR_FRAME
@@ -1064,8 +1093,7 @@ KPROBE_ENTRY(int3)
        paranoidentry do_int3, DEBUG_STACK
        jmp paranoid_exit1
        CFI_ENDPROC
-END(int3)
-       .previous .text
+KPROBE_END(int3)
 
 ENTRY(overflow)
        zeroentry do_overflow
@@ -1113,8 +1141,7 @@ END(stack_segment)
 
 KPROBE_ENTRY(general_protection)
        errorentry do_general_protection
-END(general_protection)
-       .previous .text
+KPROBE_END(general_protection)
 
 ENTRY(alignment_check)
        errorentry do_alignment_check
@@ -1151,6 +1178,7 @@ ENTRY(call_softirq)
        incl %gs:pda_irqcount
        cmove %gs:pda_irqstackptr,%rsp
        push  %rbp                      # backlink for old unwinder
+       CFI_ADJUST_CFA_OFFSET    8
        call __do_softirq
        leaveq
        CFI_DEF_CFA_REGISTER    rsp