summaryrefslogtreecommitdiff
path: root/src/thread/s390x/clone.s
blob: 2125f20b83c759056fdc0060d12e72c1484c16e1 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
.text
.global __clone
.hidden __clone
.type __clone, %function
__clone:
	# int clone(
	#    fn,      a = r2
	#    stack,   b = r3
	#    flags,   c = r4
	#    arg,     d = r5
	#    ptid,    e = r6
	#    tls,     f = *(r15+160)
	#    ctid)    g = *(r15+168)
	#
	# pseudo C code:
	# tid = syscall(SYS_clone,b,c,e,g,f);
	# if (!tid) syscall(SYS_exit, a(d));
	# return tid;

	# preserve call-saved register used as syscall arg
	stg  %r6, 48(%r15)

	# create initial stack frame for new thread
	nill %r3, 0xfff8
	aghi %r3, -160
	lghi %r0, 0
	stg  %r0, 0(%r3)

	# save fn and arg to child stack
	stg  %r2,  8(%r3)
	stg  %r5, 16(%r3)

	# shuffle args into correct registers and call SYS_clone
	lgr  %r2, %r3
	lgr  %r3, %r4
	lgr  %r4, %r6
	lg   %r5, 168(%r15)
	lg   %r6, 160(%r15)
	svc  120

	# restore call-saved register
	lg   %r6, 48(%r15)

	# if error or if we're the parent, return
	ltgr %r2, %r2
	bnzr %r14

	# we're the child. call fn(arg)
	lg   %r1,  8(%r15)
	lg   %r2, 16(%r15)
	basr %r14, %r1

	# call SYS_exit. exit code is already in r2 from fn return value
	svc  1