diff options
Diffstat (limited to 'libc/sysdeps/linux')
-rw-r--r-- | libc/sysdeps/linux/powerpc/bits/syscalls.h | 160 |
1 files changed, 127 insertions, 33 deletions
diff --git a/libc/sysdeps/linux/powerpc/bits/syscalls.h b/libc/sysdeps/linux/powerpc/bits/syscalls.h index 6168f3906..75001f218 100644 --- a/libc/sysdeps/linux/powerpc/bits/syscalls.h +++ b/libc/sysdeps/linux/powerpc/bits/syscalls.h @@ -10,62 +10,156 @@ * programs. */ #include <bits/sysnum.h> +/* 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. + On powerpc a system call basically clobbers the same registers like a + function call, with the exception of LR (which is needed for the + "sc; bnslr+" sequence) and CR (where only CR0.SO is clobbered to signal + an error return status). */ -#define __STRINGIFY(s) __STRINGIFY2 (s) -#define __STRINGIFY2(s) #s - -#undef JUMPTARGET -#ifdef __PIC__ -#define __MAKE_SYSCALL __STRINGIFY(__uClibc_syscall@plt) -#else -#define __MAKE_SYSCALL __STRINGIFY(__uClibc_syscall) +# undef INLINE_SYSCALL +#if 0 +# define INLINE_SYSCALL(name, nr, args...) \ + ({ \ + INTERNAL_SYSCALL_DECL (sc_err); \ + long int sc_ret = INTERNAL_SYSCALL (name, sc_err, nr, args); \ + if (INTERNAL_SYSCALL_ERROR_P (sc_ret, sc_err)) \ + { \ + __set_errno (INTERNAL_SYSCALL_ERRNO (sc_ret, sc_err)); \ + sc_ret = -1L; \ + } \ + sc_ret; \ + }) #endif -#define unified_syscall_body(name) \ - __asm__ ( \ - ".section \".text\"\n\t" \ - ".align 2\n\t" \ - ".globl " __STRINGIFY(name) "\n\t" \ - ".type " __STRINGIFY(name) ",@function\n\t" \ - #name":\tli 0," __STRINGIFY(__NR_##name) "\n\t" \ - "b " __MAKE_SYSCALL "\n\t" \ - ".size\t" __STRINGIFY(name) ",.""-" __STRINGIFY(name) "\n" \ - ) +# define INLINE_SYSCALL(name, nr, args...) \ + ({ \ + INTERNAL_SYSCALL_DECL (sc_err); \ + long int sc_ret = INTERNAL_SYSCALL (name, sc_err, nr, args); \ + if (INTERNAL_SYSCALL_ERROR_P (sc_ret, sc_err)) \ + { \ + sc_ret = __syscall_error(INTERNAL_SYSCALL_ERRNO (sc_ret, sc_err));\ + } \ + sc_ret; \ + }) +/* 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. + On powerpc a system call basically clobbers the same registers like a + function call, with the exception of LR (which is needed for the + "sc; bnslr+" sequence) and CR (where only CR0.SO is clobbered to signal + an error return status). */ + +# undef INTERNAL_SYSCALL_DECL +# define INTERNAL_SYSCALL_DECL(err) long int err + +# undef INTERNAL_SYSCALL +# define INTERNAL_SYSCALL_NCS(name, err, nr, args...) \ + ({ \ + 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"); \ + register long int r9 __asm__ ("r9"); \ + register long int r10 __asm__ ("r10"); \ + register long int r11 __asm__ ("r11"); \ + register long int r12 __asm__ ("r12"); \ + LOADARGS_##nr(name, args); \ + __asm__ __volatile__ \ + ("sc \n\t" \ + "mfcr %0" \ + : "=&r" (r0), \ + "=&r" (r3), "=&r" (r4), "=&r" (r5), "=&r" (r6), "=&r" (r7), \ + "=&r" (r8), "=&r" (r9), "=&r" (r10), "=&r" (r11), "=&r" (r12) \ + : ASM_INPUT_##nr \ + : "cr0", "ctr", "memory"); \ + err = r0; \ + (int) r3; \ + }) +# define INTERNAL_SYSCALL(name, err, nr, args...) \ + INTERNAL_SYSCALL_NCS (__NR_##name, err, nr, ##args) + +# undef INTERNAL_SYSCALL_ERROR_P +# define INTERNAL_SYSCALL_ERROR_P(val, err) \ + ((void) (val), __builtin_expect ((err) & (1 << 28), 0)) + +# undef INTERNAL_SYSCALL_ERRNO +# define INTERNAL_SYSCALL_ERRNO(val, err) (val) + +# define LOADARGS_0(name, dummy) \ + r0 = (long int)name +# define LOADARGS_1(name, __arg1) \ + LOADARGS_0(name, 0); \ + r3 = (long int)__arg1 +# define LOADARGS_2(name, __arg1, __arg2) \ + LOADARGS_1(name, __arg1); \ + r4 = (long int)__arg2 +# define LOADARGS_3(name, __arg1, __arg2, __arg3) \ + LOADARGS_2(name, __arg1, __arg2); \ + r5 = (long int)__arg3 +# define LOADARGS_4(name, __arg1, __arg2, __arg3, __arg4) \ + LOADARGS_3(name, __arg1, __arg2, __arg3); \ + r6 = (long int)__arg4 +# define LOADARGS_5(name, __arg1, __arg2, __arg3, __arg4, __arg5) \ + LOADARGS_4(name, __arg1, __arg2, __arg3, __arg4); \ + r7 = (long int)__arg5 +# define LOADARGS_6(name, __arg1, __arg2, __arg3, __arg4, __arg5, __arg6) \ + LOADARGS_5(name, __arg1, __arg2, __arg3, __arg4, __arg5); \ + r8 = (long int)__arg6 + +# 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) #undef _syscall0 -#define _syscall0(type,name) \ -type name(void); \ -unified_syscall_body(name) +#define _syscall0(type,name) \ +type name(void){ \ + return INLINE_SYSCALL(name, 0); \ +} #undef _syscall1 #define _syscall1(type,name,type1,arg1) \ -type name(type1 arg1); \ -unified_syscall_body(name) +type name(type1 arg1){ \ + return INLINE_SYSCALL(name, 1, arg1); \ +} #undef _syscall2 #define _syscall2(type,name,type1,arg1,type2,arg2) \ -type name(type1 arg1, type2 arg2); \ -unified_syscall_body(name) +type name(type1 arg1, type2 arg2){ \ + return INLINE_SYSCALL(name, 2, arg1, arg2); \ +} #undef _syscall3 #define _syscall3(type,name,type1,arg1,type2,arg2,type3,arg3) \ -type name(type1 arg1, type2 arg2, type3 arg3); \ -unified_syscall_body(name) +type name(type1 arg1, type2 arg2, type3 arg3){ \ + return INLINE_SYSCALL(name, 3, arg1, arg2, arg3); \ +} #undef _syscall4 #define _syscall4(type,name,type1,arg1,type2,arg2,type3,arg3,type4,arg4) \ -type name(type1 arg1, type2 arg2, type3 arg3, type4 arg4); \ -unified_syscall_body(name) +type name(type1 arg1, type2 arg2, type3 arg3, type4 arg4){ \ + return INLINE_SYSCALL(name, 4, arg1, arg2, arg3, arg4); \ +} #undef _syscall5 #define _syscall5(type,name,type1,arg1,type2,arg2,type3,arg3,type4,arg4,type5,arg5) \ -type name(type1 arg1, type2 arg2, type3 arg3, type4 arg4, type5 arg5); \ -unified_syscall_body(name) +type name(type1 arg1, type2 arg2, type3 arg3, type4 arg4, type5 arg5){ \ + return INLINE_SYSCALL(name, 5, arg1, arg2, arg3, arg4, arg5); \ +} #undef _syscall6 #define _syscall6(type,name,type1,arg1,type2,arg2,type3,arg3,type4,arg4,type5,arg5,type6,arg6) \ -type name(type1 arg1, type2 arg2, type3 arg3, type4 arg4, type5 arg5, type6 arg6); \ -unified_syscall_body(name) +type name(type1 arg1, type2 arg2, type3 arg3, type4 arg4, type5 arg5, type6 arg6){ \ + return INLINE_SYSCALL(name, 6, arg1, arg2, arg3, arg4, arg5, arg6); \ +} #endif /* _BITS_SYSCALLS_H */ |