]> git.ipfire.org Git - thirdparty/glibc.git/blobdiff - sysdeps/unix/sysv/linux/powerpc/sysdep.h
Update copyright dates with scripts/update-copyrights
[thirdparty/glibc.git] / sysdeps / unix / sysv / linux / powerpc / sysdep.h
index ea924db1685ec9d83099001498746d96ef53f06a..d3605d562d2747a83bf25979573feef6149c9ca7 100644 (file)
@@ -1,4 +1,5 @@
-/* Copyright (C) 1992,1997,1998,1999,2000,2001 Free Software Foundation, Inc.
+/* Syscall definitions, Linux PowerPC generic version.
+   Copyright (C) 2019-2021 Free Software Foundation, Inc.
    This file is part of the GNU C Library.
 
    The GNU C Library is free software; you can redistribute it and/or
    Lesser General Public License for more details.
 
    You should have received a copy of the GNU Lesser General Public
-   License along with the GNU C Library; if not, write to the Free
-   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
-   02111-1307 USA.  */
+   License along with the GNU C Library; if not, see
+   <http://www.gnu.org/licenses/>.  */
 
 #ifndef _LINUX_POWERPC_SYSDEP_H
 #define _LINUX_POWERPC_SYSDEP_H 1
 
+#include <sysdeps/unix/sysv/linux/sysdep.h>
 #include <sysdeps/unix/powerpc/sysdep.h>
+#include <tls.h>
+/* Define __set_errno() for INLINE_SYSCALL macro below.  */
+#include <errno.h>
 
 /* For Linux we can use the system call table in the header file
-       /usr/include/asm/unistd.h
+       /usr/include/asm/unistd.h
    of the kernel.  But these symbols do not follow the SYS_* syntax
    so we have to redefine the `SYS_ify' macro here.  */
 #undef SYS_ify
-#ifdef __STDC__
-# define SYS_ify(syscall_name) __NR_##syscall_name
-#else
-# define SYS_ify(syscall_name) __NR_/**/syscall_name
-#endif
+#define SYS_ify(syscall_name)  __NR_##syscall_name
 
