diff options
Diffstat (limited to 'arch/arm/kernel/entry-common.S')
-rw-r--r-- | arch/arm/kernel/entry-common.S | 65 |
1 files changed, 44 insertions, 21 deletions
diff --git a/arch/arm/kernel/entry-common.S b/arch/arm/kernel/entry-common.S index 53a7e0dea44..3f8d0e3aefa 100644 --- a/arch/arm/kernel/entry-common.S +++ b/arch/arm/kernel/entry-common.S @@ -9,19 +9,10 @@ */ #include <linux/config.h> -#include <asm/thread_info.h> -#include <asm/ptrace.h> #include <asm/unistd.h> #include "entry-header.S" -/* - * We rely on the fact that R0 is at the bottom of the stack (due to - * slow/fast restore user regs). - */ -#if S_R0 != 0 -#error "Please fix" -#endif .align 5 /* @@ -30,11 +21,19 @@ * stack. */ ret_fast_syscall: - disable_irq r1 @ disable interrupts + disable_irq @ disable interrupts ldr r1, [tsk, #TI_FLAGS] tst r1, #_TIF_WORK_MASK bne fast_work_pending - fast_restore_user_regs + + @ fast_restore_user_regs + ldr r1, [sp, #S_OFF + S_PSR] @ get calling cpsr + ldr lr, [sp, #S_OFF + S_PC]! @ get pc + msr spsr_cxsf, r1 @ save in spsr_svc + ldmdb sp, {r1 - lr}^ @ get calling r1 - lr + mov r0, r0 + add sp, sp, #S_FRAME_SIZE - S_PC + movs pc, lr @ return & move spsr_svc into cpsr /* * Ok, we need to do extra processing, enter the slow path. @@ -49,7 +48,7 @@ work_pending: mov r0, sp @ 'regs' mov r2, why @ 'syscall' bl do_notify_resume - disable_irq r1 @ disable interrupts + disable_irq @ disable interrupts b no_work_pending work_resched: @@ -59,12 +58,19 @@ work_resched: */ ENTRY(ret_to_user) ret_slow_syscall: - disable_irq r1 @ disable interrupts + disable_irq @ disable interrupts ldr r1, [tsk, #TI_FLAGS] tst r1, #_TIF_WORK_MASK bne work_pending no_work_pending: - slow_restore_user_regs + @ slow_restore_user_regs + ldr r1, [sp, #S_PSR] @ get calling cpsr + ldr lr, [sp, #S_PC]! @ get pc + msr spsr_cxsf, r1 @ save in spsr_svc + ldmdb sp, {r0 - lr}^ @ get calling r1 - lr + mov r0, r0 + add sp, sp, #S_FRAME_SIZE - S_PC + movs pc, lr @ return & move spsr_svc into cpsr /* * This is how we return from a fork. @@ -116,9 +122,26 @@ ENTRY(ret_from_fork) .align 5 ENTRY(vector_swi) - save_user_regs + sub sp, sp, #S_FRAME_SIZE + stmia sp, {r0 - r12} @ Calling r0 - r12 + add r8, sp, #S_PC + stmdb r8, {sp, lr}^ @ Calling sp, lr + mrs r8, spsr @ called from non-FIQ mode, so ok. + str lr, [sp, #S_PC] @ Save calling PC + str r8, [sp, #S_PSR] @ Save CPSR + str r0, [sp, #S_OLD_R0] @ Save OLD_R0 zero_fp - get_scno + + /* + * Get the system call number. + */ +#ifdef CONFIG_ARM_THUMB + tst r8, #PSR_T_BIT @ this is SPSR from save_user_regs + addne scno, r7, #__NR_SYSCALL_BASE @ put OS number in + ldreq scno, [lr, #-4] +#else + ldr scno, [lr, #-4] @ get SWI instruction +#endif arm710_bug_check scno, ip #ifdef CONFIG_ALIGNMENT_TRAP @@ -126,14 +149,14 @@ ENTRY(vector_swi) ldr ip, [ip] mcr p15, 0, ip, c1, c0 @ update control register #endif - enable_irq ip + enable_irq str r4, [sp, #-S_OFF]! @ push fifth arg get_thread_info tsk ldr ip, [tsk, #TI_FLAGS] @ check for syscall tracing bic scno, scno, #0xff000000 @ mask off SWI op-code - eor scno, scno, #OS_NUMBER << 20 @ check OS number + eor scno, scno, #__NR_SYSCALL_BASE @ check OS number adr tbl, sys_call_table @ load syscall table pointer tst ip, #_TIF_SYSCALL_TRACE @ are we tracing syscalls? bne __sys_trace @@ -144,8 +167,8 @@ ENTRY(vector_swi) add r1, sp, #S_OFF 2: mov why, #0 @ no longer a real syscall - cmp scno, #ARMSWI_OFFSET - eor r0, scno, #OS_NUMBER << 20 @ put OS number back + cmp scno, #(__ARM_NR_BASE - __NR_SYSCALL_BASE) + eor r0, scno, #__NR_SYSCALL_BASE @ put OS number back bcs arm_syscall b sys_ni_syscall @ not private func @@ -190,7 +213,7 @@ ENTRY(sys_call_table) @ r5 = syscall table .type sys_syscall, #function sys_syscall: - eor scno, r0, #OS_NUMBER << 20 + eor scno, r0, #__NR_SYSCALL_BASE cmp scno, #__NR_syscall - __NR_SYSCALL_BASE cmpne scno, #NR_syscalls @ check range stmloia sp, {r5, r6} @ shuffle args |