summaryrefslogtreecommitdiff
path: root/src/thread/powerpc64/clone.s
diff options
context:
space:
mode:
Diffstat (limited to 'src/thread/powerpc64/clone.s')
-rw-r--r--src/thread/powerpc64/clone.s47
1 files changed, 47 insertions, 0 deletions
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