Merge branch 'upstream-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/ieee13...
[pandora-kernel.git] / arch / i386 / kernel / entry.S
index fbdb933..5a63d6f 100644 (file)
@@ -40,9 +40,9 @@
  * "current" is in register %ebx during any slow entries.
  */
 
-#include <linux/config.h>
 #include <linux/linkage.h>
 #include <asm/thread_info.h>
+#include <asm/irqflags.h>
 #include <asm/errno.h>
 #include <asm/segment.h>
 #include <asm/smp.h>
@@ -76,13 +76,29 @@ DF_MASK             = 0x00000400
 NT_MASK                = 0x00004000
 VM_MASK                = 0x00020000
 
+/* These are replaces for paravirtualization */
+#define DISABLE_INTERRUPTS             cli
+#define ENABLE_INTERRUPTS              sti
+#define ENABLE_INTERRUPTS_SYSEXIT      sti; sysexit
+#define INTERRUPT_RETURN               iret
+#define GET_CR0_INTO_EAX               movl %cr0, %eax
+
 #ifdef CONFIG_PREEMPT
-#define preempt_stop           cli
+#define preempt_stop           DISABLE_INTERRUPTS; TRACE_IRQS_OFF
 #else
 #define preempt_stop
 #define resume_kernel          restore_nocheck
 #endif
 
+.macro TRACE_IRQS_IRET
+#ifdef CONFIG_TRACE_IRQFLAGS
+       testl $IF_MASK,EFLAGS(%esp)     # interrupts off?
+       jz 1f
+       TRACE_IRQS_ON
+1:
+#endif
+.endm
+
 #ifdef CONFIG_VM86
 #define resume_userspace_sig   check_userspace
 #else
@@ -167,18 +183,21 @@ VM_MASK           = 0x00020000
 
 #define RING0_INT_FRAME \
        CFI_STARTPROC simple;\
+       CFI_SIGNAL_FRAME;\
        CFI_DEF_CFA esp, 3*4;\
        /*CFI_OFFSET cs, -2*4;*/\
        CFI_OFFSET eip, -3*4
 
 #define RING0_EC_FRAME \
        CFI_STARTPROC simple;\
+       CFI_SIGNAL_FRAME;\
        CFI_DEF_CFA esp, 4*4;\
        /*CFI_OFFSET cs, -2*4;*/\
        CFI_OFFSET eip, -3*4
 
 #define RING0_PTREGS_FRAME \
        CFI_STARTPROC simple;\
+       CFI_SIGNAL_FRAME;\
        CFI_DEF_CFA esp, OLDESP-EBX;\
        /*CFI_OFFSET cs, CS-OLDESP;*/\
        CFI_OFFSET eip, EIP-OLDESP;\
@@ -195,11 +214,15 @@ VM_MASK           = 0x00020000
 ENTRY(ret_from_fork)
        CFI_STARTPROC
        pushl %eax
-       CFI_ADJUST_CFA_OFFSET -4
+       CFI_ADJUST_CFA_OFFSET 4
        call schedule_tail
        GET_THREAD_INFO(%ebp)
        popl %eax
        CFI_ADJUST_CFA_OFFSET -4
+       pushl $0x0202                   # Reset kernel eflags
+       CFI_ADJUST_CFA_OFFSET 4
+       popfl
+       CFI_ADJUST_CFA_OFFSET -4
        jmp syscall_exit
        CFI_ENDPROC
 
@@ -220,10 +243,11 @@ ret_from_intr:
 check_userspace:
        movl EFLAGS(%esp), %eax         # mix EFLAGS and CS
        movb CS(%esp), %al
-       testl $(VM_MASK | 3), %eax
-       jz resume_kernel
+       andl $(VM_MASK | SEGMENT_RPL_MASK), %eax
+       cmpl $USER_RPL, %eax
+       jb resume_kernel                # not returning to v8086 or userspace
 ENTRY(resume_userspace)
-       cli                             # make sure we don't miss an interrupt
+       DISABLE_INTERRUPTS              # make sure we don't miss an interrupt
                                        # setting need_resched or sigpending
                                        # between sampling and the iret
        movl TI_flags(%ebp), %ecx
