1 /* Copyright (C) 2000-2021 Free Software Foundation, Inc. 2 This file is part of the GNU C Library. 3 4 The GNU C Library is free software; you can redistribute it and/or 5 modify it under the terms of the GNU Lesser General Public 6 License as published by the Free Software Foundation; either 7 version 2.1 of the License, or (at your option) any later version. 8 9 The GNU C Library is distributed in the hope that it will be useful, 10 but WITHOUT ANY WARRANTY; without even the implied warranty of 11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 Lesser General Public License for more details. 13 14 You should have received a copy of the GNU Lesser General Public 15 License along with the GNU C Library. If not, see 16 <https://www.gnu.org/licenses/>. */ 17 18 #ifndef _LINUX_MIPS_MIPS32_SYSDEP_H 19 #define _LINUX_MIPS_MIPS32_SYSDEP_H 1 20 21 /* There is some commonality. */ 22 #include <sysdeps/unix/sysv/linux/mips/sysdep.h> 23 #include <sysdeps/unix/sysv/linux/sysdep.h> 24 #include <sysdeps/unix/mips/mips32/sysdep.h> 25 26 #include <tls.h> 27 28 /* For Linux we can use the system call table in the header file 29 /usr/include/asm/unistd.h 30 of the kernel. But these symbols do not follow the SYS_* syntax 31 so we have to redefine the `SYS_ify' macro here. */ 32 #undef SYS_ify 33 #define SYS_ify(syscall_name) __NR_##syscall_name 34 35 #ifdef __ASSEMBLER__ 36 37 /* We don't want the label for the error handler to be visible in the symbol 38 table when we define it here. */ 39 #ifdef __PIC__ 40 # undef SYSCALL_ERROR_LABEL 41 # define SYSCALL_ERROR_LABEL 99b 42 #endif 43 44 #else /* ! __ASSEMBLER__ */ 45 46 #undef HAVE_INTERNAL_BRK_ADDR_SYMBOL 47 #define HAVE_INTERNAL_BRK_ADDR_SYMBOL 1 48 49 /* Note that the original Linux syscall restart convention required the 50 instruction immediately preceding SYSCALL to initialize $v0 with the 51 syscall number. Then if a restart triggered, $v0 would have been 52 clobbered by the syscall interrupted, and needed to be reinititalized. 53 The kernel would decrement the PC by 4 before switching back to the 54 user mode so that $v0 had been reloaded before SYSCALL was executed 55 again. This implied the place $v0 was loaded from must have been 56 preserved across a syscall, e.g. an immediate, static register, stack 57 slot, etc. 58 59 The convention was relaxed in Linux with a change applied to the kernel 60 GIT repository as commit 96187fb0bc30cd7919759d371d810e928048249d, that 61 first appeared in the 2.6.36 release. Since then the kernel has had 62 code that reloads $v0 upon syscall restart and resumes right at the 63 SYSCALL instruction, so no special arrangement is needed anymore. 64 65 For backwards compatibility with existing kernel binaries we support 66 the old convention by choosing the instruction preceding SYSCALL 67 carefully. This also means we have to force a 32-bit encoding of the 68 microMIPS MOVE instruction if one is used. */ 69 70 #ifdef __mips_micromips 71 # define MOVE32 "move32" 72 #else 73 # define MOVE32 "move" 74 #endif 75 76 #undef INTERNAL_SYSCALL 77 #undef INTERNAL_SYSCALL_NCS 78 79 #define __nomips16 __attribute__ ((nomips16)) 80 81 union __mips_syscall_return 82 { 83 long long int val; 84 struct 85 { 86 long int v0; 87 long int v1; 88 } 89 reg; 90 }; 91 92 #ifdef __mips16 93 /* There's no MIPS16 syscall instruction, so we go through out-of-line 94 standard MIPS wrappers. These do use inline snippets below though, 95 through INTERNAL_SYSCALL_MIPS16. Spilling the syscall number to 96 memory gives the best code in that case, avoiding the need to save 97 and restore a static register. */ 98 99 # include <mips16-syscall.h> 100 101 # define INTERNAL_SYSCALL(name, nr, args...) \ 102 INTERNAL_SYSCALL_NCS (SYS_ify (name), nr, args) 103 104 # define INTERNAL_SYSCALL_NCS(number, nr, args...) \ 105 ({ \ 106 union __mips_syscall_return _sc_ret; \ 107 _sc_ret.val = __mips16_syscall##nr (args, number); \ 108 _sc_ret.reg.v0; \ 109 }) 110 111 # define INTERNAL_SYSCALL_MIPS16(number, err, nr, args...) \ 112 internal_syscall##nr ("lw\t%0, %2\n\t", \ 113 "R" (number), \ 114 number, err, args) 115 116 #else /* !__mips16 */ 117 # define INTERNAL_SYSCALL(name, nr, args...) \ 118 internal_syscall##nr ("li\t%0, %2\t\t\t# " #name "\n\t", \ 119 "IK" (SYS_ify (name)), \ 120 SYS_ify (name), err, args) 121 122 # define INTERNAL_SYSCALL_NCS(number, nr, args...) \ 123 internal_syscall##nr (MOVE32 "\t%0, %2\n\t", \ 124 "r" (__s0), \ 125 number, err, args) 126 127 #endif /* !__mips16 */ 128 129 #define internal_syscall0(v0_init, input, number, err, dummy...) \ 130 ({ \ 131 long int _sys_result; \ 132 \ 133 { \ 134 register long int __s0 asm ("$16") __attribute__ ((unused)) \ 135 = (number); \ 136 register long int __v0 asm ("$2"); \ 137 register long int __a3 asm ("$7"); \ 138 __asm__ volatile ( \ 139 ".set\tnoreorder\n\t" \ 140 v0_init \ 141 "syscall\n\t" \ 142 ".set reorder" \ 143 : "=r" (__v0), "=r" (__a3) \ 144 : input \ 145 : __SYSCALL_CLOBBERS); \ 146 _sys_result = __a3 != 0 ? -__v0 : __v0; \ 147 } \ 148 _sys_result; \ 149 }) 150 151 #define internal_syscall1(v0_init, input, number, err, arg1) \ 152 ({ \ 153 long int _sys_result; \ 154 \ 155 { \ 156 long int _arg1 = (long int) (arg1); \ 157 register long int __s0 asm ("$16") __attribute__ ((unused)) \ 158 = (number); \ 159 register long int __v0 asm ("$2"); \ 160 register long int __a0 asm ("$4") = _arg1; \ 161 register long int __a3 asm ("$7"); \ 162 __asm__ volatile ( \ 163 ".set\tnoreorder\n\t" \ 164 v0_init \ 165 "syscall\n\t" \ 166 ".set reorder" \ 167 : "=r" (__v0), "=r" (__a3) \ 168 : input, "r" (__a0) \ 169 : __SYSCALL_CLOBBERS); \ 170 _sys_result = __a3 != 0 ? -__v0 : __v0; \ 171 } \ 172 _sys_result; \ 173 }) 174 175 #define internal_syscall2(v0_init, input, number, err, arg1, arg2) \ 176 ({ \ 177 long int _sys_result; \ 178 \ 179 { \ 180 long int _arg1 = (long int) (arg1); \ 181 long int _arg2 = (long int) (arg2); \ 182 register long int __s0 asm ("$16") __attribute__ ((unused)) \ 183 = (number); \ 184 register long int __v0 asm ("$2"); \ 185 register long int __a0 asm ("$4") = _arg1; \ 186 register long int __a1 asm ("$5") = _arg2; \ 187 register long int __a3 asm ("$7"); \ 188 __asm__ volatile ( \ 189 ".set\tnoreorder\n\t" \ 190 v0_init \ 191 "syscall\n\t" \ 192 ".set\treorder" \ 193 : "=r" (__v0), "=r" (__a3) \ 194 : input, "r" (__a0), "r" (__a1) \ 195 : __SYSCALL_CLOBBERS); \ 196 _sys_result = __a3 != 0 ? -__v0 : __v0; \ 197 } \ 198 _sys_result; \ 199 }) 200 201 #define internal_syscall3(v0_init, input, number, err, \ 202 arg1, arg2, arg3) \ 203 ({ \ 204 long int _sys_result; \ 205 \ 206 { \ 207 long int _arg1 = (long int) (arg1); \ 208 long int _arg2 = (long int) (arg2); \ 209 long int _arg3 = (long int) (arg3); \ 210 register long int __s0 asm ("$16") __attribute__ ((unused)) \ 211 = (number); \ 212 register long int __v0 asm ("$2"); \ 213 register long int __a0 asm ("$4") = _arg1; \ 214 register long int __a1 asm ("$5") = _arg2; \ 215 register long int __a2 asm ("$6") = _arg3; \ 216 register long int __a3 asm ("$7"); \ 217 __asm__ volatile ( \ 218 ".set\tnoreorder\n\t" \ 219 v0_init \ 220 "syscall\n\t" \ 221 ".set\treorder" \ 222 : "=r" (__v0), "=r" (__a3) \ 223 : input, "r" (__a0), "r" (__a1), "r" (__a2) \ 224 : __SYSCALL_CLOBBERS); \ 225 _sys_result = __a3 != 0 ? -__v0 : __v0; \ 226 } \ 227 _sys_result; \ 228 }) 229 230 #define internal_syscall4(v0_init, input, number, err, \ 231 arg1, arg2, arg3, arg4) \ 232 ({ \ 233 long int _sys_result; \ 234 \ 235 { \ 236 long int _arg1 = (long int) (arg1); \ 237 long int _arg2 = (long int) (arg2); \ 238 long int _arg3 = (long int) (arg3); \ 239 long int _arg4 = (long int) (arg4); \ 240 register long int __s0 asm ("$16") __attribute__ ((unused)) \ 241 = (number); \ 242 register long int __v0 asm ("$2"); \ 243 register long int __a0 asm ("$4") = _arg1; \ 244 register long int __a1 asm ("$5") = _arg2; \ 245 register long int __a2 asm ("$6") = _arg3; \ 246 register long int __a3 asm ("$7") = _arg4; \ 247 __asm__ volatile ( \ 248 ".set\tnoreorder\n\t" \ 249 v0_init \ 250 "syscall\n\t" \ 251 ".set\treorder" \ 252 : "=r" (__v0), "+r" (__a3) \ 253 : input, "r" (__a0), "r" (__a1), "r" (__a2) \ 254 : __SYSCALL_CLOBBERS); \ 255 _sys_result = __a3 != 0 ? -__v0 : __v0; \ 256 } \ 257 _sys_result; \ 258 }) 259 260 /* Standalone MIPS wrappers used for 5, 6, and 7 argument syscalls, 261 which require stack arguments. We rely on the compiler arranging 262 wrapper's arguments according to the MIPS o32 function calling 263 convention, which is reused by syscalls, except for the syscall 264 number passed and the error flag returned (taken care of in the 265 wrapper called). This relieves us from relying on non-guaranteed 266 compiler specifics required for the stack arguments to be pushed, 267 which would be the case if these syscalls were inlined. */ 268 269 long long int __nomips16 __mips_syscall5 (long int arg1, long int arg2, 270 long int arg3, long int arg4, 271 long int arg5, 272 long int number); 273 libc_hidden_proto (__mips_syscall5, nomips16) 274 275 #define internal_syscall5(v0_init, input, number, err, \ 276 arg1, arg2, arg3, arg4, arg5) \ 277 ({ \ 278 union __mips_syscall_return _sc_ret; \ 279 _sc_ret.val = __mips_syscall5 ((long int) (arg1), \ 280 (long int) (arg2), \ 281 (long int) (arg3), \ 282 (long int) (arg4), \ 283 (long int) (arg5), \ 284 (long int) (number)); \ 285 _sc_ret.reg.v1 != 0 ? -_sc_ret.reg.v0 : _sc_ret.reg.v0; \ 286 }) 287 288 long long int __nomips16 __mips_syscall6 (long int arg1, long int arg2, 289 long int arg3, long int arg4, 290 long int arg5, long int arg6, 291 long int number); 292 libc_hidden_proto (__mips_syscall6, nomips16) 293 294 #define internal_syscall6(v0_init, input, number, err, \ 295 arg1, arg2, arg3, arg4, arg5, arg6) \ 296 ({ \ 297 union __mips_syscall_return _sc_ret; \ 298 _sc_ret.val = __mips_syscall6 ((long int) (arg1), \ 299 (long int) (arg2), \ 300 (long int) (arg3), \ 301 (long int) (arg4), \ 302 (long int) (arg5), \ 303 (long int) (arg6), \ 304 (long int) (number)); \ 305 _sc_ret.reg.v1 != 0 ? -_sc_ret.reg.v0 : _sc_ret.reg.v0; \ 306 }) 307 308 long long int __nomips16 __mips_syscall7 (long int arg1, long int arg2, 309 long int arg3, long int arg4, 310 long int arg5, long int arg6, 311 long int arg7, 312 long int number); 313 libc_hidden_proto (__mips_syscall7, nomips16) 314 315 #define internal_syscall7(v0_init, input, number, err, \ 316 arg1, arg2, arg3, arg4, arg5, arg6, arg7) \ 317 ({ \ 318 union __mips_syscall_return _sc_ret; \ 319 _sc_ret.val = __mips_syscall7 ((long int) (arg1), \ 320 (long int) (arg2), \ 321 (long int) (arg3), \ 322 (long int) (arg4), \ 323 (long int) (arg5), \ 324 (long int) (arg6), \ 325 (long int) (arg7), \ 326 (long int) (number)); \ 327 _sc_ret.reg.v1 != 0 ? -_sc_ret.reg.v0 : _sc_ret.reg.v0; \ 328 }) 329 330 #if __mips_isa_rev >= 6 331 # define __SYSCALL_CLOBBERS "$1", "$3", "$8", "$9", "$10", "$11", "$12", "$13", \ 332 "$14", "$15", "$24", "$25", "memory" 333 #else 334 # define __SYSCALL_CLOBBERS "$1", "$3", "$8", "$9", "$10", "$11", "$12", "$13", \ 335 "$14", "$15", "$24", "$25", "hi", "lo", "memory" 336 #endif 337 338 #endif /* __ASSEMBLER__ */ 339 340 /* Pointer mangling is not yet supported for MIPS. */ 341 #define PTR_MANGLE(var) (void) (var) 342 #define PTR_DEMANGLE(var) (void) (var) 343 344 #endif /* linux/mips/mips32/sysdep.h */ 345