xref: /netbsd-src/lib/libc/arch/arm/sys/__clone.S (revision 45433ea2c30b2014f6657db155fbd2661d0085ce)
1*45433ea2Sskrll/* $NetBSD: __clone.S,v 1.14 2021/06/30 21:20:30 skrll Exp $ */
230b6c70fSchris
330b6c70fSchris/*
430b6c70fSchris * Copyright (c) 2001 Christopher Gilbert
530b6c70fSchris * All rights reserved.
630b6c70fSchris *
730b6c70fSchris * 1. Redistributions of source code must retain the above copyright
830b6c70fSchris *    notice, this list of conditions and the following disclaimer.
930b6c70fSchris * 2. Redistributions in binary form must reproduce the above copyright
1030b6c70fSchris *    notice, this list of conditions and the following disclaimer in the
1130b6c70fSchris *    documentation and/or other materials provided with the distribution.
1230b6c70fSchris * 3. The name of the company nor the name of the author may be used to
1330b6c70fSchris *    endorse or promote products derived from this software without specific
1430b6c70fSchris *    prior written permission.
1530b6c70fSchris *
1630b6c70fSchris * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
1730b6c70fSchris * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
1830b6c70fSchris * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
1930b6c70fSchris * IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
2030b6c70fSchris * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
2130b6c70fSchris * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
2230b6c70fSchris * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2330b6c70fSchris * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2430b6c70fSchris * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2530b6c70fSchris * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2630b6c70fSchris * SUCH DAMAGE.
2730b6c70fSchris */
2830b6c70fSchris
2930b6c70fSchris#include "SYS.h"
302a674d4fSmatt#include <sys/errno.h>
3130b6c70fSchris
3230b6c70fSchris#ifdef WEAK_ALIAS
3330b6c70fSchrisWEAK_ALIAS(clone, __clone)
3430b6c70fSchris#endif
3530b6c70fSchris
3630b6c70fSchris/*
3730b6c70fSchris * int __clone(int (*fn)(void *), void *stack, int flags, void *arg);
3830b6c70fSchris */
3930b6c70fSchrisENTRY(__clone)
4030b6c70fSchris
4130b6c70fSchris	/* test stack and function are not null */
422a674d4fSmatt#if defined(__thumb__) && defined(_ARM_ARCH_T2)
432a674d4fSmatt	cbz	r0, .Leinval
442a674d4fSmatt	cbz	r1, .Leinval
452a674d4fSmatt#elif !defined(__thumb__)
462a674d4fSmatt	cmp	r0, #0x00
472a674d4fSmatt	cmpne	r1, #0x00
481b907e18Sthorpej	beq	.Leinval
492a674d4fSmatt#else
502a674d4fSmatt	cmp	r0, #0x00
512a674d4fSmatt	beq	.Leinval
522a674d4fSmatt	cmp	r1, #0x00
532a674d4fSmatt	beq	.Leinval
542a674d4fSmatt#endif
5530b6c70fSchris
56a640fe8cSsnj	/* place the func and its arg onto the child's stack */
572a674d4fSmatt#if !defined(__thumb__) || defined(_ARM_ARCH_T2)
5830b6c70fSchris	stmfd	r1!, {r0, r3}
592a674d4fSmatt#else
602a674d4fSmatt	subs	r1, r1, #8
612a674d4fSmatt	stmia	r1!, {r0, r3}
622a674d4fSmatt#endif
6330b6c70fSchris
6430b6c70fSchris	/* syscall expects (flags, stack) */
6530b6c70fSchris	mov	r0, r2
6630b6c70fSchris
6730b6c70fSchris	SYSTRAP(__clone)
682a674d4fSmatt	_INVOKE_CERROR()
6930b6c70fSchris
7030b6c70fSchris	/*
7130b6c70fSchris	 * r1 and r0 are the same as from fork:
7230b6c70fSchris	 * r1 == 0 in parent process, r1 == 1 in child process.
7330b6c70fSchris	 * r0 == pid of child in parent, r0 == pid of parent in child.
7430b6c70fSchris	 */
7530b6c70fSchris	/* if this is the parent then just return the pid */
762a674d4fSmatt#if defined(__thumb__)
772a674d4fSmatt#if defined(_ARM_ARCH_T2)
782a674d4fSmatt	cbz	r1, 1f
792a674d4fSmatt#else
802a674d4fSmatt	cmp	r1, #0x00
812a674d4fSmatt	bne	1f
822a674d4fSmatt#endif
832a674d4fSmatt	RET
842a674d4fSmatt1:
852a674d4fSmatt#else
862a674d4fSmatt	cmp	r1, #0x00
87145b31afSrearnsha	RETc(eq)
882a674d4fSmatt#endif
892a674d4fSmatt
9030b6c70fSchris	/*
9130b6c70fSchris	 * This is the child
9230b6c70fSchris	 * load the function and arg off the stack
9330b6c70fSchris	 */
942a674d4fSmatt	pop	{r1, r2}
9530b6c70fSchris
9630b6c70fSchris	/* place arg in r0 */
9730b6c70fSchris	mov	r0, r2
9830b6c70fSchris
9930b6c70fSchris	/* call the function */
1002a674d4fSmatt#ifdef _ARM_ARCH_5T
1012a674d4fSmatt	blx	r1
102145b31afSrearnsha#else
1032a674d4fSmatt	/* setup return address */
1042a674d4fSmatt	mov	lr, pc
1052a674d4fSmatt	RETr(r1)
106145b31afSrearnsha#endif
10730b6c70fSchris	/* call _exit with the returned value */
108d0dcd65cSjoerg	bl	PLT_SYM(_C_LABEL(_exit))
10930b6c70fSchris
11030b6c70fSchris	/* NOTREACHED */
11130b6c70fSchris
11230b6c70fSchris	/* error handler if func or stack is NULL */
1132a674d4fSmatt	.align	0
1141b907e18Sthorpej.Leinval:
1152a674d4fSmatt	movs	r0, #EINVAL
1162a674d4fSmatt#if !defined(__thumb__) || defined(_ARM_ARCH_T2)
1173eafa987Smatt	b	CERROR
1182a674d4fSmatt#else
1192a674d4fSmatt.Lcerror:
120*45433ea2Sskrll	push	{r3, lr}
1212a674d4fSmatt	bl	CERROR
122*45433ea2Sskrll	pop	{r3, pc}
1232a674d4fSmatt#endif
1242a674d4fSmattEND(__clone)
125