]> err.no Git - linux-2.6/blobdiff - arch/i386/kernel/entry.S
[PATCH] mark struct file_operations const 9
[linux-2.6] / arch / i386 / kernel / entry.S
index b99d4a16007872941972a88e45b44b31e91ee07a..5e47683fc63ae736e25d30e83aef093965cdc17d 100644 (file)
 #include <asm/dwarf2.h>
 #include "irq_vectors.h"
 
+/*
+ * We use macros for low-level operations which need to be overridden
+ * for paravirtualization.  The following will never clobber any registers:
+ *   INTERRUPT_RETURN (aka. "iret")
+ *   GET_CR0_INTO_EAX (aka. "movl %cr0, %eax")
+ *   ENABLE_INTERRUPTS_SYSEXIT (aka "sti; sysexit").
+ *
+ * For DISABLE_INTERRUPTS/ENABLE_INTERRUPTS (aka "cli"/"sti"), you must
+ * specify what registers can be overwritten (CLBR_NONE, CLBR_EAX/EDX/ECX/ANY).
+ * Allowing a register to be clobbered can shrink the paravirt replacement
+ * enough to patch inline, increasing performance.
+ */
+
 #define nr_syscalls ((syscall_table_size)/4)
 
 CF_MASK                = 0x00000001
@@ -62,17 +75,10 @@ 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           DISABLE_INTERRUPTS; TRACE_IRQS_OFF
+#define preempt_stop(clobbers) DISABLE_INTERRUPTS(clobbers); TRACE_IRQS_OFF
 #else
-#define preempt_stop
+#define preempt_stop(clobbers)
 #define resume_kernel          restore_nocheck
 #endif
 
@@ -233,7 +239,7 @@ ENTRY(ret_from_fork)
        ALIGN
        RING0_PTREGS_FRAME
 ret_from_exception:
-       preempt_stop
+       preempt_stop(CLBR_ANY)
 ret_from_intr:
        GET_THREAD_INFO(%ebp)
 check_userspace:
@@ -244,7 +250,7 @@ check_userspace:
        jb resume_kernel                # not returning to v8086 or userspace
 
 ENTRY(resume_userspace)
-       DISABLE_INTERRUPTS              # make sure we don't miss an interrupt
+       DISABLE_INTERRUPTS(CLBR_ANY)    # make sure we don't miss an interrupt
                                        # setting need_resched or sigpending
                                        # between sampling and the iret
        movl TI_flags(%ebp), %ecx
@@ -255,7 +261,7 @@ ENTRY(resume_userspace)
 
 #ifdef CONFIG_PREEMPT
 ENTRY(resume_kernel)
-       DISABLE_INTERRUPTS
+       DISABLE_INTERRUPTS(CLBR_ANY)
        cmpl $0,TI_preempt_count(%ebp)  # non-zero preempt_count ?
        jnz restore_nocheck
 need_resched:
@@ -284,7 +290,7 @@ sysenter_past_esp:
         * No need to follow this irqs on/off section: the syscall
         * disabled irqs and here we enable it straight after entry:
         */
-       ENABLE_INTERRUPTS
+       ENABLE_INTERRUPTS(CLBR_NONE)
        pushl $(__USER_DS)
        CFI_ADJUST_CFA_OFFSET 4
        /*CFI_REL_OFFSET ss, 0*/
@@ -296,12 +302,16 @@ sysenter_past_esp:
        pushl $(__USER_CS)
        CFI_ADJUST_CFA_OFFSET 4
        /*CFI_REL_OFFSET cs, 0*/
+#ifndef CONFIG_COMPAT_VDSO
        /*
         * Push current_thread_info()->sysenter_return to the stack.
         * A tiny bit of offset fixup is necessary - 4*4 means the 4 words
         * pushed above; +8 corresponds to copy_thread's esp0 setting.
         */
        pushl (TI_sysenter_return-THREAD_SIZE+8+4*4)(%esp)
