1 /* Copyright (C) 2000-2022 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_SYSDEP_H 19 #define _LINUX_MIPS_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/mips64/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 # undef SYSCALL_ERROR_LABEL 40 # define SYSCALL_ERROR_LABEL 99b 41 42 #else /* ! __ASSEMBLER__ */ 43 44 #undef HAVE_INTERNAL_BRK_ADDR_SYMBOL 45 #define HAVE_INTERNAL_BRK_ADDR_SYMBOL 1 46 47 #if _MIPS_SIM == _ABIN32 48 /* Convert X to a long long, without losing any bits if it is one 49 already or warning if it is a 32-bit pointer. */ 50 # define ARGIFY(X) ((long long int) (__typeof__ ((X) - (X))) (X)) 51 typedef long long int __syscall_arg_t; 52 #else 53 # define ARGIFY(X) ((long int) (X)) 54 typedef long int __syscall_arg_t; 55 #endif 56 57 /* Note that the original Linux syscall restart convention required the 58 instruction immediately preceding SYSCALL to initialize $v0 with the 59 syscall number. Then if a restart triggered, $v0 would have been 60 clobbered by the syscall interrupted, and needed to be reinititalized. 61 The kernel would decrement the PC by 4 before switching back to the 62 user mode so that $v0 had been reloaded before SYSCALL was executed 63 again. This implied the place $v0 was loaded from must have been 64 preserved across a syscall, e.g. an immediate, static register, stack 65 slot, etc. 66 67 The convention was relaxed in Linux with a change applied to the kernel 68 GIT repository as commit 96187fb0bc30cd7919759d371d810e928048249d, that 69 first appeared in the 2.6.36 release. Since then the kernel has had 70 code that reloads $v0 upon syscall restart and resumes right at the 71 SYSCALL instruction, so no special arrangement is needed anymore. 72 73 For backwards compatibility with existing kernel binaries we support 74 the old convention by choosing the instruction preceding SYSCALL 75 carefully. This also means we have to force a 32-bit encoding of the 76 microMIPS MOVE instruction if one is used. */ 77 78 #ifdef __mips_micromips 79 # define MOVE32 "move32" 80 #else 81 # define MOVE32 "move" 82 #endif 83 84 #undef INTERNAL_SYSCALL 85 #define INTERNAL_SYSCALL(name, nr, args...) \ 86 internal_syscall##nr ("li\t%0, %2\t\t\t# " #name "\n\t", \ 87 "IK" (SYS_ify (name)), \ 88 0, args) 89 90 #undef INTERNAL_SYSCALL_NCS 91 #define INTERNAL_SYSCALL_NCS(number, nr, args...) \ 92 internal_syscall##nr (MOVE32 "\t%0, %2\n\t", \ 93 "r" (__s0), \ 94 number, args) 95 96 #define internal_syscall0(v0_init, input, number, dummy...) \ 97 ({ \ 98 long int _sys_result; \ 99 \ 100 { \ 101 register __syscall_arg_t __s0 asm ("$16") __attribute__ ((unused))\ 102 = (number); \ 103 register __syscall_arg_t __v0 asm ("$2"); \ 104 register __syscall_arg_t __a3 asm ("$7"); \ 105 __asm__ volatile ( \ 106 ".set\tnoreorder\n\t" \ 107 v0_init \ 108 "syscall\n\t" \ 109 ".set reorder" \ 110 : "=r" (__v0), "=r" (__a3) \ 111 : input \ 112 : __SYSCALL_CLOBBERS); \ 113 _sys_result = __a3 != 0 ? -__v0 : __v0; \ 114 } \ 115 _sys_result; \ 116 }) 117 118 #define internal_syscall1(v0_init, input, number, arg1) \ 119 ({ \ 120 long int _sys_result; \ 121 \ 122 { \ 123 __syscall_arg_t _arg1 = ARGIFY (arg1); \ 124 register __syscall_arg_t __s0 asm ("$16") __attribute__ ((unused))\ 125 = (number); \ 126 register __syscall_arg_t __v0 asm ("$2"); \ 127 register __syscall_arg_t __a0 asm ("$4") = _arg1; \ 128 register __syscall_arg_t __a3 asm ("$7"); \ 129 __asm__ volatile ( \ 130 ".set\tnoreorder\n\t" \ 131 v0_init \ 132 "syscall\n\t" \ 133 ".set reorder" \ 134 : "=r" (__v0), "=r" (__a3) \ 135 : input, "r" (__a0) \ 136 : __SYSCALL_CLOBBERS); \ 137 _sys_result = __a3 != 0 ? -__v0 : __v0; \ 138 } \ 139 _sys_result; \ 140 }) 141 142 #define internal_syscall2(v0_init, input, number, arg1, arg2) \ 143 ({ \ 144 long int _sys_result; \ 145 \ 146 { \ 147 __syscall_arg_t _arg1 = ARGIFY (arg1); \ 148 __syscall_arg_t _arg2 = ARGIFY (arg2); \ 149 register __syscall_arg_t __s0 asm ("$16") __attribute__ ((unused))\ 150 = (number); \ 151 register __syscall_arg_t __v0 asm ("$2"); \ 152 register __syscall_arg_t __a0 asm ("$4") = _arg1; \ 153 register __syscall_arg_t __a1 asm ("$5") = _arg2; \ 154 register __syscall_arg_t __a3 asm ("$7"); \ 155 __asm__ volatile ( \ 156 ".set\tnoreorder\n\t" \ 157 v0_init \ 158 "syscall\n\t" \ 159 ".set\treorder" \ 160 : "=r" (__v0), "=r" (__a3) \ 161 : input, "r" (__a0), "r" (__a1) \ 162 : __SYSCALL_CLOBBERS); \ 163 _sys_result = __a3 != 0 ? -__v0 : __v0; \ 164 } \ 165 _sys_result; \ 166 }) 167 168 #define internal_syscall3(v0_init, input, number, arg1, arg2, arg3) \ 169 ({ \ 170 long int _sys_result; \ 171 \ 172 { \ 173 __syscall_arg_t _arg1 = ARGIFY (arg1); \ 174 __syscall_arg_t _arg2 = ARGIFY (arg2); \ 175 __syscall_arg_t _arg3 = ARGIFY (arg3); \ 176 register __syscall_arg_t __s0 asm ("$16") __attribute__ ((unused))\ 177 = (number); \ 178 register __syscall_arg_t __v0 asm ("$2"); \ 179 register __syscall_arg_t __a0 asm ("$4") = _arg1; \ 180 register __syscall_arg_t __a1 asm ("$5") = _arg2; \ 181 register __syscall_arg_t __a2 asm ("$6") = _arg3; \ 182 register __syscall_arg_t __a3 asm ("$7"); \ 183 __asm__ volatile ( \ 184 ".set\tnoreorder\n\t" \ 185 v0_init \ 186 "syscall\n\t" \ 187 ".set\treorder" \ 188 : "=r" (__v0), "=r" (__a3) \ 189 : input, "r" (__a0), "r" (__a1), "r" (__a2) \ 190 : __SYSCALL_CLOBBERS); \ 191 _sys_result = __a3 != 0 ? -__v0 : __v0; \ 192 } \ 193 _sys_result; \ 194 }) 195 196 #define internal_syscall4(v0_init, input, number, arg1, arg2, arg3, \ 197 arg4) \ 198 ({ \ 199 long int _sys_result; \ 200 \ 201 { \ 202 __syscall_arg_t _arg1 = ARGIFY (arg1); \ 203 __syscall_arg_t _arg2 = ARGIFY (arg2); \ 204 __syscall_arg_t _arg3 = ARGIFY (arg3); \ 205 __syscall_arg_t _arg4 = ARGIFY (arg4); \ 206 register __syscall_arg_t __s0 asm ("$16") __attribute__ ((unused))\ 207 = (number); \ 208 register __syscall_arg_t __v0 asm ("$2"); \ 209 register __syscall_arg_t __a0 asm ("$4") = _arg1; \ 210 register __syscall_arg_t __a1 asm ("$5") = _arg2; \ 211 register __syscall_arg_t __a2 asm ("$6") = _arg3; \ 212 register __syscall_arg_t __a3 asm ("$7") = _arg4; \ 213 __asm__ volatile ( \ 214 ".set\tnoreorder\n\t" \ 215 v0_init \ 216 "syscall\n\t" \ 217 ".set\treorder" \ 218 : "=r" (__v0), "+r" (__a3) \ 219 : input, "r" (__a0), "r" (__a1), "r" (__a2) \ 220 : __SYSCALL_CLOBBERS); \ 221 _sys_result = __a3 != 0 ? -__v0 : __v0; \ 222 } \ 223 _sys_result; \ 224 }) 225 226 #define internal_syscall5(v0_init, input, number, arg1, arg2, arg3, \ 227 arg4, arg5) \ 228 ({ \ 229 long int _sys_result; \ 230 \ 231 { \ 232 __syscall_arg_t _arg1 = ARGIFY (arg1); \ 233 __syscall_arg_t _arg2 = ARGIFY (arg2); \ 234 __syscall_arg_t _arg3 = ARGIFY (arg3); \ 235 __syscall_arg_t _arg4 = ARGIFY (arg4); \ 236 __syscall_arg_t _arg5 = ARGIFY (arg5); \ 237 register __syscall_arg_t __s0 asm ("$16") __attribute__ ((unused))\ 238 = (number); \ 239 register __syscall_arg_t __v0 asm ("$2"); \ 240 register __syscall_arg_t __a0 asm ("$4") = _arg1; \ 241 register __syscall_arg_t __a1 asm ("$5") = _arg2; \ 242 register __syscall_arg_t __a2 asm ("$6") = _arg3; \ 243 register __syscall_arg_t __a3 asm ("$7") = _arg4; \ 244 register __syscall_arg_t __a4 asm ("$8") = _arg5; \ 245 __asm__ volatile ( \ 246 ".set\tnoreorder\n\t" \ 247 v0_init \ 248 "syscall\n\t" \ 249 ".set\treorder" \ 250 : "=r" (__v0), "+r" (__a3) \ 251 : input, "r" (__a0), "r" (__a1), "r" (__a2), "r" (__a4) \ 252 : __SYSCALL_CLOBBERS); \ 253 _sys_result = __a3 != 0 ? -__v0 : __v0; \ 254 } \ 255 _sys_result; \ 256 }) 257 258 #define internal_syscall6(v0_init, input, number, arg1, arg2, arg3, \ 259 arg4, arg5, arg6) \ 260 ({ \ 261 long int _sys_result; \ 262 \ 263 { \ 264 __syscall_arg_t _arg1 = ARGIFY (arg1); \ 265 __syscall_arg_t _arg2 = ARGIFY (arg2); \ 266 __syscall_arg_t _arg3 = ARGIFY (arg3); \ 267 __syscall_arg_t _arg4 = ARGIFY (arg4); \ 268 __syscall_arg_t _arg5 = ARGIFY (arg5); \ 269 __syscall_arg_t _arg6 = ARGIFY (arg6); \ 270 register __syscall_arg_t __s0 asm ("$16") __attribute__ ((unused))\ 271 = (number); \ 272 register __syscall_arg_t __v0 asm ("$2"); \ 273 register __syscall_arg_t __a0 asm ("$4") = _arg1; \ 274 register __syscall_arg_t __a1 asm ("$5") = _arg2; \ 275 register __syscall_arg_t __a2 asm ("$6") = _arg3; \ 276 register __syscall_arg_t __a3 asm ("$7") = _arg4; \ 277 register __syscall_arg_t __a4 asm ("$8") = _arg5; \ 278 register __syscall_arg_t __a5 asm ("$9") = _arg6; \ 279 __asm__ volatile ( \ 280 ".set\tnoreorder\n\t" \ 281 v0_init \ 282 "syscall\n\t" \ 283 ".set\treorder" \ 284 : "=r" (__v0), "+r" (__a3) \ 285 : input, "r" (__a0), "r" (__a1), "r" (__a2), "r" (__a4), \ 286 "r" (__a5) \ 287 : __SYSCALL_CLOBBERS); \ 288 _sys_result = __a3 != 0 ? -__v0 : __v0; \ 289 } \ 290 _sys_result; \ 291 }) 292 293 #if __mips_isa_rev >= 6 294 # define __SYSCALL_CLOBBERS "$1", "$3", "$10", "$11", "$12", "$13", \ 295 "$14", "$15", "$24", "$25", "memory" 296 #else 297 # define __SYSCALL_CLOBBERS "$1", "$3", "$10", "$11", "$12", "$13", \ 298 "$14", "$15", "$24", "$25", "hi", "lo", "memory" 299 #endif 300 301 #endif /* __ASSEMBLER__ */ 302 303 /* Pointer mangling is not yet supported for MIPS. */ 304 #define PTR_MANGLE(var) (void) (var) 305 #define PTR_DEMANGLE(var) (void) (var) 306 307 #endif /* linux/mips/sysdep.h */ 308