diff options
Diffstat (limited to 'sysdeps/unix/sysv/linux/microblaze/sysdep.h')
-rw-r--r-- | sysdeps/unix/sysv/linux/microblaze/sysdep.h | 307 |
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__ */ |