| 1 | /* Assembly macros for RISC-V. |
| 2 | Copyright (C) 2011-2018 |
| 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_RISCV_SYSDEP_H |
| 20 | #define _LINUX_RISCV_SYSDEP_H 1 |
| 21 | |
| 22 | #include <sysdeps/unix/sysv/linux/sysdep.h> |
| 23 | #include <sysdeps/unix/sysdep.h> |
| 24 | #include <tls.h> |
| 25 | |
| 26 | #undef SYS_ify |
| 27 | #define SYS_ify(syscall_name)	__NR_##syscall_name |
| 28 | |
| 29 | #if __WORDSIZE == 32 |
| 30 | |
| 31 | /* Workarounds for generic code needing to handle 64-bit time_t. */ |
| 32 | |
| 33 | /* Fix sysdeps/unix/sysv/linux/clock_getcpuclockid.c. */ |
| 34 | #define __NR_clock_getres	__NR_clock_getres_time64 |
| 35 | /* Fix sysdeps/nptl/lowlevellock-futex.h. */ |
| 36 | #define __NR_futex		__NR_futex_time64 |
| 37 | /* Fix sysdeps/unix/sysv/linux/pause.c. */ |
| 38 | #define __NR_ppoll		__NR_ppoll_time64 |
| 39 | /* Fix sysdeps/unix/sysv/linux/select.c. */ |
| 40 | #define __NR_pselect6		__NR_pselect6_time64 |
| 41 | /* Fix sysdeps/unix/sysv/linux/recvmmsg.c. */ |
| 42 | #define __NR_recvmmsg		__NR_recvmmsg_time64 |
| 43 | /* Fix sysdeps/unix/sysv/linux/sigtimedwait.c. */ |
| 44 | #define __NR_rt_sigtimedwait	__NR_rt_sigtimedwait_time64 |
| 45 | /* Fix sysdeps/unix/sysv/linux/semtimedop.c. */ |
| 46 | #define __NR_semtimedop		__NR_semtimedop_time64 |
| 47 | /* Hack sysdeps/unix/sysv/linux/generic/utimes.c. */ |
| 48 | #define __NR_utimensat		__NR_utimensat_time64 |
| 49 | |
| 50 | #endif /* __WORDSIZE == 32 */ |
| 51 | |
| 52 | #ifdef __ASSEMBLER__ |
| 53 | |
| 54 | # include <sys/asm.h> |
| 55 | |
| 56 | # define ENTRY(name) LEAF(name) |
| 57 | |
| 58 | # define L(label) .L ## label |
| 59 | |
| 60 | /* Performs a system call, handling errors by setting errno. Linux indicates |
| 61 | errors by setting a0 to a value between -1 and -4095. */ |
| 62 | # undef PSEUDO |
| 63 | # define PSEUDO(name, syscall_name, args)			\ |
| 64 | .text;							\ |
| 65 | .align 2;							\ |
| 66 | ENTRY (name);							\ |
| 67 | li a7, SYS_ify (syscall_name);				\ |
| 68 | scall;							\ |
| 69 | li a7, -4096;							\ |
| 70 | bgtu a0, a7, .Lsyscall_error ## name; |
| 71 | |
| 72 | # undef PSEUDO_END |
| 73 | # define PSEUDO_END(sym) 					\ |
| 74 | SYSCALL_ERROR_HANDLER (sym)					\ |
| 75 | ret;								\ |
| 76 | END (sym) |
| 77 | |
| 78 | # if !IS_IN (libc) |
| 79 | # if RTLD_PRIVATE_ERRNO |
| 80 | # define SYSCALL_ERROR_HANDLER(name)				\ |
| 81 | .Lsyscall_error ## name:					\ |
| 82 | 	li t1, -4096;						\ |
| 83 | 	neg a0, a0;						\ |
| 84 | sw a0, rtld_errno, t1;					\ |
| 85 | li a0, -1; |
| 86 | # elif defined (__PIC__) |
| 87 | # define SYSCALL_ERROR_HANDLER(name)				\ |
| 88 | .Lsyscall_error ## name:					\ |
| 89 | la.tls.ie t1, errno;					\ |
| 90 | 	add t1, t1, tp;						\ |
| 91 | 	neg a0, a0;						\ |
| 92 | 	sw a0, 0(t1);						\ |
| 93 | li a0, -1; |
| 94 | # else |
| 95 | # define SYSCALL_ERROR_HANDLER(name)				\ |
| 96 | .Lsyscall_error ## name:					\ |
| 97 | lui t1, %tprel_hi(errno);				\ |
| 98 | add t1, t1, tp, %tprel_add(errno);			\ |
| 99 | 	neg a0, a0;						\ |
| 100 | sw a0, %tprel_lo(errno)(t1);				\ |
| 101 | li a0, -1; |
| 102 | # endif |
| 103 | # else |
| 104 | # define SYSCALL_ERROR_HANDLER(name)				\ |
| 105 | .Lsyscall_error ## name:					\ |
| 106 | tail __syscall_error; |
| 107 | # endif |
| 108 | |
| 109 | /* Performs a system call, not setting errno. */ |
| 110 | # undef PSEUDO_NEORRNO |
| 111 | # define PSEUDO_NOERRNO(name, syscall_name, args)	\ |
| 112 | .align 2;						\ |
| 113 | ENTRY (name);						\ |
| 114 | li a7, SYS_ify (syscall_name);			\ |
| 115 | scall; |
| 116 | |
| 117 | # undef PSEUDO_END_NOERRNO |
| 118 | # define PSEUDO_END_NOERRNO(name)			\ |
| 119 | END (name) |
| 120 | |
| 121 | # undef ret_NOERRNO |
| 122 | # define ret_NOERRNO ret |
| 123 | |
| 124 | /* Performs a system call, returning the error code. */ |
| 125 | # undef PSEUDO_ERRVAL |
| 126 | # define PSEUDO_ERRVAL(name, syscall_name, args) 	\ |
| 127 | PSEUDO_NOERRNO (name, syscall_name, args)		\ |
| 128 | neg a0, a0; |
| 129 | |
| 130 | # undef PSEUDO_END_ERRVAL |
| 131 | # define PSEUDO_END_ERRVAL(name)			\ |
| 132 | END (name) |
| 133 | |
| 134 | # undef ret_ERRVAL |
| 135 | # define ret_ERRVAL ret |
| 136 | |
| 137 | #else /* !__ASSEMBLER__ */ |
| 138 | |
| 139 | # if __WORDSIZE == 64 |
| 140 | # define VDSO_NAME	"LINUX_4.15" |
| 141 | # define VDSO_HASH	182943605 |
| 142 | |
| 143 | /* List of system calls which are supported as vsyscalls only |
| 144 | for RV64. */ |
| 145 | # define HAVE_CLOCK_GETRES64_VSYSCALL	"__vdso_clock_getres" |
| 146 | # define HAVE_CLOCK_GETTIME64_VSYSCALL	"__vdso_clock_gettime" |
| 147 | # define HAVE_GETTIMEOFDAY_VSYSCALL	"__vdso_gettimeofday" |
| 148 | # define HAVE_GETRANDOM_VSYSCALL	"__vdso_getrandom" |
| 149 | # else |
| 150 | # define VDSO_NAME	"LINUX_5.4" |
| 151 | # define VDSO_HASH	61765876 |
| 152 | |
| 153 | /* RV32 does not support the gettime and getrandom VDSO syscalls. */ |
| 154 | # endif |
| 155 | # define HAVE_CLONE3_WRAPPER		1 |
| 156 | |
| 157 | /* List of system calls which are supported as vsyscalls (for RV32 and |
| 158 | RV64). */ |
| 159 | # define HAVE_GETCPU_VSYSCALL		"__vdso_getcpu" |
| 160 | # define HAVE_RISCV_HWPROBE		"__vdso_riscv_hwprobe" |
| 161 | |
| 162 | # undef HAVE_INTERNAL_BRK_ADDR_SYMBOL |
| 163 | # define HAVE_INTERNAL_BRK_ADDR_SYMBOL 1 |
| 164 | |
| 165 | # define INTERNAL_SYSCALL(name, nr, args...) \ |
| 166 | 	internal_syscall##nr (SYS_ify (name), args) |
| 167 | |
| 168 | # define INTERNAL_SYSCALL_NCS(number, nr, args...) \ |
| 169 | 	internal_syscall##nr (number, args) |
| 170 | |
| 171 | # define internal_syscall0(number, dummy...)			\ |
| 172 | ({ 									\ |
| 173 | 	long int _sys_result;						\ |
| 174 | 									\ |
| 175 | 	{								\ |
| 176 | 	register long int __a7 asm ("a7") = number;			\ |
| 177 | 	register long int __a0 asm ("a0");				\ |
| 178 | 	__asm__ volatile ( 						\ |
| 179 | 	"scall\n\t" 							\ |
| 180 | 	: "=r" (__a0)							\ |
| 181 | 	: "r" (__a7)							\ |
| 182 | 	: __SYSCALL_CLOBBERS); 						\ |
| 183 | 	_sys_result = __a0;						\ |
| 184 | 	}								\ |
| 185 | 	_sys_result;							\ |
| 186 | }) |
| 187 | |
| 188 | # define internal_syscall1(number, arg0)				\ |
| 189 | ({ 									\ |
| 190 | 	long int _sys_result;						\ |
| 191 | 	long int _arg0 = (long int) (arg0);				\ |
| 192 | 									\ |
| 193 | 	{								\ |
| 194 | 	register long int __a7 asm ("a7") = number;			\ |
| 195 | 	register long int __a0 asm ("a0") = _arg0;			\ |
| 196 | 	__asm__ volatile ( 						\ |
| 197 | 	"scall\n\t" 							\ |
| 198 | 	: "+r" (__a0)							\ |
| 199 | 	: "r" (__a7)							\ |
| 200 | 	: __SYSCALL_CLOBBERS); 						\ |
| 201 | 	_sys_result = __a0;						\ |
| 202 | 	}								\ |
| 203 | 	_sys_result;							\ |
| 204 | }) |
| 205 | |
| 206 | # define internal_syscall2(number, arg0, arg1)	 		\ |
| 207 | ({ 									\ |
| 208 | 	long int _sys_result;						\ |
| 209 | 	long int _arg0 = (long int) (arg0);				\ |
| 210 | 	long int _arg1 = (long int) (arg1);				\ |
| 211 | 									\ |
| 212 | 	{								\ |
| 213 | 	register long int __a7 asm ("a7") = number;			\ |
| 214 | 	register long int __a0 asm ("a0") = _arg0;			\ |
| 215 | 	register long int __a1 asm ("a1") = _arg1;			\ |
| 216 | 	__asm__ volatile ( 						\ |
| 217 | 	"scall\n\t" 							\ |
| 218 | 	: "+r" (__a0)							\ |
| 219 | 	: "r" (__a7), "r" (__a1)					\ |
| 220 | 	: __SYSCALL_CLOBBERS); 						\ |
| 221 | 	_sys_result = __a0;						\ |
| 222 | 	}								\ |
| 223 | 	_sys_result;							\ |
| 224 | }) |
| 225 | |
| 226 | # define internal_syscall3(number, arg0, arg1, arg2) 		\ |
| 227 | ({ 									\ |
| 228 | 	long int _sys_result;						\ |
| 229 | 	long int _arg0 = (long int) (arg0);				\ |
| 230 | 	long int _arg1 = (long int) (arg1);				\ |
| 231 | 	long int _arg2 = (long int) (arg2);				\ |
| 232 | 									\ |
| 233 | 	{								\ |
| 234 | 	register long int __a7 asm ("a7") = number;			\ |
| 235 | 	register long int __a0 asm ("a0") = _arg0;			\ |
| 236 | 	register long int __a1 asm ("a1") = _arg1;			\ |
| 237 | 	register long int __a2 asm ("a2") = _arg2;			\ |
| 238 | 	__asm__ volatile ( 						\ |
| 239 | 	"scall\n\t" 							\ |
| 240 | 	: "+r" (__a0)							\ |
| 241 | 	: "r" (__a7), "r" (__a1), "r" (__a2)				\ |
| 242 | 	: __SYSCALL_CLOBBERS); 						\ |
| 243 | 	_sys_result = __a0;						\ |
| 244 | 	}								\ |
| 245 | 	_sys_result;							\ |
| 246 | }) |
| 247 | |
| 248 | # define internal_syscall4(number, arg0, arg1, arg2, arg3)	 \ |
| 249 | ({ 									\ |
| 250 | 	long int _sys_result;						\ |
| 251 | 	long int _arg0 = (long int) (arg0);				\ |
| 252 | 	long int _arg1 = (long int) (arg1);				\ |
| 253 | 	long int _arg2 = (long int) (arg2);				\ |
| 254 | 	long int _arg3 = (long int) (arg3);				\ |
| 255 | 									\ |
| 256 | 	{								\ |
| 257 | 	register long int __a7 asm ("a7") = number;			\ |
| 258 | 	register long int __a0 asm ("a0") = _arg0;			\ |
| 259 | 	register long int __a1 asm ("a1") = _arg1;			\ |
| 260 | 	register long int __a2 asm ("a2") = _arg2;			\ |
| 261 | 	register long int __a3 asm ("a3") = _arg3;			\ |
| 262 | 	__asm__ volatile ( 						\ |
| 263 | 	"scall\n\t" 							\ |
| 264 | 	: "+r" (__a0)							\ |
| 265 | 	: "r" (__a7), "r" (__a1), "r" (__a2), "r" (__a3)		\ |
| 266 | 	: __SYSCALL_CLOBBERS); 						\ |
| 267 | 	_sys_result = __a0;						\ |
| 268 | 	}								\ |
| 269 | 	_sys_result;							\ |
| 270 | }) |
| 271 | |
| 272 | # define internal_syscall5(number, arg0, arg1, arg2, arg3, arg4) \ |
| 273 | ({ 									\ |
| 274 | 	long int _sys_result;						\ |
| 275 | 	long int _arg0 = (long int) (arg0);				\ |
| 276 | 	long int _arg1 = (long int) (arg1);				\ |
| 277 | 	long int _arg2 = (long int) (arg2);				\ |
| 278 | 	long int _arg3 = (long int) (arg3);				\ |
| 279 | 	long int _arg4 = (long int) (arg4);				\ |
| 280 | 									\ |
| 281 | 	{								\ |
| 282 | 	register long int __a7 asm ("a7") = number;			\ |
| 283 | 	register long int __a0 asm ("a0") = _arg0;			\ |
| 284 | 	register long int __a1 asm ("a1") = _arg1;			\ |
| 285 | 	register long int __a2 asm ("a2") = _arg2;			\ |
| 286 | 	register long int __a3 asm ("a3") = _arg3;			\ |
| 287 | 	register long int __a4 asm ("a4") = _arg4;			\ |
| 288 | 	__asm__ volatile ( 						\ |
| 289 | 	"scall\n\t" 							\ |
| 290 | 	: "+r" (__a0)							\ |
| 291 | 	: "r" (__a7), "r"(__a1), "r"(__a2), "r"(__a3), "r" (__a4)	\ |
| 292 | 	: __SYSCALL_CLOBBERS); 						\ |
| 293 | 	_sys_result = __a0;						\ |
| 294 | 	}								\ |
| 295 | 	_sys_result;							\ |
| 296 | }) |
| 297 | |
| 298 | # define internal_syscall6(number, arg0, arg1, arg2, arg3, arg4, arg5) \ |
| 299 | ({ 									\ |
| 300 | 	long int _sys_result;						\ |
| 301 | 	long int _arg0 = (long int) (arg0);				\ |
| 302 | 	long int _arg1 = (long int) (arg1);				\ |
| 303 | 	long int _arg2 = (long int) (arg2);				\ |
| 304 | 	long int _arg3 = (long int) (arg3);				\ |
| 305 | 	long int _arg4 = (long int) (arg4);				\ |
| 306 | 	long int _arg5 = (long int) (arg5);				\ |
| 307 | 									\ |
| 308 | 	{								\ |
| 309 | 	register long int __a7 asm ("a7") = number;			\ |
| 310 | 	register long int __a0 asm ("a0") = _arg0;			\ |
| 311 | 	register long int __a1 asm ("a1") = _arg1;			\ |
| 312 | 	register long int __a2 asm ("a2") = _arg2;			\ |
| 313 | 	register long int __a3 asm ("a3") = _arg3;			\ |
| 314 | 	register long int __a4 asm ("a4") = _arg4;			\ |
| 315 | 	register long int __a5 asm ("a5") = _arg5;			\ |
| 316 | 	__asm__ volatile ( 						\ |
| 317 | 	"scall\n\t" 							\ |
| 318 | 	: "+r" (__a0)							\ |
| 319 | 	: "r" (__a7), "r" (__a1), "r" (__a2), "r" (__a3),		\ |
| 320 | 	 "r" (__a4), "r" (__a5)					\ |
| 321 | 	: __SYSCALL_CLOBBERS); 						\ |
| 322 | 	_sys_result = __a0;						\ |
| 323 | 	}								\ |
| 324 | 	_sys_result;							\ |
| 325 | }) |
| 326 | |
| 327 | # define internal_syscall7(number, arg0, arg1, arg2, arg3, arg4, arg5, arg6) \ |
| 328 | ({ 									\ |
| 329 | 	long int _sys_result;						\ |
| 330 | 	long int _arg0 = (long int) (arg0);				\ |
| 331 | 	long int _arg1 = (long int) (arg1);				\ |
| 332 | 	long int _arg2 = (long int) (arg2);				\ |
| 333 | 	long int _arg3 = (long int) (arg3);				\ |
| 334 | 	long int _arg4 = (long int) (arg4);				\ |
| 335 | 	long int _arg5 = (long int) (arg5);				\ |
| 336 | 	long int _arg6 = (long int) (arg6);				\ |
| 337 | 									\ |
| 338 | 	{								\ |
| 339 | 	register long int __a7 asm ("a7") = number;			\ |
| 340 | 	register long int __a0 asm ("a0") = _arg0;			\ |
| 341 | 	register long int __a1 asm ("a1") = _arg1;			\ |
| 342 | 	register long int __a2 asm ("a2") = _arg2;			\ |
| 343 | 	register long int __a3 asm ("a3") = _arg3;			\ |
| 344 | 	register long int __a4 asm ("a4") = _arg4;			\ |
| 345 | 	register long int __a5 asm ("a5") = _arg5;			\ |
| 346 | 	register long int __a6 asm ("a6") = _arg6;			\ |
| 347 | 	__asm__ volatile ( 						\ |
| 348 | 	"scall\n\t" 							\ |
| 349 | 	: "+r" (__a0)							\ |
| 350 | 	: "r" (__a7), "r" (__a1), "r" (__a2), "r" (__a3),		\ |
| 351 | 	 "r" (__a4), "r" (__a5), "r" (__a6)				\ |
| 352 | 	: __SYSCALL_CLOBBERS); 						\ |
| 353 | 	_sys_result = __a0;						\ |
| 354 | 	}								\ |
| 355 | 	_sys_result;							\ |
| 356 | }) |
| 357 | |
| 358 | #ifdef __riscv_v |
| 359 | # define __SYSCALL_CLOBBERS "v0", "v1", "v2", "v3", "v4", "v5", "v6", "v7", "v8", "v9", \ |
| 360 | 			 "v10", "v11", "v12", "v13", "v14", "v15", "v16", "v17", "v18", "v19", \ |
| 361 | 			 "v20", "v21", "v22", "v23", "v24", "v25", "v26", "v27", "v28", "v29", \ |
| 362 | 			 "v30", "v31", "vl", "vtype", "vxrm", "vxsat", "memory" |
| 363 | #else |
| 364 | # define __SYSCALL_CLOBBERS "memory" |
| 365 | #endif |
| 366 | |
| 367 | extern long int __syscall_error (long int neg_errno); |
| 368 | |
| 369 | #endif /* ! __ASSEMBLER__ */ |
| 370 | |
| 371 | #endif /* linux/riscv/sysdep.h */ |