1 /* Assembler macros for ARC. 2 Copyright (C) 2020-2021 Free Software Foundation, Inc. 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 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 16 License along with the GNU C Library; if not, see 17 <https://www.gnu.org/licenses/>. */ 18 19 #ifndef _LINUX_ARC_SYSDEP_H 20 #define _LINUX_ARC_SYSDEP_H 1 21 22 #include <sysdeps/arc/sysdep.h> 23 #include <sysdeps/unix/sysv/linux/generic/sysdep.h> 24 25 /* "workarounds" for generic code needing to handle 64-bit time_t. */ 26 27 /* Fix sysdeps/unix/sysv/linux/clock_getcpuclockid.c. */ 28 #define __NR_clock_getres __NR_clock_getres_time64 29 /* Fix sysdeps/nptl/lowlevellock-futex.h. */ 30 #define __NR_futex __NR_futex_time64 31 /* Fix sysdeps/unix/sysv/linux/pause.c. */ 32 #define __NR_ppoll __NR_ppoll_time64 33 /* Fix sysdeps/unix/sysv/linux/select.c. */ 34 #define __NR_pselect6 __NR_pselect6_time64 35 /* Fix sysdeps/unix/sysv/linux/recvmmsg.c. */ 36 #define __NR_recvmmsg __NR_recvmmsg_time64 37 /* Fix sysdeps/unix/sysv/linux/sigtimedwait.c. */ 38 #define __NR_rt_sigtimedwait __NR_rt_sigtimedwait_time64 39 /* Fix sysdeps/unix/sysv/linux/semtimedop.c. */ 40 #define __NR_semtimedop __NR_semtimedop_time64 41 /* Hack sysdeps/unix/sysv/linux/generic/utimes.c. */ 42 #define __NR_utimensat __NR_utimensat_time64 43 44 /* For RTLD_PRIVATE_ERRNO. */ 45 #include <dl-sysdep.h> 46 47 #include <tls.h> 48 49 #undef SYS_ify 50 #define SYS_ify(syscall_name) __NR_##syscall_name 51 52 #ifdef __ASSEMBLER__ 53 54 /* This is a "normal" system call stub: if there is an error, 55 it returns -1 and sets errno. */ 56 57 # undef PSEUDO 58 # define PSEUDO(name, syscall_name, args) \ 59 PSEUDO_NOERRNO(name, syscall_name, args) ASM_LINE_SEP \ 60 brhi r0, -4096, L (call_syscall_err) ASM_LINE_SEP 61 62 # define ret j_s [blink] 63 64 # undef PSEUDO_END 65 # define PSEUDO_END(name) \ 66 SYSCALL_ERROR_HANDLER ASM_LINE_SEP \ 67 END (name) 68 69 /* --------- Helper for SYSCALL_NOERRNO ----------- 70 This kind of system call stub never returns an error. 71 We return the return value register to the caller unexamined. */ 72 73 # undef PSEUDO_NOERRNO 74 # define PSEUDO_NOERRNO(name, syscall_name, args) \ 75 .text ASM_LINE_SEP \ 76 ENTRY (name) ASM_LINE_SEP \ 77 DO_CALL (syscall_name, args) ASM_LINE_SEP \ 78 79 /* Return the return value register unexamined. Since r0 is both 80 syscall return reg and function return reg, no work needed. */ 81 # define ret_NOERRNO \ 82 j_s [blink] ASM_LINE_SEP 83 84 # undef PSEUDO_END_NOERRNO 85 # define PSEUDO_END_NOERRNO(name) \ 86 END (name) 87 88 /* --------- Helper for SYSCALL_ERRVAL ----------- 89 This kind of system call stub returns the errno code as its return 90 value, or zero for success. We may massage the kernel's return value 91 to meet that ABI, but we never set errno here. */ 92 93 # undef PSEUDO_ERRVAL 94 # define PSEUDO_ERRVAL(name, syscall_name, args) \ 95 PSEUDO_NOERRNO(name, syscall_name, args) ASM_LINE_SEP 96 97 /* Don't set errno, return kernel error (in errno form) or zero. */ 98 # define ret_ERRVAL \ 99 rsub r0, r0, 0 ASM_LINE_SEP \ 100 ret_NOERRNO 101 102 # undef PSEUDO_END_ERRVAL 103 # define PSEUDO_END_ERRVAL(name) \ 104 END (name) 105 106 107 /* To reduce the code footprint, we confine the actual errno access 108 to single place in __syscall_error(). 109 This takes raw kernel error value, sets errno and returns -1. */ 110 # if IS_IN (libc) 111 # define CALL_ERRNO_SETTER_C bl PLTJMP(HIDDEN_JUMPTARGET(__syscall_error)) 112 # else 113 # define CALL_ERRNO_SETTER_C bl PLTJMP(__syscall_error) 114 # endif 115 116 # define SYSCALL_ERROR_HANDLER \ 117 L (call_syscall_err): ASM_LINE_SEP \ 118 push_s blink ASM_LINE_SEP \ 119 cfi_adjust_cfa_offset (4) ASM_LINE_SEP \ 120 cfi_rel_offset (blink, 0) ASM_LINE_SEP \ 121 CALL_ERRNO_SETTER_C ASM_LINE_SEP \ 122 pop_s blink ASM_LINE_SEP \ 123 cfi_adjust_cfa_offset (-4) ASM_LINE_SEP \ 124 cfi_restore (blink) ASM_LINE_SEP \ 125 j_s [blink] 126 127 # define DO_CALL(syscall_name, args) \ 128 mov r8, __NR_##syscall_name ASM_LINE_SEP \ 129 ARC_TRAP_INSN ASM_LINE_SEP 130 131 # define ARC_TRAP_INSN trap_s 0 132 133 #else /* !__ASSEMBLER__ */ 134 135 # define SINGLE_THREAD_BY_GLOBAL 1 136 137 # if IS_IN (libc) 138 extern long int __syscall_error (long int); 139 hidden_proto (__syscall_error) 140 # endif 141 142 # define ARC_TRAP_INSN "trap_s 0 \n\t" 143 144 # undef INTERNAL_SYSCALL_NCS 145 # define INTERNAL_SYSCALL_NCS(number, nr_args, args...) \ 146 ({ \ 147 /* Per ABI, r0 is 1st arg and return reg. */ \ 148 register long int __ret __asm__("r0"); \ 149 register long int _sys_num __asm__("r8"); \ 150 \ 151 LOAD_ARGS_##nr_args (number, args) \ 152 \ 153 __asm__ volatile ( \ 154 ARC_TRAP_INSN \ 155 : "+r" (__ret) \ 156 : "r"(_sys_num) ASM_ARGS_##nr_args \ 157 : "memory"); \ 158 \ 159 __ret; }) 160 161 # undef INTERNAL_SYSCALL 162 # define INTERNAL_SYSCALL(name, nr, args...) \ 163 INTERNAL_SYSCALL_NCS(__NR_##name, nr, args) 164 165 /* Macros for setting up inline __asm__ input regs. */ 166 # define ASM_ARGS_0 167 # define ASM_ARGS_1 ASM_ARGS_0, "r" (__ret) 168 # define ASM_ARGS_2 ASM_ARGS_1, "r" (_arg2) 169 # define ASM_ARGS_3 ASM_ARGS_2, "r" (_arg3) 170 # define ASM_ARGS_4 ASM_ARGS_3, "r" (_arg4) 171 # define ASM_ARGS_5 ASM_ARGS_4, "r" (_arg5) 172 # define ASM_ARGS_6 ASM_ARGS_5, "r" (_arg6) 173 # define ASM_ARGS_7 ASM_ARGS_6, "r" (_arg7) 174 175 /* Macros for converting sys-call wrapper args into sys call args. */ 176 # define LOAD_ARGS_0(nm, arg) \ 177 _sys_num = (long int) (nm); 178 179 # define LOAD_ARGS_1(nm, arg1) \ 180 __ret = (long int) (arg1); \ 181 LOAD_ARGS_0 (nm, arg1) 182 183 /* Note that the use of _tmpX might look superflous, however it is needed 184 to ensure that register variables are not clobbered if arg happens to be 185 a function call itself. e.g. sched_setaffinity() calling getpid() for arg2 186 Also this specific order of recursive calling is important to segregate 187 the tmp args evaluation (function call case described above) and assigment 188 of register variables. */ 189 190 # define LOAD_ARGS_2(nm, arg1, arg2) \ 191 long int _tmp2 = (long int) (arg2); \ 192 LOAD_ARGS_1 (nm, arg1) \ 193 register long int _arg2 __asm__ ("r1") = _tmp2; 194 195 # define LOAD_ARGS_3(nm, arg1, arg2, arg3) \ 196 long int _tmp3 = (long int) (arg3); \ 197 LOAD_ARGS_2 (nm, arg1, arg2) \ 198 register long int _arg3 __asm__ ("r2") = _tmp3; 199 200 #define LOAD_ARGS_4(nm, arg1, arg2, arg3, arg4) \ 201 long int _tmp4 = (long int) (arg4); \ 202 LOAD_ARGS_3 (nm, arg1, arg2, arg3) \ 203 register long int _arg4 __asm__ ("r3") = _tmp4; 204 205 # define LOAD_ARGS_5(nm, arg1, arg2, arg3, arg4, arg5) \ 206 long int _tmp5 = (long int) (arg5); \ 207 LOAD_ARGS_4 (nm, arg1, arg2, arg3, arg4) \ 208 register long int _arg5 __asm__ ("r4") = _tmp5; 209 210 # define LOAD_ARGS_6(nm, arg1, arg2, arg3, arg4, arg5, arg6)\ 211 long int _tmp6 = (long int) (arg6); \ 212 LOAD_ARGS_5 (nm, arg1, arg2, arg3, arg4, arg5) \ 213 register long int _arg6 __asm__ ("r5") = _tmp6; 214 215 # define LOAD_ARGS_7(nm, arg1, arg2, arg3, arg4, arg5, arg6, arg7)\ 216 long int _tmp7 = (int) (arg7); \ 217 LOAD_ARGS_6 (nm, arg1, arg2, arg3, arg4, arg5, arg6) \ 218 register long int _arg7 __asm__ ("r6") = _tmp7; 219 220 /* Pointer mangling not yet supported. */ 221 # define PTR_MANGLE(var) (void) (var) 222 # define PTR_DEMANGLE(var) (void) (var) 223 224 # undef HAVE_INTERNAL_BRK_ADDR_SYMBOL 225 # define HAVE_INTERNAL_BRK_ADDR_SYMBOL 1 226 227 #endif /* !__ASSEMBLER__ */ 228 229 #endif /* linux/arc/sysdep.h */ 230