+#else
+       pushl $SYSENTER_RETURN
+#endif
        CFI_ADJUST_CFA_OFFSET 4
        CFI_REL_OFFSET eip, 0
 
@@ -329,7 +339,7 @@ sysenter_past_esp:
        jae syscall_badsys
        call *sys_call_table(,%eax,4)
        movl %eax,PT_EAX(%esp)
-       DISABLE_INTERRUPTS
+       DISABLE_INTERRUPTS(CLBR_ECX|CLBR_EDX)
        TRACE_IRQS_OFF
        movl TI_flags(%ebp), %ecx
        testw $_TIF_ALLWORK_MASK, %cx
@@ -371,7 +381,7 @@ syscall_call:
        call *sys_call_table(,%eax,4)
        movl %eax,PT_EAX(%esp)          # store the return value
 syscall_exit:
-       DISABLE_INTERRUPTS              # make sure we don't miss an interrupt
+       DISABLE_INTERRUPTS(CLBR_ANY)    # make sure we don't miss an interrupt
                                        # setting need_resched or sigpending
                                        # between sampling and the iret
        TRACE_IRQS_OFF
@@ -400,7 +410,7 @@ restore_nocheck_notrace:
 .section .fixup,"ax"
 iret_exc:
        TRACE_IRQS_ON
-       ENABLE_INTERRUPTS
+       ENABLE_INTERRUPTS(CLBR_NONE)
        pushl $0                        # no error code
        pushl $do_iret_error
        jmp error_code
@@ -416,6 +426,20 @@ ldt_ss:
        jnz restore_nocheck
        testl $0x00400000, %eax         # returning to 32bit stack?
        jnz restore_nocheck             # allright, normal return
+
+#ifdef CONFIG_PARAVIRT
+       /*
+        * The kernel can't run on a non-flat stack if paravirt mode
+        * is active.  Rather than try to fixup the high bits of
+        * ESP, bypass this code entirely.  This may break DOSemu
+        * and/or Wine support in a paravirt VM, although the option
+        * is still available to implement the setting of the high
+        * 16-bits in the INTERRUPT_RETURN paravirt-op.
+        */
+       cmpl $0, paravirt_ops+PARAVIRT_enabled
+       jne restore_nocheck
+#endif
+
        /* If returning to userspace with 16bit stack,
         * try to fix the higher word of ESP, as the CPU
         * won't restore it.
@@ -429,7 +453,7 @@ ldt_ss:
        CFI_ADJUST_CFA_OFFSET 4
        pushl %eax
        CFI_ADJUST_CFA_OFFSET 4
-       DISABLE_INTERRUPTS
+       DISABLE_INTERRUPTS(CLBR_EAX)
        TRACE_IRQS_OFF
        lss (%esp), %esp
        CFI_ADJUST_CFA_OFFSET -8
@@ -444,7 +468,7 @@ work_pending:
        jz work_notifysig
 work_resched:
        call schedule
-       DISABLE_INTERRUPTS              # make sure we don't miss an interrupt
+       DISABLE_INTERRUPTS(CLBR_ANY)    # make sure we don't miss an interrupt
                                        # setting need_resched or sigpending
                                        # between sampling and the iret
        TRACE_IRQS_OFF
@@ -457,6 +481,7 @@ work_resched:
 
 work_notifysig:                                # deal with pending signals and
                                        # notify-resume requests
+#ifdef CONFIG_VM86
        testl $VM_MASK, PT_EFLAGS(%esp)
        movl %esp, %eax
        jne work_notifysig_v86          # returning to kernel-space or
@@ -467,17 +492,18 @@ work_notifysig:                           # deal with pending signals and
 
        ALIGN
 work_notifysig_v86:
-#ifdef CONFIG_VM86
        pushl %ecx                      # save ti_flags for do_notify_resume
        CFI_ADJUST_CFA_OFFSET 4
        call save_v86_state             # %eax contains pt_regs pointer
        popl %ecx
        CFI_ADJUST_CFA_OFFSET -4
        movl %eax, %esp
+#else
+       movl %esp, %eax
+#endif
        xorl %edx, %edx
        call do_notify_resume
        jmp resume_userspace_sig
-#endif
 
        # perform syscall exit tracing
        ALIGN
@@ -500,7 +526,7 @@ syscall_exit_work:
        testb $(_TIF_SYSCALL_TRACE|_TIF_SYSCALL_AUDIT|_TIF_SINGLESTEP), %cl
        jz work_pending
        TRACE_IRQS_ON
-       ENABLE_INTERRUPTS               # could let do_syscall_trace() call
+       ENABLE_INTERRUPTS(CLBR_ANY)     # could let do_syscall_trace() call
                                        # schedule() instead
        movl %esp, %eax
        movl $1, %edx
@@ -524,8 +550,7 @@ syscall_badsys:
 
 #define FIXUP_ESPFIX_STACK \
        /* since we are on a wrong stack, we cant make it a C code :( */ \
