]>
Commit | Line | Data |
---|---|---|
d4697bc9 | 1 | /* Copyright (C) 2011-2014 Free Software Foundation, Inc. |
63d143a2 CM |
2 | This file is part of the GNU C Library. |
3 | Contributed by Chris Metcalf <cmetcalf@tilera.com>, 2011. | |
4 | ||
5 | The GNU C Library is free software; you can redistribute it and/or | |
6 | modify it under the terms of the GNU Lesser General Public | |
7 | License as published by the Free Software Foundation; either | |
8 | version 2.1 of the License, or (at your option) any later version. | |
9 | ||
10 | The GNU C Library is distributed in the hope that it will be useful, | |
11 | but WITHOUT ANY WARRANTY; without even the implied warranty of | |
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
13 | Lesser General Public License for more details. | |
14 | ||
15 | You should have received a copy of the GNU Lesser General Public | |
ab84e3ff PE |
16 | License along with the GNU C Library. If not, see |
17 | <http://www.gnu.org/licenses/>. */ | |
63d143a2 CM |
18 | |
19 | #include <asm/unistd.h> | |
20 | #include <sysdeps/tile/sysdep.h> | |
21 | #include <sysdeps/unix/sysv/linux/generic/sysdep.h> | |
22 | #include <sys/syscall.h> | |
23 | ||
24 | #undef SYS_ify | |
25 | #define SYS_ify(syscall_name) __NR_##syscall_name | |
26 | ||
27 | ||
28 | #ifdef __ASSEMBLER__ | |
29 | ||
30 | /* The actual implementation of doing a syscall. */ | |
31 | #define DO_CALL(syscall_name, args) \ | |
32 | moveli TREG_SYSCALL_NR_NAME, SYS_ify(syscall_name); \ | |
33 | swint1 | |
34 | ||
35 | /* TILE Linux returns the result in r0 (or a negative errno). | |
36 | The kernel "owns" the code to decide if a given value is an error, | |
37 | and puts errno in r1 if so, or otherwise zero. */ | |
38 | #define PSEUDO(name, syscall_name, args) \ | |
39 | ENTRY (name); \ | |
40 | DO_CALL(syscall_name, args); \ | |
41 | BNEZ r1, 0f | |
42 | ||
43 | #define ret jrp lr | |
44 | ||
45 | #ifndef PIC | |
46 | /* For static code, on error jump to __syscall_error directly. */ | |
47 | # define SYSCALL_ERROR_NAME __syscall_error | |
48 | #elif !defined NOT_IN_libc || defined IS_IN_libpthread | |
49 | /* Use the internal name for libc/libpthread shared objects. */ | |
50 | # define SYSCALL_ERROR_NAME __GI___syscall_error | |
51 | #else | |
52 | /* Otherwise, on error do a full PLT jump. */ | |
53 | # define SYSCALL_ERROR_NAME plt(__syscall_error) | |
54 | #endif | |
55 | ||
56 | #define PSEUDO_END(name) \ | |
57 | 0: \ | |
58 | j SYSCALL_ERROR_NAME; \ | |
59 | END (name) | |
60 | ||
61 | #define PSEUDO_NOERRNO(name, syscall_name, args) \ | |
62 | ENTRY (name); \ | |
63 | DO_CALL(syscall_name, args) | |
64 | ||
65 | #define ret_NOERRNO jrp lr | |
66 | ||
67 | #define PSEUDO_END_NOERRNO(name) \ | |
68 | END (name) | |
69 | ||
70 | /* Convenience wrappers. */ | |
71 | #define SYSCALL__(name, args) PSEUDO (__##name, name, args) | |
72 | #define SYSCALL(name, args) PSEUDO (name, name, args) | |
73 | ||
74 | #else /* not __ASSEMBLER__ */ | |
75 | ||
76 | #include <errno.h> | |
77 | ||
78 | /* Define a macro which expands inline into the wrapper code for a system | |
79 | call. */ | |
80 | # undef INLINE_SYSCALL | |
81 | # define INLINE_SYSCALL(name, nr, args...) \ | |
82 | ({ \ | |
83 | INTERNAL_SYSCALL_DECL (err); \ | |
84 | unsigned long val = INTERNAL_SYSCALL (name, err, nr, args); \ | |
85 | if (__builtin_expect (INTERNAL_SYSCALL_ERROR_P (val, err), 0)) \ | |
86 | { \ | |
87 | __set_errno (INTERNAL_SYSCALL_ERRNO (val, err)); \ | |
88 | val = -1; \ | |
89 | } \ | |
90 | (long) val; }) | |
91 | ||
92 | #undef INTERNAL_SYSCALL | |
93 | #define INTERNAL_SYSCALL(name, err, nr, args...) \ | |
94 | internal_syscall##nr (SYS_ify (name), err, args) | |
95 | ||
96 | #undef INTERNAL_SYSCALL_NCS | |
97 | #define INTERNAL_SYSCALL_NCS(number, err, nr, args...) \ | |
98 | internal_syscall##nr (number, err, args) | |
99 | ||
100 | #undef INTERNAL_SYSCALL_DECL | |
101 | #define INTERNAL_SYSCALL_DECL(err) int err | |
102 | ||
103 | #undef INTERNAL_SYSCALL_ERROR_P | |
104 | #define INTERNAL_SYSCALL_ERROR_P(val, err) ({ (void) (val); (err) != 0; }) | |
105 | ||
106 | #undef INTERNAL_SYSCALL_ERRNO | |
107 | #define INTERNAL_SYSCALL_ERRNO(val, err) ({ (void) (val); (err); }) | |
108 | ||
109 | #define internal_syscall0(num, err, dummy...) \ | |
110 | ({ \ | |
111 | long _sys_result, __SYSCALL_CLOBBER_DECLS; \ | |
112 | __asm__ __volatile__ ( \ | |
113 | "swint1" \ | |
114 | : "=R00" (_sys_result), "=R01" (err), __SYSCALL_CLOBBER_OUTPUTS \ | |
115 | : "R10" (num) \ | |
116 | : __SYSCALL_CLOBBERS); \ | |
117 | _sys_result; \ | |
118 | }) | |
119 | ||
120 | #define internal_syscall1(num, err, arg0) \ | |
121 | ({ \ | |
122 | long _sys_result, __SYSCALL_CLOBBER_DECLS; \ | |
123 | __asm__ __volatile__ ( \ | |
124 | "swint1" \ | |
125 | : "=R00" (_sys_result), "=R01" (err), __SYSCALL_CLOBBER_OUTPUTS \ | |
126 | : "R10" (num), "R00" (arg0) \ | |
127 | : __SYSCALL_CLOBBERS); \ | |
128 | _sys_result; \ | |
129 | }) | |
130 | ||
131 | #define internal_syscall2(num, err, arg0, arg1) \ | |
132 | ({ \ | |
133 | long _sys_result, __SYSCALL_CLOBBER_DECLS; \ | |
134 | __asm__ __volatile__ ( \ | |
135 | "swint1" \ | |
136 | : "=R00" (_sys_result), "=R01" (err), __SYSCALL_CLOBBER_OUTPUTS \ | |
137 | : "R10" (num), "R00" (arg0), "R01" (arg1) \ | |
138 | : __SYSCALL_CLOBBERS); \ | |
139 | _sys_result; \ | |
140 | }) | |
141 | ||
142 | #define internal_syscall3(num, err, arg0, arg1, arg2) \ | |
143 | ({ \ | |
144 | long _sys_result, __SYSCALL_CLOBBER_DECLS; \ | |
145 | __asm__ __volatile__ ( \ | |
146 | "swint1" \ | |
147 | : "=R00" (_sys_result), "=R01" (err), __SYSCALL_CLOBBER_OUTPUTS \ | |
148 | : "R10" (num), "R00" (arg0), "R01" (arg1), "R02" (arg2) \ | |
149 | : __SYSCALL_CLOBBERS); \ | |
150 | _sys_result; \ | |
151 | }) | |
152 | ||
153 | #define internal_syscall4(num, err, arg0, arg1, arg2, arg3) \ | |
154 | ({ \ | |
155 | long _sys_result, __SYSCALL_CLOBBER_DECLS; \ | |
156 | __asm__ __volatile__ ( \ | |
157 | "swint1" \ | |
158 | : "=R00" (_sys_result), "=R01" (err), __SYSCALL_CLOBBER_OUTPUTS \ | |
159 | : "R10" (num), "R00" (arg0), "R01" (arg1), "R02" (arg2), \ | |
160 | "R03" (arg3) \ | |
161 | : __SYSCALL_CLOBBERS); \ | |
162 | _sys_result; \ | |
163 | }) | |
164 | ||
165 | #define internal_syscall5(num, err, arg0, arg1, arg2, arg3, arg4) \ | |
166 | ({ \ | |
167 | long _sys_result, __SYSCALL_CLOBBER_DECLS; \ | |
168 | __asm__ __volatile__ ( \ | |
169 | "swint1" \ | |
170 | : "=R00" (_sys_result), "=R01" (err), __SYSCALL_CLOBBER_OUTPUTS \ | |
171 | : "R10" (num), "R00" (arg0), "R01" (arg1), "R02" (arg2), \ | |
172 | "R03" (arg3), "R04" (arg4) \ | |
173 | : __SYSCALL_CLOBBERS); \ | |
174 | _sys_result; \ | |
175 | }) | |
176 | ||
177 | #define internal_syscall6(num, err, arg0, arg1, arg2, arg3, arg4, arg5) \ | |
178 | ({ \ | |
179 | long _sys_result, __SYSCALL_CLOBBER_DECLS; \ | |
180 | __asm__ __volatile__ ( \ | |
181 | "swint1" \ | |
182 | : "=R00" (_sys_result), "=R01" (err), __SYSCALL_CLOBBER_OUTPUTS \ | |
183 | : "R10" (num), "R00" (arg0), "R01" (arg1), "R02" (arg2), \ | |
184 | "R03" (arg3), "R04" (arg4), "R05" (arg5) \ | |
185 | : __SYSCALL_CLOBBERS); \ | |
186 | _sys_result; \ | |
187 | }) | |
188 | ||
189 | #undef __SYSCALL_CLOBBERS | |
190 | #define __SYSCALL_CLOBBERS \ | |
191 | "r6", "r7", \ | |
192 | "r8", "r9", "r11", "r12", "r13", "r14", "r15", \ | |
193 | "r16", "r17", "r18", "r19", "r20", "r21", "r22", "r23", \ | |
194 | "r24", "r25", "r26", "r27", "r28", "r29", "memory" | |
195 | ||
196 | /* gcc doesn't seem to allow an input operand to be clobbered, so we | |
197 | fake it with dummy outputs. */ | |
198 | #define __SYSCALL_CLOBBER_DECLS \ | |
199 | _clobber_r2, _clobber_r3, _clobber_r4, _clobber_r5, _clobber_r10 | |
200 | ||
201 | #define __SYSCALL_CLOBBER_OUTPUTS \ | |
202 | "=R02" (_clobber_r2), "=R03" (_clobber_r3), "=R04" (_clobber_r4), \ | |
203 | "=R05" (_clobber_r5), "=R10" (_clobber_r10) | |
204 | ||
205 | #endif /* not __ASSEMBLER__ */ | |
206 | ||
207 | /* Pointer mangling support. */ | |
208 | #if defined NOT_IN_libc && defined IS_IN_rtld | |
209 | /* We cannot use the thread descriptor because in ld.so we use setjmp | |
210 | earlier than the descriptor is initialized. */ | |
211 | #else | |
212 | # ifdef __ASSEMBLER__ | |
213 | # define PTR_MANGLE(reg, tmpreg) \ | |
214 | ADDLI_PTR tmpreg, pt, POINTER_GUARD; \ | |
215 | LD tmpreg, tmpreg; \ | |
216 | xor reg, tmpreg, reg | |
217 | # define PTR_DEMANGLE(reg, tmpreg) PTR_MANGLE (reg, tmpreg) | |
218 | # else | |
219 | # define PTR_MANGLE(var) \ | |
220 | (var) = (__typeof (var)) ((uintptr_t) (var) ^ THREAD_GET_POINTER_GUARD ()) | |
221 | # define PTR_DEMANGLE(var) PTR_MANGLE (var) | |
222 | # endif | |
223 | #endif |