]>
Commit | Line | Data |
---|---|---|
7feefb69 | 1 | /* Copyright (C) 1992, 93, 95-99, 2000 Free Software Foundation, Inc. |
bfbc5754 UD |
2 | This file is part of the GNU C Library. |
3 | Contributed by Ulrich Drepper, <drepper@gnu.ai.mit.edu>, August 1995. | |
4 | ARM changes by Philip Blundell, <pjb27@cam.ac.uk>, May 1997. | |
1f205a47 | 5 | |
bfbc5754 UD |
6 | The GNU C Library is free software; you can redistribute it and/or |
7 | modify it under the terms of the GNU Library General Public License as | |
8 | published by the Free Software Foundation; either version 2 of the | |
9 | License, or (at your option) any later version. | |
1f205a47 | 10 | |
bfbc5754 UD |
11 | The GNU C Library is distributed in the hope that it will be useful, |
12 | but WITHOUT ANY WARRANTY; without even the implied warranty of | |
13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
14 | Library General Public License for more details. | |
1f205a47 | 15 | |
bfbc5754 UD |
16 | You should have received a copy of the GNU Library General Public |
17 | License along with the GNU C Library; see the file COPYING.LIB. If not, | |
18 | write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, | |
19 | Boston, MA 02111-1307, USA. */ | |
1f205a47 UD |
20 | |
21 | #ifndef _LINUX_ARM_SYSDEP_H | |
22 | #define _LINUX_ARM_SYSDEP_H 1 | |
23 | ||
24 | /* There is some commonality. */ | |
25 | #include <sysdeps/unix/arm/sysdep.h> | |
26 | ||
27 | /* For Linux we can use the system call table in the header file | |
28 | /usr/include/asm/unistd.h | |
29 | of the kernel. But these symbols do not follow the SYS_* syntax | |
30 | so we have to redefine the `SYS_ify' macro here. */ | |
31 | #undef SYS_ify | |
fe0ec73e UD |
32 | #define SWI_BASE (0x900000) |
33 | #define SYS_ify(syscall_name) (__NR_##syscall_name) | |
1f205a47 UD |
34 | |
35 | ||
66715f83 | 36 | #ifdef __ASSEMBLER__ |
1f205a47 UD |
37 | |
38 | /* Linux uses a negative return value to indicate syscall errors, | |
39 | unlike most Unices, which use the condition codes' carry flag. | |
40 | ||
41 | Since version 2.1 the return value of a system call might be | |
42 | negative even if the call succeeded. E.g., the `lseek' system call | |
43 | might return a large offset. Therefore we must not anymore test | |
31161268 | 44 | for < 0, but test for a real error by making sure the value in R0 |
1f205a47 UD |
45 | is a real error number. Linus said he will make sure the no syscall |
46 | returns a value in -1 .. -4095 as a valid result so we can savely | |
47 | test with -4095. */ | |
652e8a1e | 48 | |
1f205a47 UD |
49 | #undef PSEUDO |
50 | #define PSEUDO(name, syscall_name, args) \ | |
51 | .text; \ | |
28c9c2c4 UD |
52 | .type syscall_error,%function; \ |
53 | ENTRY (name); \ | |
1f205a47 | 54 | DO_CALL (args, syscall_name); \ |
497b8ef4 UD |
55 | cmn r0, $4096; |
56 | ||
57 | #define PSEUDO_RET \ | |
58 | RETINSTR(movcc, pc, lr); \ | |
59 | b PLTJMP(__syscall_error) | |
60 | #undef ret | |
61 | #define ret PSEUDO_RET | |
1f205a47 UD |
62 | |
63 | #undef PSEUDO_END | |
64 | #define PSEUDO_END(name) \ | |
65 | SYSCALL_ERROR_HANDLER \ | |
66 | END (name) | |
67 | ||
1f205a47 | 68 | #define SYSCALL_ERROR_HANDLER /* Nothing here; code in sysdep.S is used. */ |
652e8a1e UD |
69 | |
70 | /* Linux takes system call args in registers: | |
71 | syscall number in the SWI instruction | |
72 | arg 1 r0 | |
73 | arg 2 r1 | |
74 | arg 3 r2 | |
75 | arg 4 r3 | |
76 | arg 5 r4 (this is different from the APCS convention) | |
010d7766 UD |
77 | arg 6 r5 |
78 | arg 7 r6 | |
652e8a1e UD |
79 | |
80 | The compiler is going to form a call by coming here, through PSEUDO, with | |
81 | arguments | |
82 | syscall number in the DO_CALL macro | |
83 | arg 1 r0 | |
84 | arg 2 r1 | |
85 | arg 3 r2 | |
86 | arg 4 r3 | |
87 | arg 5 [sp] | |
010d7766 UD |
88 | arg 6 [sp+4] |
89 | arg 7 [sp+8] | |
652e8a1e | 90 | |
010d7766 UD |
91 | We need to shuffle values between R4..R6 and the stack so that the |
92 | caller's v1..v3 and stack frame are not corrupted, and the kernel | |
93 | sees the right arguments. | |
652e8a1e UD |
94 | |
95 | */ | |
1f205a47 UD |
96 | |
97 | #undef DO_CALL | |
652e8a1e UD |
98 | #define DO_CALL(args, syscall_name) \ |
99 | DOARGS_##args \ | |
100 | swi SYS_ify (syscall_name); \ | |
101 | UNDOARGS_##args | |
102 | ||
103 | #define DOARGS_0 /* nothing */ | |
104 | #define DOARGS_1 /* nothing */ | |
105 | #define DOARGS_2 /* nothing */ | |
106 | #define DOARGS_3 /* nothing */ | |
107 | #define DOARGS_4 /* nothing */ | |
010d7766 UD |
108 | #define DOARGS_5 str r4, [sp, $-4]!; ldr r4, [sp, $4]; |
109 | #define DOARGS_6 mov ip, sp; stmfd sp!, {r4, r5}; ldmia ip, {r4, r5}; | |
110 | #define DOARGS_7 mov ip, sp; stmfd sp!, {r4, r5, r6}; ldmia ip, {r4, r5, r6}; | |
652e8a1e UD |
111 | |
112 | #define UNDOARGS_0 /* nothing */ | |
113 | #define UNDOARGS_1 /* nothing */ | |
114 | #define UNDOARGS_2 /* nothing */ | |
115 | #define UNDOARGS_3 /* nothing */ | |
116 | #define UNDOARGS_4 /* nothing */ | |
7feefb69 | 117 | #define UNDOARGS_5 ldr r4, [sp], $4; |
010d7766 UD |
118 | #define UNDOARGS_6 ldmfd sp!, {r4, r5}; |
119 | #define UNDOARGS_7 ldmfd sp!, {r4, r5, r6}; | |
1f205a47 | 120 | |
edb570bb UD |
121 | #else /* not __ASSEMBLER__ */ |
122 | ||
123 | /* Define a macro which expands into the inline wrapper code for a system | |
124 | call. */ | |
125 | #undef INLINE_SYSCALL | |
126 | #define INLINE_SYSCALL(name, nr, args...) \ | |
127 | ({ unsigned int _sys_result; \ | |
128 | { \ | |
129 | register int _a1 asm ("a1"); \ | |
130 | LOAD_ARGS_##nr (args) \ | |
a64e578b | 131 | asm volatile ("swi %1 @ syscall " #name \ |
edb570bb UD |
132 | : "=r" (_a1) \ |
133 | : "i" (SYS_ify(name)) ASM_ARGS_##nr \ | |
134 | : "a1"); \ | |
135 | _sys_result = _a1; \ | |
136 | } \ | |
137 | if (_sys_result >= (unsigned int) -4095) \ | |
138 | { \ | |
139 | __set_errno (-_sys_result); \ | |
140 | _sys_result = (unsigned int) -1; \ | |
141 | } \ | |
142 | (int) _sys_result; }) | |
143 | ||
144 | #define LOAD_ARGS_0() | |
145 | #define ASM_ARGS_0 | |
146 | #define LOAD_ARGS_1(a1) \ | |
147 | _a1 = (int) (a1); \ | |
148 | LOAD_ARGS_0 () | |
149 | #define ASM_ARGS_1 ASM_ARGS_0, "r" (_a1) | |
150 | #define LOAD_ARGS_2(a1, a2) \ | |
151 | register int _a2 asm ("a2") = (int) (a2); \ | |
152 | LOAD_ARGS_1 (a1) | |
153 | #define ASM_ARGS_2 ASM_ARGS_1, "r" (_a2) | |
154 | #define LOAD_ARGS_3(a1, a2, a3) \ | |
155 | register int _a3 asm ("a3") = (int) (a3); \ | |
156 | LOAD_ARGS_2 (a1, a2) | |
157 | #define ASM_ARGS_3 ASM_ARGS_2, "r" (_a3) | |
158 | #define LOAD_ARGS_4(a1, a2, a3, a4) \ | |
159 | register int _a4 asm ("a4") = (int) (a4); \ | |
160 | LOAD_ARGS_3 (a1, a2, a3) | |
161 | #define ASM_ARGS_4 ASM_ARGS_3, "r" (_a4) | |
162 | #define LOAD_ARGS_5(a1, a2, a3, a4, a5) \ | |
163 | register int _v1 asm ("v1") = (int) (a5); \ | |
164 | LOAD_ARGS_4 (a1, a2, a3, a4) | |
165 | #define ASM_ARGS_5 ASM_ARGS_4, "r" (_v1) | |
010d7766 UD |
166 | #define LOAD_ARGS_6(a1, a2, a3, a4, a5, a6) \ |
167 | register int _v2 asm ("v2") = (int) (a6); \ | |
168 | LOAD_ARGS_5 (a1, a2, a3, a4, a5) | |
169 | #define ASM_ARGS_6 ASM_ARGS_5, "r" (_v2) | |
170 | #define LOAD_ARGS_7(a1, a2, a3, a4, a5, a6, a7) \ | |
171 | register int _v3 asm ("v3") = (int) (a7); \ | |
172 | LOAD_ARGS_6 (a1, a2, a3, a4, a5, a6) | |
173 | #define ASM_ARGS_7 ASM_ARGS_6, "r" (_v3) | |
edb570bb | 174 | |
66715f83 | 175 | #endif /* __ASSEMBLER__ */ |
1f205a47 UD |
176 | |
177 | #endif /* linux/arm/sysdep.h */ |