1/*
2 * Copyright (c) 1999-2007 Apple Inc. All rights reserved.
3 *
4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
5 *
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. The rights granted to you under the License
10 * may not be used to create, or enable the creation or redistribution of,
11 * unlawful or unlicensed copies of an Apple operating system, or to
12 * circumvent, violate, or enable the circumvention or violation of, any
13 * terms of an Apple operating system software license agreement.
14 *
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
17 *
18 * The Original Code and all software distributed under the License are
19 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
20 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
22 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
23 * Please see the License for the specific language governing rights and
24 * limitations under the License.
25 *
26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
27 */
28/* Copyright (c) 1992 NeXT Computer, Inc.  All rights reserved.
29 *
30 *	File:	libc/ppc/sys/fork.s
31 *
32 * HISTORY
33 * 18-Nov-92  Ben Fathi (benf@next.com)
34 *	Created from M88K sources
35 *
36 * 11-Jan-92  Peter King (king@next.com)
37 *	Created from M68K sources
38 */
39
40#include "SYS.h"
41
42#if defined(__ppc__) || defined(__ppc64__)
43
44/* We use mode-independent "g" opcodes such as "srgi".  These expand
45 * into word operations when targeting __ppc__, and into doubleword
46 * operations when targeting __ppc64__.
47 */
48#include <architecture/ppc/mode_independent_asm.h>
49
50MI_ENTRY_POINT(___fork)
51    MI_PUSH_STACK_FRAME
52
53    MI_CALL_EXTERNAL(__cthread_fork_prepare)
54
55	li      r0,SYS_fork
56	sc                      // do the fork
57	b       Lbotch			// error return
58
59	cmpwi	r4,0            // parent (r4==0) or child (r4==1) ?
60	beq     Lparent         // parent, since r4==0
61
62
63/* Here if we are the child.  */
64
65#if defined(__DYNAMIC__)
66    .cstring
67LC3:
68	.ascii	"__dyld_fork_child\0"
69    .text
70	.align 2
71	mflr	r0
72	bcl     20,31,1f
731:	mflr	r3
74	mtlr	r0
75	addis	r3,r3,ha16(LC3-1b)
76	addi	r3,r3,lo16(LC3-1b)
77	addi 	r4,r1,SF_LOCAL1
78	bl      __dyld_func_lookup
79	lg      r3,SF_LOCAL1(r1)
80	mtspr 	ctr,r3
81	bctrl
82#endif
83
84    li      r9,0
85    MI_GET_ADDRESS(r8,__current_pid)
86    stw     r9,0(r8)            // clear cached pid in child
87
88	MI_CALL_EXTERNAL(__cthread_fork_child)
89
90	li	r3,0        // flag for "we are the child"
91	b	Lreturn
92
93
94/* Here if we are the parent, with:
95 *  r3 = child's pid
96 */
97Lparent:
98	stg     r3,SF_LOCAL2(r1)	// save child pid in stack
99
100    b       Lparent_return      // clean up and return child's pid
101
102
103/* Here if the fork() syscall failed.  We're still the parent.  */
104
105Lbotch:
106
107	MI_CALL_EXTERNAL(cerror)
108    li      r3,-1               // get an error return code
109	stg     r3,SF_LOCAL2(r1)	// save return code in stack
110
111	/*
112	 * We use cthread_fork_parent() to clean up after a fork error
113	 * (unlock cthreads and mailloc packages) so the parent
114	 * process can Malloc() after fork() errors without
115	 * deadlocking.
116	 */
117
118Lparent_return:
119	MI_CALL_EXTERNAL(__cthread_fork_parent)
120	lg      r3,SF_LOCAL2(r1)    // return -1 on error, child's pid on success
121
122Lreturn:
123    MI_POP_STACK_FRAME_AND_RETURN
124
125#elif defined(__i386__)
126
127LEAF(___fork, 0)
128	subl  $28, %esp   // Align the stack, with 16 bytes of extra padding that we'll need
129	CALL_EXTERN(__cthread_fork_prepare)
130
131	movl 	$ SYS_fork,%eax; 	// code for fork -> eax
132	UNIX_SYSCALL_TRAP		// do the system call
133	jnc	L1			// jump if CF==0
134
135	CALL_EXTERN(cerror)
136	CALL_EXTERN(__cthread_fork_parent)
137	movl	$-1,%eax
138	addl	$28, %esp   // restore the stack
139	ret
140
141L1:
142	orl	%edx,%edx	// CF=OF=0,  ZF set if zero result
143	jz	L2		// parent, since r1 == 0 in parent, 1 in child
144
145	//child here...
146#if defined(__DYNAMIC__)
147// Here on the child side of the fork we need to tell the dynamic linker that
148// we have forked.  To do this we call __dyld_fork_child in the dyanmic
149// linker.  But since we can't dynamically bind anything until this is done we
150// do this by using the private extern __dyld_func_lookup() function to get the
151// address of __dyld_fork_child (the 'C' code equivlent):
152//
153//	_dyld_func_lookup("__dyld_fork_child", &address);
154//	address();
155//
156.cstring
157LC0:
158	.ascii "__dyld_fork_child\0"
159
160.text
161	leal	0x8(%esp),%eax		// get the address where we're going to store the pointer
162	movl	%eax, 0x4(%esp)		// copy the address of the pointer
163	call	1f
1641:	popl	%eax
165	leal	LC0-1b(%eax),%eax
166	movl 	%eax, 0x0(%esp)		// copy the name of the function to look up
167	call 	__dyld_func_lookup
168	movl	0x8(%esp),%eax		// move the value returned in address parameter
169	call	*%eax		// call __dyld_fork_child indirectly
170#endif
171	xorl	%eax, %eax
172	REG_TO_EXTERN(%eax, __current_pid)
173	CALL_EXTERN(__cthread_fork_child)
174
175	xorl	%eax,%eax	// zero eax
176	addl	$28, %esp   // restore the stack
177	ret
178
179	//parent here...
180L2:
181	movl	%eax, 0xc(%esp)		// save pid
182
183	CALL_EXTERN_AGAIN(__cthread_fork_parent)
184	movl	0xc(%esp), %eax		// return pid
185	addl	$28, %esp   // restore the stack
186	ret
187
188#elif defined(__x86_64__)
189
190LEAF(___fork, 0)
191	subq  $24, %rsp   // Align the stack, plus room for local storage
192	CALL_EXTERN(__cthread_fork_prepare)
193
194	movl 	$ SYSCALL_CONSTRUCT_UNIX(SYS_fork),%eax; // code for fork -> rax
195	UNIX_SYSCALL_TRAP		// do the system call
196	jnc	L1			// jump if CF==0
197
198	CALL_EXTERN(cerror)
199	CALL_EXTERN(__cthread_fork_parent)
200	movq	$-1, %rax
201	addq	$24, %rsp   // restore the stack
202	ret
203
204L1:
205	orl	%edx,%edx	// CF=OF=0,  ZF set if zero result
206	jz	L2		// parent, since r1 == 0 in parent, 1 in child
207
208	//child here...
209#if defined(__DYNAMIC__)
210// Here on the child side of the fork we need to tell the dynamic linker that
211// we have forked.  To do this we call __dyld_fork_child in the dyanmic
212// linker.  But since we can't dynamically bind anything until this is done we
213// do this by using the private extern __dyld_func_lookup() function to get the
214// address of __dyld_fork_child (the 'C' code equivlent):
215//
216//	_dyld_func_lookup("__dyld_fork_child", &address);
217//	address();
218//
219.cstring
220LC0:
221	.ascii "__dyld_fork_child\0"
222
223.text
224	leaq	8(%rsp),%rsi		// get the address where we're going to store the pointer
225	leaq 	LC0(%rip), %rdi		// copy the name of the function to look up
226	call 	__dyld_func_lookup
227	call	*8(%rsp)		// call __dyld_fork_child indirectly
228#endif
229	xorq	%rax, %rax
230	REG_TO_EXTERN(%rax, __current_pid)
231	CALL_EXTERN(__cthread_fork_child)
232
233	xorq	%rax,%rax	// zero rax
234	addq	$24, %rsp   // restore the stack
235	ret
236
237	//parent here...
238L2:
239	movl	%eax, 16(%rsp)		// save pid
240
241	CALL_EXTERN_AGAIN(__cthread_fork_parent)
242	movl	16(%rsp), %eax		// return pid
243	addq	$24, %rsp   // restore the stack
244	ret
245
246#else
247#error Unsupported architecture
248#endif
249