master
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 */