@@ -234,7 +258,7 @@ ENTRY(resume_userspace)
 
 #ifdef CONFIG_PREEMPT
 ENTRY(resume_kernel)
-       cli
+       DISABLE_INTERRUPTS
        cmpl $0,TI_preempt_count(%ebp)  # non-zero preempt_count ?
        jnz restore_nocheck
 need_resched:
@@ -254,11 +278,16 @@ need_resched:
        # sysenter call handler stub
 ENTRY(sysenter_entry)
        CFI_STARTPROC simple
+       CFI_SIGNAL_FRAME
        CFI_DEF_CFA esp, 0
        CFI_REGISTER esp, ebp
        movl TSS_sysenter_esp0(%esp),%esp
 sysenter_past_esp:
-       sti
+       /*
+        * No need to follow this irqs on/off section: the syscall
+        * disabled irqs and here we enable it straight after entry:
+        */
+       ENABLE_INTERRUPTS
        pushl $(__USER_DS)
        CFI_ADJUST_CFA_OFFSET 4
        /*CFI_REL_OFFSET ss, 0*/
@@ -303,7 +332,8 @@ sysenter_past_esp:
        jae syscall_badsys
        call *sys_call_table(,%eax,4)
        movl %eax,EAX(%esp)
-       cli
+       DISABLE_INTERRUPTS
+       TRACE_IRQS_OFF
        movl TI_flags(%ebp), %ecx
        testw $_TIF_ALLWORK_MASK, %cx
        jne syscall_exit_work
@@ -311,8 +341,8 @@ sysenter_past_esp:
        movl EIP(%esp), %edx
        movl OLDESP(%esp), %ecx
        xorl %ebp,%ebp
-       sti
-       sysexit
+       TRACE_IRQS_ON
+       ENABLE_INTERRUPTS_SYSEXIT
        CFI_ENDPROC
 
 
@@ -337,9 +367,10 @@ syscall_call:
        call *sys_call_table(,%eax,4)
        movl %eax,EAX(%esp)             # store the return value
 syscall_exit:
-       cli                             # make sure we don't miss an interrupt
+       DISABLE_INTERRUPTS              # make sure we don't miss an interrupt
                                        # setting need_resched or sigpending
                                        # between sampling and the iret
+       TRACE_IRQS_OFF
        movl TI_flags(%ebp), %ecx
        testw $_TIF_ALLWORK_MASK, %cx   # current->work
        jne syscall_exit_work
@@ -351,18 +382,21 @@ restore_all:
        # See comments in process.c:copy_thread() for details.
        movb OLDSS(%esp), %ah
        movb CS(%esp), %al
-       andl $(VM_MASK | (4 << 8) | 3), %eax
-       cmpl $((4 << 8) | 3), %eax
+       andl $(VM_MASK | (SEGMENT_TI_MASK << 8) | SEGMENT_RPL_MASK), %eax
+       cmpl $((SEGMENT_LDT << 8) | USER_RPL), %eax
        CFI_REMEMBER_STATE
        je ldt_ss                       # returning to user-space with LDT SS
 restore_nocheck:
+       TRACE_IRQS_IRET
+restore_nocheck_notrace:
        RESTORE_REGS
        addl $4, %esp
        CFI_ADJUST_CFA_OFFSET -4
-1:     iret
+1:     INTERRUPT_RETURN
 .section .fixup,"ax"
 iret_exc:
-       sti
+       TRACE_IRQS_ON
+       ENABLE_INTERRUPTS
        pushl $0                        # no error code
        pushl $do_iret_error
        jmp error_code
@@ -386,15 +420,17 @@ ldt_ss:
         * dosemu and wine happy. */
        subl $8, %esp           # reserve space for switch16 pointer
        CFI_ADJUST_CFA_OFFSET 8
-       cli
+       DISABLE_INTERRUPTS
+       TRACE_IRQS_OFF
        movl %esp, %eax
        /* Set up the 16bit stack frame with switch32 pointer on top,
         * and a switch16 pointer on top of the current frame. */
        call setup_x86_bogus_stack
        CFI_ADJUST_CFA_OFFSET -8        # frame has moved
+       TRACE_IRQS_IRET
        RESTORE_REGS
        lss 20+4(%esp), %esp    # switch to 16bit stack
