1 /* Copyright (C) 1992, 1995, 1996, 2000, 2003, 2004, 2006
2    Free Software Foundation, Inc.
3    This file is part of the GNU C Library.
4    Contributed by Brendan Kehoe (brendan@zen.org).
5 
6    The GNU C Library is free software; you can redistribute it and/or
7    modify it under the terms of the GNU Lesser General Public
8    License as published by the Free Software Foundation; either
9    version 2.1 of the License, or (at your option) any later version.
10 
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    Lesser General Public License for more details.
15 
16    You should have received a copy of the GNU Lesser General Public
17    License along with the GNU C Library; if not, see
18    <http://www.gnu.org/licenses/>.  */
19 
20 #ifndef _BITS_SYSCALLS_H
21 #define _BITS_SYSCALLS_H
22 #ifndef _SYSCALL_H
23 # error "Never use <bits/syscalls.h> directly; include <sys/syscall.h> instead."
24 #endif
25 
26 #ifndef __ASSEMBLER__
27 
28 #define INLINE_SYSCALL_NCS(name, nr, args...)	\
29 (__extension__					\
30  ({						\
31 	long _sc_ret, _sc_err;			\
32 	inline_syscall##nr(name, args);		\
33 	if (unlikely (_sc_err))			\
34 	  {					\
35 	    __set_errno (_sc_ret);		\
36 	    _sc_ret = -1L;			\
37 	  }					\
38 	_sc_ret;				\
39   })						\
40 )
41 
42 #define INTERNAL_SYSCALL_NCS(name, err_out, nr, args...) \
43 (__extension__ \
44  ({							\
45 	long _sc_ret, _sc_err;				\
46 	inline_syscall##nr(name, args);			\
47 	err_out = _sc_err;				\
48 	_sc_ret;					\
49   }) \
50 )
51 #define INTERNAL_SYSCALL_DECL(err)		long int err
52 #define INTERNAL_SYSCALL_ERROR_P(val, err)	err
53 #define INTERNAL_SYSCALL_ERRNO(val, err)	val
54 
55 #define inline_syscall_clobbers				\
56 	"$1", "$2", "$3", "$4", "$5", "$6", "$7", "$8",	\
57 	"$22", "$23", "$24", "$25", "$27", "$28", "memory"
58 
59 /* If TLS is in use, we have a conflict between the PAL_rduniq primitive,
60    as modeled within GCC, and explicit use of the R0 register.  If we use
61    the register via the asm, the scheduler may place the PAL_rduniq insn
62    before we've copied the data from R0 into _sc_ret.  If this happens
63    we'll get a reload abort, since R0 is live at the same time it is
64    needed for the PAL_rduniq.
65 
66    Solve this by using the "v" constraint instead of an asm for the syscall
67    output.  We don't do this unconditionally to allow compilation with
68    older compilers.  */
69 
70 #ifdef HAVE___THREAD
71 #define inline_syscall_r0_asm
72 #define inline_syscall_r0_out_constraint	"=v"
73 #else
74 #define inline_syscall_r0_asm			__asm__("$0")
75 #define inline_syscall_r0_out_constraint	"=r"
76 #endif
77 
78 /* It is moderately important optimization-wise to limit the lifetime
79    of the hard-register variables as much as possible.  Thus we copy
80    in/out as close to the asm as possible.  */
81 
82 #define inline_syscall0(name, args...)				\
83 {								\
84 	register long _sc_0 inline_syscall_r0_asm;		\
85 	register long _sc_19 __asm__("$19");			\
86 								\
87 	_sc_0 = name;						\
88 	__asm__ __volatile__					\
89 	  ("callsys # %0 %1 <= %2"				\
90 	   : inline_syscall_r0_out_constraint (_sc_0),		\
91 	     "=r"(_sc_19)					\
92 	   : "0"(_sc_0)						\
93 	   : inline_syscall_clobbers,				\
94 	     "$16", "$17", "$18", "$20", "$21");		\
95 	_sc_ret = _sc_0, _sc_err = _sc_19;			\
96 }
97 
98 #define inline_syscall1(name,arg1)				\
99 {								\
100 	register long _sc_0 inline_syscall_r0_asm;		\
101 	register long _sc_16 __asm__("$16");			\
102 	register long _sc_19 __asm__("$19");			\
103 	register long _tmp_16 = (long) (arg1);			\
104 								\
105 	_sc_0 = name;						\
106 	_sc_16 = _tmp_16;					\
107 	__asm__ __volatile__					\
108 	  ("callsys # %0 %1 <= %2 %3"				\
109 	   : inline_syscall_r0_out_constraint (_sc_0),		\
110 	     "=r"(_sc_19), "=r"(_sc_16)				\
111 	   : "0"(_sc_0), "2"(_sc_16)				\
112 	   : inline_syscall_clobbers,				\
113 	     "$17", "$18", "$20", "$21");			\
114 	_sc_ret = _sc_0, _sc_err = _sc_19;			\
115 }
116 
117 #define inline_syscall2(name,arg1,arg2)				\
118 {								\
119 	register long _sc_0 inline_syscall_r0_asm;		\
120 	register long _sc_16 __asm__("$16");			\
121 	register long _sc_17 __asm__("$17");			\
122 	register long _sc_19 __asm__("$19");			\
123 	register long _tmp_16 = (long) (arg1);			\
124 	register long _tmp_17 = (long) (arg2);			\
125 								\
126 	_sc_0 = name;						\
127 	_sc_16 = _tmp_16;					\
128 	_sc_17 = _tmp_17;					\
129 	__asm__ __volatile__					\
130 	  ("callsys # %0 %1 <= %2 %3 %4"			\
131 	   : inline_syscall_r0_out_constraint (_sc_0),		\
132 	     "=r"(_sc_19), "=r"(_sc_16), "=r"(_sc_17)		\
133 	   : "0"(_sc_0), "2"(_sc_16), "3"(_sc_17)		\
134 	   : inline_syscall_clobbers,				\
135 	     "$18", "$20", "$21");				\
136 	_sc_ret = _sc_0, _sc_err = _sc_19;			\
137 }
138 
139 #define inline_syscall3(name,arg1,arg2,arg3)			\
140 {								\
141 	register long _sc_0 inline_syscall_r0_asm;		\
142 	register long _sc_16 __asm__("$16");			\
143 	register long _sc_17 __asm__("$17");			\
144 	register long _sc_18 __asm__("$18");			\
145 	register long _sc_19 __asm__("$19");			\
146 	register long _tmp_16 = (long) (arg1);			\
147 	register long _tmp_17 = (long) (arg2);			\
148 	register long _tmp_18 = (long) (arg3);			\
149 								\
150 	_sc_0 = name;						\
151 	_sc_16 = _tmp_16;					\
152 	_sc_17 = _tmp_17;					\
153 	_sc_18 = _tmp_18;					\
154 	__asm__ __volatile__					\
155 	  ("callsys # %0 %1 <= %2 %3 %4 %5"			\
156 	   : inline_syscall_r0_out_constraint (_sc_0),		\
157 	     "=r"(_sc_19), "=r"(_sc_16), "=r"(_sc_17),		\
158 	     "=r"(_sc_18)					\
159 	   : "0"(_sc_0), "2"(_sc_16), "3"(_sc_17),		\
160 	     "4"(_sc_18)					\
161 	   : inline_syscall_clobbers, "$20", "$21");		\
162 	_sc_ret = _sc_0, _sc_err = _sc_19;			\
163 }
164 
165 #define inline_syscall4(name,arg1,arg2,arg3,arg4)		\
166 {								\
167 	register long _sc_0 inline_syscall_r0_asm;		\
168 	register long _sc_16 __asm__("$16");			\
169 	register long _sc_17 __asm__("$17");			\
170 	register long _sc_18 __asm__("$18");			\
171 	register long _sc_19 __asm__("$19");			\
172 	register long _tmp_16 = (long) (arg1);			\
173 	register long _tmp_17 = (long) (arg2);			\
174 	register long _tmp_18 = (long) (arg3);			\
175 	register long _tmp_19 = (long) (arg4);			\
176 								\
177 	_sc_0 = name;						\
178 	_sc_16 = _tmp_16;					\
179 	_sc_17 = _tmp_17;					\
180 	_sc_18 = _tmp_18;					\
181 	_sc_19 = _tmp_19;					\
182 	__asm__ __volatile__					\
183 	  ("callsys # %0 %1 <= %2 %3 %4 %5 %6"			\
184 	   : inline_syscall_r0_out_constraint (_sc_0),		\
185 	     "=r"(_sc_19), "=r"(_sc_16), "=r"(_sc_17),		\
186 	     "=r"(_sc_18)					\
187 	   : "0"(_sc_0), "2"(_sc_16), "3"(_sc_17),		\
188 	     "4"(_sc_18), "1"(_sc_19)				\
189 	   : inline_syscall_clobbers, "$20", "$21");		\
190 	_sc_ret = _sc_0, _sc_err = _sc_19;			\
191 }
192 
193 #define inline_syscall5(name,arg1,arg2,arg3,arg4,arg5)		\
194 {								\
195 	register long _sc_0 inline_syscall_r0_asm;		\
196 	register long _sc_16 __asm__("$16");			\
197 	register long _sc_17 __asm__("$17");			\
198 	register long _sc_18 __asm__("$18");			\
199 	register long _sc_19 __asm__("$19");			\
200 	register long _sc_20 __asm__("$20");			\
201 	register long _tmp_16 = (long) (arg1);			\
202 	register long _tmp_17 = (long) (arg2);			\
203 	register long _tmp_18 = (long) (arg3);			\
204 	register long _tmp_19 = (long) (arg4);			\
205 	register long _tmp_20 = (long) (arg5);			\
206 								\
207 	_sc_0 = name;						\
208 	_sc_16 = _tmp_16;					\
209 	_sc_17 = _tmp_17;					\
210 	_sc_18 = _tmp_18;					\
211 	_sc_19 = _tmp_19;					\
212 	_sc_20 = _tmp_20;					\
213 	__asm__ __volatile__					\
214 	  ("callsys # %0 %1 <= %2 %3 %4 %5 %6 %7"		\
215 	   : inline_syscall_r0_out_constraint (_sc_0),		\
216 	     "=r"(_sc_19), "=r"(_sc_16), "=r"(_sc_17),		\
217 	     "=r"(_sc_18), "=r"(_sc_20)				\
218 	   : "0"(_sc_0), "2"(_sc_16), "3"(_sc_17),		\
219 	     "4"(_sc_18), "1"(_sc_19), "5"(_sc_20)		\
220 	   : inline_syscall_clobbers, "$21");			\
221 	_sc_ret = _sc_0, _sc_err = _sc_19;			\
222 }
223 
224 #define inline_syscall6(name,arg1,arg2,arg3,arg4,arg5,arg6)	\
225 {								\
226 	register long _sc_0 inline_syscall_r0_asm;		\
227 	register long _sc_16 __asm__("$16");			\
228 	register long _sc_17 __asm__("$17");			\
229 	register long _sc_18 __asm__("$18");			\
230 	register long _sc_19 __asm__("$19");			\
231 	register long _sc_20 __asm__("$20");			\
232 	register long _sc_21 __asm__("$21");			\
233 	register long _tmp_16 = (long) (arg1);			\
234 	register long _tmp_17 = (long) (arg2);			\
235 	register long _tmp_18 = (long) (arg3);			\
236 	register long _tmp_19 = (long) (arg4);			\
237 	register long _tmp_20 = (long) (arg5);			\
238 	register long _tmp_21 = (long) (arg6);			\
239 								\
240 	_sc_0 = name;						\
241 	_sc_16 = _tmp_16;					\
242 	_sc_17 = _tmp_17;					\
243 	_sc_18 = _tmp_18;					\
244 	_sc_19 = _tmp_19;					\
245 	_sc_20 = _tmp_20;					\
246 	_sc_21 = _tmp_21;					\
247 	__asm__ __volatile__					\
248 	  ("callsys # %0 %1 <= %2 %3 %4 %5 %6 %7 %8"		\
249 	   : inline_syscall_r0_out_constraint (_sc_0),		\
250 	     "=r"(_sc_19), "=r"(_sc_16), "=r"(_sc_17),		\
251 	     "=r"(_sc_18), "=r"(_sc_20), "=r"(_sc_21)		\
252 	   : "0"(_sc_0), "2"(_sc_16), "3"(_sc_17), "4"(_sc_18),	\
253 	     "1"(_sc_19), "5"(_sc_20), "6"(_sc_21)		\
254 	   : inline_syscall_clobbers);				\
255 	_sc_ret = _sc_0, _sc_err = _sc_19;			\
256 }
257 
258 #endif /* __ASSEMBLER__ */
259 #endif /* _BITS_SYSCALLS_H */
260