From c0ede9e4046a0882d83ae4b45c7dfac86fb7c15d Mon Sep 17 00:00:00 2001 From: Bobby Bingham Date: Sat, 30 Apr 2016 19:18:17 -0500 Subject: add powerpc64 port --- src/fenv/powerpc64/fenv.c | 68 ++++++++++++++++++++++++++++ src/internal/powerpc64/syscall.s | 17 +++++++ src/ldso/powerpc64/dlsym.s | 12 +++++ src/setjmp/powerpc64/longjmp.s | 77 +++++++++++++++++++++++++++++++ src/setjmp/powerpc64/setjmp.s | 78 ++++++++++++++++++++++++++++++++ src/signal/powerpc64/restore.s | 11 +++++ src/signal/powerpc64/sigsetjmp.s | 30 ++++++++++++ src/thread/powerpc64/__set_thread_area.s | 8 ++++ src/thread/powerpc64/__unmapself.s | 9 ++++ src/thread/powerpc64/clone.s | 47 +++++++++++++++++++ src/thread/powerpc64/syscall_cp.s | 37 +++++++++++++++ 11 files changed, 394 insertions(+) create mode 100644 src/fenv/powerpc64/fenv.c create mode 100644 src/internal/powerpc64/syscall.s create mode 100644 src/ldso/powerpc64/dlsym.s create mode 100644 src/setjmp/powerpc64/longjmp.s create mode 100644 src/setjmp/powerpc64/setjmp.s create mode 100644 src/signal/powerpc64/restore.s create mode 100644 src/signal/powerpc64/sigsetjmp.s create mode 100644 src/thread/powerpc64/__set_thread_area.s create mode 100644 src/thread/powerpc64/__unmapself.s create mode 100644 src/thread/powerpc64/clone.s create mode 100644 src/thread/powerpc64/syscall_cp.s (limited to 'src') diff --git a/src/fenv/powerpc64/fenv.c b/src/fenv/powerpc64/fenv.c new file mode 100644 index 00000000..739420b7 --- /dev/null +++ b/src/fenv/powerpc64/fenv.c @@ -0,0 +1,68 @@ +#define _GNU_SOURCE +#include + +static inline double get_fpscr_f(void) +{ + double d; + __asm__ __volatile__("mffs %0" : "=d"(d)); + return d; +} + +static inline long get_fpscr(void) +{ + return (union {double f; long i;}) {get_fpscr_f()}.i; +} + +static inline void set_fpscr_f(double fpscr) +{ + __asm__ __volatile__("mtfsf 255, %0" : : "d"(fpscr)); +} + +static void set_fpscr(long fpscr) +{ + set_fpscr_f((union {long i; double f;}) {fpscr}.f); +} + +int feclearexcept(int mask) +{ + mask &= FE_ALL_EXCEPT; + if (mask & FE_INVALID) mask |= FE_ALL_INVALID; + set_fpscr(get_fpscr() & ~mask); + return 0; +} + +int feraiseexcept(int mask) +{ + mask &= FE_ALL_EXCEPT; + if (mask & FE_INVALID) mask |= FE_INVALID_SOFTWARE; + set_fpscr(get_fpscr() | mask); + return 0; +} + +int fetestexcept(int mask) +{ + return get_fpscr() & mask & FE_ALL_EXCEPT; +} + +int fegetround(void) +{ + return get_fpscr() & 3; +} + +int __fesetround(int r) +{ + set_fpscr(get_fpscr() & ~3L | r); + return 0; +} + +int fegetenv(fenv_t *envp) +{ + *envp = get_fpscr_f(); + return 0; +} + +int fesetenv(const fenv_t *envp) +{ + set_fpscr_f(envp != FE_DFL_ENV ? *envp : 0); + return 0; +} diff --git a/src/internal/powerpc64/syscall.s b/src/internal/powerpc64/syscall.s new file mode 100644 index 00000000..fe21f9e1 --- /dev/null +++ b/src/internal/powerpc64/syscall.s @@ -0,0 +1,17 @@ + .global __syscall + .hidden __syscall + .type __syscall,@function +__syscall: + mr 0, 3 # Save the system call number + mr 3, 4 # Shift the arguments: arg1 + mr 4, 5 # arg2 + mr 5, 6 # arg3 + mr 6, 7 # arg4 + mr 7, 8 # arg5 + mr 8, 9 # arg6 + sc + bnslr+ # return if not summary overflow + neg 3, 3 # otherwise error: return negated value. + blr + .end __syscall + .size __syscall, .-__syscall diff --git a/src/ldso/powerpc64/dlsym.s b/src/ldso/powerpc64/dlsym.s new file mode 100644 index 00000000..7eb691d9 --- /dev/null +++ b/src/ldso/powerpc64/dlsym.s @@ -0,0 +1,12 @@ + .text + .global dlsym + .hidden __dlsym + .type dlsym,@function +dlsym: + addis 2, 12, .TOC.-dlsym@ha + addi 2, 2, .TOC.-dlsym@l + .localentry dlsym,.-dlsym + mflr 5 # The return address is arg3. + b __dlsym + .end dlsym + .size dlsym, .-dlsym diff --git a/src/setjmp/powerpc64/longjmp.s b/src/setjmp/powerpc64/longjmp.s new file mode 100644 index 00000000..7f241c2d --- /dev/null +++ b/src/setjmp/powerpc64/longjmp.s @@ -0,0 +1,77 @@ + .global _longjmp + .global longjmp + .type _longjmp,@function + .type longjmp,@function +_longjmp: +longjmp: + # 0) move old return address into the link register + ld 0, 0*8(3) + mtlr 0 + # 1) restore cr + ld 0, 1*8(3) + mtcr 0 + # 2) restore r1-r2 (SP and TOC) + ld 1, 2*8(3) + ld 2, 3*8(3) + # 3) restore r14-r31 + ld 14, 4*8(3) + ld 15, 5*8(3) + ld 16, 6*8(3) + ld 17, 7*8(3) + ld 18, 8*8(3) + ld 19, 9*8(3) + ld 20, 10*8(3) + ld 21, 11*8(3) + ld 22, 12*8(3) + ld 23, 13*8(3) + ld 24, 14*8(3) + ld 25, 15*8(3) + ld 26, 16*8(3) + ld 27, 17*8(3) + ld 28, 18*8(3) + ld 29, 19*8(3) + ld 30, 20*8(3) + ld 31, 21*8(3) + # 4) restore floating point registers f14-f31 + lfd 14, 22*8(3) + lfd 15, 23*8(3) + lfd 16, 24*8(3) + lfd 17, 25*8(3) + lfd 18, 26*8(3) + lfd 19, 27*8(3) + lfd 20, 28*8(3) + lfd 21, 29*8(3) + lfd 22, 30*8(3) + lfd 23, 31*8(3) + lfd 24, 32*8(3) + lfd 25, 33*8(3) + lfd 26, 34*8(3) + lfd 27, 35*8(3) + lfd 28, 36*8(3) + lfd 29, 37*8(3) + lfd 30, 38*8(3) + lfd 31, 39*8(3) + + # 5) restore vector registers v20-v31 + addi 3, 3, 40*8 + lvx 20, 0, 3 ; addi 3, 3, 16 + lvx 21, 0, 3 ; addi 3, 3, 16 + lvx 22, 0, 3 ; addi 3, 3, 16 + lvx 23, 0, 3 ; addi 3, 3, 16 + lvx 24, 0, 3 ; addi 3, 3, 16 + lvx 25, 0, 3 ; addi 3, 3, 16 + lvx 26, 0, 3 ; addi 3, 3, 16 + lvx 27, 0, 3 ; addi 3, 3, 16 + lvx 28, 0, 3 ; addi 3, 3, 16 + lvx 29, 0, 3 ; addi 3, 3, 16 + lvx 30, 0, 3 ; addi 3, 3, 16 + lvx 31, 0, 3 + + # 6) return r4 ? r4 : 1 + mr 3, 4 + cmpwi cr7, 4, 0 + bne cr7, 1f + li 3, 1 +1: + blr + diff --git a/src/setjmp/powerpc64/setjmp.s b/src/setjmp/powerpc64/setjmp.s new file mode 100644 index 00000000..d16d4bae --- /dev/null +++ b/src/setjmp/powerpc64/setjmp.s @@ -0,0 +1,78 @@ + .global ___setjmp + .hidden ___setjmp + .global __setjmp + .global _setjmp + .global setjmp + .type __setjmp,@function + .type _setjmp,@function + .type setjmp,@function +___setjmp: +__setjmp: +_setjmp: +setjmp: + # 0) store IP into 0, then into the jmpbuf pointed to by r3 (first arg) + mflr 0 + std 0, 0*8(3) + # 1) store cr + mfcr 0 + std 0, 1*8(3) + # 2) store r1-r2 (SP and TOC) + std 1, 2*8(3) + std 2, 3*8(3) + # 3) store r14-31 + std 14, 4*8(3) + std 15, 5*8(3) + std 16, 6*8(3) + std 17, 7*8(3) + std 18, 8*8(3) + std 19, 9*8(3) + std 20, 10*8(3) + std 21, 11*8(3) + std 22, 12*8(3) + std 23, 13*8(3) + std 24, 14*8(3) + std 25, 15*8(3) + std 26, 16*8(3) + std 27, 17*8(3) + std 28, 18*8(3) + std 29, 19*8(3) + std 30, 20*8(3) + std 31, 21*8(3) + # 4) store floating point registers f14-f31 + stfd 14, 22*8(3) + stfd 15, 23*8(3) + stfd 16, 24*8(3) + stfd 17, 25*8(3) + stfd 18, 26*8(3) + stfd 19, 27*8(3) + stfd 20, 28*8(3) + stfd 21, 29*8(3) + stfd 22, 30*8(3) + stfd 23, 31*8(3) + stfd 24, 32*8(3) + stfd 25, 33*8(3) + stfd 26, 34*8(3) + stfd 27, 35*8(3) + stfd 28, 36*8(3) + stfd 29, 37*8(3) + stfd 30, 38*8(3) + stfd 31, 39*8(3) + + # 5) store vector registers v20-v31 + addi 3, 3, 40*8 + stvx 20, 0, 3 ; addi 3, 3, 16 + stvx 21, 0, 3 ; addi 3, 3, 16 + stvx 22, 0, 3 ; addi 3, 3, 16 + stvx 23, 0, 3 ; addi 3, 3, 16 + stvx 24, 0, 3 ; addi 3, 3, 16 + stvx 25, 0, 3 ; addi 3, 3, 16 + stvx 26, 0, 3 ; addi 3, 3, 16 + stvx 27, 0, 3 ; addi 3, 3, 16 + stvx 28, 0, 3 ; addi 3, 3, 16 + stvx 29, 0, 3 ; addi 3, 3, 16 + stvx 30, 0, 3 ; addi 3, 3, 16 + stvx 31, 0, 3 + + # 6) return 0 + li 3, 0 + blr diff --git a/src/signal/powerpc64/restore.s b/src/signal/powerpc64/restore.s new file mode 100644 index 00000000..4d41c27a --- /dev/null +++ b/src/signal/powerpc64/restore.s @@ -0,0 +1,11 @@ + .global __restore + .type __restore,%function +__restore: + li 0, 119 #__NR_sigreturn + sc + + .global __restore_rt + .type __restore_rt,%function +__restore_rt: + li 0, 172 # __NR_rt_sigreturn + sc diff --git a/src/signal/powerpc64/sigsetjmp.s b/src/signal/powerpc64/sigsetjmp.s new file mode 100644 index 00000000..52ac1d03 --- /dev/null +++ b/src/signal/powerpc64/sigsetjmp.s @@ -0,0 +1,30 @@ + .global sigsetjmp + .global __sigsetjmp + .type sigsetjmp,%function + .type __sigsetjmp,%function + .hidden ___setjmp +sigsetjmp: +__sigsetjmp: + addis 2, 12, .TOC.-__sigsetjmp@ha + addi 2, 2, .TOC.-__sigsetjmp@l + .localentry sigsetjmp,.-sigsetjmp + .localentry __sigsetjmp,.-__sigsetjmp + + cmpwi cr7, 4, 0 + beq- cr7, ___setjmp + + mflr 5 + std 5, 512(3) + std 16, 512+8+8(3) + mr 16, 3 + + bl ___setjmp + + mr 4, 3 + mr 3, 16 + ld 5, 512(3) + mtlr 5 + ld 16, 512+8+8(3) + +.hidden __sigsetjmp_tail + b __sigsetjmp_tail diff --git a/src/thread/powerpc64/__set_thread_area.s b/src/thread/powerpc64/__set_thread_area.s new file mode 100644 index 00000000..9622826d --- /dev/null +++ b/src/thread/powerpc64/__set_thread_area.s @@ -0,0 +1,8 @@ +.text +.global __set_thread_area +.type __set_thread_area, %function +__set_thread_area: + mr 13, 3 + li 3, 0 + blr + diff --git a/src/thread/powerpc64/__unmapself.s b/src/thread/powerpc64/__unmapself.s new file mode 100644 index 00000000..c9360b47 --- /dev/null +++ b/src/thread/powerpc64/__unmapself.s @@ -0,0 +1,9 @@ + .text + .global __unmapself + .type __unmapself,%function +__unmapself: + li 0, 91 # __NR_munmap + sc + li 0, 1 #__NR_exit + sc + blr diff --git a/src/thread/powerpc64/clone.s b/src/thread/powerpc64/clone.s new file mode 100644 index 00000000..03aa4468 --- /dev/null +++ b/src/thread/powerpc64/clone.s @@ -0,0 +1,47 @@ +.text +.global __clone +.type __clone, %function +__clone: + # int clone(fn, stack, flags, arg, ptid, tls, ctid) + # a b c d e f g + # 3 4 5 6 7 8 9 + # pseudo C code: + # tid = syscall(SYS_clone,c,b,e,f,g); + # if (!tid) syscall(SYS_exit, a(d)); + # return tid; + + # create initial stack frame for new thread + clrrdi 4, 4, 4 + li 0, 0 + stdu 0,-32(4) + + # save fn and arg to child stack + std 3, 8(4) + std 6, 16(4) + + # shuffle args into correct registers and call SYS_clone + mr 3, 5 + #mr 4, 4 + mr 5, 7 + mr 6, 8 + mr 7, 9 + li 0, 120 # SYS_clone = 120 + sc + + # if error, negate return (errno) + bns+ 1f + neg 3, 3 + +1: # if we're the parent, return + cmpwi cr7, 3, 0 + bnelr cr7 + + # we're the child. call fn(arg) + ld 3, 16(1) + ld 12, 8(1) + mtctr 12 + bctrl + + # call SYS_exit. exit code is already in r3 from fn return value + li 0, 1 # SYS_exit = 1 + sc diff --git a/src/thread/powerpc64/syscall_cp.s b/src/thread/powerpc64/syscall_cp.s new file mode 100644 index 00000000..d420dbde --- /dev/null +++ b/src/thread/powerpc64/syscall_cp.s @@ -0,0 +1,37 @@ + .global __cp_begin + .hidden __cp_begin + .global __cp_end + .hidden __cp_end + .global __cp_cancel + .hidden __cp_cancel + .hidden __cancel + .global __syscall_cp_asm + .hidden __syscall_cp_asm + .text + .type __syscall_cp_asm,%function +__syscall_cp_asm: + # at enter: r3 = pointer to self->cancel, r4: syscall no, r5: first arg, r6: 2nd, r7: 3rd, r8: 4th, r9: 5th, r10: 6th +__cp_begin: + # if (self->cancel) goto __cp_cancel + lwz 0, 0(3) + cmpwi cr7, 0, 0 + bne- cr7, __cp_cancel + + # make syscall + mr 0, 4 + mr 3, 5 + mr 4, 6 + mr 5, 7 + mr 6, 8 + mr 7, 9 + mr 8, 10 + sc + +__cp_end: + # return error ? -r3 : r3 + bnslr+ + neg 3, 3 + blr + +__cp_cancel: + b __cancel -- cgit v1.2.1