summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorRich Felker <dalias@aerifal.cx>2012-11-14 14:01:39 -0500
committerRich Felker <dalias@aerifal.cx>2012-11-14 14:01:39 -0500
commitc6d441e3a246370d9c459396ec22b096db93850e (patch)
treefa3d4a4ca03531ceab9e60abb50e37780fce60ed /src
parentc4a35f8c2a4b1a7e62a4b9e5b2748fb4fbcace79 (diff)
parent1c8eb8bad791fe9d01d0d4ab77882db634fa933d (diff)
downloadmusl-c6d441e3a246370d9c459396ec22b096db93850e.tar.gz
musl-c6d441e3a246370d9c459396ec22b096db93850e.tar.bz2
musl-c6d441e3a246370d9c459396ec22b096db93850e.tar.xz
musl-c6d441e3a246370d9c459396ec22b096db93850e.zip
Merge remote-tracking branch 'ppc-port/ppc-squashed'
Diffstat (limited to 'src')
-rw-r--r--src/internal/powerpc/syscall.s18
-rw-r--r--src/ldso/powerpc/dlsym.s8
-rw-r--r--src/ldso/powerpc/start.s23
-rw-r--r--src/setjmp/powerpc/longjmp.s47
-rw-r--r--src/setjmp/powerpc/setjmp.s40
-rw-r--r--src/signal/powerpc/restore.s11
-rw-r--r--src/signal/powerpc/sigsetjmp.s34
-rw-r--r--src/thread/powerpc/__set_thread_area.s11
-rw-r--r--src/thread/powerpc/__unmapself.s9
-rw-r--r--src/thread/powerpc/clone.s83
-rw-r--r--src/thread/powerpc/syscall_cp.s51
11 files changed, 335 insertions, 0 deletions
diff --git a/src/internal/powerpc/syscall.s b/src/internal/powerpc/syscall.s
new file mode 100644
index 00000000..bca620db
--- /dev/null
+++ b/src/internal/powerpc/syscall.s
@@ -0,0 +1,18 @@
+ .global __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
+ #else error:
+ # return negated value.
+ neg 3, 3
+ blr
+ .end __syscall
+ .size __syscall, .-__syscall
diff --git a/src/ldso/powerpc/dlsym.s b/src/ldso/powerpc/dlsym.s
new file mode 100644
index 00000000..20796176
--- /dev/null
+++ b/src/ldso/powerpc/dlsym.s
@@ -0,0 +1,8 @@
+ .text
+ .global dlsym
+ .type dlsym,@function
+dlsym:
+ mflr 5 # The return address is arg3.
+ b __dlsym
+ .end dlsym
+ .size dlsym, .-dlsym
diff --git a/src/ldso/powerpc/start.s b/src/ldso/powerpc/start.s
new file mode 100644
index 00000000..d2060e3d
--- /dev/null
+++ b/src/ldso/powerpc/start.s
@@ -0,0 +1,23 @@
+# FIXME : does not work, the small data array needs to be relocated.
+# see elfspec_ppc.pdf, page 76-84
+ .global _start
+ .type _start,@function
+_start:
+ mr 9, 1 # Save the original stack pointer.
+ clrrwi 1, 1, 4 # Align the stack to 16 bytes.
+ lis 13, _SDA_BASE_@ha # r13 points to the small data area.
+ addi 13, 13, _SDA_BASE_@l
+ li 0, 0 # Zero the frame pointer.
+ lwz 3, 0(9) # and argc...
+ addi 4, 9, 4 # and argv ...
+ mtlr 0 # Clear the link register.
+ # Go to the musl dynamic linker entry point.
+ bl __dynlink
+ cmpi 4, 0, 3, 1 # Check for a 1.
+ bne 4, . # Stay here
+ mtlr 3 # Set the link address...
+ li 3, 0
+ blr # and go.
+ .end _start
+ .size _start, .-_start
+
diff --git a/src/setjmp/powerpc/longjmp.s b/src/setjmp/powerpc/longjmp.s
new file mode 100644
index 00000000..e3740901
--- /dev/null
+++ b/src/setjmp/powerpc/longjmp.s
@@ -0,0 +1,47 @@
+ .global _longjmp
+ .global longjmp
+ .type _longjmp,@function
+ .type longjmp,@function
+_longjmp:
+longjmp:
+# void longjmp(jmp_buf env, int val);
+# put val into return register and restore the env saved in setjmp
+# if val(r4) is 0, put 1 there.
+ # 0) move old return address into r0
+ lwz 0, 0(3)
+ # 1) put it into link reg
+ mtlr 0
+ #2 ) restore stack ptr
+ lwz 1, 4(3)
+ #3) restore control reg
+ lwz 0, 8(3)
+ mtcr 0
+ #4) restore r14-r31
+ lwz 14, 12(3)
+ lwz 15, 16(3)
+ lwz 16, 20(3)
+ lwz 17, 24(3)
+ lwz 18, 28(3)
+ lwz 19, 32(3)
+ lwz 20, 36(3)
+ lwz 21, 40(3)
+ lwz 22, 44(3)
+ lwz 23, 48(3)
+ lwz 24, 52(3)
+ lwz 25, 56(3)
+ lwz 26, 60(3)
+ lwz 27, 64(3)
+ lwz 28, 68(3)
+ lwz 29, 72(3)
+ lwz 30, 76(3)
+ lwz 31, 80(3)
+ #5) put val into return reg r3
+ mr 3, 4
+
+ #6) check if return value is 0, make it 1 in that case
+ cmpwi cr7, 4, 0
+ bne cr7, 1f
+ li 3, 1
+1:
+ blr
+
diff --git a/src/setjmp/powerpc/setjmp.s b/src/setjmp/powerpc/setjmp.s
new file mode 100644
index 00000000..27c975e4
--- /dev/null
+++ b/src/setjmp/powerpc/setjmp.s
@@ -0,0 +1,40 @@
+ .global __setjmp
+ .global _setjmp
+ .global setjmp
+ .type __setjmp,@function
+ .type _setjmp,@function
+ .type setjmp,@function
+__setjmp:
+_setjmp:
+setjmp:
+ # 0) store IP int 0, then into the jmpbuf pointed to by r3 (first arg)
+ mflr 0
+ stw 0, 0(3)
+ # 1) store reg1 (SP)
+ stw 1, 4(3)
+ # 2) store cr
+ mfcr 0
+ stw 0, 8(3)
+ # 3) store r14-31
+ stw 14, 12(3)
+ stw 15, 16(3)
+ stw 16, 20(3)
+ stw 17, 24(3)
+ stw 18, 28(3)
+ stw 19, 32(3)
+ stw 20, 36(3)
+ stw 21, 40(3)
+ stw 22, 44(3)
+ stw 23, 48(3)
+ stw 24, 52(3)
+ stw 25, 56(3)
+ stw 26, 60(3)
+ stw 27, 64(3)
+ stw 28, 68(3)
+ stw 29, 72(3)
+ stw 30, 76(3)
+ stw 31, 80(3)
+ # 4) set return value to 0
+ li 3, 0
+ # 5) return
+ blr
diff --git a/src/signal/powerpc/restore.s b/src/signal/powerpc/restore.s
new file mode 100644
index 00000000..fd7bcba5
--- /dev/null
+++ b/src/signal/powerpc/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/powerpc/sigsetjmp.s b/src/signal/powerpc/sigsetjmp.s
new file mode 100644
index 00000000..0b79dcce
--- /dev/null
+++ b/src/signal/powerpc/sigsetjmp.s
@@ -0,0 +1,34 @@
+ .global sigsetjmp
+ .type sigsetjmp,%function
+sigsetjmp:
+ #int sigsetjmp(sigjmp_buf buf, int save)
+ # r3 r4
+ #0) store save into buf->__fl
+ stw 4, 256(3)
+ #1) compare save with 0
+ cmpwi cr7, 4, 0
+ #2) if its 0, goto setjmp code
+ beq- cr7, 1f
+ #3) else: we must call pthread_sigmask(SIG_SETMASK, 0, (sigset_t *)buf->__ss);
+ # thus store r3 on the stack, to restore it later
+ stw 3, -4(1)
+ # store old link reg
+ mflr 0
+ stw 0, -8(1)
+ # increase stack frame by 16
+ subi 1, 1, 16
+ # put pointer to ss buf into r5 (3rd arg)
+ addi 5, 3, 260
+ # put "2" i.e. SIG_SETMASK in r3
+ li 3, 2
+ li 4, 0
+ bl pthread_sigmask
+ #restore sp
+ addi 1, 1, 16
+ #restore r3
+ lwz 3, -4(1)
+ #restore link reg
+ lwz 0, -8(1)
+ mtlr 0
+1:
+ b setjmp
diff --git a/src/thread/powerpc/__set_thread_area.s b/src/thread/powerpc/__set_thread_area.s
new file mode 100644
index 00000000..c1a34c1f
--- /dev/null
+++ b/src/thread/powerpc/__set_thread_area.s
@@ -0,0 +1,11 @@
+.text
+.global __set_thread_area
+.type __set_thread_area, %function
+__set_thread_area:
+ # mov pointer in reg3 into r2
+ mr 2, 3
+ # put 0 into return reg
+ li 3, 0
+ # return
+ blr
+
diff --git a/src/thread/powerpc/__unmapself.s b/src/thread/powerpc/__unmapself.s
new file mode 100644
index 00000000..bb3724e3
--- /dev/null
+++ b/src/thread/powerpc/__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/powerpc/clone.s b/src/thread/powerpc/clone.s
new file mode 100644
index 00000000..cea69e99
--- /dev/null
+++ b/src/thread/powerpc/clone.s
@@ -0,0 +1,83 @@
+.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;
+
+# SYS_clone = 120
+# SYS_exit = 1
+
+# in order that the child can find the start func and its arg, we need to store it into
+# non-volative regs. to do so, we have to store those 2 regs into our stackframe, so
+# we can restore them later.
+stw 30, -4(1)
+stw 31, -8(1)
+subi 1, 1, 16
+
+# save r3 (func) into r30, and r6(arg) into r31
+mr 30, 3
+mr 31, 6
+
+#move c into first arg
+mr 3, 5
+#mr 4, 4
+mr 5, 7
+mr 6, 8
+mr 7, 9
+
+# move syscall number into r0
+li 0, 120
+
+sc
+
+# check for syscall error
+#this code should be more efficient, but it borks
+#bns+ 1f # jump to label 1 if no summary overflow.
+#else
+#neg 3, 3 #negate the result (errno)
+#b 2f # jump to epilogue
+
+# this error check code at least does not spoil the clone call.
+#mfcr 0 # Check for an error
+#rlwinm 4, 0, 0, 3, 3 # by checking for bit 28.
+#cmplwi 0, 4, 0 # It is an error if non-zero.
+#beq 0, 1f # Jump if not an error.
+#neg 3, 3 # Negate the error number.
+#b 2f # jump to epilogue
+1:
+# compare sc result with 0
+cmpwi cr7, 3, 0
+
+# if not 0, jump to end
+bne cr7, 2f
+
+#else: we're the child
+#call funcptr
+# move arg (d) into r3
+mr 3, 31
+#move r30 (funcptr) into CTR reg
+mtctr 30
+# call CTR reg
+bctrl
+# mov SYS_exit into r0 (the exit param is already in r3)
+li 0, 1
+sc
+
+2:
+
+# restore stack
+addi 1, 1, 16
+lwz 30, -4(1)
+lwz 31, -8(1)
+
+blr
+
+
+
+
diff --git a/src/thread/powerpc/syscall_cp.s b/src/thread/powerpc/syscall_cp.s
new file mode 100644
index 00000000..2c97ca04
--- /dev/null
+++ b/src/thread/powerpc/syscall_cp.s
@@ -0,0 +1,51 @@
+#r0: volatile. may be modified during linkage.
+#r1: stack frame: 16 byte alignment.
+#r2: tls/thread pointer on pp32
+#r3,r4: return values, first args
+#r5-r10: args
+#r11-r12: volatile. may be modified during linkage
+#r13: "small data area" pointer
+#r14 - r30: local vars
+#r31: local or environment pointer
+
+#r1, r14-31: belong to the caller, must be saved and restored
+#r0, r3-r12, ctr, xer: volatile, not preserved
+#r0,r11,r12: may be altered by cross-module call,
+#"a func cannot depend on that these regs have the values placed by the caller"
+
+#the fields CR2,CR2,CR4 of the cond reg must be preserved
+#LR (link reg) shall contain the funcs return address
+ .text
+ .global __syscall_cp_asm
+ .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
+ .global __cp_begin
+__cp_begin:
+ # r3 holds first argument, its a pointer to self->cancel.
+ # we must compare the dereferenced value with 0 and jump to __cancel if its not
+
+ lwz 0, 0(3) #deref pointer into r0
+
+ cmpwi cr7, 0, 0 #compare r0 with 0, store result in cr7.
+ beq+ cr7, 1f #jump to label 1 if r0 was 0
+
+ b __cancel #else call cancel
+ # (the return address is not needed, since __cancel never returns)
+1:
+ #ok, the cancel flag was not set
+ # syscall: number goes to r0, the rest 3-8
+ mr 0, 4 # put the system call number into r0
+ mr 3, 5 # Shift the arguments: arg1
+ mr 4, 6 # arg2
+ mr 5, 7 # arg3
+ mr 6, 8 # arg4
+ mr 7, 9 # arg5
+ mr 8, 10 # arg6
+ sc
+ .global __cp_end
+__cp_end:
+ bnslr+ # return if no summary overflow.
+ #else negate result.
+ neg 3, 3
+ blr