-1:     iret
+1:     INTERRUPT_RETURN
 .section __ex_table,"a"
        .align 4
        .long 1b,iret_exc
@@ -409,9 +445,10 @@ work_pending:
        jz work_notifysig
 work_resched:
        call schedule
-       cli                             # make sure we don't miss an interrupt
+       DISABLE_INTERRUPTS              # make sure we don't miss an interrupt
                                        # setting need_resched or sigpending
                                        # between sampling and the iret
+       TRACE_IRQS_OFF
        movl TI_flags(%ebp), %ecx
        andl $_TIF_WORK_MASK, %ecx      # is there any work to be done other
                                        # than syscall tracing?
@@ -463,7 +500,8 @@ syscall_trace_entry:
 syscall_exit_work:
        testb $(_TIF_SYSCALL_TRACE|_TIF_SYSCALL_AUDIT|_TIF_SINGLESTEP), %cl
        jz work_pending
-       sti                             # could let do_syscall_trace() call
+       TRACE_IRQS_ON
+       ENABLE_INTERRUPTS               # could let do_syscall_trace() call
                                        # schedule() instead
        movl %esp, %eax
        movl $1, %edx
@@ -536,9 +574,14 @@ ENTRY(irq_entries_start)
 vector=vector+1
 .endr
 
+/*
+ * the CPU automatically disables interrupts when executing an IRQ vector,
+ * so IRQ-flags tracing has to follow that:
+ */
        ALIGN
 common_interrupt:
        SAVE_ALL
+       TRACE_IRQS_OFF
        movl %esp,%eax
        call do_IRQ
        jmp ret_from_intr
@@ -550,19 +593,18 @@ ENTRY(name)                               \
        pushl $~(nr);                   \
        CFI_ADJUST_CFA_OFFSET 4;        \
        SAVE_ALL;                       \
+       TRACE_IRQS_OFF                  \
        movl %esp,%eax;                 \
        call smp_/**/name;              \
-       jmp ret_from_intr;      \
+       jmp ret_from_intr;              \
        CFI_ENDPROC
 
 /* The include is where all of the SMP etc. interrupts come from */
 #include "entry_arch.h"
 
-ENTRY(divide_error)
-       RING0_INT_FRAME
-       pushl $0                        # no error code
-       CFI_ADJUST_CFA_OFFSET 4
-       pushl $do_divide_error
+KPROBE_ENTRY(page_fault)
+       RING0_EC_FRAME
+       pushl $do_page_fault
        CFI_ADJUST_CFA_OFFSET 4
        ALIGN
 error_code:
@@ -612,6 +654,7 @@ error_code:
        call *%edi
        jmp ret_from_exception
        CFI_ENDPROC
+KPROBE_END(page_fault)
 
 ENTRY(coprocessor_error)
        RING0_INT_FRAME
@@ -636,7 +679,7 @@ ENTRY(device_not_available)
        pushl $-1                       # mark this as an int
        CFI_ADJUST_CFA_OFFSET 4
        SAVE_ALL
-       movl %cr0, %eax
+       GET_CR0_INTO_EAX
        testl $0x4, %eax                # EM (math emulation bit)
        jne device_not_available_emulate
        preempt_stop
@@ -669,9 +712,15 @@ device_not_available_emulate:
        jne ok;                                 \
 label:                                         \
        movl TSS_sysenter_esp0+offset(%esp),%esp;       \
+       CFI_DEF_CFA esp, 0;                     \
+       CFI_UNDEFINED eip;                      \
        pushfl;                                 \
+       CFI_ADJUST_CFA_OFFSET 4;                \
        pushl $__KERNEL_CS;                     \
-       pushl $sysenter_past_esp
+       CFI_ADJUST_CFA_OFFSET 4;                \
+       pushl $sysenter_past_esp;               \
+       CFI_ADJUST_CFA_OFFSET 4;                \
+       CFI_REL_OFFSET eip, 0
 
 KPROBE_ENTRY(debug)
        RING0_INT_FRAME
@@ -687,7 +736,8 @@ debug_stack_correct:
        call do_debug
        jmp ret_from_exception
        CFI_ENDPROC