-#ifdef __ASSEMBLER__
-
-/* This seems to always be the case on PPC.  */
-#define ALIGNARG(log2) log2
-/* For ELF we need the `.type' directive to make shared libs work right.  */
-#define ASM_TYPE_DIRECTIVE(name,typearg) .type name,typearg;
-#define ASM_SIZE_DIRECTIVE(name) .size name,.-name
-
-/* If compiled for profiling, call `_mcount' at the start of each function.  */
-#ifdef PROF
-/* The mcount code relies on a the return address being on the stack
-   to locate our caller and so it can restore it; so store one just
-   for its benefit.  */
-#ifdef PIC
-#define CALL_MCOUNT                                                          \
-  .pushsection;                                                                      \
-  .section ".data";                                                                  \
-  .align ALIGNARG(2);                                                        \
-0:.long 0;                                                                   \
-  .previous;                                                                 \
-  mflr  r0;                                                                  \
-  stw   r0,4(r1);                                                            \
-  bl    _GLOBAL_OFFSET_TABLE_@local-4;                                       \
-  mflr  r11;                                                                 \
-  lwz   r0,0b@got(r11);                                                              \
-  bl    JUMPTARGET(_mcount);
-#else  /* PIC */
-#define CALL_MCOUNT                                                          \
-  .section ".data";                                                          \
-  .align ALIGNARG(2);                                                        \
-0:.long 0;                                                                   \
-  .previous;                                                                 \
-  mflr  r0;                                                                  \
-  lis   r11,0b@ha;                                                           \
-  stw   r0,4(r1);                                                            \
-  addi  r0,r11,0b@l;                                                         \
-  bl    JUMPTARGET(_mcount);
-#endif /* PIC */
-#else  /* PROF */
-#define CALL_MCOUNT            /* Do nothing.  */
-#endif /* PROF */
-
-#define        ENTRY(name)                                                           \
-  ASM_GLOBAL_DIRECTIVE C_SYMBOL_NAME(name);                                  \
-  ASM_TYPE_DIRECTIVE (C_SYMBOL_NAME(name),@function)                         \
-  .align ALIGNARG(2);                                                        \
-  C_LABEL(name)                                                                      \
-  CALL_MCOUNT
-
-#define EALIGN_W_0  /* No words to insert.  */
-#define EALIGN_W_1  nop
-#define EALIGN_W_2  nop;nop
-#define EALIGN_W_3  nop;nop;nop
-#define EALIGN_W_4  EALIGN_W_3;nop
-#define EALIGN_W_5  EALIGN_W_4;nop
-#define EALIGN_W_6  EALIGN_W_5;nop
-#define EALIGN_W_7  EALIGN_W_6;nop
-
-/* EALIGN is like ENTRY, but does alignment to 'words'*4 bytes
-   past a 2^align boundary.  */
-#ifdef PROF
-#define EALIGN(name, alignt, words)                                          \
-  ASM_GLOBAL_DIRECTIVE C_SYMBOL_NAME(name);                                  \
-  ASM_TYPE_DIRECTIVE (C_SYMBOL_NAME(name),@function)                         \
-  .align ALIGNARG(2);                                                        \
-  C_LABEL(name)                                                                      \
-  CALL_MCOUNT                                                                \
-  b 0f;                                                                              \
-  .align ALIGNARG(alignt);                                                   \
-  EALIGN_W_##words;                                                          \
-  0:
-#else /* PROF */
-#define EALIGN(name, alignt, words)                                          \
-  ASM_GLOBAL_DIRECTIVE C_SYMBOL_NAME(name);                                  \
-  ASM_TYPE_DIRECTIVE (C_SYMBOL_NAME(name),@function)                         \
-  .align ALIGNARG(alignt);                                                   \
-  EALIGN_W_##words;                                                          \
-  C_LABEL(name)
-#endif
+/* Define a macro which expands inline into the wrapper code for a system
+   call. This use is for internal calls that do not need to handle errors
+   normally. It will never touch errno. This returns just what the kernel
+   gave back in the non-error (CR0.SO cleared) case, otherwise (CR0.SO set)
+   the negation of the return value in the kernel gets reverted.  */
+
+#define INTERNAL_VSYSCALL_CALL_TYPE(funcptr, type, nr, args...)         \
+  ({                                                                   \
+    register void *r0  __asm__ ("r0");                                 \
+    register long int r3  __asm__ ("r3");                              \
+    register long int r4  __asm__ ("r4");                              \
+    register long int r5  __asm__ ("r5");                              \
+    register long int r6  __asm__ ("r6");                              \
+    register long int r7  __asm__ ("r7");                              \
+    register long int r8  __asm__ ("r8");                              \
+    register type rval  __asm__ ("r3");                                        \
+    LOADARGS_##nr (funcptr, args);                                     \
+    __asm__ __volatile__                                               \
+      ("mtctr %0\n\t"                                                  \
+       "bctrl\n\t"                                                     \
+       "mfcr  %0\n\t"                                                  \
+       "0:"                                                            \
+       : "+r" (r0), "+r" (r3), "+r" (r4), "+r" (r5),  "+r" (r6),        \
+         "+r" (r7), "+r" (r8)                                          \
+       : : "r9", "r10", "r11", "r12", "cr0", "ctr", "lr", "memory");   \
+    __asm__ __volatile__ ("" : "=r" (rval) : "r" (r3));                        \
+    (long int) r0 & (1 << 28) ? -rval : rval;                          \
+  })
+
+#define INTERNAL_VSYSCALL_CALL(funcptr, nr, args...)                   \
+  INTERNAL_VSYSCALL_CALL_TYPE(funcptr, long int, nr, args)
+
+#define DECLARE_REGS                           \
+  register long int r0  __asm__ ("r0");                \
+  register long int r3  __asm__ ("r3");                \
+  register long int r4  __asm__ ("r4");                \
+  register long int r5  __asm__ ("r5");                \
+  register long int r6  __asm__ ("r6");                \
+  register long int r7  __asm__ ("r7");                \
+  register long int r8  __asm__ ("r8");
+
+#define SYSCALL_SCV(nr)                                \
+  ({                                           \
+    __asm__ __volatile__                       \
+      ("scv 0\n\t"                             \
+       "0:"                                    \
+       : "=&r" (r0),                           \
+        "=&r" (r3), "=&r" (r4), "=&r" (r5),    \
+        "=&r" (r6), "=&r" (r7), "=&r" (r8)     \
+       : ASM_INPUT_##nr                        \
+       : "r9", "r10", "r11", "r12",            \
+        "lr", "ctr", "memory");                \
+    r3;                                        \
+  })
+
+#define SYSCALL_SC(nr)                         \
+  ({                                           \
+    __asm__ __volatile__                       \
+      ("sc\n\t"                                \
+       "mfcr %0\n\t"                           \
+       "0:"                                    \
+       : "=&r" (r0),                           \
+        "=&r" (r3), "=&r" (r4), "=&r" (r5),    \
+        "=&r" (r6), "=&r" (r7), "=&r" (r8)     \
+       : ASM_INPUT_##nr                        \
+       : "r9", "r10", "r11", "r12",            \
+        "cr0", "ctr", "memory");               \
+    r0 & (1 << 28) ? -r3 : r3;                 \
+  })
+
+/* This will only be non-empty for 64-bit systems, see below.  */
+#define TRY_SYSCALL_SCV(nr)
+
+#if defined(__PPC64__) || defined(__powerpc64__)
+# define SYSCALL_ARG_SIZE 8
 
