123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191 |
- /*
- * Copyright (C) 2013 Synopsys, Inc. (www.synopsys.com)
- *
- * Licensed under LGPL v2.1 or later, see the file COPYING.LIB in this tarball.
- *
- */
- #ifndef _BITS_SYSCALLS_H
- #define _BITS_SYSCALLS_H
- #ifndef _SYSCALL_H
- #error "Never use <bits/syscalls.h> directly; include <sys/syscall.h> instead."
- #endif
- #ifndef __ASSEMBLER__
- #include <errno.h>
- /*
- * Fine tuned code for errno handling in syscall wrappers.
- *
- * 1. __syscall_error(raw_syscall_ret_val) is used to set the errno (vs.
- * the typical __set_errno). This helps elide the generated code for
- * GOT fetch for __errno_location pointer etc, in each wrapper.
- *
- * 2. The call to above is also disguised in inline asm. This elides
- * unconditional save/restore of a few callee regs which gcc almost
- * always generates if the call is exposed
- *
- * 3. The function can't be hidden because wrappers from librt et all also
- * call it. However hidden is not really needed to bypass PLT for
- * intra-libc calls as the branch insn w/o @plt is sufficient.
- */
- #ifdef IS_IN_rtld
- /* ldso doesn't have real errno */
- #define ERRNO_ERRANDS(_sys_result)
- #else /* !IS_IN_rtld */
- extern long __syscall_error (int);
- #ifndef IS_IN_libc
- /* Inter-libc callers use PLT */
- #define CALL_ERRNO_SETTER "bl __syscall_error@plt \n\t"
- #else
- /* intra-libc callers, despite PIC can bypass PLT */
- #define CALL_ERRNO_SETTER "bl __syscall_error \n\t"
- #endif
- #define ERRNO_ERRANDS(_sys_result) \
- __asm__ volatile ( \
- "st.a blink, [sp, -4] \n\t" \
- CALL_ERRNO_SETTER \
- "ld.ab blink, [sp, 4] \n\t" \
- :"+r" (_sys_result) \
- : \
- :"r1","r2","r3","r4","r5","r6", \
- "r7","r8","r9","r10","r11","r12" \
- );
- #endif /* IS_IN_rtld */
- /* -1 to -1023 as valid error values will suffice for some time */
- #define INTERNAL_SYSCALL_ERROR_P(val, err) \
- ((unsigned int) (val) > (unsigned int) -1024)
- /*
- * Standard sycall wrapper
- * -Gets syscall name (conv to __NR_xxx)
- * -sets errno, return success/error-codes
- */
- #define INLINE_SYSCALL(name, nr_args, args...) \
- ({ \
- register int __res __asm__("r0"); \
- __res = INTERNAL_SYSCALL_NCS(__NR_##name, , nr_args, args); \
- if (__builtin_expect (INTERNAL_SYSCALL_ERROR_P ((__res), ), 0)) \
- { \
- ERRNO_ERRANDS(__res); \
- } \
- __res; \
- })
- /* variant of INLINE_SYSCALL, gets syscall number
- */
- #define INLINE_SYSCALL_NCS(num, nr_args, args...) \
- ({ \
- register int __res __asm__("r0"); \
- __res = INTERNAL_SYSCALL_NCS(num, , nr_args, args); \
- if (__builtin_expect (INTERNAL_SYSCALL_ERROR_P ((__res), ), 0)) \
- { \
- ERRNO_ERRANDS(__res); \
- } \
- __res; \
- })
- /*-------------------------------------------------------------------------
- * Mechanics of Trap - specific to ARC700
- *
- * Note the memory clobber is not strictly needed for intended semantics of
- * the inline asm. However some of the cases, such as old-style 6 arg mmap
- * gcc was generating code for inline syscall ahead of buffer packing needed
- * for syscall itself.
- *-------------------------------------------------------------------------*/
- #ifdef __A7__
- #define ARC_TRAP_INSN "trap0 \n\t"
- #else
- #define ARC_TRAP_INSN "trap_s 0 \n\t"
- #endif
- #define INTERNAL_SYSCALL_NCS(nm, err, nr_args, args...) \
- ({ \
- /* Per ABI, r0 is 1st arg and return reg */ \
- register int __ret __asm__("r0"); \
- register int _sys_num __asm__("r8"); \
- \
- LOAD_ARGS_##nr_args (nm, args) \
- \
- __asm__ volatile ( \
- ARC_TRAP_INSN \
- : "+r" (__ret) \
- : "r"(_sys_num) ASM_ARGS_##nr_args \
- : "memory"); \
- \
- __ret; \
- })
- /* Macros for setting up inline __asm__ input regs */
- #define ASM_ARGS_0
- #define ASM_ARGS_1 ASM_ARGS_0, "r" (__ret)
- #define ASM_ARGS_2 ASM_ARGS_1, "r" (_arg2)
- #define ASM_ARGS_3 ASM_ARGS_2, "r" (_arg3)
- #define ASM_ARGS_4 ASM_ARGS_3, "r" (_arg4)
- #define ASM_ARGS_5 ASM_ARGS_4, "r" (_arg5)
- #define ASM_ARGS_6 ASM_ARGS_5, "r" (_arg6)
- #define ASM_ARGS_7 ASM_ARGS_6, "r" (_arg7)
- /* Macros for converting sys-call wrapper args into sys call args */
- #define LOAD_ARGS_0(nm, arg) \
- _sys_num = (int) (nm); \
- #define LOAD_ARGS_1(nm, arg1) \
- __ret = (int) (arg1); \
- LOAD_ARGS_0 (nm, arg1)
- /*
- * Note that the use of _tmpX might look superflous, however it is needed
- * to ensure that register variables are not clobbered if arg happens to be
- * a function call itself. e.g. sched_setaffinity() calling getpid() for arg2
- *
- * Also this specific order of recursive calling is important to segregate
- * the tmp args evaluation (function call case described above) and assigment
- * of register variables
- */
- #define LOAD_ARGS_2(nm, arg1, arg2) \
- int _tmp2 = (int) (arg2); \
- LOAD_ARGS_1 (nm, arg1) \
- register int _arg2 __asm__ ("r1") = _tmp2;
- #define LOAD_ARGS_3(nm, arg1, arg2, arg3) \
- int _tmp3 = (int) (arg3); \
- LOAD_ARGS_2 (nm, arg1, arg2) \
- register int _arg3 __asm__ ("r2") = _tmp3;
- #define LOAD_ARGS_4(nm, arg1, arg2, arg3, arg4) \
- int _tmp4 = (int) (arg4); \
- LOAD_ARGS_3 (nm, arg1, arg2, arg3) \
- register int _arg4 __asm__ ("r3") = _tmp4;
- #define LOAD_ARGS_5(nm, arg1, arg2, arg3, arg4, arg5) \
- int _tmp5 = (int) (arg5); \
- LOAD_ARGS_4 (nm, arg1, arg2, arg3, arg4) \
- register int _arg5 __asm__ ("r4") = _tmp5;
- #define LOAD_ARGS_6(nm, arg1, arg2, arg3, arg4, arg5, arg6) \
- int _tmp6 = (int) (arg6); \
- LOAD_ARGS_5 (nm, arg1, arg2, arg3, arg4, arg5) \
- register int _arg6 __asm__ ("r5") = _tmp6;
- #define LOAD_ARGS_7(nm, arg1, arg2, arg3, arg4, arg5, arg6, arg7)\
- int _tmp7 = (int) (arg7); \
- LOAD_ARGS_6 (nm, arg1, arg2, arg3, arg4, arg5, arg6) \
- register int _arg7 __asm__ ("r6") = _tmp7;
- #else
- #ifdef __A7__
- #define ARC_TRAP_INSN trap0
- #else
- #define ARC_TRAP_INSN trap_s 0
- #endif
- #endif /* __ASSEMBLER__ */
- #endif /* _BITS_SYSCALLS_H */
|