-       GET_THREAD_INFO(%ebp); \
-       movl TI_cpu(%ebp), %ebx; \
+       movl %gs:PDA_cpu, %ebx; \
        PER_CPU(cpu_gdt_descr, %ebx); \
        movl GDS_address(%ebx), %ebx; \
        GET_DESC_BASE(GDT_ENTRY_ESPFIX_SS, %ebx, %eax, %ax, %al, %ah); \
@@ -685,7 +710,7 @@ ENTRY(device_not_available)
        GET_CR0_INTO_EAX
        testl $0x4, %eax                # EM (math emulation bit)
        jne device_not_available_emulate
-       preempt_stop
+       preempt_stop(CLBR_ANY)
        call math_state_restore
        jmp ret_from_exception
 device_not_available_emulate:
@@ -832,6 +857,19 @@ nmi_espfix_stack:
 .previous
 KPROBE_END(nmi)
 
+#ifdef CONFIG_PARAVIRT
+ENTRY(native_iret)
+1:     iret
+.section __ex_table,"a"
+       .align 4
+       .long 1b,iret_exc
+.previous
+
+ENTRY(native_irq_enable_sysexit)
+       sti
+       sysexit
+#endif
+
 KPROBE_ENTRY(int3)
        RING0_INT_FRAME
        pushl $-1                       # mark this as an int
@@ -945,38 +983,6 @@ ENTRY(spurious_interrupt_bug)
        jmp error_code
        CFI_ENDPROC
 
-#ifdef CONFIG_STACK_UNWIND
-ENTRY(arch_unwind_init_running)
-       CFI_STARTPROC
-       movl    4(%esp), %edx
-       movl    (%esp), %ecx
-       leal    4(%esp), %eax
-       movl    %ebx, PT_EBX(%edx)
-       xorl    %ebx, %ebx
-       movl    %ebx, PT_ECX(%edx)
-       movl    %ebx, PT_EDX(%edx)
-       movl    %esi, PT_ESI(%edx)
-       movl    %edi, PT_EDI(%edx)
-       movl    %ebp, PT_EBP(%edx)
-       movl    %ebx, PT_EAX(%edx)
-       movl    $__USER_DS, PT_DS(%edx)
-       movl    $__USER_DS, PT_ES(%edx)
-       movl    $0, PT_GS(%edx)
-       movl    %ebx, PT_ORIG_EAX(%edx)
-       movl    %ecx, PT_EIP(%edx)
-       movl    12(%esp), %ecx
-       movl    $__KERNEL_CS, PT_CS(%edx)
-       movl    %ebx, PT_EFLAGS(%edx)
-       movl    %eax, PT_OLDESP(%edx)
-       movl    8(%esp), %eax
-       movl    %ecx, 8(%esp)
-       movl    PT_EBX(%edx), %ebx
-       movl    $__KERNEL_DS, PT_OLDSS(%edx)
-       jmpl    *%eax
-       CFI_ENDPROC
-ENDPROC(arch_unwind_init_running)
-#endif
-
 ENTRY(kernel_thread_helper)
        pushl $0                # fake return address for unwinder
        CFI_STARTPROC