[ARM] 3105/4: ARM EABI: new syscall entry convention
Nicolas Pitre [Sat, 14 Jan 2006 16:31:29 +0000 (16:31 +0000)]
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: Nicolas Pitre <nico@cam.org>
Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>

arch/arm/kernel/entry-common.S
arch/arm/kernel/traps.c
include/asm-arm/unistd.h

index e2b4299..34826bc 100644 (file)
@@ -98,20 +98,14 @@ ENTRY(ret_from_fork)
           run on an ARM7 and we can save a couple of instructions.  
                                                                --pb */
 #ifdef CONFIG_CPU_ARM710
-       .macro  arm710_bug_check, instr, temp
-       and     \temp, \instr, #0x0f000000      @ check for SWI
-       teq     \temp, #0x0f000000
-       bne     .Larm700bug
-       .endm
-
-.Larm700bug:
+#define A710(code...) code
+.Larm710bug:
        ldmia   sp, {r0 - lr}^                  @ Get calling r0 - lr
        mov     r0, r0
        add     sp, sp, #S_FRAME_SIZE
        subs    pc, lr, #4
 #else
-       .macro  arm710_bug_check, instr, temp
-       .endm
+#define A710(code...)
 #endif
 
        .align  5
@@ -129,14 +123,24 @@ ENTRY(vector_swi)
        /*
         * 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
        addne   scno, r7, #__NR_SYSCALL_BASE    @ put OS number in
        ldreq   scno, [lr, #-4]
 #else
        ldr     scno, [lr, #-4]                 @ get SWI instruction
+  A710(        and     ip, scno, #0x0f000000           @ check for SWI         )
+  A710(        teq     ip, #0x0f000000                                         )
+  A710(        bne     .Larm710bug                                             )
 #endif
-       arm710_bug_check scno, ip
 
 #ifdef CONFIG_ALIGNMENT_TRAP
        ldr     ip, __cr_alignment
@@ -145,18 +149,19 @@ ENTRY(vector_swi)
 #endif
        enable_irq
 
-       stmdb   sp!, {r4, r5}                   @ push fifth and sixth args
-
        get_thread_info tsk
        ldr     ip, [tsk, #TI_FLAGS]            @ check for syscall tracing
+#ifndef CONFIG_AEABI
        bic     scno, scno, #0xff000000         @ mask off SWI op-code
        eor     scno, scno, #__NR_SYSCALL_BASE  @ check OS number
+#endif
        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?
        bne     __sys_trace
 
-       adr     lr, ret_fast_syscall            @ return address
        cmp     scno, #NR_syscalls              @ check upper syscall limit
+       adr     lr, ret_fast_syscall            @ return address
        ldrcc   pc, [tbl, scno, lsl #2]         @ call sys_* routine
 
        add     r1, sp, #S_OFF
@@ -207,6 +212,7 @@ ENTRY(sys_call_table)
 @ r8 = syscall table
                .type   sys_syscall, #function
 sys_syscall:
+#ifndef CONFIG_AEABI
                eor     scno, r0, #__NR_SYSCALL_BASE
                cmp     scno, #__NR_syscall - __NR_SYSCALL_BASE
                cmpne   scno, #NR_syscalls      @ check range
@@ -216,6 +222,7 @@ sys_syscall:
                movlo   r2, r3
                movlo   r3, r4
                ldrlo   pc, [tbl, scno, lsl #2]
+#endif
                b       sys_ni_syscall
 
 sys_fork_wrapper:
index 93cfd3f..10235b0 100644 (file)
@@ -404,7 +404,7 @@ asmlinkage int arm_syscall(int no, struct pt_regs *regs)
        struct thread_info *thread = current_thread_info();
        siginfo_t info;
 
-       if ((no >> 16) != 0x9f)
+       if ((no >> 16) != (__ARM_NR_BASE>> 16))
                return bad_syscall(no, regs);
 
        switch (no & 0xffff) {
index d626e70..c9e087f 100644 (file)
 
 #include <linux/linkage.h>
 
-#if defined(__thumb__)
+#define __NR_OABI_SYSCALL_BASE 0x900000
+
+#if defined(__thumb__) || defined(__ARM_EABI__)
 #define __NR_SYSCALL_BASE      0
 #else
-#define __NR_SYSCALL_BASE      0x900000
+#define __NR_SYSCALL_BASE      __NR_OABI_SYSCALL_BASE
 #endif
 
 /*
 #define __sys1(x) __sys2(x)
 
 #ifndef __syscall
-#if defined(__thumb__)
-#define __syscall(name)                                        \
-       "push   {r7}\n\t"                               \
-       "mov    r7, #" __sys1(__NR_##name) "\n\t"       \
-       "swi    0\n\t"                                  \
-       "pop    {r7}"
+#if defined(__thumb__) || defined(__ARM_EABI__)
+#define __SYS_REG(name) register long __sysreg __asm__("r7") = __NR_##name;
+#define __SYS_REG_LIST(regs...) "r" (__sysreg) , ##regs
+#define __syscall(name) "swi\t0"
 #else
+#define __SYS_REG(name)
+#define __SYS_REG_LIST(regs...) regs
 #define __syscall(name) "swi\t" __sys1(__NR_##name) ""
 #endif
 #endif
@@ -395,33 +397,34 @@ do {                                                                      \
 
 #define _syscall0(type,name)                                           \
 type name(void) {                                                      \
+  __SYS_REG(name)                                                      \
   register long __res_r0 __asm__("r0");                                        \
   long __res;                                                          \
   __asm__ __volatile__ (                                               \
   __syscall(name)                                                      \
        : "=r" (__res_r0)                                               \
-       :                                                               \
-       : "lr");                                                        \
+       : __SYS_REG_LIST() );                                           \
   __res = __res_r0;                                                    \
   __syscall_return(type,__res);                                                \
 }
 
 #define _syscall1(type,name,type1,arg1)                                \
 type name(type1 arg1) {                                                \
+  __SYS_REG(name)                                                      \
   register long __r0 __asm__("r0") = (long)arg1;                       \
   register long __res_r0 __asm__("r0");                                        \
   long __res;                                                          \
   __asm__ __volatile__ (                                               \
   __syscall(name)                                                      \
        : "=r" (__res_r0)                                               \
-       : "r" (__r0)                                                    \
-       : "lr");                                                        \
+       : __SYS_REG_LIST( "0" (__r0) ) );                               \
   __res = __res_r0;                                                    \
   __syscall_return(type,__res);                                                \
 }
 
 #define _syscall2(type,name,type1,arg1,type2,arg2)                     \
 type name(type1 arg1,type2 arg2) {                                     \
+  __SYS_REG(name)                                                      \
   register long __r0 __asm__("r0") = (long)arg1;                       \
   register long __r1 __asm__("r1") = (long)arg2;                       \
   register long __res_r0 __asm__("r0");                                        \
@@ -429,8 +432,7 @@ type name(type1 arg1,type2 arg2) {                                  \
   __asm__ __volatile__ (                                               \
   __syscall(name)                                                      \
        : "=r" (__res_r0)                                               \
-       : "r" (__r0),"r" (__r1)                                         \
-       : "lr");                                                        \
+       : __SYS_REG_LIST( "0" (__r0), "r" (__r1) ) );                   \
   __res = __res_r0;                                                    \
   __syscall_return(type,__res);                                                \
 }
@@ -438,6 +440,7 @@ type name(type1 arg1,type2 arg2) {                                  \
 
 #define _syscall3(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 __r1 __asm__("r1") = (long)arg2;                       \
   register long __r2 __asm__("r2") = (long)arg3;                       \
@@ -446,8 +449,7 @@ type name(type1 arg1,type2 arg2,type3 arg3) {                               \
   __asm__ __volatile__ (                                               \
   __syscall(name)                                                      \
        : "=r" (__res_r0)                                               \
-       : "r" (__r0),"r" (__r1),"r" (__r2)                              \
-       : "lr");                                                        \
+       : __SYS_REG_LIST( "0" (__r0), "r" (__r1), "r" (__r2) ) );       \
   __res = __res_r0;                                                    \
   __syscall_return(type,__res);                                                \
 }
@@ -455,6 +457,7 @@ type name(type1 arg1,type2 arg2,type3 arg3) {                               \
 
 #define _syscall4(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 __r1 __asm__("r1") = (long)arg2;                       \
   register long __r2 __asm__("r2") = (long)arg3;                       \
@@ -464,8 +467,7 @@ type name(type1 arg1, type2 arg2, type3 arg3, type4 arg4) {         \
   __asm__ __volatile__ (                                               \
   __syscall(name)                                                      \
        : "=r" (__res_r0)                                               \
-       : "r" (__r0),"r" (__r1),"r" (__r2),"r" (__r3)                   \
-       : "lr");                                                        \
+       : __SYS_REG_LIST( "0" (__r0), "r" (__r1), "r" (__r2), "r" (__r3) ) ); \
   __res = __res_r0;                                                    \
   __syscall_return(type,__res);                                                \
 }
@@ -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)    \
 type name(type1 arg1, type2 arg2, type3 arg3, type4 arg4, type5 arg5) {        \
+  __SYS_REG(name)                                                      \
   register long __r0 __asm__("r0") = (long)arg1;                       \
   register long __r1 __asm__("r1") = (long)arg2;                       \
   register long __r2 __asm__("r2") = (long)arg3;                       \
@@ -483,14 +486,15 @@ type name(type1 arg1, type2 arg2, type3 arg3, type4 arg4, type5 arg5) {   \
   __asm__ __volatile__ (                                               \
   __syscall(name)                                                      \
        : "=r" (__res_r0)                                               \
-       : "r" (__r0),"r" (__r1),"r" (__r2),"r" (__r3),"r" (__r4)        \
-       : "lr");                                                        \
+       : __SYS_REG_LIST( "0" (__r0), "r" (__r1), "r" (__r2),           \
+                         "r" (__r3), "r" (__r4) ) );                   \
   __res = __res_r0;                                                    \
   __syscall_return(type,__res);                                                \
 }
 
 #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) {    \
+  __SYS_REG(name)                                                      \
   register long __r0 __asm__("r0") = (long)arg1;                       \
   register long __r1 __asm__("r1") = (long)arg2;                       \
   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
   __asm__ __volatile__ (                                               \
   __syscall(name)                                                      \
        : "=r" (__res_r0)                                               \
-       : "r" (__r0),"r" (__r1),"r" (__r2),"r" (__r3), "r" (__r4),"r" (__r5)            \
-       : "lr");                                                        \
+       : __SYS_REG_LIST( "0" (__r0), "r" (__r1), "r" (__r2),           \
+                         "r" (__r3), "r" (__r4), "r" (__r5) ) );       \
   __res = __res_r0;                                                    \
   __syscall_return(type,__res);                                                \
 }