about summary refs log tree commit diff
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