diff options
author | Adhemerval Zanella <adhemerval.zanella@linaro.org> | 2020-01-30 19:13:31 +0000 |
---|---|---|
committer | Adhemerval Zanella <adhemerval.zanella@linaro.org> | 2020-02-14 21:09:12 -0300 |
commit | cd72a13f22dbb56f56ed63e9899050cba7a286ad (patch) | |
tree | 68aec56681b6c5d357413ab4b2d467fa9c760916 /sysdeps/unix/sysv/linux/powerpc/sysdep.h | |
parent | i386: Enable CET support in ucontext functions (diff) | |
download | glibc-cd72a13f22dbb56f56ed63e9899050cba7a286ad.tar.gz glibc-cd72a13f22dbb56f56ed63e9899050cba7a286ad.tar.bz2 glibc-cd72a13f22dbb56f56ed63e9899050cba7a286ad.zip |
powerpc: Consolidate Linux syscall definition
The diferences between powerpc64{le} and powerpc32 Linux sysdep.h
are:
1. On both vDSO and syscall macros the volatile registers r9, r10,
r11, and r12 are used as input operands on powerpc32 and as
clobber registers on powerpc64. However the outcome is essentially
the same, it advertise the register might be clobbered by the
kernel (although Linux won't leak register information to userland
in such case).
2. The LOADARGS* macros uses a different size to check for invalid
types.
3. The pointer mangling support guard pointer loading uses ABI
specific instruction and register.
This patch consolidates on only one sysdep by using the the powerpc64
version as default and add the adjustments required for powerpc32.
Checked on powerpc64-linux-gnu, powerpc64le-linux-gnu, and
powerpc-linux-gnu-power4.
Diffstat (limited to 'sysdeps/unix/sysv/linux/powerpc/sysdep.h')
-rw-r--r-- | sysdeps/unix/sysv/linux/powerpc/sysdep.h | 208 |
1 files changed, 207 insertions, 1 deletions
diff --git a/sysdeps/unix/sysv/linux/powerpc/sysdep.h b/sysdeps/unix/sysv/linux/powerpc/sysdep.h index 1f477a945d..0f067db8cc 100644 --- a/sysdeps/unix/sysv/linux/powerpc/sysdep.h +++ b/sysdeps/unix/sysv/linux/powerpc/sysdep.h @@ -16,10 +16,214 @@ 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 + 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 + +/* 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, err, 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"); \ + err = (long int) r0; \ + __asm__ __volatile__ ("" : "=r" (rval) : "r" (r3)); \ + rval; \ + }) + +#define INTERNAL_VSYSCALL_CALL(funcptr, err, nr, args...) \ + INTERNAL_VSYSCALL_CALL_TYPE(funcptr, err, long int, nr, args) + +/* This version is for kernels that implement system calls that + behave like function calls as far as register saving. */ +#undef INLINE_SYSCALL +#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; \ + }) + +/* 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. */ + +#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"); \ + LOADARGS_##nr (name, ##args); \ + __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"); \ + err = r0; \ + r3; \ + }) +#define INTERNAL_SYSCALL(name, err, nr, args...) \ + INTERNAL_SYSCALL_NCS (__NR_##name, err, nr, args) + +#undef INTERNAL_SYSCALL_DECL +#define INTERNAL_SYSCALL_DECL(err) long int err __attribute__ ((unused)) + +#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) + +#if defined(__PPC64__) || defined(__powerpc64__) +# define SYSCALL_ARG_SIZE 8 +#else +# define SYSCALL_ARG_SIZE 4 +#endif + +#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 + +#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) + + +/* 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 -/* List of system calls which are supported as vsyscalls. */ #if defined(__PPC64__) || defined(__powerpc64__) #define HAVE_CLOCK_GETRES64_VSYSCALL "__kernel_clock_getres" #define HAVE_CLOCK_GETTIME64_VSYSCALL "__kernel_clock_gettime" @@ -38,3 +242,5 @@ # define HAVE_SIGTRAMP_32 "__kernel_sigtramp32" # define HAVE_SIGTRAMP_RT32 "__kernel_sigtramp_rt32" #endif + +#endif /* _LINUX_POWERPC_SYSDEP_H */ |