-       .previous .text
+KPROBE_END(debug)
+
 /*
  * NMI is doubly nasty. It can happen _while_ we're handling
  * a debug fault, and the debug fault hasn't yet been able to
@@ -696,7 +746,7 @@ debug_stack_correct:
  * check whether we got an NMI on the debug path where the debug
  * fault happened on the sysenter path.
  */
-ENTRY(nmi)
+KPROBE_ENTRY(nmi)
        RING0_INT_FRAME
        pushl %eax
        CFI_ADJUST_CFA_OFFSET 4
@@ -721,19 +771,23 @@ ENTRY(nmi)
        cmpl $sysenter_entry,12(%esp)
        je nmi_debug_stack_check
 nmi_stack_correct:
+       /* We have a RING0_INT_FRAME here */
        pushl %eax
        CFI_ADJUST_CFA_OFFSET 4
        SAVE_ALL
        xorl %edx,%edx          # zero error code
        movl %esp,%eax          # pt_regs pointer
        call do_nmi
-       jmp restore_all
+       jmp restore_nocheck_notrace
        CFI_ENDPROC
 
 nmi_stack_fixup:
+       RING0_INT_FRAME
        FIX_STACK(12,nmi_stack_correct, 1)
        jmp nmi_stack_correct
+
 nmi_debug_stack_check:
+       /* We have a RING0_INT_FRAME here */
        cmpw $__KERNEL_CS,16(%esp)
        jne nmi_stack_correct
        cmpl $debug,(%esp)
@@ -744,8 +798,10 @@ nmi_debug_stack_check:
        jmp nmi_stack_correct
 
 nmi_16bit_stack:
-       RING0_INT_FRAME
-       /* create the pointer to lss back */
+       /* We have a RING0_INT_FRAME here.
+        *
+        * create the pointer to lss back
+        */
        pushl %ss
        CFI_ADJUST_CFA_OFFSET 4
        pushl %esp
@@ -766,12 +822,13 @@ nmi_16bit_stack:
        call do_nmi
        RESTORE_REGS
        lss 12+4(%esp), %esp            # back to 16bit stack
-1:     iret
+1:     INTERRUPT_RETURN
        CFI_ENDPROC
 .section __ex_table,"a"
        .align 4
        .long 1b,iret_exc
 .previous
+KPROBE_END(nmi)
 
 KPROBE_ENTRY(int3)
        RING0_INT_FRAME
@@ -783,7 +840,7 @@ KPROBE_ENTRY(int3)
        call do_int3
        jmp ret_from_exception
        CFI_ENDPROC
-       .previous .text
+KPROBE_END(int3)
 
 ENTRY(overflow)
        RING0_INT_FRAME
@@ -848,7 +905,7 @@ KPROBE_ENTRY(general_protection)
        CFI_ADJUST_CFA_OFFSET 4
        jmp error_code
        CFI_ENDPROC
-       .previous .text
+KPROBE_END(general_protection)
 
 ENTRY(alignment_check)
        RING0_EC_FRAME
@@ -857,13 +914,14 @@ ENTRY(alignment_check)
        jmp error_code
        CFI_ENDPROC
 
-KPROBE_ENTRY(page_fault)
-       RING0_EC_FRAME
-       pushl $do_page_fault
+ENTRY(divide_error)
+       RING0_INT_FRAME
+       pushl $0                        # no error code
+       CFI_ADJUST_CFA_OFFSET 4
+       pushl $do_divide_error
        CFI_ADJUST_CFA_OFFSET 4
        jmp error_code
        CFI_ENDPROC
-       .previous .text
 
 #ifdef CONFIG_X86_MCE
 ENTRY(machine_check)
@@ -916,6 +974,19 @@ ENTRY(arch_unwind_init_running)
 ENDPROC(arch_unwind_init_running)
 #endif
 
+ENTRY(kernel_thread_helper)
+       pushl $0                # fake return address for unwinder
+       CFI_STARTPROC
+       movl %edx,%eax
+       push %edx
+       CFI_ADJUST_CFA_OFFSET 4
+       call *%ebx
+       push %eax
+       CFI_ADJUST_CFA_OFFSET 4
+       call do_exit
+       CFI_ENDPROC
+ENDPROC(kernel_thread_helper)
+
 .section .rodata,"a"
 #include "syscall_table.S"