-#undef END
-#define END(name)                                                            \
-  ASM_SIZE_DIRECTIVE(name)
+/* For the static case, unlike the dynamic loader, there is no compile-time way
+   to check if we are inside startup code.  So we need to check if the thread
+   pointer has already been setup before trying to access the TLS.  */
+# ifndef SHARED
+#  define CHECK_THREAD_POINTER (__thread_register != 0)
+# else
+#  define CHECK_THREAD_POINTER (1)
+# endif
 
-#define DO_CALL(syscall)                                                     \
-    li 0,syscall;                                                            \
-    sc
+/* When inside the dynamic loader, the thread pointer may not have been
+   initialized yet, so don't check for scv support in that case.  */
+# if !IS_IN(rtld)
+#  undef TRY_SYSCALL_SCV
+#  define TRY_SYSCALL_SCV(nr)                                          \
+  CHECK_THREAD_POINTER && THREAD_GET_HWCAP() & PPC_FEATURE2_SCV ?      \
+      SYSCALL_SCV(nr) :
+# endif
 
-#ifdef PIC
-#define JUMPTARGET(name) name##@plt
 #else
-#define JUMPTARGET(name) name
+# define SYSCALL_ARG_SIZE 4
 #endif
 
-#define PSEUDO(name, syscall_name, args)                                     \
-  .section ".text";                                                          \
-  ENTRY (name)                                                               \
-    DO_CALL (SYS_ify (syscall_name));
+# define INTERNAL_SYSCALL_NCS(name, nr, args...)       \
+  ({                                                   \
+    DECLARE_REGS;                                      \
+    LOADARGS_##nr (name, ##args);                      \
+    TRY_SYSCALL_SCV(nr)                                        \
+    SYSCALL_SC(nr);                                    \
+  })
 
-#define PSEUDO_RET                                                           \
-    bnslr;                                                                   \
-    b JUMPTARGET(__syscall_error)
-#define ret PSEUDO_RET
+#undef INTERNAL_SYSCALL
+#define INTERNAL_SYSCALL(name, nr, args...)                            \
+  INTERNAL_SYSCALL_NCS (__NR_##name, nr, args)
 
-#undef PSEUDO_END
-#define        PSEUDO_END(name)                                                      \
-  END (name)
+#define LOADARGS_0(name, dummy) \
+       r0 = name
+#define LOADARGS_1(name, __arg1) \
+       long int _arg1 = (long int) (__arg1); \
+       LOADARGS_0(name, 0); \
+       extern void __illegally_sized_syscall_arg1 (void); \
+       if (__builtin_classify_type (__arg1) != 5 \
+           && sizeof (__arg1) > SYSCALL_ARG_SIZE) \
+         __illegally_sized_syscall_arg1 (); \
+       r3 = _arg1
+#define LOADARGS_2(name, __arg1, __arg2) \
+       long int _arg2 = (long int) (__arg2); \
+       LOADARGS_1(name, __arg1); \
+       extern void __illegally_sized_syscall_arg2 (void); \
+       if (__builtin_classify_type (__arg2) != 5 \
+           && sizeof (__arg2) > SYSCALL_ARG_SIZE) \
+         __illegally_sized_syscall_arg2 (); \
+       r4 = _arg2
+#define LOADARGS_3(name, __arg1, __arg2, __arg3) \
+       long int _arg3 = (long int) (__arg3); \
+       LOADARGS_2(name, __arg1, __arg2); \
+       extern void __illegally_sized_syscall_arg3 (void); \
+       if (__builtin_classify_type (__arg3) != 5 \
+           && sizeof (__arg3) > SYSCALL_ARG_SIZE) \
+         __illegally_sized_syscall_arg3 (); \
+       r5 = _arg3
+#define LOADARGS_4(name, __arg1, __arg2, __arg3, __arg4) \
+       long int _arg4 = (long int) (__arg4); \
+       LOADARGS_3(name, __arg1, __arg2, __arg3); \
+       extern void __illegally_sized_syscall_arg4 (void); \
+       if (__builtin_classify_type (__arg4) != 5 \
+           && sizeof (__arg4) > SYSCALL_ARG_SIZE) \
+         __illegally_sized_syscall_arg4 (); \
+       r6 = _arg4
+#define LOADARGS_5(name, __arg1, __arg2, __arg3, __arg4, __arg5) \
+       long int _arg5 = (long int) (__arg5); \
+       LOADARGS_4(name, __arg1, __arg2, __arg3, __arg4); \
+       extern void __illegally_sized_syscall_arg5 (void); \
+       if (__builtin_classify_type (__arg5) != 5 \
+           && sizeof (__arg5) > SYSCALL_ARG_SIZE) \
+         __illegally_sized_syscall_arg5 (); \
+       r7 = _arg5
+#define LOADARGS_6(name, __arg1, __arg2, __arg3, __arg4, __arg5, __arg6) \
+       long int _arg6 = (long int) (__arg6); \
+       LOADARGS_5(name, __arg1, __arg2, __arg3, __arg4, __arg5); \
+       extern void __illegally_sized_syscall_arg6 (void); \
+       if (__builtin_classify_type (__arg6) != 5 \
+           && sizeof (__arg6) > SYSCALL_ARG_SIZE) \
+         __illegally_sized_syscall_arg6 (); \
+       r8 = _arg6
 
-/* Local labels stripped out by the linker.  */
-#undef L
-#define L(x) .L##x
+#define ASM_INPUT_0 "0" (r0)
+#define ASM_INPUT_1 ASM_INPUT_0, "1" (r3)
+#define ASM_INPUT_2 ASM_INPUT_1, "2" (r4)
+#define ASM_INPUT_3 ASM_INPUT_2, "3" (r5)
+#define ASM_INPUT_4 ASM_INPUT_3, "4" (r6)
+#define ASM_INPUT_5 ASM_INPUT_4, "5" (r7)
+#define ASM_INPUT_6 ASM_INPUT_5, "6" (r8)
 
-/* Label in text section.  */
-#define C_TEXT(name) name
 
-#endif /* __ASSEMBLER__ */
+/* Pointer mangling support.  */
+#if IS_IN (rtld)
+/* We cannot use the thread descriptor because in ld.so we use setjmp
+   earlier than the descriptor is initialized.  */
+#else
+# ifdef __ASSEMBLER__
+#  if defined(__PPC64__) || defined(__powerpc64__)
+#   define LOAD  ld
+#   define TPREG r13
+#  else
+#   define LOAD  lwz
+#   define TPREG r2
+#  endif
+#  define PTR_MANGLE(reg, tmpreg) \
+       LOAD    tmpreg,POINTER_GUARD(TPREG); \
+       xor     reg,tmpreg,reg
+#  define PTR_MANGLE2(reg, tmpreg) \
+       xor     reg,tmpreg,reg
+#  define PTR_MANGLE3(destreg, reg, tmpreg) \
+       LOAD    tmpreg,POINTER_GUARD(TPREG); \
+       xor     destreg,tmpreg,reg
+#  define PTR_DEMANGLE(reg, tmpreg) PTR_MANGLE (reg, tmpreg)
+#  define PTR_DEMANGLE2(reg, tmpreg) PTR_MANGLE2 (reg, tmpreg)
+#  define PTR_DEMANGLE3(destreg, reg, tmpreg) PTR_MANGLE3 (destreg, reg, tmpreg)
+# else
+#  define PTR_MANGLE(var) \
+  (var) = (__typeof (var)) ((uintptr_t) (var) ^ THREAD_GET_POINTER_GUARD ())
+#  define PTR_DEMANGLE(var)    PTR_MANGLE (var)
+# endif
+#endif
+
+/* List of system calls which are supported as vsyscalls.  */
+#define VDSO_NAME  "LINUX_2.6.15"
+#define VDSO_HASH  123718565
+
+#if defined(__PPC64__) || defined(__powerpc64__)
+#define HAVE_CLOCK_GETRES64_VSYSCALL   "__kernel_clock_getres"
+#define HAVE_CLOCK_GETTIME64_VSYSCALL  "__kernel_clock_gettime"
+#else
+#define HAVE_CLOCK_GETRES_VSYSCALL     "__kernel_clock_getres"
+#define HAVE_CLOCK_GETTIME_VSYSCALL    "__kernel_clock_gettime"
+#endif
+#define HAVE_GETCPU_VSYSCALL           "__kernel_getcpu"
+#define HAVE_TIME_VSYSCALL             "__kernel_time"
+#define HAVE_GETTIMEOFDAY_VSYSCALL      "__kernel_gettimeofday"
+#define HAVE_GET_TBFREQ                 "__kernel_get_tbfreq"
+
+#if defined(__PPC64__) || defined(__powerpc64__)
+# define HAVE_SIGTRAMP_RT64            "__kernel_sigtramp_rt64"
+#else
+# define HAVE_SIGTRAMP_32              "__kernel_sigtramp32"
+# define HAVE_SIGTRAMP_RT32            "__kernel_sigtramp_rt32"
+#endif
 
-#endif /* linux/powerpc/sysdep.h */
+#endif /* _LINUX_POWERPC_SYSDEP_H  */