diff options
author | Nicolas Pitre <nico@cam.org> | 2006-01-14 11:31:29 -0500 |
---|---|---|
committer | Russell King <rmk+kernel@arm.linux.org.uk> | 2006-01-14 11:31:29 -0500 |
commit | 3f2829a31573e3e502b874c8d69a765f7a778793 (patch) | |
tree | 40f64826c0d2964c56c366f770e2d3959123eb59 /arch/arm/kernel | |
parent | ba95e4e4a0a8a3c6aba363d45f78d5f2e2d111eb (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>
Diffstat (limited to 'arch/arm/kernel')
-rw-r--r-- | arch/arm/kernel/entry-common.S | 35 | ||||
-rw-r--r-- | arch/arm/kernel/traps.c | 2 |
2 files changed, 22 insertions, 15 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 |
209 | sys_syscall: | 214 | sys_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 | ||
221 | sys_fork_wrapper: | 228 | sys_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) { |