11da177e4SLinus Torvalds/* 21da177e4SLinus Torvalds * linux/arch/arm/kernel/entry-common.S 31da177e4SLinus Torvalds * 41da177e4SLinus Torvalds * Copyright (C) 2000 Russell King 51da177e4SLinus Torvalds * 61da177e4SLinus Torvalds * This program is free software; you can redistribute it and/or modify 71da177e4SLinus Torvalds * it under the terms of the GNU General Public License version 2 as 81da177e4SLinus Torvalds * published by the Free Software Foundation. 91da177e4SLinus Torvalds */ 101da177e4SLinus Torvalds#include <linux/config.h> 111da177e4SLinus Torvalds 121da177e4SLinus Torvalds#include <asm/unistd.h> 131da177e4SLinus Torvalds 141da177e4SLinus Torvalds#include "entry-header.S" 151da177e4SLinus Torvalds 161da177e4SLinus Torvalds 171da177e4SLinus Torvalds .align 5 181da177e4SLinus Torvalds/* 191da177e4SLinus Torvalds * This is the fast syscall return path. We do as little as 201da177e4SLinus Torvalds * possible here, and this includes saving r0 back into the SVC 211da177e4SLinus Torvalds * stack. 221da177e4SLinus Torvalds */ 231da177e4SLinus Torvaldsret_fast_syscall: 241ec42c0cSRussell King disable_irq @ disable interrupts 251da177e4SLinus Torvalds ldr r1, [tsk, #TI_FLAGS] 261da177e4SLinus Torvalds tst r1, #_TIF_WORK_MASK 271da177e4SLinus Torvalds bne fast_work_pending 28f4dc9a4cSRussell King 29f4dc9a4cSRussell King @ fast_restore_user_regs 30f4dc9a4cSRussell King ldr r1, [sp, #S_OFF + S_PSR] @ get calling cpsr 31f4dc9a4cSRussell King ldr lr, [sp, #S_OFF + S_PC]! @ get pc 32f4dc9a4cSRussell King msr spsr_cxsf, r1 @ save in spsr_svc 33f4dc9a4cSRussell King ldmdb sp, {r1 - lr}^ @ get calling r1 - lr 34f4dc9a4cSRussell King mov r0, r0 35f4dc9a4cSRussell King add sp, sp, #S_FRAME_SIZE - S_PC 36f4dc9a4cSRussell King movs pc, lr @ return & move spsr_svc into cpsr 371da177e4SLinus Torvalds 381da177e4SLinus Torvalds/* 391da177e4SLinus Torvalds * Ok, we need to do extra processing, enter the slow path. 401da177e4SLinus Torvalds */ 411da177e4SLinus Torvaldsfast_work_pending: 421da177e4SLinus Torvalds str r0, [sp, #S_R0+S_OFF]! @ returned r0 431da177e4SLinus Torvaldswork_pending: 441da177e4SLinus Torvalds tst r1, #_TIF_NEED_RESCHED 451da177e4SLinus Torvalds bne work_resched 461da177e4SLinus Torvalds tst r1, #_TIF_NOTIFY_RESUME | _TIF_SIGPENDING 471da177e4SLinus Torvalds beq no_work_pending 481da177e4SLinus Torvalds mov r0, sp @ 'regs' 491da177e4SLinus Torvalds mov r2, why @ 'syscall' 501da177e4SLinus Torvalds bl do_notify_resume 511ec42c0cSRussell King disable_irq @ disable interrupts 521da177e4SLinus Torvalds b no_work_pending 531da177e4SLinus Torvalds 541da177e4SLinus Torvaldswork_resched: 551da177e4SLinus Torvalds bl schedule 561da177e4SLinus Torvalds/* 571da177e4SLinus Torvalds * "slow" syscall return path. "why" tells us if this was a real syscall. 581da177e4SLinus Torvalds */ 591da177e4SLinus TorvaldsENTRY(ret_to_user) 601da177e4SLinus Torvaldsret_slow_syscall: 611ec42c0cSRussell King disable_irq @ disable interrupts 621da177e4SLinus Torvalds ldr r1, [tsk, #TI_FLAGS] 631da177e4SLinus Torvalds tst r1, #_TIF_WORK_MASK 641da177e4SLinus Torvalds bne work_pending 651da177e4SLinus Torvaldsno_work_pending: 66f4dc9a4cSRussell King @ slow_restore_user_regs 67f4dc9a4cSRussell King ldr r1, [sp, #S_PSR] @ get calling cpsr 68f4dc9a4cSRussell King ldr lr, [sp, #S_PC]! @ get pc 69f4dc9a4cSRussell King msr spsr_cxsf, r1 @ save in spsr_svc 70f4dc9a4cSRussell King ldmdb sp, {r0 - lr}^ @ get calling r1 - lr 71f4dc9a4cSRussell King mov r0, r0 72f4dc9a4cSRussell King add sp, sp, #S_FRAME_SIZE - S_PC 73f4dc9a4cSRussell King movs pc, lr @ return & move spsr_svc into cpsr 741da177e4SLinus Torvalds 751da177e4SLinus Torvalds/* 761da177e4SLinus Torvalds * This is how we return from a fork. 771da177e4SLinus Torvalds */ 781da177e4SLinus TorvaldsENTRY(ret_from_fork) 791da177e4SLinus Torvalds bl schedule_tail 801da177e4SLinus Torvalds get_thread_info tsk 811da177e4SLinus Torvalds ldr r1, [tsk, #TI_FLAGS] @ check for syscall tracing 821da177e4SLinus Torvalds mov why, #1 831da177e4SLinus Torvalds tst r1, #_TIF_SYSCALL_TRACE @ are we tracing syscalls? 841da177e4SLinus Torvalds beq ret_slow_syscall 851da177e4SLinus Torvalds mov r1, sp 861da177e4SLinus Torvalds mov r0, #1 @ trace exit [IP = 1] 871da177e4SLinus Torvalds bl syscall_trace 881da177e4SLinus Torvalds b ret_slow_syscall 891da177e4SLinus Torvalds 901da177e4SLinus Torvalds 911da177e4SLinus Torvalds#include "calls.S" 921da177e4SLinus Torvalds 931da177e4SLinus Torvalds/*============================================================================= 941da177e4SLinus Torvalds * SWI handler 951da177e4SLinus Torvalds *----------------------------------------------------------------------------- 961da177e4SLinus Torvalds */ 971da177e4SLinus Torvalds 981da177e4SLinus Torvalds /* If we're optimising for StrongARM the resulting code won't 991da177e4SLinus Torvalds run on an ARM7 and we can save a couple of instructions. 1001da177e4SLinus Torvalds --pb */ 1011da177e4SLinus Torvalds#ifdef CONFIG_CPU_ARM710 1021da177e4SLinus Torvalds .macro arm710_bug_check, instr, temp 1031da177e4SLinus Torvalds and \temp, \instr, #0x0f000000 @ check for SWI 1041da177e4SLinus Torvalds teq \temp, #0x0f000000 1051da177e4SLinus Torvalds bne .Larm700bug 1061da177e4SLinus Torvalds .endm 1071da177e4SLinus Torvalds 1081da177e4SLinus Torvalds.Larm700bug: 1091da177e4SLinus Torvalds ldr r0, [sp, #S_PSR] @ Get calling cpsr 1101da177e4SLinus Torvalds sub lr, lr, #4 1111da177e4SLinus Torvalds str lr, [r8] 1121da177e4SLinus Torvalds msr spsr_cxsf, r0 1131da177e4SLinus Torvalds ldmia sp, {r0 - lr}^ @ Get calling r0 - lr 1141da177e4SLinus Torvalds mov r0, r0 1151da177e4SLinus Torvalds ldr lr, [sp, #S_PC] @ Get PC 1161da177e4SLinus Torvalds add sp, sp, #S_FRAME_SIZE 1171da177e4SLinus Torvalds movs pc, lr 1181da177e4SLinus Torvalds#else 1191da177e4SLinus Torvalds .macro arm710_bug_check, instr, temp 1201da177e4SLinus Torvalds .endm 1211da177e4SLinus Torvalds#endif 1221da177e4SLinus Torvalds 1231da177e4SLinus Torvalds .align 5 1241da177e4SLinus TorvaldsENTRY(vector_swi) 125f4dc9a4cSRussell King sub sp, sp, #S_FRAME_SIZE 126f4dc9a4cSRussell King stmia sp, {r0 - r12} @ Calling r0 - r12 127f4dc9a4cSRussell King add r8, sp, #S_PC 128f4dc9a4cSRussell King stmdb r8, {sp, lr}^ @ Calling sp, lr 129f4dc9a4cSRussell King mrs r8, spsr @ called from non-FIQ mode, so ok. 130f4dc9a4cSRussell King str lr, [sp, #S_PC] @ Save calling PC 131f4dc9a4cSRussell King str r8, [sp, #S_PSR] @ Save CPSR 132f4dc9a4cSRussell King str r0, [sp, #S_OLD_R0] @ Save OLD_R0 1331da177e4SLinus Torvalds zero_fp 134e0f9f4a6SRussell King 135e0f9f4a6SRussell King /* 136e0f9f4a6SRussell King * Get the system call number. 137e0f9f4a6SRussell King */ 138e0f9f4a6SRussell King#ifdef CONFIG_ARM_THUMB 139e0f9f4a6SRussell King tst r8, #PSR_T_BIT @ this is SPSR from save_user_regs 140e0f9f4a6SRussell King addne scno, r7, #__NR_SYSCALL_BASE @ put OS number in 141e0f9f4a6SRussell King ldreq scno, [lr, #-4] 142e0f9f4a6SRussell King#else 143e0f9f4a6SRussell King ldr scno, [lr, #-4] @ get SWI instruction 144e0f9f4a6SRussell King#endif 1451da177e4SLinus Torvalds arm710_bug_check scno, ip 1461da177e4SLinus Torvalds 1471da177e4SLinus Torvalds#ifdef CONFIG_ALIGNMENT_TRAP 1481da177e4SLinus Torvalds ldr ip, __cr_alignment 1491da177e4SLinus Torvalds ldr ip, [ip] 1501da177e4SLinus Torvalds mcr p15, 0, ip, c1, c0 @ update control register 1511da177e4SLinus Torvalds#endif 1521ec42c0cSRussell King enable_irq 1531da177e4SLinus Torvalds 1541da177e4SLinus Torvalds str r4, [sp, #-S_OFF]! @ push fifth arg 1551da177e4SLinus Torvalds 1561da177e4SLinus Torvalds get_thread_info tsk 1571da177e4SLinus Torvalds ldr ip, [tsk, #TI_FLAGS] @ check for syscall tracing 1581da177e4SLinus Torvalds bic scno, scno, #0xff000000 @ mask off SWI op-code 159e0f9f4a6SRussell King eor scno, scno, #__NR_SYSCALL_BASE @ check OS number 1601da177e4SLinus Torvalds adr tbl, sys_call_table @ load syscall table pointer 1611da177e4SLinus Torvalds tst ip, #_TIF_SYSCALL_TRACE @ are we tracing syscalls? 1621da177e4SLinus Torvalds bne __sys_trace 1631da177e4SLinus Torvalds 1641da177e4SLinus Torvalds adr lr, ret_fast_syscall @ return address 1651da177e4SLinus Torvalds cmp scno, #NR_syscalls @ check upper syscall limit 1661da177e4SLinus Torvalds ldrcc pc, [tbl, scno, lsl #2] @ call sys_* routine 1671da177e4SLinus Torvalds 1681da177e4SLinus Torvalds add r1, sp, #S_OFF 1691da177e4SLinus Torvalds2: mov why, #0 @ no longer a real syscall 170e0f9f4a6SRussell King cmp scno, #(__ARM_NR_BASE - __NR_SYSCALL_BASE) 171e0f9f4a6SRussell King eor r0, scno, #__NR_SYSCALL_BASE @ put OS number back 1721da177e4SLinus Torvalds bcs arm_syscall 1731da177e4SLinus Torvalds b sys_ni_syscall @ not private func 1741da177e4SLinus Torvalds 1751da177e4SLinus Torvalds /* 1761da177e4SLinus Torvalds * This is the really slow path. We're going to be doing 1771da177e4SLinus Torvalds * context switches, and waiting for our parent to respond. 1781da177e4SLinus Torvalds */ 1791da177e4SLinus Torvalds__sys_trace: 1801da177e4SLinus Torvalds add r1, sp, #S_OFF 1811da177e4SLinus Torvalds mov r0, #0 @ trace entry [IP = 0] 1821da177e4SLinus Torvalds bl syscall_trace 1831da177e4SLinus Torvalds 1841da177e4SLinus Torvalds adr lr, __sys_trace_return @ return address 1851da177e4SLinus Torvalds add r1, sp, #S_R0 + S_OFF @ pointer to regs 1861da177e4SLinus Torvalds cmp scno, #NR_syscalls @ check upper syscall limit 1871da177e4SLinus Torvalds ldmccia r1, {r0 - r3} @ have to reload r0 - r3 1881da177e4SLinus Torvalds ldrcc pc, [tbl, scno, lsl #2] @ call sys_* routine 1891da177e4SLinus Torvalds b 2b 1901da177e4SLinus Torvalds 1911da177e4SLinus Torvalds__sys_trace_return: 1921da177e4SLinus Torvalds str r0, [sp, #S_R0 + S_OFF]! @ save returned r0 1931da177e4SLinus Torvalds mov r1, sp 1941da177e4SLinus Torvalds mov r0, #1 @ trace exit [IP = 1] 1951da177e4SLinus Torvalds bl syscall_trace 1961da177e4SLinus Torvalds b ret_slow_syscall 1971da177e4SLinus Torvalds 1981da177e4SLinus Torvalds .align 5 1991da177e4SLinus Torvalds#ifdef CONFIG_ALIGNMENT_TRAP 2001da177e4SLinus Torvalds .type __cr_alignment, #object 2011da177e4SLinus Torvalds__cr_alignment: 2021da177e4SLinus Torvalds .word cr_alignment 2031da177e4SLinus Torvalds#endif 2041da177e4SLinus Torvalds 2051da177e4SLinus Torvalds .type sys_call_table, #object 2061da177e4SLinus TorvaldsENTRY(sys_call_table) 2071da177e4SLinus Torvalds#include "calls.S" 2081da177e4SLinus Torvalds 2091da177e4SLinus Torvalds/*============================================================================ 2101da177e4SLinus Torvalds * Special system call wrappers 2111da177e4SLinus Torvalds */ 2121da177e4SLinus Torvalds@ r0 = syscall number 2131da177e4SLinus Torvalds@ r5 = syscall table 2141da177e4SLinus Torvalds .type sys_syscall, #function 2151da177e4SLinus Torvaldssys_syscall: 216e0f9f4a6SRussell King eor scno, r0, #__NR_SYSCALL_BASE 2171da177e4SLinus Torvalds cmp scno, #__NR_syscall - __NR_SYSCALL_BASE 2181da177e4SLinus Torvalds cmpne scno, #NR_syscalls @ check range 2191da177e4SLinus Torvalds stmloia sp, {r5, r6} @ shuffle args 2201da177e4SLinus Torvalds movlo r0, r1 2211da177e4SLinus Torvalds movlo r1, r2 2221da177e4SLinus Torvalds movlo r2, r3 2231da177e4SLinus Torvalds movlo r3, r4 2241da177e4SLinus Torvalds ldrlo pc, [tbl, scno, lsl #2] 2251da177e4SLinus Torvalds b sys_ni_syscall 2261da177e4SLinus Torvalds 2271da177e4SLinus Torvaldssys_fork_wrapper: 2281da177e4SLinus Torvalds add r0, sp, #S_OFF 2291da177e4SLinus Torvalds b sys_fork 2301da177e4SLinus Torvalds 2311da177e4SLinus Torvaldssys_vfork_wrapper: 2321da177e4SLinus Torvalds add r0, sp, #S_OFF 2331da177e4SLinus Torvalds b sys_vfork 2341da177e4SLinus Torvalds 2351da177e4SLinus Torvaldssys_execve_wrapper: 2361da177e4SLinus Torvalds add r3, sp, #S_OFF 2371da177e4SLinus Torvalds b sys_execve 2381da177e4SLinus Torvalds 2391da177e4SLinus Torvaldssys_clone_wrapper: 2401da177e4SLinus Torvalds add ip, sp, #S_OFF 2411da177e4SLinus Torvalds str ip, [sp, #4] 2421da177e4SLinus Torvalds b sys_clone 2431da177e4SLinus Torvalds 2441da177e4SLinus Torvaldssys_sigsuspend_wrapper: 2451da177e4SLinus Torvalds add r3, sp, #S_OFF 2461da177e4SLinus Torvalds b sys_sigsuspend 2471da177e4SLinus Torvalds 2481da177e4SLinus Torvaldssys_rt_sigsuspend_wrapper: 2491da177e4SLinus Torvalds add r2, sp, #S_OFF 2501da177e4SLinus Torvalds b sys_rt_sigsuspend 2511da177e4SLinus Torvalds 2521da177e4SLinus Torvaldssys_sigreturn_wrapper: 2531da177e4SLinus Torvalds add r0, sp, #S_OFF 2541da177e4SLinus Torvalds b sys_sigreturn 2551da177e4SLinus Torvalds 2561da177e4SLinus Torvaldssys_rt_sigreturn_wrapper: 2571da177e4SLinus Torvalds add r0, sp, #S_OFF 2581da177e4SLinus Torvalds b sys_rt_sigreturn 2591da177e4SLinus Torvalds 2601da177e4SLinus Torvaldssys_sigaltstack_wrapper: 2611da177e4SLinus Torvalds ldr r2, [sp, #S_OFF + S_SP] 2621da177e4SLinus Torvalds b do_sigaltstack 2631da177e4SLinus Torvalds 2641da177e4SLinus Torvaldssys_futex_wrapper: 2651da177e4SLinus Torvalds str r5, [sp, #4] @ push sixth arg 2661da177e4SLinus Torvalds b sys_futex 2671da177e4SLinus Torvalds 26868d9102fSNicolas Pitresys_arm_fadvise64_64_wrapper: 26968d9102fSNicolas Pitre str r5, [sp, #4] @ push r5 to stack 27068d9102fSNicolas Pitre b sys_arm_fadvise64_64 27168d9102fSNicolas Pitre 2729b9eb8c0SRussell Kingsys_mbind_wrapper: 2739b9eb8c0SRussell King str r5, [sp, #4] 2749b9eb8c0SRussell King b sys_mbind 2759b9eb8c0SRussell King 27634f521fdSGeorge G. Davissys_ipc_wrapper: 27734f521fdSGeorge G. Davis str r5, [sp, #4] @ push sixth arg 27834f521fdSGeorge G. Davis b sys_ipc 27934f521fdSGeorge G. Davis 2801da177e4SLinus Torvalds/* 2811da177e4SLinus Torvalds * Note: off_4k (r5) is always units of 4K. If we can't do the requested 2821da177e4SLinus Torvalds * offset, we return EINVAL. 2831da177e4SLinus Torvalds */ 2841da177e4SLinus Torvaldssys_mmap2: 2851da177e4SLinus Torvalds#if PAGE_SHIFT > 12 2861da177e4SLinus Torvalds tst r5, #PGOFF_MASK 2871da177e4SLinus Torvalds moveq r5, r5, lsr #PAGE_SHIFT - 12 2881da177e4SLinus Torvalds streq r5, [sp, #4] 2891da177e4SLinus Torvalds beq do_mmap2 2901da177e4SLinus Torvalds mov r0, #-EINVAL 2911da177e4SLinus Torvalds RETINSTR(mov,pc, lr) 2921da177e4SLinus Torvalds#else 2931da177e4SLinus Torvalds str r5, [sp, #4] 2941da177e4SLinus Torvalds b do_mmap2 2951da177e4SLinus Torvalds#endif 296