1 /* Copyright (C) 2000-2021 Free Software Foundation, Inc.
2 
3    This file is part of the GNU C Library.
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 License as
7    published by the Free Software Foundation; either version 2.1 of the
8    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
16    License along with the GNU C Library; if not, see
17    <https://www.gnu.org/licenses/>.  */
18 
19 #ifndef _LINUX_MICROBLAZE_SYSDEP_H
20 #define _LINUX_MICROBLAZE_SYSDEP_H 1
21 
22 #include <sysdeps/unix/sysdep.h>
23 #include <sysdeps/unix/sysv/linux/sysdep.h>
24 #include <sysdeps/microblaze/sysdep.h>
25 
26 /* Defines RTLD_PRIVATE_ERRNO.  */
27 #include <dl-sysdep.h>
28 
29 #include <tls.h>
30 
31 /* In order to get __set_errno() definition in INLINE_SYSCALL.  */
32 #ifndef __ASSEMBLER__
33 # include <errno.h>
34 #endif
35 
36 /* For Linux we can use the system call table in the header file
37     /usr/include/asm/unistd.h
38    of the kernel.  But these symbols do not follow the SYS_* syntax
39    so we have to redefine the `SYS_ify' macro here.  */
40 #undef SYS_ify
41 #define SYS_ify(syscall_name)   __NR_##syscall_name
42 
43 #ifdef __ASSEMBLER__
44 
45 /* In microblaze ABI function call arguments are passed in registers
46    r5...r10. The return value is stored in r3 (or r3:r4 regiters pair).
47    Linux syscall uses the same convention with the addition that the
48    syscall number is passed in r12. To enter the kernel "brki r14,8"
49    instruction is used.
50    None of the abovementioned registers are presumed across function call
51    or syscall.
52 */
53 /* Linux uses a negative return value to indicate syscall errors, unlike
54    most Unices, which use the condition codes' carry flag.
55 
56    Since version 2.1 the return value of a system call might be negative
57    even if the call succeeded.  E.g., the `lseek' system call might return
58    a large offset.  Therefore we must not anymore test for < 0, but test
59    for a real error by making sure the value in %d0 is a real error
60    number.  Linus said he will make sure the no syscall returns a value
61    in -1 .. -4095 as a valid result so we can savely test with -4095.  */
62 
63 /* We don't want the label for the error handler to be visible in the symbol
64    table when we define it here.  */
65 # undef SYSCALL_ERROR_LABEL
66 # ifdef PIC
67 #  define SYSCALL_ERROR_LABEL 0f
68 # else
69 #  define SYSCALL_ERROR_LABEL __syscall_error
70 # endif
71 
72 # undef PSEUDO
73 # define PSEUDO(name, syscall_name, args)           \
74   .text;                                            \
75   ENTRY (name)                                      \
76     DO_CALL (syscall_name, args);                   \
77     addik r12,r0,-4095;                             \
78     cmpu  r12,r12,r3;                               \
79     bgei  r12,SYSCALL_ERROR_LABEL;
80 
81 # undef PSEUDO_END
82 # define PSEUDO_END(name)                           \
83   SYSCALL_ERROR_HANDLER;                            \
84   END (name)
85 
86 # undef PSEUDO_NOERRNO
87 # define PSEUDO_NOERRNO(name, syscall_name, args)   \
88   .text;                                            \
89   ENTRY (name)                                      \
90     DO_CALL (syscall_name, args);
91 
92 # undef PSEUDO_END_NOERRNO
93 # define PSEUDO_END_NOERRNO(name)                   \
94   END (name)
95 
96 /* The function has to return the error code.  */
97 # undef  PSEUDO_ERRVAL
98 # define PSEUDO_ERRVAL(name, syscall_name, args)    \
99   .text;                                            \
100   ENTRY (name)                                      \
101     DO_CALL (syscall_name, args);                   \
102 
103 # undef  PSEUDO_END_ERRVAL
104 # define PSEUDO_END_ERRVAL(name)                    \
105   END (name)
106 
107 # define ret_NOERRNO                                \
108   rtsd r15,8; addk r0,r0,r0;
109 
110 # define ret_ERRVAL                                 \
111   rtsd r15,8; rsubk r3,r3,r0;
112 
113 # ifdef PIC
114 #  define SYSCALL_ERROR_LABEL_DCL 0
115 #  if RTLD_PRIVATE_ERRNO
116 #   define SYSCALL_ERROR_HANDLER                    \
117 SYSCALL_ERROR_LABEL_DCL:                            \
118     mfs   r12,rpc;                                  \
119     addik r12,r12,_GLOBAL_OFFSET_TABLE_+8;          \
120     lwi   r12,r12,rtld_errno@GOT;                   \
121     rsubk r3,r3,r0;                                 \
122     swi   r3,r12,0;                                 \
123     rtsd  r15,8;                                    \
124     addik r3,r0,-1;
125 #  else /* !RTLD_PRIVATE_ERRNO.  */
126 /* Store (-r3) into errno through the GOT.  */
127 #   if defined _LIBC_REENTRANT
128 #    define SYSCALL_ERROR_HANDLER                   \
129 SYSCALL_ERROR_LABEL_DCL:                            \
130     addik r1,r1,-16;                                \
131     swi   r15,r1,0;                                 \
132     swi   r20,r1,8;                                 \
133     rsubk r3,r3,r0;                                 \
134     swi   r3,r1,12;                                 \
135     mfs   r20,rpc;                                  \
136     addik r20,r20,_GLOBAL_OFFSET_TABLE_+8;          \
137     brlid r15,__errno_location@PLT;                 \
138     nop;                                            \
139     lwi   r4,r1,12;                                 \
140     swi   r4,r3,0;                                  \
141     lwi   r20,r1,8;                                 \
142     lwi   r15,r1,0;                                 \
143     addik r1,r1,16;                                 \
144     rtsd  r15,8;                                    \
145     addik r3,r0,-1;
146 #   else /* !_LIBC_REENTRANT.  */
147 #    define SYSCALL_ERROR_HANDLER                   \
148 SYSCALL_ERROR_LABEL_DCL:                            \
149     mfs   r12,rpc;                                  \
150     addik r12,r12,_GLOBAL_OFFSET_TABLE_+8;          \
151     lwi   r12,r12,errno@GOT;                        \
152     rsubk r3,r3,r0;                                 \
153     swi   r3,r12,0;                                 \
154     rtsd  r15,8;                                    \
155     addik r3,r0,-1;
156 #    endif /* _LIBC_REENTRANT.  */
157 # endif /* RTLD_PRIVATE_ERRNO.  */
158 # else
159 #  define SYSCALL_ERROR_HANDLER  /* Nothing here; code in sysdep.S is used.  */
160 # endif /* PIC.  */
161 
162 # define DO_CALL(syscall_name, args)                \
163     addik r12,r0,SYS_ify (syscall_name);            \
164     brki  r14,8;                                    \
165     addk  r0,r0,r0;
166 
167 #else /* not __ASSEMBLER__ */
168 
169 /* Define a macro which expands inline into the wrapper code for a system
170    call.  This use is for internal calls that do not need to handle errors
171    normally.  It will never touch errno.  This returns just what the kernel
172    gave back.  */
173 # undef INTERNAL_SYSCALL
174 # define INTERNAL_SYSCALL(name, nr, args...)                    \
175   inline_syscall##nr(SYS_ify(name), args)
176 
177 # undef INTERNAL_SYSCALL_NCS
178 # define INTERNAL_SYSCALL_NCS(name, nr, args...)                \
179   inline_syscall##nr(name, args)
180 
181 # define SYSCALL_CLOBBERS_6 "r11", "r4", "memory"
182 # define SYSCALL_CLOBBERS_5 "r10", SYSCALL_CLOBBERS_6
183 # define SYSCALL_CLOBBERS_4 "r9", SYSCALL_CLOBBERS_5
184 # define SYSCALL_CLOBBERS_3 "r8", SYSCALL_CLOBBERS_4
185 # define SYSCALL_CLOBBERS_2 "r7", SYSCALL_CLOBBERS_3
186 # define SYSCALL_CLOBBERS_1 "r6", SYSCALL_CLOBBERS_2
187 # define SYSCALL_CLOBBERS_0 "r5", SYSCALL_CLOBBERS_1
188 
189 # define inline_syscall0(name,dummy)                                          \
190   ({                                                                          \
191     register long int __ret __asm__("r3");                                    \
192     register long int __r12 __asm__("r12") = name;                            \
193     __asm__ __volatile__( "brki r14,8; nop;"                                  \
194       : "=r"(__ret)                                                           \
195       : "r"(__r12)                                                            \
196       : SYSCALL_CLOBBERS_0 ); __ret;                                          \
197   })
198 
199 # define inline_syscall1(name,arg1)                                           \
200   ({                                                                          \
201     long int __arg1 = (long int) (arg1);                                      \
202     register long int __ret __asm__("r3");                                    \
203     register long int __r12 __asm__("r12") = name;                            \
204     register long int __r5 __asm__("r5") = __arg1;                            \
205     __asm__ __volatile__( "brki r14,8; nop;"                                  \
206       : "=r"(__ret)                                                           \
207       : "r"(__r5), "r"(__r12)                                                 \
208       : SYSCALL_CLOBBERS_1 ); __ret;                                          \
209   })
210 
211 # define inline_syscall2(name,arg1,arg2)                                      \
212   ({                                                                          \
213     long int __arg1 = (long int) (arg1);                                      \
214     long int __arg2 = (long int) (arg2);                                      \
215     register long int __ret __asm__("r3");                                    \
216     register long int __r12 __asm__("r12") = name;                            \
217     register long int __r5 __asm__("r5") = __arg1;                            \
218     register long int __r6 __asm__("r6") = __arg2;                            \
219     __asm__ __volatile__( "brki r14,8; nop;"                                  \
220       : "=r"(__ret)                                                           \
221       : "r"(__r5), "r"(__r6), "r"(__r12)                                      \
222       : SYSCALL_CLOBBERS_2 ); __ret;                                          \
223   })
224 
225 
226 # define inline_syscall3(name,arg1,arg2,arg3)                                 \
227   ({                                                                          \
228     long int __arg1 = (long int) (arg1);                                      \
229     long int __arg2 = (long int) (arg2);                                      \
230     long int __arg3 = (long int) (arg3);                                      \
231     register long int __ret __asm__("r3");                                    \
232     register long int __r12 __asm__("r12") = name;                            \
233     register long int __r5 __asm__("r5") = __arg1;                            \
234     register long int __r6 __asm__("r6") = __arg2;                            \
235     register long int __r7 __asm__("r7") = __arg3;                            \
236     __asm__ __volatile__( "brki r14,8; nop;"                                  \
237       : "=r"(__ret)                                                           \
238       : "r"(__r5), "r"(__r6), "r"(__r7), "r"(__r12)                           \
239       : SYSCALL_CLOBBERS_3 ); __ret;                                          \
240   })
241 
242 
243 # define inline_syscall4(name,arg1,arg2,arg3,arg4)                            \
244   ({                                                                          \
245     long int __arg1 = (long int) (arg1);                                      \
246     long int __arg2 = (long int) (arg2);                                      \
247     long int __arg3 = (long int) (arg3);                                      \
248     long int __arg4 = (long int) (arg4);                                      \
249     register long int __ret __asm__("r3");                                    \
250     register long int __r12 __asm__("r12") = name;                            \
251     register long int __r5 __asm__("r5") = __arg1;                            \
252     register long int __r6 __asm__("r6") = __arg2;                            \
253     register long int __r7 __asm__("r7") = __arg3;                            \
254     register long int __r8 __asm__("r8") = __arg4;                            \
255     __asm__ __volatile__( "brki r14,8; nop;"                                  \
256       : "=r"(__ret)                                                           \
257       : "r"(__r5), "r"(__r6), "r"(__r7), "r"(__r8),"r"(__r12)                 \
258       : SYSCALL_CLOBBERS_4 ); __ret;                                          \
259   })
260 
261 
262 # define inline_syscall5(name,arg1,arg2,arg3,arg4,arg5)                       \
263   ({                                                                          \
264     long int __arg1 = (long int) (arg1);                                      \
265     long int __arg2 = (long int) (arg2);                                      \
266     long int __arg3 = (long int) (arg3);                                      \
267     long int __arg4 = (long int) (arg4);                                      \
268     long int __arg5 = (long int) (arg5);                                      \
269     register long int __ret __asm__("r3");                                    \
270     register long int __r12 __asm__("r12") = name;                            \
271     register long int __r5 __asm__("r5") = __arg1;                            \
272     register long int __r6 __asm__("r6") = __arg2;                            \
273     register long int __r7 __asm__("r7") = __arg3;                            \
274     register long int __r8 __asm__("r8") = __arg4;                            \
275     register long int __r9 __asm__("r9") = __arg5;                            \
276     __asm__ __volatile__( "brki r14,8; nop;"                                  \
277       : "=r"(__ret)                                                           \
278       : "r"(__r5), "r"(__r6), "r"(__r7), "r"(__r8),"r"(__r9), "r"(__r12)      \
279       : SYSCALL_CLOBBERS_5 ); __ret;                                          \
280   })
281 
282 
283 # define inline_syscall6(name,arg1,arg2,arg3,arg4,arg5,arg6)                  \
284   ({                                                                          \
285     long int __arg1 = (long int) (arg1);                                      \
286     long int __arg2 = (long int) (arg2);                                      \
287     long int __arg3 = (long int) (arg3);                                      \
288     long int __arg4 = (long int) (arg4);                                      \
289     long int __arg5 = (long int) (arg5);                                      \
290     long int __arg6 = (long int) (arg6);                                      \
291     register long int __ret __asm__("r3");                                    \
292     register long int __r12 __asm__("r12") = name;                            \
293     register long int __r5 __asm__("r5") = __arg1;                            \
294     register long int __r6 __asm__("r6") = __arg2;                            \
295     register long int __r7 __asm__("r7") = __arg3;                            \
296     register long int __r8 __asm__("r8") = __arg4;                            \
297     register long int __r9 __asm__("r9") = __arg5;                            \
298     register long int __r10 __asm__("r10") = __arg6;                          \
299     __asm__ __volatile__( "brki r14,8; nop;"                                  \
300       : "=r"(__ret)                                                           \
301       : "r"(__r5), "r"(__r6), "r"(__r7), "r"(__r8),"r"(__r9), "r"(__r10),     \
302       "r"(__r12)                                                              \
303       : SYSCALL_CLOBBERS_6 ); __ret;                                          \
304   })
305 
306 
307 /* Pointer mangling is not yet supported for Microblaze.  */
308 # define PTR_MANGLE(var) (void) (var)
309 # define PTR_DEMANGLE(var) (void) (var)
310 
311 # define SINGLE_THREAD_BY_GLOBAL	1
312 
313 #undef HAVE_INTERNAL_BRK_ADDR_SYMBOL
314 #define HAVE_INTERNAL_BRK_ADDR_SYMBOL 1
315 
316 #endif /* not __ASSEMBLER__ */
317 
318 #endif /* _LINUX_MICROBLAZE_SYSDEP_H */
319