Commit 3f2829a3 authored by Nicolas Pitre's avatar Nicolas Pitre Committed by Russell King

[ARM] 3105/4: ARM EABI: new syscall entry convention

Patch from Nicolas Pitre

For a while we wanted to change the way syscalls were called on ARM.
Instead of encoding the syscall number in the swi instruction which
requires reading back the instruction from memory to extract that number
and polluting the data cache, it was decided that simply storing the
syscall number into r7 would be more efficient. Since this represents
an ABI change then making that change at the same time as EABI support
is the right thing to do.

It is now expected that EABI user space binaries put the syscall number
into r7 and use "swi 0" to call the kernel. Syscall register argument
are also expected to have "EABI arrangement" i.e. 64-bit arguments
should be put in a pair of registers from an even register number.

Example with long ftruncate64(unsigned int fd, loff_t length):

	legacy ABI:
	- put fd into r0
	- put length into r1-r2
	- use "swi #(0x900000 + 194)" to call the kernel

	new ARM EABI:
	- put fd into r0
	- put length into r2-r3 (skipping over r1)
	- put 194 into r7
	- use "swi 0" to call the kernel

Note that it is important to use 0 for the swi argument as backward
compatibility with legacy ABI user space relies on this.
The syscall macros in asm-arm/unistd.h were also updated to support
both ABIs and implement the right call method automatically.
Signed-off-by: default avatarNicolas Pitre <nico@cam.org>
Signed-off-by: default avatarRussell King <rmk+kernel@arm.linux.org.uk>
parent ba95e4e4
...@@ -98,20 +98,14 @@ ENTRY(ret_from_fork) ...@@ -98,20 +98,14 @@ ENTRY(ret_from_fork)
run on an ARM7 and we can save a couple of instructions. run on an ARM7 and we can save a couple of instructions.
--pb */ --pb */
#ifdef CONFIG_CPU_ARM710 #ifdef CONFIG_CPU_ARM710
.macro arm710_bug_check, instr, temp #define A710(code...) code
and \temp, \instr, #0x0f000000 @ check for SWI .Larm710bug:
teq \temp, #0x0f000000
bne .Larm700bug
.endm
.Larm700bug:
ldmia sp, {r0 - lr}^ @ Get calling r0 - lr ldmia sp, {r0 - lr}^ @ Get calling r0 - lr
mov r0, r0 mov r0, r0
add sp, sp, #S_FRAME_SIZE add sp, sp, #S_FRAME_SIZE
subs pc, lr, #4 subs pc, lr, #4
#else #else
.macro arm710_bug_check, instr, temp #define A710(code...)
.endm
#endif #endif
.align 5 .align 5
...@@ -129,14 +123,24 @@ ENTRY(vector_swi) ...@@ -129,14 +123,24 @@ ENTRY(vector_swi)
/* /*
* Get the system call number. * Get the system call number.
*/ */
#ifdef CONFIG_ARM_THUMB #if defined(CONFIG_AEABI)
@ syscall number is in scno (r7) already.
A710( ldr ip, [lr, #-4] @ get SWI instruction )
A710( and ip, ip, #0x0f000000 @ check for SWI )
A710( teq ip, #0x0f000000 )
A710( bne .Larm710bug )
#elif defined(CONFIG_ARM_THUMB)
tst r8, #PSR_T_BIT @ this is SPSR from save_user_regs tst r8, #PSR_T_BIT @ this is SPSR from save_user_regs
addne scno, r7, #__NR_SYSCALL_BASE @ put OS number in addne scno, r7, #__NR_SYSCALL_BASE @ put OS number in
ldreq scno, [lr, #-4] ldreq scno, [lr, #-4]
#else #else
ldr scno, [lr, #-4] @ get SWI instruction ldr scno, [lr, #-4] @ get SWI instruction
A710( and ip, scno, #0x0f000000 @ check for SWI )
A710( teq ip, #0x0f000000 )
A710( bne .Larm710bug )
#endif #endif
arm710_bug_check scno, ip
#ifdef CONFIG_ALIGNMENT_TRAP #ifdef CONFIG_ALIGNMENT_TRAP
ldr ip, __cr_alignment ldr ip, __cr_alignment
...@@ -145,18 +149,19 @@ ENTRY(vector_swi) ...@@ -145,18 +149,19 @@ ENTRY(vector_swi)
#endif #endif
enable_irq enable_irq
stmdb sp!, {r4, r5} @ push fifth and sixth args
get_thread_info tsk get_thread_info tsk
ldr ip, [tsk, #TI_FLAGS] @ check for syscall tracing ldr ip, [tsk, #TI_FLAGS] @ check for syscall tracing
#ifndef CONFIG_AEABI
bic scno, scno, #0xff000000 @ mask off SWI op-code bic scno, scno, #0xff000000 @ mask off SWI op-code
eor scno, scno, #__NR_SYSCALL_BASE @ check OS number eor scno, scno, #__NR_SYSCALL_BASE @ check OS number
#endif
adr tbl, sys_call_table @ load syscall table pointer adr tbl, sys_call_table @ load syscall table pointer
stmdb sp!, {r4, r5} @ push fifth and sixth args
tst ip, #_TIF_SYSCALL_TRACE @ are we tracing syscalls? tst ip, #_TIF_SYSCALL_TRACE @ are we tracing syscalls?
bne __sys_trace bne __sys_trace
adr lr, ret_fast_syscall @ return address
cmp scno, #NR_syscalls @ check upper syscall limit cmp scno, #NR_syscalls @ check upper syscall limit
adr lr, ret_fast_syscall @ return address
ldrcc pc, [tbl, scno, lsl #2] @ call sys_* routine ldrcc pc, [tbl, scno, lsl #2] @ call sys_* routine
add r1, sp, #S_OFF add r1, sp, #S_OFF
...@@ -207,6 +212,7 @@ ENTRY(sys_call_table) ...@@ -207,6 +212,7 @@ ENTRY(sys_call_table)
@ r8 = syscall table @ r8 = syscall table
.type sys_syscall, #function .type sys_syscall, #function
sys_syscall: sys_syscall:
#ifndef CONFIG_AEABI
eor scno, r0, #__NR_SYSCALL_BASE eor scno, r0, #__NR_SYSCALL_BASE
cmp scno, #__NR_syscall - __NR_SYSCALL_BASE cmp scno, #__NR_syscall - __NR_SYSCALL_BASE
cmpne scno, #NR_syscalls @ check range cmpne scno, #NR_syscalls @ check range
...@@ -216,6 +222,7 @@ sys_syscall: ...@@ -216,6 +222,7 @@ sys_syscall:
movlo r2, r3 movlo r2, r3
movlo r3, r4 movlo r3, r4
ldrlo pc, [tbl, scno, lsl #2] ldrlo pc, [tbl, scno, lsl #2]
#endif
b sys_ni_syscall b sys_ni_syscall
sys_fork_wrapper: sys_fork_wrapper:
......
...@@ -404,7 +404,7 @@ asmlinkage int arm_syscall(int no, struct pt_regs *regs) ...@@ -404,7 +404,7 @@ asmlinkage int arm_syscall(int no, struct pt_regs *regs)
struct thread_info *thread = current_thread_info(); struct thread_info *thread = current_thread_info();
siginfo_t info; siginfo_t info;
if ((no >> 16) != 0x9f) if ((no >> 16) != (__ARM_NR_BASE>> 16))
return bad_syscall(no, regs); return bad_syscall(no, regs);
switch (no & 0xffff) { switch (no & 0xffff) {
......
...@@ -15,10 +15,12 @@ ...@@ -15,10 +15,12 @@
#include <linux/linkage.h> #include <linux/linkage.h>
#if defined(__thumb__) #define __NR_OABI_SYSCALL_BASE 0x900000
#if defined(__thumb__) || defined(__ARM_EABI__)
#define __NR_SYSCALL_BASE 0 #define __NR_SYSCALL_BASE 0
#else #else
#define __NR_SYSCALL_BASE 0x900000 #define __NR_SYSCALL_BASE __NR_OABI_SYSCALL_BASE
#endif #endif
/* /*
...@@ -373,13 +375,13 @@ ...@@ -373,13 +375,13 @@
#define __sys1(x) __sys2(x) #define __sys1(x) __sys2(x)
#ifndef __syscall #ifndef __syscall
#if defined(__thumb__) #if defined(__thumb__) || defined(__ARM_EABI__)
#define __syscall(name) \ #define __SYS_REG(name) register long __sysreg __asm__("r7") = __NR_##name;
"push {r7}\n\t" \ #define __SYS_REG_LIST(regs...) "r" (__sysreg) , ##regs
"mov r7, #" __sys1(__NR_##name) "\n\t" \ #define __syscall(name) "swi\t0"
"swi 0\n\t" \
"pop {r7}"
#else #else
#define __SYS_REG(name)
#define __SYS_REG_LIST(regs...) regs
#define __syscall(name) "swi\t" __sys1(__NR_##name) "" #define __syscall(name) "swi\t" __sys1(__NR_##name) ""
#endif #endif
#endif #endif
...@@ -395,33 +397,34 @@ do { \ ...@@ -395,33 +397,34 @@ do { \
#define _syscall0(type,name) \ #define _syscall0(type,name) \
type name(void) { \ type name(void) { \
__SYS_REG(name) \
register long __res_r0 __asm__("r0"); \ register long __res_r0 __asm__("r0"); \
long __res; \ long __res; \
__asm__ __volatile__ ( \ __asm__ __volatile__ ( \
__syscall(name) \ __syscall(name) \
: "=r" (__res_r0) \ : "=r" (__res_r0) \
: \ : __SYS_REG_LIST() ); \
: "lr"); \
__res = __res_r0; \ __res = __res_r0; \
__syscall_return(type,__res); \ __syscall_return(type,__res); \
} }
#define _syscall1(type,name,type1,arg1) \ #define _syscall1(type,name,type1,arg1) \
type name(type1 arg1) { \ type name(type1 arg1) { \
__SYS_REG(name) \
register long __r0 __asm__("r0") = (long)arg1; \ register long __r0 __asm__("r0") = (long)arg1; \
register long __res_r0 __asm__("r0"); \ register long __res_r0 __asm__("r0"); \
long __res; \ long __res; \
__asm__ __volatile__ ( \ __asm__ __volatile__ ( \
__syscall(name) \ __syscall(name) \
: "=r" (__res_r0) \ : "=r" (__res_r0) \
: "r" (__r0) \ : __SYS_REG_LIST( "0" (__r0) ) ); \
: "lr"); \
__res = __res_r0; \ __res = __res_r0; \
__syscall_return(type,__res); \ __syscall_return(type,__res); \
} }
#define _syscall2(type,name,type1,arg1,type2,arg2) \ #define _syscall2(type,name,type1,arg1,type2,arg2) \
type name(type1 arg1,type2 arg2) { \ type name(type1 arg1,type2 arg2) { \
__SYS_REG(name) \
register long __r0 __asm__("r0") = (long)arg1; \ register long __r0 __asm__("r0") = (long)arg1; \
register long __r1 __asm__("r1") = (long)arg2; \ register long __r1 __asm__("r1") = (long)arg2; \
register long __res_r0 __asm__("r0"); \ register long __res_r0 __asm__("r0"); \
...@@ -429,8 +432,7 @@ type name(type1 arg1,type2 arg2) { \ ...@@ -429,8 +432,7 @@ type name(type1 arg1,type2 arg2) { \
__asm__ __volatile__ ( \ __asm__ __volatile__ ( \
__syscall(name) \ __syscall(name) \
: "=r" (__res_r0) \ : "=r" (__res_r0) \
: "r" (__r0),"r" (__r1) \ : __SYS_REG_LIST( "0" (__r0), "r" (__r1) ) ); \
: "lr"); \
__res = __res_r0; \ __res = __res_r0; \
__syscall_return(type,__res); \ __syscall_return(type,__res); \
} }
...@@ -438,6 +440,7 @@ type name(type1 arg1,type2 arg2) { \ ...@@ -438,6 +440,7 @@ type name(type1 arg1,type2 arg2) { \
#define _syscall3(type,name,type1,arg1,type2,arg2,type3,arg3) \ #define _syscall3(type,name,type1,arg1,type2,arg2,type3,arg3) \
type name(type1 arg1,type2 arg2,type3 arg3) { \ type name(type1 arg1,type2 arg2,type3 arg3) { \
__SYS_REG(name) \
register long __r0 __asm__("r0") = (long)arg1; \ register long __r0 __asm__("r0") = (long)arg1; \
register long __r1 __asm__("r1") = (long)arg2; \ register long __r1 __asm__("r1") = (long)arg2; \
register long __r2 __asm__("r2") = (long)arg3; \ register long __r2 __asm__("r2") = (long)arg3; \
...@@ -446,8 +449,7 @@ type name(type1 arg1,type2 arg2,type3 arg3) { \ ...@@ -446,8 +449,7 @@ type name(type1 arg1,type2 arg2,type3 arg3) { \
__asm__ __volatile__ ( \ __asm__ __volatile__ ( \
__syscall(name) \ __syscall(name) \
: "=r" (__res_r0) \ : "=r" (__res_r0) \
: "r" (__r0),"r" (__r1),"r" (__r2) \ : __SYS_REG_LIST( "0" (__r0), "r" (__r1), "r" (__r2) ) ); \
: "lr"); \
__res = __res_r0; \ __res = __res_r0; \
__syscall_return(type,__res); \ __syscall_return(type,__res); \
} }
...@@ -455,6 +457,7 @@ type name(type1 arg1,type2 arg2,type3 arg3) { \ ...@@ -455,6 +457,7 @@ type name(type1 arg1,type2 arg2,type3 arg3) { \
#define _syscall4(type,name,type1,arg1,type2,arg2,type3,arg3,type4,arg4)\ #define _syscall4(type,name,type1,arg1,type2,arg2,type3,arg3,type4,arg4)\
type name(type1 arg1, type2 arg2, type3 arg3, type4 arg4) { \ type name(type1 arg1, type2 arg2, type3 arg3, type4 arg4) { \
__SYS_REG(name) \
register long __r0 __asm__("r0") = (long)arg1; \ register long __r0 __asm__("r0") = (long)arg1; \
register long __r1 __asm__("r1") = (long)arg2; \ register long __r1 __asm__("r1") = (long)arg2; \
register long __r2 __asm__("r2") = (long)arg3; \ register long __r2 __asm__("r2") = (long)arg3; \
...@@ -464,8 +467,7 @@ type name(type1 arg1, type2 arg2, type3 arg3, type4 arg4) { \ ...@@ -464,8 +467,7 @@ type name(type1 arg1, type2 arg2, type3 arg3, type4 arg4) { \
__asm__ __volatile__ ( \ __asm__ __volatile__ ( \
__syscall(name) \ __syscall(name) \
: "=r" (__res_r0) \ : "=r" (__res_r0) \
: "r" (__r0),"r" (__r1),"r" (__r2),"r" (__r3) \ : __SYS_REG_LIST( "0" (__r0), "r" (__r1), "r" (__r2), "r" (__r3) ) ); \
: "lr"); \
__res = __res_r0; \ __res = __res_r0; \
__syscall_return(type,__res); \ __syscall_return(type,__res); \
} }
...@@ -473,6 +475,7 @@ type name(type1 arg1, type2 arg2, type3 arg3, type4 arg4) { \ ...@@ -473,6 +475,7 @@ type name(type1 arg1, type2 arg2, type3 arg3, type4 arg4) { \
#define _syscall5(type,name,type1,arg1,type2,arg2,type3,arg3,type4,arg4,type5,arg5) \ #define _syscall5(type,name,type1,arg1,type2,arg2,type3,arg3,type4,arg4,type5,arg5) \
type name(type1 arg1, type2 arg2, type3 arg3, type4 arg4, type5 arg5) { \ type name(type1 arg1, type2 arg2, type3 arg3, type4 arg4, type5 arg5) { \
__SYS_REG(name) \
register long __r0 __asm__("r0") = (long)arg1; \ register long __r0 __asm__("r0") = (long)arg1; \
register long __r1 __asm__("r1") = (long)arg2; \ register long __r1 __asm__("r1") = (long)arg2; \
register long __r2 __asm__("r2") = (long)arg3; \ register long __r2 __asm__("r2") = (long)arg3; \
...@@ -483,14 +486,15 @@ type name(type1 arg1, type2 arg2, type3 arg3, type4 arg4, type5 arg5) { \ ...@@ -483,14 +486,15 @@ type name(type1 arg1, type2 arg2, type3 arg3, type4 arg4, type5 arg5) { \
__asm__ __volatile__ ( \ __asm__ __volatile__ ( \
__syscall(name) \ __syscall(name) \
: "=r" (__res_r0) \ : "=r" (__res_r0) \
: "r" (__r0),"r" (__r1),"r" (__r2),"r" (__r3),"r" (__r4) \ : __SYS_REG_LIST( "0" (__r0), "r" (__r1), "r" (__r2), \
: "lr"); \ "r" (__r3), "r" (__r4) ) ); \
__res = __res_r0; \ __res = __res_r0; \
__syscall_return(type,__res); \ __syscall_return(type,__res); \
} }
#define _syscall6(type,name,type1,arg1,type2,arg2,type3,arg3,type4,arg4,type5,arg5,type6,arg6) \ #define _syscall6(type,name,type1,arg1,type2,arg2,type3,arg3,type4,arg4,type5,arg5,type6,arg6) \
type name(type1 arg1, type2 arg2, type3 arg3, type4 arg4, type5 arg5, type6 arg6) { \ type name(type1 arg1, type2 arg2, type3 arg3, type4 arg4, type5 arg5, type6 arg6) { \
__SYS_REG(name) \
register long __r0 __asm__("r0") = (long)arg1; \ register long __r0 __asm__("r0") = (long)arg1; \
register long __r1 __asm__("r1") = (long)arg2; \ register long __r1 __asm__("r1") = (long)arg2; \
register long __r2 __asm__("r2") = (long)arg3; \ register long __r2 __asm__("r2") = (long)arg3; \
...@@ -502,8 +506,8 @@ type name(type1 arg1, type2 arg2, type3 arg3, type4 arg4, type5 arg5, type6 arg6 ...@@ -502,8 +506,8 @@ type name(type1 arg1, type2 arg2, type3 arg3, type4 arg4, type5 arg5, type6 arg6
__asm__ __volatile__ ( \ __asm__ __volatile__ ( \
__syscall(name) \ __syscall(name) \
: "=r" (__res_r0) \ : "=r" (__res_r0) \
: "r" (__r0),"r" (__r1),"r" (__r2),"r" (__r3), "r" (__r4),"r" (__r5) \ : __SYS_REG_LIST( "0" (__r0), "r" (__r1), "r" (__r2), \
: "lr"); \ "r" (__r3), "r" (__r4), "r" (__r5) ) ); \
__res = __res_r0; \ __res = __res_r0; \
__syscall_return(type,__res); \ __syscall_return(type,__res); \
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment