about summary refs log tree commit diff
path: root/sysdeps/unix/sysv/linux/microblaze/sysdep.h
diff options
context:
space:
mode:
Diffstat (limited to 'sysdeps/unix/sysv/linux/microblaze/sysdep.h')
-rw-r--r--sysdeps/unix/sysv/linux/microblaze/sysdep.h307
1 files changed, 307 insertions, 0 deletions
diff --git a/sysdeps/unix/sysv/linux/microblaze/sysdep.h b/sysdeps/unix/sysv/linux/microblaze/sysdep.h
new file mode 100644
index 0000000000..5a98d72144
--- /dev/null
+++ b/sysdeps/unix/sysv/linux/microblaze/sysdep.h
@@ -0,0 +1,307 @@
+/* Copyright (C) 2000-2014 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
+   modify it under the terms of the GNU Lesser General Public License as
+   published by the Free Software Foundation; either version 2.1 of the
+   License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   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, see
+   <http://www.gnu.org/licenses/>.  */
+
+#include <sysdeps/microblaze/sysdep.h>
+#include <sys/syscall.h>
+
+/* Defines RTLD_PRIVATE_ERRNO.  */
+#include <dl-sysdep.h>
+
+/* In order to get __set_errno() definition in INLINE_SYSCALL.  */
+#ifndef __ASSEMBLER__
+# include <errno.h>
+#endif
+
+/* For Linux we can use the system call table in the header file
+    /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
+#define SYS_ify(syscall_name)   __NR_##syscall_name
+
+#ifdef __ASSEMBLER__
+
+/* In microblaze ABI function call arguments are passed in registers
+   r5...r10. The return value is stored in r3 (or r3:r4 regiters pair).
+   Linux syscall uses the same convention with the addition that the
+   syscall number is passed in r12. To enter the kernel "brki r14,8"
+   instruction is used.
+   None of the abovementioned registers are presumed across function call
+   or syscall.
+*/
+/* Linux uses a negative return value to indicate syscall errors, unlike
+   most Unices, which use the condition codes' carry flag.
+
+   Since version 2.1 the return value of a system call might be negative
+   even if the call succeeded.  E.g., the `lseek' system call might return
+   a large offset.  Therefore we must not anymore test for < 0, but test
+   for a real error by making sure the value in %d0 is a real error
+   number.  Linus said he will make sure the no syscall returns a value
+   in -1 .. -4095 as a valid result so we can savely test with -4095.  */
+
+/* We don't want the label for the error handler to be visible in the symbol
+   table when we define it here.  */
+# ifdef PIC
+#  define SYSCALL_ERROR_LABEL 0f
+# else
+#  define SYSCALL_ERROR_LABEL __syscall_error
+# endif
+
+# undef PSEUDO
+# define PSEUDO(name, syscall_name, args)           \
+  .text;                                            \
+  ENTRY (name)                                      \
+    DO_CALL (syscall_name, args);                   \
+    addik r12,r0,-4095;                             \
+    cmpu  r12,r12,r3;                               \
+    bgei  r12,SYSCALL_ERROR_LABEL;
+
+# undef PSEUDO_END
+# define PSEUDO_END(name)                           \
+  SYSCALL_ERROR_HANDLER;                            \
+  END (name)
+
+# undef PSEUDO_NOERRNO
+# define PSEUDO_NOERRNO(name, syscall_name, args)   \
+  .text;                                            \
+  ENTRY (name)                                      \
+    DO_CALL (syscall_name, args);
+
+# undef PSEUDO_END_NOERRNO
+# define PSEUDO_END_NOERRNO(name)                   \
+  END (name)
+
+/* The function has to return the error code.  */
+# undef  PSEUDO_ERRVAL
+# define PSEUDO_ERRVAL(name, syscall_name, args)    \
+  .text;                                            \
+  ENTRY (name)                                      \
+    DO_CALL (syscall_name, args);                   \
+
+# undef  PSEUDO_END_ERRVAL
+# define PSEUDO_END_ERRVAL(name)                    \
+  END (name)
+
+# define ret_NOERRNO                                \
+  rtsd r15,8; addk r0,r0,r0;
+
+# define ret_ERRVAL                                 \
+  rtsd r15,8; rsubk r3,r3,r0;
+
+# ifdef PIC
+#  define SYSCALL_ERROR_LABEL_DCL 0
+#  if RTLD_PRIVATE_ERRNO
+#   define SYSCALL_ERROR_HANDLER                    \
+SYSCALL_ERROR_LABEL_DCL:                            \
+    mfs   r12,rpc;                                  \
+    addik r12,r12,_GLOBAL_OFFSET_TABLE_+8;          \
+    lwi   r12,r12,rtld_errno@GOT;                   \
+    rsubk r3,r3,r0;                                 \
+    swi   r3,r12,0;                                 \
+    rtsd  r15,8;                                    \
+    addik r3,r0,-1;
+#  else /* !RTLD_PRIVATE_ERRNO.  */
+/* Store (-r3) into errno through the GOT.  */
+#   if defined _LIBC_REENTRANT
+#    define SYSCALL_ERROR_HANDLER                   \
+SYSCALL_ERROR_LABEL_DCL:                            \
+    addik r1,r1,-16;                                \
+    swi   r15,r1,0;                                 \
+    swi   r20,r1,8;                                 \
+    rsubk r3,r3,r0;                                 \
+    swi   r3,r1,12;                                 \
+    mfs   r20,rpc;                                  \
+    addik r20,r20,_GLOBAL_OFFSET_TABLE_+8;          \
+    brlid r15,__errno_location@PLT;                 \
+    nop;                                            \
+    lwi   r4,r1,12;                                 \
+    swi   r4,r3,0;                                  \
+    lwi   r20,r1,8;                                 \
+    lwi   r15,r1,0;                                 \
+    addik r1,r1,16;                                 \
+    rtsd  r15,8;                                    \
+    addik r3,r0,-1;
+#   else /* !_LIBC_REENTRANT.  */
+#    define SYSCALL_ERROR_HANDLER                   \
+SYSCALL_ERROR_LABEL_DCL:                            \
+    mfs   r12,rpc;                                  \
+    addik r12,r12,_GLOBAL_OFFSET_TABLE_+8;          \
+    lwi   r12,r12,errno@GOT;                        \
+    rsubk r3,r3,r0;                                 \
+    swi   r3,r12,0;                                 \
+    rtsd  r15,8;                                    \
+    addik r3,r0,-1;
+#    endif /* _LIBC_REENTRANT.  */
+# endif /* RTLD_PRIVATE_ERRNO.  */
+# else
+#  define SYSCALL_ERROR_HANDLER  /* Nothing here; code in sysdep.S is used.  */
+# endif /* PIC.  */
+
+# define DO_CALL(syscall_name, args)                \
+    addik r12,r0,SYS_ify (syscall_name);            \
+    brki  r14,8;                                    \
+    addk  r0,r0,r0;
+
+#else /* not __ASSEMBLER__ */
+
+/* Define a macro which expands into the inline wrapper code for a system
+   call.  */
+# undef INLINE_SYSCALL
+# define INLINE_SYSCALL(name, nr, args...)                           \
+({  INTERNAL_SYSCALL_DECL(err);                                      \
+    unsigned long resultvar = INTERNAL_SYSCALL(name, err, nr, args); \
+    if (INTERNAL_SYSCALL_ERROR_P (resultvar, err))                   \
+       {                                                             \
+        __set_errno (INTERNAL_SYSCALL_ERRNO (resultvar, err));       \
+        resultvar = (unsigned long) -1;                              \
+       }                                                             \
+    (long) resultvar;                                                \
+})
+
+# undef INTERNAL_SYSCALL_DECL
+# define INTERNAL_SYSCALL_DECL(err) do { } while (0)
+
+/* 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.  */
+# undef INTERNAL_SYSCALL
+# define INTERNAL_SYSCALL(name, err, nr, args...)                    \
+  inline_syscall##nr(SYS_ify(name), args)
+
+# undef INTERNAL_SYSCALL_NCS
+# define INTERNAL_SYSCALL_NCS(name, err, nr, args...)                \
+  inline_syscall##nr(name, args)
+
+# undef INTERNAL_SYSCALL_ERROR_P
+# define INTERNAL_SYSCALL_ERROR_P(val, err)                          \
+  ((unsigned int) (val) >= -4095U)
+
+# undef INTERNAL_SYSCALL_ERRNO
+# define INTERNAL_SYSCALL_ERRNO(val, err)    (-(val))
+
+# define SYSCALL_CLOBBERS_6 "r11", "r4", "memory"
+# define SYSCALL_CLOBBERS_5 "r10", SYSCALL_CLOBBERS_6
+# define SYSCALL_CLOBBERS_4 "r9", SYSCALL_CLOBBERS_5
+# define SYSCALL_CLOBBERS_3 "r8", SYSCALL_CLOBBERS_4
+# define SYSCALL_CLOBBERS_2 "r7", SYSCALL_CLOBBERS_3
+# define SYSCALL_CLOBBERS_1 "r6", SYSCALL_CLOBBERS_2
+# define SYSCALL_CLOBBERS_0 "r5", SYSCALL_CLOBBERS_1
+
+# define inline_syscall0(name,dummy)                                          \
+  ({                                                                          \
+    register long ret __asm__("r3");                                          \
+    register long __r12 __asm__("r12") = name;                                \
+    __asm__ __volatile__( "brki r14,8; nop;"                                  \
+      : "=r"(ret)                                                             \
+      : "r"(__r12)                                                            \
+      : SYSCALL_CLOBBERS_0 ); ret;                                            \
+  })
+
+# define inline_syscall1(name,arg1)                                           \
+  ({                                                                          \
+    register long ret __asm__("r3");                                          \
+    register long __r12 __asm__("r12") = name;                                \
+    register long __r5 __asm__("r5") = (long)(arg1);                          \
+    __asm__ __volatile__( "brki r14,8; nop;"                                  \
+      : "=r"(ret)                                                             \
+      : "r"(__r5), "r"(__r12)                                                 \
+      : SYSCALL_CLOBBERS_1 ); ret;                                            \
+  })
+
+# define inline_syscall2(name,arg1,arg2)                                      \
+  ({                                                                          \
+    register long ret __asm__("r3");                                          \
+    register long __r12 __asm__("r12") = name;                                \
+    register long __r5 __asm__("r5") = (long)(arg1);                          \
+    register long __r6 __asm__("r6") = (long)(arg2);                          \
+    __asm__ __volatile__( "brki r14,8; nop;"                                  \
+      : "=r"(ret)                                                             \
+      : "r"(__r5), "r"(__r6), "r"(__r12)                                      \
+      : SYSCALL_CLOBBERS_2 ); ret;                                            \
+  })
+
+
+# define inline_syscall3(name,arg1,arg2,arg3)                                 \
+  ({                                                                          \
+    register long ret __asm__("r3");                                          \
+    register long __r12 __asm__("r12") = name;                                \
+    register long __r5 __asm__("r5") = (long)(arg1);                          \
+    register long __r6 __asm__("r6") = (long)(arg2);                          \
+    register long __r7 __asm__("r7") = (long)(arg3);                          \
+    __asm__ __volatile__( "brki r14,8; nop;"                                  \
+      : "=r"(ret)                                                             \
+      : "r"(__r5), "r"(__r6), "r"(__r7), "r"(__r12)                           \
+      : SYSCALL_CLOBBERS_3 ); ret;                                            \
+  })
+
+
+# define inline_syscall4(name,arg1,arg2,arg3,arg4)                            \
+  ({                                                                          \
+    register long ret __asm__("r3");                                          \
+    register long __r12 __asm__("r12") = name;                                \
+    register long __r5 __asm__("r5") = (long)(arg1);                          \
+    register long __r6 __asm__("r6") = (long)(arg2);                          \
+    register long __r7 __asm__("r7") = (long)(arg3);                          \
+    register long __r8 __asm__("r8") = (long)(arg4);                          \
+    __asm__ __volatile__( "brki r14,8; nop;"                                  \
+      : "=r"(ret)                                                             \
+      : "r"(__r5), "r"(__r6), "r"(__r7), "r"(__r8),"r"(__r12)                 \
+      : SYSCALL_CLOBBERS_4 ); ret;                                            \
+  })
+
+
+# define inline_syscall5(name,arg1,arg2,arg3,arg4,arg5)                       \
+  ({                                                                          \
+    register long ret __asm__("r3");                                          \
+    register long __r12 __asm__("r12") = name;                                \
+    register long __r5 __asm__("r5") = (long)(arg1);                          \
+    register long __r6 __asm__("r6") = (long)(arg2);                          \
+    register long __r7 __asm__("r7") = (long)(arg3);                          \
+    register long __r8 __asm__("r8") = (long)(arg4);                          \
+    register long __r9 __asm__("r9") = (long)(arg5);                          \
+    __asm__ __volatile__( "brki r14,8; nop;"                                  \
+      : "=r"(ret)                                                             \
+      : "r"(__r5), "r"(__r6), "r"(__r7), "r"(__r8),"r"(__r9), "r"(__r12)      \
+      : SYSCALL_CLOBBERS_5 ); ret;                                            \
+  })
+
+
+# define inline_syscall6(name,arg1,arg2,arg3,arg4,arg5,arg6)                  \
+  ({                                                                          \
+    register long ret __asm__("r3");                                          \
+    register long __r12 __asm__("r12") = name;                                \
+    register long __r5 __asm__("r5") = (long)(arg1);                          \
+    register long __r6 __asm__("r6") = (long)(arg2);                          \
+    register long __r7 __asm__("r7") = (long)(arg3);                          \
+    register long __r8 __asm__("r8") = (long)(arg4);                          \
+    register long __r9 __asm__("r9") = (long)(arg5);                          \
+    register long __r10 __asm__("r10") = (long)(arg6);                        \
+    __asm__ __volatile__( "brki r14,8; nop;"                                  \
+      : "=r"(ret)                                                             \
+      : "r"(__r5), "r"(__r6), "r"(__r7), "r"(__r8),"r"(__r9), "r"(__r10),     \
+      "r"(__r12)                                                              \
+      : SYSCALL_CLOBBERS_6 ); ret;                                            \
+  })
+
+
+/* Pointer mangling is not yet supported for Microblaze.  */
+# define PTR_MANGLE(var) (void) (var)
+# define PTR_DEMANGLE(var) (void) (var)
+
+#endif /* not __ASSEMBLER__ */