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 51a6c61e9dSDaniel Jacobowitz b ret_slow_syscall @ Check work again 521da177e4SLinus Torvalds 531da177e4SLinus Torvaldswork_resched: 541da177e4SLinus Torvalds bl schedule 551da177e4SLinus Torvalds/* 561da177e4SLinus Torvalds * "slow" syscall return path. "why" tells us if this was a real syscall. 571da177e4SLinus Torvalds */ 581da177e4SLinus TorvaldsENTRY(ret_to_user) 591da177e4SLinus Torvaldsret_slow_syscall: 601ec42c0cSRussell King disable_irq @ disable interrupts 611da177e4SLinus Torvalds ldr r1, [tsk, #TI_FLAGS] 621da177e4SLinus Torvalds tst r1, #_TIF_WORK_MASK 631da177e4SLinus Torvalds bne work_pending 641da177e4SLinus Torvaldsno_work_pending: 65f4dc9a4cSRussell King @ slow_restore_user_regs 66f4dc9a4cSRussell King ldr r1, [sp, #S_PSR] @ get calling cpsr 67f4dc9a4cSRussell King ldr lr, [sp, #S_PC]! @ get pc 68f4dc9a4cSRussell King msr spsr_cxsf, r1 @ save in spsr_svc 69f4dc9a4cSRussell King ldmdb sp, {r0 - lr}^ @ get calling r1 - lr 70f4dc9a4cSRussell King mov r0, r0 71f4dc9a4cSRussell King add sp, sp, #S_FRAME_SIZE - S_PC 72f4dc9a4cSRussell King movs pc, lr @ return & move spsr_svc into cpsr 731da177e4SLinus Torvalds 741da177e4SLinus Torvalds/* 751da177e4SLinus Torvalds * This is how we return from a fork. 761da177e4SLinus Torvalds */ 771da177e4SLinus TorvaldsENTRY(ret_from_fork) 781da177e4SLinus Torvalds bl schedule_tail 791da177e4SLinus Torvalds get_thread_info tsk 801da177e4SLinus Torvalds ldr r1, [tsk, #TI_FLAGS] @ check for syscall tracing 811da177e4SLinus Torvalds mov why, #1 821da177e4SLinus Torvalds tst r1, #_TIF_SYSCALL_TRACE @ are we tracing syscalls? 831da177e4SLinus Torvalds beq ret_slow_syscall 841da177e4SLinus Torvalds mov r1, sp 851da177e4SLinus Torvalds mov r0, #1 @ trace exit [IP = 1] 861da177e4SLinus Torvalds bl syscall_trace 871da177e4SLinus Torvalds b ret_slow_syscall 881da177e4SLinus Torvalds 891da177e4SLinus Torvalds 901da177e4SLinus Torvalds#include "calls.S" 911da177e4SLinus Torvalds 921da177e4SLinus Torvalds/*============================================================================= 931da177e4SLinus Torvalds * SWI handler 941da177e4SLinus Torvalds *----------------------------------------------------------------------------- 951da177e4SLinus Torvalds */ 961da177e4SLinus Torvalds 971da177e4SLinus Torvalds /* If we're optimising for StrongARM the resulting code won't 981da177e4SLinus Torvalds run on an ARM7 and we can save a couple of instructions. 991da177e4SLinus Torvalds --pb */ 1001da177e4SLinus Torvalds#ifdef CONFIG_CPU_ARM710 1011da177e4SLinus Torvalds .macro arm710_bug_check, instr, temp 1021da177e4SLinus Torvalds and \temp, \instr, #0x0f000000 @ check for SWI 1031da177e4SLinus Torvalds teq \temp, #0x0f000000 1041da177e4SLinus Torvalds bne .Larm700bug 1051da177e4SLinus Torvalds .endm 1061da177e4SLinus Torvalds 1071da177e4SLinus Torvalds.Larm700bug: 1081da177e4SLinus Torvalds ldmia sp, {r0 - lr}^ @ Get calling r0 - lr 1091da177e4SLinus Torvalds mov r0, r0 1101da177e4SLinus Torvalds add sp, sp, #S_FRAME_SIZE 11160ac133aSNicolas Pitre subs pc, lr, #4 1121da177e4SLinus Torvalds#else 1131da177e4SLinus Torvalds .macro arm710_bug_check, instr, temp 1141da177e4SLinus Torvalds .endm 1151da177e4SLinus Torvalds#endif 1161da177e4SLinus Torvalds 1171da177e4SLinus Torvalds .align 5 1181da177e4SLinus TorvaldsENTRY(vector_swi) 119f4dc9a4cSRussell King sub sp, sp, #S_FRAME_SIZE 120f4dc9a4cSRussell King stmia sp, {r0 - r12} @ Calling r0 - r12 121f4dc9a4cSRussell King add r8, sp, #S_PC 122f4dc9a4cSRussell King stmdb r8, {sp, lr}^ @ Calling sp, lr 123f4dc9a4cSRussell King mrs r8, spsr @ called from non-FIQ mode, so ok. 124f4dc9a4cSRussell King str lr, [sp, #S_PC] @ Save calling PC 125f4dc9a4cSRussell King str r8, [sp, #S_PSR] @ Save CPSR 126f4dc9a4cSRussell King str r0, [sp, #S_OLD_R0] @ Save OLD_R0 1271da177e4SLinus Torvalds zero_fp 128e0f9f4a6SRussell King 129e0f9f4a6SRussell King /* 130e0f9f4a6SRussell King * Get the system call number. 131e0f9f4a6SRussell King */ 132e0f9f4a6SRussell King#ifdef CONFIG_ARM_THUMB 133e0f9f4a6SRussell King tst r8, #PSR_T_BIT @ this is SPSR from save_user_regs 134e0f9f4a6SRussell King addne scno, r7, #__NR_SYSCALL_BASE @ put OS number in 135e0f9f4a6SRussell King ldreq scno, [lr, #-4] 136e0f9f4a6SRussell King#else 137e0f9f4a6SRussell King ldr scno, [lr, #-4] @ get SWI instruction 138e0f9f4a6SRussell King#endif 1391da177e4SLinus Torvalds arm710_bug_check scno, ip 1401da177e4SLinus Torvalds 1411da177e4SLinus Torvalds#ifdef CONFIG_ALIGNMENT_TRAP 1421da177e4SLinus Torvalds ldr ip, __cr_alignment 1431da177e4SLinus Torvalds ldr ip, [ip] 1441da177e4SLinus Torvalds mcr p15, 0, ip, c1, c0 @ update control register 1451da177e4SLinus Torvalds#endif 1461ec42c0cSRussell King enable_irq 1471da177e4SLinus Torvalds 1481da177e4SLinus Torvalds str r4, [sp, #-S_OFF]! @ push fifth arg 1491da177e4SLinus Torvalds 1501da177e4SLinus Torvalds get_thread_info tsk 1511da177e4SLinus Torvalds ldr ip, [tsk, #TI_FLAGS] @ check for syscall tracing 1521da177e4SLinus Torvalds bic scno, scno, #0xff000000 @ mask off SWI op-code 153e0f9f4a6SRussell King eor scno, scno, #__NR_SYSCALL_BASE @ check OS number 1541da177e4SLinus Torvalds adr tbl, sys_call_table @ load syscall table pointer 1551da177e4SLinus Torvalds tst ip, #_TIF_SYSCALL_TRACE @ are we tracing syscalls? 1561da177e4SLinus Torvalds bne __sys_trace 1571da177e4SLinus Torvalds 1581da177e4SLinus Torvalds adr lr, ret_fast_syscall @ return address 1591da177e4SLinus Torvalds cmp scno, #NR_syscalls @ check upper syscall limit 1601da177e4SLinus Torvalds ldrcc pc, [tbl, scno, lsl #2] @ call sys_* routine 1611da177e4SLinus Torvalds 1621da177e4SLinus Torvalds add r1, sp, #S_OFF 1631da177e4SLinus Torvalds2: mov why, #0 @ no longer a real syscall 164e0f9f4a6SRussell King cmp scno, #(__ARM_NR_BASE - __NR_SYSCALL_BASE) 165e0f9f4a6SRussell King eor r0, scno, #__NR_SYSCALL_BASE @ put OS number back 1661da177e4SLinus Torvalds bcs arm_syscall 1671da177e4SLinus Torvalds b sys_ni_syscall @ not private func 1681da177e4SLinus Torvalds 1691da177e4SLinus Torvalds /* 1701da177e4SLinus Torvalds * This is the really slow path. We're going to be doing 1711da177e4SLinus Torvalds * context switches, and waiting for our parent to respond. 1721da177e4SLinus Torvalds */ 1731da177e4SLinus Torvalds__sys_trace: 1741da177e4SLinus Torvalds add r1, sp, #S_OFF 1751da177e4SLinus Torvalds mov r0, #0 @ trace entry [IP = 0] 1761da177e4SLinus Torvalds bl syscall_trace 1771da177e4SLinus Torvalds 1781da177e4SLinus Torvalds adr lr, __sys_trace_return @ return address 1791da177e4SLinus Torvalds add r1, sp, #S_R0 + S_OFF @ pointer to regs 1801da177e4SLinus Torvalds cmp scno, #NR_syscalls @ check upper syscall limit 1811da177e4SLinus Torvalds ldmccia r1, {r0 - r3} @ have to reload r0 - r3 1821da177e4SLinus Torvalds ldrcc pc, [tbl, scno, lsl #2] @ call sys_* routine 1831da177e4SLinus Torvalds b 2b 1841da177e4SLinus Torvalds 1851da177e4SLinus Torvalds__sys_trace_return: 1861da177e4SLinus Torvalds str r0, [sp, #S_R0 + S_OFF]! @ save returned r0 1871da177e4SLinus Torvalds mov r1, sp 1881da177e4SLinus Torvalds mov r0, #1 @ trace exit [IP = 1] 1891da177e4SLinus Torvalds bl syscall_trace 1901da177e4SLinus Torvalds b ret_slow_syscall 1911da177e4SLinus Torvalds 1921da177e4SLinus Torvalds .align 5 1931da177e4SLinus Torvalds#ifdef CONFIG_ALIGNMENT_TRAP 1941da177e4SLinus Torvalds .type __cr_alignment, #object 1951da177e4SLinus Torvalds__cr_alignment: 1961da177e4SLinus Torvalds .word cr_alignment 1971da177e4SLinus Torvalds#endif 1981da177e4SLinus Torvalds 1991da177e4SLinus Torvalds .type sys_call_table, #object 2001da177e4SLinus TorvaldsENTRY(sys_call_table) 2011da177e4SLinus Torvalds#include "calls.S" 2021da177e4SLinus Torvalds 2031da177e4SLinus Torvalds/*============================================================================ 2041da177e4SLinus Torvalds * Special system call wrappers 2051da177e4SLinus Torvalds */ 2061da177e4SLinus Torvalds@ r0 = syscall number 2071da177e4SLinus Torvalds@ r5 = syscall table 2081da177e4SLinus Torvalds .type sys_syscall, #function 2091da177e4SLinus Torvaldssys_syscall: 210e0f9f4a6SRussell King eor scno, r0, #__NR_SYSCALL_BASE 2111da177e4SLinus Torvalds cmp scno, #__NR_syscall - __NR_SYSCALL_BASE 2121da177e4SLinus Torvalds cmpne scno, #NR_syscalls @ check range 2131da177e4SLinus Torvalds stmloia sp, {r5, r6} @ shuffle args 2141da177e4SLinus Torvalds movlo r0, r1 2151da177e4SLinus Torvalds movlo r1, r2 2161da177e4SLinus Torvalds movlo r2, r3 2171da177e4SLinus Torvalds movlo r3, r4 2181da177e4SLinus Torvalds ldrlo pc, [tbl, scno, lsl #2] 2191da177e4SLinus Torvalds b sys_ni_syscall 2201da177e4SLinus Torvalds 2211da177e4SLinus Torvaldssys_fork_wrapper: 2221da177e4SLinus Torvalds add r0, sp, #S_OFF 2231da177e4SLinus Torvalds b sys_fork 2241da177e4SLinus Torvalds 2251da177e4SLinus Torvaldssys_vfork_wrapper: 2261da177e4SLinus Torvalds add r0, sp, #S_OFF 2271da177e4SLinus Torvalds b sys_vfork 2281da177e4SLinus Torvalds 2291da177e4SLinus Torvaldssys_execve_wrapper: 2301da177e4SLinus Torvalds add r3, sp, #S_OFF 2311da177e4SLinus Torvalds b sys_execve 2321da177e4SLinus Torvalds 2331da177e4SLinus Torvaldssys_clone_wrapper: 2341da177e4SLinus Torvalds add ip, sp, #S_OFF 2351da177e4SLinus Torvalds str ip, [sp, #4] 2361da177e4SLinus Torvalds b sys_clone 2371da177e4SLinus Torvalds 2381da177e4SLinus Torvaldssys_sigsuspend_wrapper: 2391da177e4SLinus Torvalds add r3, sp, #S_OFF 2401da177e4SLinus Torvalds b sys_sigsuspend 2411da177e4SLinus Torvalds 2421da177e4SLinus Torvaldssys_rt_sigsuspend_wrapper: 2431da177e4SLinus Torvalds add r2, sp, #S_OFF 2441da177e4SLinus Torvalds b sys_rt_sigsuspend 2451da177e4SLinus Torvalds 2461da177e4SLinus Torvaldssys_sigreturn_wrapper: 2471da177e4SLinus Torvalds add r0, sp, #S_OFF 2481da177e4SLinus Torvalds b sys_sigreturn 2491da177e4SLinus Torvalds 2501da177e4SLinus Torvaldssys_rt_sigreturn_wrapper: 2511da177e4SLinus Torvalds add r0, sp, #S_OFF 2521da177e4SLinus Torvalds b sys_rt_sigreturn 2531da177e4SLinus Torvalds 2541da177e4SLinus Torvaldssys_sigaltstack_wrapper: 2551da177e4SLinus Torvalds ldr r2, [sp, #S_OFF + S_SP] 2561da177e4SLinus Torvalds b do_sigaltstack 2571da177e4SLinus Torvalds 2581da177e4SLinus Torvaldssys_futex_wrapper: 2591da177e4SLinus Torvalds str r5, [sp, #4] @ push sixth arg 2601da177e4SLinus Torvalds b sys_futex 2611da177e4SLinus Torvalds 26268d9102fSNicolas Pitresys_arm_fadvise64_64_wrapper: 26368d9102fSNicolas Pitre str r5, [sp, #4] @ push r5 to stack 26468d9102fSNicolas Pitre b sys_arm_fadvise64_64 26568d9102fSNicolas Pitre 2669b9eb8c0SRussell Kingsys_mbind_wrapper: 2679b9eb8c0SRussell King str r5, [sp, #4] 2689b9eb8c0SRussell King b sys_mbind 2699b9eb8c0SRussell King 27034f521fdSGeorge G. Davissys_ipc_wrapper: 27134f521fdSGeorge G. Davis str r5, [sp, #4] @ push sixth arg 27234f521fdSGeorge G. Davis b sys_ipc 27334f521fdSGeorge G. Davis 2741da177e4SLinus Torvalds/* 2751da177e4SLinus Torvalds * Note: off_4k (r5) is always units of 4K. If we can't do the requested 2761da177e4SLinus Torvalds * offset, we return EINVAL. 2771da177e4SLinus Torvalds */ 2781da177e4SLinus Torvaldssys_mmap2: 2791da177e4SLinus Torvalds#if PAGE_SHIFT > 12 2801da177e4SLinus Torvalds tst r5, #PGOFF_MASK 2811da177e4SLinus Torvalds moveq r5, r5, lsr #PAGE_SHIFT - 12 2821da177e4SLinus Torvalds streq r5, [sp, #4] 2831da177e4SLinus Torvalds beq do_mmap2 2841da177e4SLinus Torvalds mov r0, #-EINVAL 2851da177e4SLinus Torvalds RETINSTR(mov,pc, lr) 2861da177e4SLinus Torvalds#else 2871da177e4SLinus Torvalds str r5, [sp, #4] 2881da177e4SLinus Torvalds b do_mmap2 2891da177e4SLinus Torvalds#endif 290