| 1 | /* Copyright (C) 2005-2026 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_AARCH64_SYSDEP_H |
| 20 | #define _LINUX_AARCH64_SYSDEP_H 1 |
| 21 | |
| 22 | #include <sysdeps/unix/sysdep.h> |
| 23 | #include <sysdeps/aarch64/sysdep.h> |
| 24 | #include <sysdeps/unix/sysdep.h> |
| 25 | #include <sysdeps/unix/sysv/linux/sysdep.h> |
| 26 | |
| 27 | /* Defines RTLD_PRIVATE_ERRNO and USE_DL_SYSINFO. */ |
| 28 | #include <dl-sysdep.h> |
| 29 | |
| 30 | #include <tls.h> |
| 31 | |
| 32 | /* In order to get __set_errno() definition in INLINE_SYSCALL. */ |
| 33 | #ifndef __ASSEMBLER__ |
| 34 | #include <errno.h> |
| 35 | #endif |
| 36 | |
| 37 | /* For Linux we can use the system call table in the header file |
| 38 | 	/usr/include/asm/unistd.h |
| 39 | of the kernel. But these symbols do not follow the SYS_* syntax |
| 40 | so we have to redefine the `SYS_ify' macro here. */ |
| 41 | #undef SYS_ify |
| 42 | #define SYS_ify(syscall_name)	(__NR_##syscall_name) |
| 43 | |
| 44 | #ifdef __ASSEMBLER__ |
| 45 | |
| 46 | /* Linux uses a negative return value to indicate syscall errors, |
| 47 | unlike most Unices, which use the condition codes' carry flag. |
| 48 | |
| 49 | Since version 2.1 the return value of a system call might be |
| 50 | negative even if the call succeeded. E.g., the `lseek' system call |
| 51 | might return a large offset. Therefore we must not anymore test |
| 52 | for < 0, but test for a real error by making sure the value in R0 |
| 53 | is a real error number. Linus said he will make sure the no syscall |
| 54 | returns a value in -1 .. -4095 as a valid result so we can safely |
| 55 | test with -4095. */ |
| 56 | |
| 57 | # undef	PSEUDO |
| 58 | # define PSEUDO(name, syscall_name, args)				 \ |
| 59 | .text;								 \ |
| 60 | ENTRY (name);								 \ |
| 61 | DO_CALL (syscall_name, args);					 \ |
| 62 | cmn x0, #4095;							 \ |
| 63 | b.cs .Lsyscall_error; |
| 64 | |
| 65 | # undef	PSEUDO_END |
| 66 | # define PSEUDO_END(name)						 \ |
| 67 | SYSCALL_ERROR_HANDLER							 \ |
| 68 | END (name) |
| 69 | |
| 70 | # undef	PSEUDO_NOERRNO |
| 71 | # define PSEUDO_NOERRNO(name, syscall_name, args)			 \ |
| 72 | .text;								 \ |
| 73 | ENTRY (name);								 \ |
| 74 | DO_CALL (syscall_name, args); |
| 75 | |
| 76 | # undef	PSEUDO_END_NOERRNO |
| 77 | # define PSEUDO_END_NOERRNO(name)					 \ |
| 78 | END (name) |
| 79 | |
| 80 | # define ret_NOERRNO ret |
| 81 | |
| 82 | /* The function has to return the error code. */ |
| 83 | # undef	PSEUDO_ERRVAL |
| 84 | # define PSEUDO_ERRVAL(name, syscall_name, args) \ |
| 85 | .text;								 \ |
| 86 | ENTRY (name)								 \ |
| 87 | DO_CALL (syscall_name, args);					 \ |
| 88 | neg x0, x0 |
| 89 | |
| 90 | # undef	PSEUDO_END_ERRVAL |
| 91 | # define PSEUDO_END_ERRVAL(name) \ |
| 92 | END (name) |
| 93 | |
| 94 | # define ret_ERRVAL ret |
| 95 | |
| 96 | # if !IS_IN (libc) |
| 97 | # define SYSCALL_ERROR .Lsyscall_error |
| 98 | # if RTLD_PRIVATE_ERRNO |
| 99 | # define SYSCALL_ERROR_HANDLER				\ |
| 100 | .Lsyscall_error:						\ |
| 101 | 	adrp	x1, C_SYMBOL_NAME(rtld_errno);			\ |
| 102 | 	neg w0, w0;						\ |
| 103 | 	str w0, [x1, :lo12:C_SYMBOL_NAME(rtld_errno)];	\ |
| 104 | 	mov	x0, -1;						\ |
| 105 | 	RET; |
| 106 | # else |
| 107 | |
| 108 | # define SYSCALL_ERROR_HANDLER				\ |
| 109 | .Lsyscall_error:						\ |
| 110 | 	adrp	x1, :gottprel:errno;				\ |
| 111 | 	neg	w2, w0;						\ |
| 112 | 	ldr	PTR_REG(1), [x1, :gottprel_lo12:errno];		\ |
| 113 | 	mrs	x3, tpidr_el0;					\ |
| 114 | 	mov	x0, -1;						\ |
| 115 | 	str	w2, [x1, x3];					\ |
| 116 | 	RET; |
| 117 | # endif |
| 118 | # else |
| 119 | # define SYSCALL_ERROR __syscall_error |
| 120 | # define SYSCALL_ERROR_HANDLER \ |
| 121 | .Lsyscall_error: \ |
| 122 | 	b	__syscall_error; |
| 123 | # endif |
| 124 | |
| 125 | /* Linux takes system call args in registers: |
| 126 | 	syscall number	x8 |
| 127 | 	arg 1		x0 |
| 128 | 	arg 2		x1 |
| 129 | 	arg 3		x2 |
| 130 | 	arg 4		x3 |
| 131 | 	arg 5		x4 |
| 132 | 	arg 6		x5 |
| 133 | 	arg 7		x6 |
| 134 | |
| 135 | The compiler is going to form a call by coming here, through PSEUDO, with |
| 136 | arguments |
| 137 | 	syscall number	in the DO_CALL macro |
| 138 | 	arg 1		x0 |
| 139 | 	arg 2		x1 |
| 140 | 	arg 3		x2 |
| 141 | 	arg 4		x3 |
| 142 | 	arg 5		x4 |
| 143 | 	arg 6		x5 |
| 144 | 	arg 7		x6 |
| 145 | |
| 146 | */ |
| 147 | |
| 148 | # undef	DO_CALL |
| 149 | # define DO_CALL(syscall_name, args)		\ |
| 150 | mov x8, SYS_ify (syscall_name);		\ |
| 151 | svc 0 |
| 152 | |
| 153 | /* Clear ZA state of SME (ASM version). */ |
| 154 | /* The __libc_arm_za_disable function has special calling convention |
| 155 | that allows to call it without stack manipulation and preserving |
| 156 | most of the registers. */ |
| 157 | 	.macro CALL_LIBC_ARM_ZA_DISABLE |
| 158 | 	cfi_remember_state |
| 159 | 	mov		x13, x30 |
| 160 | 	cfi_register(x30, x13) |
| 161 | 	bl		__libc_arm_za_disable |
| 162 | 	mov		x30, x13 |
| 163 | 	cfi_restore_state |
| 164 | 	.endm |
| 165 | |
| 166 | #else /* not __ASSEMBLER__ */ |
| 167 | |
| 168 | # define VDSO_NAME "LINUX_2.6.39" |
| 169 | # define VDSO_HASH 123718537 |
| 170 | |
| 171 | /* List of system calls which are supported as vsyscalls. */ |
| 172 | # define HAVE_CLOCK_GETRES64_VSYSCALL	"__kernel_clock_getres" |
| 173 | # define HAVE_CLOCK_GETTIME64_VSYSCALL	"__kernel_clock_gettime" |
| 174 | # define HAVE_GETTIMEOFDAY_VSYSCALL	"__kernel_gettimeofday" |
| 175 | # define HAVE_GETRANDOM_VSYSCALL "__kernel_getrandom" |
| 176 | |
| 177 | # define HAVE_CLONE3_WRAPPER		1 |
| 178 | |
| 179 | # undef INTERNAL_SYSCALL_RAW |
| 180 | # define INTERNAL_SYSCALL_RAW(name, nr, args...)		\ |
| 181 | ({ long _sys_result;						\ |
| 182 | {								\ |
| 183 | LOAD_ARGS_##nr (args)					\ |
| 184 | register long _x8 asm ("x8") = (name);			\ |
| 185 | asm volatile ("svc	0	// syscall " # name \ |
| 186 | 		 : "=r" (_x0) : "r"(_x8) ASM_ARGS_##nr : "memory");	\ |
| 187 | _sys_result = _x0;					\ |
| 188 | }								\ |
| 189 | _sys_result; }) |
| 190 | |
| 191 | # undef INTERNAL_SYSCALL |
| 192 | # define INTERNAL_SYSCALL(name, nr, args...)			\ |
| 193 | 	INTERNAL_SYSCALL_RAW(SYS_ify(name), nr, args) |
| 194 | |
| 195 | # undef INTERNAL_SYSCALL_AARCH64 |
| 196 | # define INTERNAL_SYSCALL_AARCH64(name, nr, args...)		\ |
| 197 | 	INTERNAL_SYSCALL_RAW(__ARM_NR_##name, nr, args) |
| 198 | |
| 199 | # define LOAD_ARGS_0()				\ |
| 200 | register long _x0 asm ("x0"); |
| 201 | # define LOAD_ARGS_1(x0)			\ |
| 202 | long _x0tmp = (long) (x0);			\ |
| 203 | LOAD_ARGS_0 ()				\ |
| 204 | _x0 = _x0tmp; |
| 205 | # define LOAD_ARGS_2(x0, x1)			\ |
| 206 | long _x1tmp = (long) (x1);			\ |
| 207 | LOAD_ARGS_1 (x0)				\ |
| 208 | register long _x1 asm ("x1") = _x1tmp; |
| 209 | # define LOAD_ARGS_3(x0, x1, x2)		\ |
| 210 | long _x2tmp = (long) (x2);			\ |
| 211 | LOAD_ARGS_2 (x0, x1)				\ |
| 212 | register long _x2 asm ("x2") = _x2tmp; |
| 213 | # define LOAD_ARGS_4(x0, x1, x2, x3)		\ |
| 214 | long _x3tmp = (long) (x3);			\ |
| 215 | LOAD_ARGS_3 (x0, x1, x2)			\ |
| 216 | register long _x3 asm ("x3") = _x3tmp; |
| 217 | # define LOAD_ARGS_5(x0, x1, x2, x3, x4)	\ |
| 218 | long _x4tmp = (long) (x4);			\ |
| 219 | LOAD_ARGS_4 (x0, x1, x2, x3)			\ |
| 220 | register long _x4 asm ("x4") = _x4tmp; |
| 221 | # define LOAD_ARGS_6(x0, x1, x2, x3, x4, x5)	\ |
| 222 | long _x5tmp = (long) (x5);			\ |
| 223 | LOAD_ARGS_5 (x0, x1, x2, x3, x4)		\ |
| 224 | register long _x5 asm ("x5") = _x5tmp; |
| 225 | # define LOAD_ARGS_7(x0, x1, x2, x3, x4, x5, x6)\ |
| 226 | long _x6tmp = (long) (x6);			\ |
| 227 | LOAD_ARGS_6 (x0, x1, x2, x3, x4, x5)		\ |
| 228 | register long _x6 asm ("x6") = _x6tmp; |
| 229 | |
| 230 | # define ASM_ARGS_0 |
| 231 | # define ASM_ARGS_1	, "r" (_x0) |
| 232 | # define ASM_ARGS_2	ASM_ARGS_1, "r" (_x1) |
| 233 | # define ASM_ARGS_3	ASM_ARGS_2, "r" (_x2) |
| 234 | # define ASM_ARGS_4	ASM_ARGS_3, "r" (_x3) |
| 235 | # define ASM_ARGS_5	ASM_ARGS_4, "r" (_x4) |
| 236 | # define ASM_ARGS_6	ASM_ARGS_5, "r" (_x5) |
| 237 | # define ASM_ARGS_7	ASM_ARGS_6, "r" (_x6) |
| 238 | |
| 239 | # undef INTERNAL_SYSCALL_NCS |
| 240 | # define INTERNAL_SYSCALL_NCS(number, nr, args...)	\ |
| 241 | 	INTERNAL_SYSCALL_RAW (number, nr, args) |
| 242 | |
| 243 | #undef HAVE_INTERNAL_BRK_ADDR_SYMBOL |
| 244 | #define HAVE_INTERNAL_BRK_ADDR_SYMBOL 1 |
| 245 | |
| 246 | /* Clear ZA state of SME (C version). */ |
| 247 | /* The __libc_arm_za_disable function has special calling convention |
| 248 | that allows to call it without stack manipulation and preserving |
| 249 | most of the registers. */ |
| 250 | #define CALL_LIBC_ARM_ZA_DISABLE()			\ |
| 251 | ({							\ |
| 252 | unsigned long int __tmp;				\ |
| 253 | asm volatile (					\ |
| 254 | "	.cfi_remember_state\n"			\ |
| 255 | "	mov		%0, x30\n"			\ |
| 256 | "	.cfi_register x30, %0\n" \ |
| 257 | "	bl		__libc_arm_za_disable\n"	\ |
| 258 | "	mov		x30, %0\n"			\ |
| 259 | "	.cfi_restore_state\n"			\ |
| 260 | : "=r" (__tmp)					\ |
| 261 | :							\ |
| 262 | : "x14", "x15", "x16", "x17", "x18", "memory" );	\ |
| 263 | }) |
| 264 | |
| 265 | /* Do clear ZA state of SME before making normal clone syscall. */ |
| 266 | #define INLINE_CLONE_SYSCALL(a0, a1, a2, a3, a4)	\ |
| 267 | ({							\ |
| 268 | CALL_LIBC_ARM_ZA_DISABLE ();				\ |
| 269 | INLINE_SYSCALL_CALL (clone, a0, a1, a2, a3, a4);	\ |
| 270 | }) |
| 271 | |
| 272 | #endif	/* __ASSEMBLER__ */ |
| 273 | |
| 274 | #endif /* linux/aarch64/sysdep.h */ |