1/* Syscall definitions, Linux PowerPC generic version.
  2   Copyright (C) 2019-2025 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   <http://www.gnu.org/licenses/>.  */
 18
 19#ifndef _LINUX_POWERPC_SYSDEP_H
 20#define _LINUX_POWERPC_SYSDEP_H 1
 21
 22#include <sysdeps/unix/sysv/linux/sysdep.h>
 23#include <sysdeps/unix/powerpc/sysdep.h>
 24#include <tls.h>
 25/* Define __set_errno() for INLINE_SYSCALL macro below.  */
 26#include <errno.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#define tostring(s) #s
 36#define stringify(s) tostring(s)
 37
 38#ifdef _ARCH_PWR4
 39/* Power4 and later cpus introduced a faster instruction to copy one
 40   CR field, rather than the slower microcoded mfcr which copies all
 41   CR fields.  */
 42# define MFCR0(REG) "mfocrf " stringify(REG) ",0x80"
 43#else
 44# define MFCR0(REG) "mfcr " stringify(REG)
 45#endif
 46
 47/* Define a macro which expands inline into the wrapper code for a system
 48   call. This use is for internal calls that do not need to handle errors
 49   normally. It will never touch errno. This returns just what the kernel
 50   gave back in the non-error (CR0.SO cleared) case, otherwise (CR0.SO set)
 51   the negation of the return value in the kernel gets reverted.  */
 52
 53#define INTERNAL_VSYSCALL_CALL_TYPE(funcptr, type, nr, args...)         \
 54  ({									\
 55    register void *r0  __asm__ ("r0");					\
 56    register long int r3  __asm__ ("r3");				\
 57    register long int r4  __asm__ ("r4");				\
 58    register long int r5  __asm__ ("r5");				\
 59    register long int r6  __asm__ ("r6");				\
 60    register long int r7  __asm__ ("r7");				\
 61    register long int r8  __asm__ ("r8");				\
 62    register type rval  __asm__ ("r3");				        \
 63    LOADARGS_##nr (funcptr, args);					\
 64    __asm__ __volatile__						\
 65      ("mtctr %0\n\t"							\
 66       "bctrl\n\t"							\
 67       MFCR0(%0) "\n\t"							\
 68       "0:"								\
 69       : "+r" (r0), "+r" (r3), "+r" (r4), "+r" (r5),  "+r" (r6),        \
 70         "+r" (r7), "+r" (r8)						\
 71       : : "r9", "r10", "r11", "r12",					\
 72           "cr0", "cr1", "cr5", "cr6", "cr7",				\
 73           "xer", "lr", "ctr", "memory");				\
 74    __asm__ __volatile__ ("" : "=r" (rval) : "r" (r3));		        \
 75    (long int) r0 & (1 << 28) ? -rval : rval;				\
 76  })
 77
 78#define INTERNAL_VSYSCALL_CALL(funcptr, nr, args...)			\
 79  INTERNAL_VSYSCALL_CALL_TYPE(funcptr, long int, nr, args)
 80
 81#define DECLARE_REGS				\
 82  register long int r0  __asm__ ("r0");		\
 83  register long int r3  __asm__ ("r3");		\
 84  register long int r4  __asm__ ("r4");		\
 85  register long int r5  __asm__ ("r5");		\
 86  register long int r6  __asm__ ("r6");		\
 87  register long int r7  __asm__ ("r7");		\
 88  register long int r8  __asm__ ("r8");
 89
 90#define SYSCALL_SCV(nr)				\
 91  ({						\
 92    __asm__ __volatile__			\
 93      (".machine \"push\"\n\t"			\
 94       ".machine \"power9\"\n\t"		\
 95       "scv 0\n\t"				\
 96       ".machine \"pop\"\n\t"			\
 97       "0:"					\
 98       : "+r" (r0),				\
 99	 "+r" (r3), "+r" (r4), "+r" (r5),	\
100	 "+r" (r6), "+r" (r7), "+r" (r8)	\
101       : : "r9", "r10", "r11", "r12",		\
102	 "cr0", "cr1", "cr5", "cr6", "cr7",	\
103	 "xer", "lr", "ctr", "memory"); 	\
104    r3;					\
105  })
106
107#define SYSCALL_SC(nr)				\
108  ({						\
109    __asm__ __volatile__			\
110      ("sc\n\t"				\
111       MFCR0(%0) "\n\t"				\
112       "0:"					\
113       : "+r" (r0),				\
114	 "+r" (r3), "+r" (r4), "+r" (r5),	\
115	 "+r" (r6), "+r" (r7), "+r" (r8)	\
116       : : "r9", "r10", "r11", "r12",		\
117	 "xer", "cr0", "ctr", "memory");	\
118    r0 & (1 << 28) ? -r3 : r3;			\
119  })
120
121/* This will only be non-empty for 64-bit systems, see below.  */
122#define TRY_SYSCALL_SCV(nr)
123
124#if defined(__PPC64__) || defined(__powerpc64__)
125# define SYSCALL_ARG_SIZE 8
126
127/* For the static case, unlike the dynamic loader, there is no compile-time way
128   to check if we are inside startup code.  So we need to check if the thread
129   pointer has already been setup before trying to access the TLS.  */
130# ifndef SHARED
131#  define CHECK_THREAD_POINTER (__thread_register != 0)
132# else
133#  define CHECK_THREAD_POINTER (1)
134# endif
135
136/* When inside the dynamic loader, the thread pointer may not have been
137   initialized yet, so don't check for scv support in that case.  */
138# if defined(USE_PPC_SCV) && !IS_IN(rtld)
139#  undef TRY_SYSCALL_SCV
140#  define TRY_SYSCALL_SCV(nr)						\
141  CHECK_THREAD_POINTER && THREAD_GET_HWCAP() & PPC_FEATURE2_SCV ?	\
142      SYSCALL_SCV(nr) :
143# endif
144
145#else
146# define SYSCALL_ARG_SIZE 4
147#endif
148
149# define INTERNAL_SYSCALL_NCS(name, nr, args...)	\
150  ({							\
151    DECLARE_REGS;					\
152    LOADARGS_##nr (name, ##args);			\
153    TRY_SYSCALL_SCV(nr)					\
154    SYSCALL_SC(nr);					\
155  })
156
157#undef INTERNAL_SYSCALL
158#define INTERNAL_SYSCALL(name, nr, args...)				\
159  INTERNAL_SYSCALL_NCS (__NR_##name, nr, args)
160
161#define LOADARGS_0(name, dummy) \
162	r0 = name
163#define LOADARGS_1(name, __arg1) \
164	long int _arg1 = (long int) (__arg1); \
165	LOADARGS_0(name, 0); \
166	extern void __illegally_sized_syscall_arg1 (void); \
167	if (__builtin_classify_type (__arg1) != 5 \
168	    && sizeof (__arg1) > SYSCALL_ARG_SIZE) \
169	  __illegally_sized_syscall_arg1 (); \
170	r3 = _arg1
171#define LOADARGS_2(name, __arg1, __arg2) \
172	long int _arg2 = (long int) (__arg2); \
173	LOADARGS_1(name, __arg1); \
174	extern void __illegally_sized_syscall_arg2 (void); \
175	if (__builtin_classify_type (__arg2) != 5 \
176	    && sizeof (__arg2) > SYSCALL_ARG_SIZE) \
177	  __illegally_sized_syscall_arg2 (); \
178	r4 = _arg2
179#define LOADARGS_3(name, __arg1, __arg2, __arg3) \
180	long int _arg3 = (long int) (__arg3); \
181	LOADARGS_2(name, __arg1, __arg2); \
182	extern void __illegally_sized_syscall_arg3 (void); \
183	if (__builtin_classify_type (__arg3) != 5 \
184	    && sizeof (__arg3) > SYSCALL_ARG_SIZE) \
185	  __illegally_sized_syscall_arg3 (); \
186	r5 = _arg3
187#define LOADARGS_4(name, __arg1, __arg2, __arg3, __arg4) \
188	long int _arg4 = (long int) (__arg4); \
189	LOADARGS_3(name, __arg1, __arg2, __arg3); \
190	extern void __illegally_sized_syscall_arg4 (void); \
191	if (__builtin_classify_type (__arg4) != 5 \
192	    && sizeof (__arg4) > SYSCALL_ARG_SIZE) \
193	  __illegally_sized_syscall_arg4 (); \
194	r6 = _arg4
195#define LOADARGS_5(name, __arg1, __arg2, __arg3, __arg4, __arg5) \
196	long int _arg5 = (long int) (__arg5); \
197	LOADARGS_4(name, __arg1, __arg2, __arg3, __arg4); \
198	extern void __illegally_sized_syscall_arg5 (void); \
199	if (__builtin_classify_type (__arg5) != 5 \
200	    && sizeof (__arg5) > SYSCALL_ARG_SIZE) \
201	  __illegally_sized_syscall_arg5 (); \
202	r7 = _arg5
203#define LOADARGS_6(name, __arg1, __arg2, __arg3, __arg4, __arg5, __arg6) \
204	long int _arg6 = (long int) (__arg6); \
205	LOADARGS_5(name, __arg1, __arg2, __arg3, __arg4, __arg5); \
206	extern void __illegally_sized_syscall_arg6 (void); \
207	if (__builtin_classify_type (__arg6) != 5 \
208	    && sizeof (__arg6) > SYSCALL_ARG_SIZE) \
209	  __illegally_sized_syscall_arg6 (); \
210	r8 = _arg6
211
212/* List of system calls which are supported as vsyscalls.  */
213#define VDSO_NAME  "LINUX_2.6.15"
214#define VDSO_HASH  123718565
215
216#if defined(__PPC64__) || defined(__powerpc64__)
217#define HAVE_CLOCK_GETRES64_VSYSCALL	"__kernel_clock_getres"
218#define HAVE_CLOCK_GETTIME64_VSYSCALL	"__kernel_clock_gettime"
219#define HAVE_CLONE3_WRAPPER		1
220#else
221#define HAVE_CLOCK_GETRES_VSYSCALL	"__kernel_clock_getres"
222#define HAVE_CLOCK_GETTIME_VSYSCALL	"__kernel_clock_gettime"
223#endif
224#define HAVE_GETCPU_VSYSCALL		"__kernel_getcpu"
225#define HAVE_TIME_VSYSCALL		"__kernel_time"
226#define HAVE_GETTIMEOFDAY_VSYSCALL      "__kernel_gettimeofday"
227#define HAVE_GET_TBFREQ                 "__kernel_get_tbfreq"
228#define HAVE_GETRANDOM_VSYSCALL         "__kernel_getrandom"
229
230#endif /* _LINUX_POWERPC_SYSDEP_H  */