/* Copyright (C) 2003, 2004 Free Software Foudnation, Inc.
   This file is part of the GNU C Library.
   Contributed by Alexandre Oliva <aoliva@redhat.com>, 2003.

   The GNU C Library is free software; you can redistribute it and/or
   modify it under the terms of the GNU Lesser General Public
   License as published by the Free Software Foundation; either
   version 2.1 of the License, or (at your option) any later version.

   The GNU C Library is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
   Lesser General Public License for more details.

   You should have received a copy of the GNU Lesser General Public
   License along with the GNU C Library; if not, write to the Free
   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
   02111-1307 USA.  */

/* clone() is even more special than fork() as it mucks with stacks
   and invokes a function in the right context after its all over.  */

#include <sysdep.h>
#include <asm/unistd.h>
#define _ERRNO_H	1
#include <bits/errno.h>

	.text
	.globl	__clone
	.type __clone,@function
	
/* int clone(int (*fn)(void *arg), void *child_stack, int flags,
	     void *arg, pid_t *ptid, void *tls, pid_t *ctid);

   Note that everything past ARG is technically optional, based
   on FLAGS, and that CTID is arg 7, and thus is on the stack.
   However, since a load from top-of-stack better be legal always,
   we don't bother checking FLAGS.  */

ENTRY(__clone)
	/* Sanity check arguments.  */
	cmp.p	gr8, gr0, icc0
	cmp	gr9, gr0, icc1
	mov.p	gr8, gr4
	beq	icc0, #0, .Lerror
	mov.p	gr11, gr5
	beq	icc1, #0, .Lerror

	/* The syscall is of the form clone(flags, usp, ptid, ctid, tls).
	   Shift the flags, tls, ptid and ctid arguments into place; the
	   usp argument is already in place.  */

	mov.p	gr10, gr8
	setlos	#SYS_ify(clone), gr7
	mov.p	gr12, gr10
	setlos #-4096, gr6
	ld.p	@(sp,gr0), gr11
	mov	gr13, gr12
	tra	gr0,gr0

	cmp.p	gr8, gr0, icc0
	cmp	gr8, gr6, icc1
	beq	icc0, #0, .Lthread_start
	blslr	icc1, #2

.Lsys_error:
	SYSCALL_ERROR_HANDLER

.Lerror:
	setlos.p #-EINVAL, gr8
	bra	.Lsys_error

###############################################################################
#
# come here as the new thread [GR4 is fn, GR5 is arg]
#
###############################################################################
.Lthread_start:
	/* Save the PIC register.  */
	mov	gr15, gr17

	/* Call the user's function.  */
	ldd.p	@(gr4, gr0), gr14
	mov	gr5, gr8
	calll	@(gr14, gr0)

	/* Call _exit, rather simply inlining the syscall, such that
	   breakpoints work.*/

	mov.p	gr17, gr15
	call	_exit

	/* Should never get here.  */
	jmpl	@(gr0, gr0)
PSEUDO_END (__clone)

weak_alias (__clone, clone)
