aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorNicolas Pitre <nico@cam.org>2006-01-14 11:31:29 -0500
committerRussell King <rmk+kernel@arm.linux.org.uk>2006-01-14 11:31:29 -0500
commit3f2829a31573e3e502b874c8d69a765f7a778793 (patch)
tree40f64826c0d2964c56c366f770e2d3959123eb59
parentba95e4e4a0a8a3c6aba363d45f78d5f2e2d111eb (diff)
[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: Nicolas Pitre <nico@cam.org> Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
-rw-r--r--arch/arm/kernel/entry-common.S35
-rw-r--r--arch/arm/kernel/traps.c2
-rw-r--r--include/asm-arm/unistd.h48
3 files changed, 48 insertions, 37 deletions
diff --git a/arch/arm/kernel/entry-common.S b/arch/arm/kernel/entry-common.S
index e2b42997ad33..34826bcceb7a 100644
--- a/arch/arm/kernel/entry-common.S
+++ b/arch/arm/kernel/entry-common.S
@@ -98,20 +98,14 @@ ENTRY(ret_from_fork)
98 run on an ARM7 and we can save a couple of instructions. 98 run on an ARM7 and we can save a couple of instructions.
99 --pb */ 99 --pb */
100#ifdef CONFIG_CPU_ARM710 100#ifdef CONFIG_CPU_ARM710
101 .macro arm710_bug_check, instr, temp 101#define A710(code...) code
102 and \temp, \instr, #0x0f000000 @ check for SWI 102.Larm710bug:
103 teq \temp, #0x0f000000
104 bne .Larm700bug
105 .endm
106
107.Larm700bug:
108 ldmia sp, {r0 - lr}^ @ Get calling r0 - lr 103 ldmia sp, {r0 - lr}^ @ Get calling r0 - lr
109 mov r0, r0 104 mov r0, r0
110 add sp, sp, #S_FRAME_SIZE 105 add sp, sp, #S_FRAME_SIZE
111 subs pc, lr, #4 106 subs pc, lr, #4
112#else 107#else
113 .macro arm710_bug_check, instr, temp 108#define A710(code...)
114 .endm
115#endif 109#endif
116 110
117 .align 5 111 .align 5
@@ -129,14 +123,24 @@ ENTRY(vector_swi)
129 /* 123 /*
130 * Get the system call number. 124 * Get the system call number.
131 */ 125 */
132#ifdef CONFIG_ARM_THUMB 126#if defined(CONFIG_AEABI)
127
128 @ syscall number is in scno (r7) already.
129
130 A710( ldr ip, [lr, #-4] @ get SWI instruction )
131 A710( and ip, ip, #0x0f000000 @ check for SWI )
132 A710( teq ip, #0x0f000000 )
133 A710( bne .Larm710bug )
134#elif defined(CONFIG_ARM_THUMB)
133 tst r8, #PSR_T_BIT @ this is SPSR from save_user_regs 135 tst r8, #PSR_T_BIT @ this is SPSR from save_user_regs
134 addne scno, r7, #__NR_SYSCALL_BASE @ put OS number in 136 addne scno, r7, #__NR_SYSCALL_BASE @ put OS number in
135 ldreq scno, [lr, #-4] 137 ldreq scno, [lr, #-4]
136#else 138#else
137 ldr scno, [lr, #-4] @ get SWI instruction 139 ldr scno, [lr, #-4] @ get SWI instruction
140 A710( and ip, scno, #0x0f000000 @ check for SWI )
141 A710( teq ip, #0x0f000000 )
142 A710( bne .Larm710bug )
138#endif 143#endif
139 arm710_bug_check scno, ip
140 144
141#ifdef CONFIG_ALIGNMENT_TRAP 145#ifdef CONFIG_ALIGNMENT_TRAP
142 ldr ip, __cr_alignment 146 ldr ip, __cr_alignment
@@ -145,18 +149,19 @@ ENTRY(vector_swi)
145#endif 149#endif
146 enable_irq 150 enable_irq
147 151
148 stmdb sp!, {r4, r5} @ push fifth and sixth args
149
150 get_thread_info tsk 152 get_thread_info tsk
151 ldr ip, [tsk, #TI_FLAGS] @ check for syscall tracing 153 ldr ip, [tsk, #TI_FLAGS] @ check for syscall tracing
154#ifndef CONFIG_AEABI
152 bic scno, scno, #0xff000000 @ mask off SWI op-code 155 bic scno, scno, #0xff000000 @ mask off SWI op-code
153 eor scno, scno, #__NR_SYSCALL_BASE @ check OS number 156 eor scno, scno, #__NR_SYSCALL_BASE @ check OS number
157#endif
154 adr tbl, sys_call_table @ load syscall table pointer 158 adr tbl, sys_call_table @ load syscall table pointer
159 stmdb sp!, {r4, r5} @ push fifth and sixth args
155 tst ip, #_TIF_SYSCALL_TRACE @ are we tracing syscalls? 160 tst ip, #_TIF_SYSCALL_TRACE @ are we tracing syscalls?
156 bne __sys_trace 161 bne __sys_trace
157 162
158 adr lr, ret_fast_syscall @ return address
159 cmp scno, #NR_syscalls @ check upper syscall limit 163 cmp scno, #NR_syscalls @ check upper syscall limit
164 adr lr, ret_fast_syscall @ return address
160 ldrcc pc, [tbl, scno, lsl #2] @ call sys_* routine 165 ldrcc pc, [tbl, scno, lsl #2] @ call sys_* routine
161 166
162 add r1, sp, #S_OFF 167 add r1, sp, #S_OFF
@@ -207,6 +212,7 @@ ENTRY(sys_call_table)
207@ r8 = syscall table 212@ r8 = syscall table
208 .type sys_syscall, #function 213 .type sys_syscall, #function
209sys_syscall: 214sys_syscall:
215#ifndef CONFIG_AEABI
210 eor scno, r0, #__NR_SYSCALL_BASE 216 eor scno, r0, #__NR_SYSCALL_BASE
211 cmp scno, #__NR_syscall - __NR_SYSCALL_BASE 217 cmp scno, #__NR_syscall - __NR_SYSCALL_BASE
212 cmpne scno, #NR_syscalls @ check range 218 cmpne scno, #NR_syscalls @ check range
@@ -216,6 +222,7 @@ sys_syscall:
216 movlo r2, r3 222 movlo r2, r3
217 movlo r3, r4 223 movlo r3, r4
218 ldrlo pc, [tbl, scno, lsl #2] 224 ldrlo pc, [tbl, scno, lsl #2]
225#endif
219 b sys_ni_syscall 226 b sys_ni_syscall
220 227
221sys_fork_wrapper: 228sys_fork_wrapper:
diff --git a/arch/arm/kernel/traps.c b/arch/arm/kernel/traps.c
index 93cfd3ffcc72..10235b01582e 100644
--- a/arch/arm/kernel/traps.c
+++ b/arch/arm/kernel/traps.c
@@ -404,7 +404,7 @@ asmlinkage int arm_syscall(int no, struct pt_regs *regs)
404 struct thread_info *thread = current_thread_info(); 404 struct thread_info *thread = current_thread_info();
405 siginfo_t info; 405 siginfo_t info;
406 406
407 if ((no >> 16) != 0x9f) 407 if ((no >> 16) != (__ARM_NR_BASE>> 16))
408 return bad_syscall(no, regs); 408 return bad_syscall(no, regs);
409 409
410 switch (no & 0xffff) { 410 switch (no & 0xffff) {
diff --git a/include/asm-arm/unistd.h b/include/asm-arm/unistd.h
index d626e70faded..c9e087fe7e11 100644
--- a/include/asm-arm/unistd.h
+++ b/include/asm-arm/unistd.h
@@ -15,10 +15,12 @@
15 15
16#include <linux/linkage.h> 16#include <linux/linkage.h>
17 17
18#if defined(__thumb__) 18#define __NR_OABI_SYSCALL_BASE 0x900000
19
20#if defined(__thumb__) || defined(__ARM_EABI__)
19#define __NR_SYSCALL_BASE 0 21#define __NR_SYSCALL_BASE 0
20#else 22#else
21#define __NR_SYSCALL_BASE 0x900000 23#define __NR_SYSCALL_BASE __NR_OABI_SYSCALL_BASE
22#endif 24#endif
23 25
24/* 26/*
@@ -373,13 +375,13 @@
373#define __sys1(x) __sys2(x) 375#define __sys1(x) __sys2(x)
374 376
375#ifndef __syscall 377#ifndef __syscall
376#if defined(__thumb__) 378#if defined(__thumb__) || defined(__ARM_EABI__)
377#define __syscall(name) \ 379#define __SYS_REG(name) register long __sysreg __asm__("r7") = __NR_##name;
378 "push {r7}\n\t" \ 380#define __SYS_REG_LIST(regs...) "r" (__sysreg) , ##regs
379 "mov r7, #" __sys1(__NR_##name) "\n\t" \ 381#define __syscall(name) "swi\t0"
380 "swi 0\n\t" \
381 "pop {r7}"
382#else 382#else
383#define __SYS_REG(name)
384#define __SYS_REG_LIST(regs...) regs
383#define __syscall(name) "swi\t" __sys1(__NR_##name) "" 385#define __syscall(name) "swi\t" __sys1(__NR_##name) ""
384#endif 386#endif
385#endif 387#endif
@@ -395,33 +397,34 @@ do { \
395 397
396#define _syscall0(type,name) \ 398#define _syscall0(type,name) \
397type name(void) { \ 399type name(void) { \
400 __SYS_REG(name) \
398 register long __res_r0 __asm__("r0"); \ 401 register long __res_r0 __asm__("r0"); \
399 long __res; \ 402 long __res; \
400 __asm__ __volatile__ ( \ 403 __asm__ __volatile__ ( \
401 __syscall(name) \ 404 __syscall(name) \
402 : "=r" (__res_r0) \ 405 : "=r" (__res_r0) \
403 : \ 406 : __SYS_REG_LIST() ); \
404 : "lr"); \
405 __res = __res_r0; \ 407 __res = __res_r0; \
406 __syscall_return(type,__res); \ 408 __syscall_return(type,__res); \
407} 409}
408 410
409#define _syscall1(type,name,type1,arg1) \ 411#define _syscall1(type,name,type1,arg1) \
410type name(type1 arg1) { \ 412type name(type1 arg1) { \
413 __SYS_REG(name) \
411 register long __r0 __asm__("r0") = (long)arg1; \ 414 register long __r0 __asm__("r0") = (long)arg1; \
412 register long __res_r0 __asm__("r0"); \ 415 register long __res_r0 __asm__("r0"); \
413 long __res; \ 416 long __res; \
414 __asm__ __volatile__ ( \ 417 __asm__ __volatile__ ( \
415 __syscall(name) \ 418 __syscall(name) \
416 : "=r" (__res_r0) \ 419 : "=r" (__res_r0) \
417 : "r" (__r0) \ 420 : __SYS_REG_LIST( "0" (__r0) ) ); \
418 : "lr"); \
419 __res = __res_r0; \ 421 __res = __res_r0; \
420 __syscall_return(type,__res); \ 422 __syscall_return(type,__res); \
421} 423}
422 424
423#define _syscall2(type,name,type1,arg1,type2,arg2) \ 425#define _syscall2(type,name,type1,arg1,type2,arg2) \
424type name(type1 arg1,type2 arg2) { \ 426type name(type1 arg1,type2 arg2) { \
427 __SYS_REG(name) \
425 register long __r0 __asm__("r0") = (long)arg1; \ 428 register long __r0 __asm__("r0") = (long)arg1; \
426 register long __r1 __asm__("r1") = (long)arg2; \ 429 register long __r1 __asm__("r1") = (long)arg2; \
427 register long __res_r0 __asm__("r0"); \ 430 register long __res_r0 __asm__("r0"); \
@@ -429,8 +432,7 @@ type name(type1 arg1,type2 arg2) { \
429 __asm__ __volatile__ ( \ 432 __asm__ __volatile__ ( \
430 __syscall(name) \ 433 __syscall(name) \
431 : "=r" (__res_r0) \ 434 : "=r" (__res_r0) \
432 : "r" (__r0),"r" (__r1) \ 435 : __SYS_REG_LIST( "0" (__r0), "r" (__r1) ) ); \
433 : "lr"); \
434 __res = __res_r0; \ 436 __res = __res_r0; \
435 __syscall_return(type,__res); \ 437 __syscall_return(type,__res); \
436} 438}
@@ -438,6 +440,7 @@ type name(type1 arg1,type2 arg2) { \
438 440
439#define _syscall3(type,name,type1,arg1,type2,arg2,type3,arg3) \ 441#define _syscall3(type,name,type1,arg1,type2,arg2,type3,arg3) \
440type name(type1 arg1,type2 arg2,type3 arg3) { \ 442type name(type1 arg1,type2 arg2,type3 arg3) { \
443 __SYS_REG(name) \
441 register long __r0 __asm__("r0") = (long)arg1; \ 444 register long __r0 __asm__("r0") = (long)arg1; \
442 register long __r1 __asm__("r1") = (long)arg2; \ 445 register long __r1 __asm__("r1") = (long)arg2; \
443 register long __r2 __asm__("r2") = (long)arg3; \ 446 register long __r2 __asm__("r2") = (long)arg3; \
@@ -446,8 +449,7 @@ type name(type1 arg1,type2 arg2,type3 arg3) { \
446 __asm__ __volatile__ ( \ 449 __asm__ __volatile__ ( \
447 __syscall(name) \ 450 __syscall(name) \
448 : "=r" (__res_r0) \ 451 : "=r" (__res_r0) \
449 : "r" (__r0),"r" (__r1),"r" (__r2) \ 452 : __SYS_REG_LIST( "0" (__r0), "r" (__r1), "r" (__r2) ) ); \
450 : "lr"); \
451 __res = __res_r0; \ 453 __res = __res_r0; \
452 __syscall_return(type,__res); \ 454 __syscall_return(type,__res); \
453} 455}
@@ -455,6 +457,7 @@ type name(type1 arg1,type2 arg2,type3 arg3) { \
455 457
456#define _syscall4(type,name,type1,arg1,type2,arg2,type3,arg3,type4,arg4)\ 458#define _syscall4(type,name,type1,arg1,type2,arg2,type3,arg3,type4,arg4)\
457type name(type1 arg1, type2 arg2, type3 arg3, type4 arg4) { \ 459type name(type1 arg1, type2 arg2, type3 arg3, type4 arg4) { \
460 __SYS_REG(name) \
458 register long __r0 __asm__("r0") = (long)arg1; \ 461 register long __r0 __asm__("r0") = (long)arg1; \
459 register long __r1 __asm__("r1") = (long)arg2; \ 462 register long __r1 __asm__("r1") = (long)arg2; \
460 register long __r2 __asm__("r2") = (long)arg3; \ 463 register long __r2 __asm__("r2") = (long)arg3; \
@@ -464,8 +467,7 @@ type name(type1 arg1, type2 arg2, type3 arg3, type4 arg4) { \
464 __asm__ __volatile__ ( \ 467 __asm__ __volatile__ ( \
465 __syscall(name) \ 468 __syscall(name) \
466 : "=r" (__res_r0) \ 469 : "=r" (__res_r0) \
467 : "r" (__r0),"r" (__r1),"r" (__r2),"r" (__r3) \ 470 : __SYS_REG_LIST( "0" (__r0), "r" (__r1), "r" (__r2), "r" (__r3) ) ); \
468 : "lr"); \
469 __res = __res_r0; \ 471 __res = __res_r0; \
470 __syscall_return(type,__res); \ 472 __syscall_return(type,__res); \
471} 473}
@@ -473,6 +475,7 @@ type name(type1 arg1, type2 arg2, type3 arg3, type4 arg4) { \
473 475
474#define _syscall5(type,name,type1,arg1,type2,arg2,type3,arg3,type4,arg4,type5,arg5) \ 476#define _syscall5(type,name,type1,arg1,type2,arg2,type3,arg3,type4,arg4,type5,arg5) \
475type name(type1 arg1, type2 arg2, type3 arg3, type4 arg4, type5 arg5) { \ 477type name(type1 arg1, type2 arg2, type3 arg3, type4 arg4, type5 arg5) { \
478 __SYS_REG(name) \
476 register long __r0 __asm__("r0") = (long)arg1; \ 479 register long __r0 __asm__("r0") = (long)arg1; \
477 register long __r1 __asm__("r1") = (long)arg2; \ 480 register long __r1 __asm__("r1") = (long)arg2; \
478 register long __r2 __asm__("r2") = (long)arg3; \ 481 register long __r2 __asm__("r2") = (long)arg3; \
@@ -483,14 +486,15 @@ type name(type1 arg1, type2 arg2, type3 arg3, type4 arg4, type5 arg5) { \
483 __asm__ __volatile__ ( \ 486 __asm__ __volatile__ ( \
484 __syscall(name) \ 487 __syscall(name) \
485 : "=r" (__res_r0) \ 488 : "=r" (__res_r0) \
486 : "r" (__r0),"r" (__r1),"r" (__r2),"r" (__r3),"r" (__r4) \ 489 : __SYS_REG_LIST( "0" (__r0), "r" (__r1), "r" (__r2), \
487 : "lr"); \ 490 "r" (__r3), "r" (__r4) ) ); \
488 __res = __res_r0; \ 491 __res = __res_r0; \
489 __syscall_return(type,__res); \ 492 __syscall_return(type,__res); \
490} 493}
491 494
492#define _syscall6(type,name,type1,arg1,type2,arg2,type3,arg3,type4,arg4,type5,arg5,type6,arg6) \ 495#define _syscall6(type,name,type1,arg1,type2,arg2,type3,arg3,type4,arg4,type5,arg5,type6,arg6) \
493type name(type1 arg1, type2 arg2, type3 arg3, type4 arg4, type5 arg5, type6 arg6) { \ 496type name(type1 arg1, type2 arg2, type3 arg3, type4 arg4, type5 arg5, type6 arg6) { \
497 __SYS_REG(name) \
494 register long __r0 __asm__("r0") = (long)arg1; \ 498 register long __r0 __asm__("r0") = (long)arg1; \
495 register long __r1 __asm__("r1") = (long)arg2; \ 499 register long __r1 __asm__("r1") = (long)arg2; \
496 register long __r2 __asm__("r2") = (long)arg3; \ 500 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 __asm__ __volatile__ ( \ 506 __asm__ __volatile__ ( \
503 __syscall(name) \ 507 __syscall(name) \
504 : "=r" (__res_r0) \ 508 : "=r" (__res_r0) \
505 : "r" (__r0),"r" (__r1),"r" (__r2),"r" (__r3), "r" (__r4),"r" (__r5) \ 509 : __SYS_REG_LIST( "0" (__r0), "r" (__r1), "r" (__r2), \
506 : "lr"); \ 510 "r" (__r3), "r" (__r4), "r" (__r5) ) ); \
507 __res = __res_r0; \ 511 __res = __res_r0; \
508 __syscall_return(type,__res); \ 512 __syscall_return(type,__res); \
509} 513}