xref: /onnv-gate/usr/src/lib/libc/amd64/sys/vforkx.s (revision 11913:283e725df792)
13235Sraf/*
23235Sraf * CDDL HEADER START
33235Sraf *
43235Sraf * The contents of this file are subject to the terms of the
53235Sraf * Common Development and Distribution License (the "License").
63235Sraf * You may not use this file except in compliance with the License.
73235Sraf *
83235Sraf * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
93235Sraf * or http://www.opensolaris.org/os/licensing.
103235Sraf * See the License for the specific language governing permissions
113235Sraf * and limitations under the License.
123235Sraf *
133235Sraf * When distributing Covered Code, include this CDDL HEADER in each
143235Sraf * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
153235Sraf * If applicable, add the following below this CDDL HEADER, with the
163235Sraf * fields enclosed by brackets "[]" replaced with your own identifying
173235Sraf * information: Portions Copyright [yyyy] [name of copyright owner]
183235Sraf *
193235Sraf * CDDL HEADER END
203235Sraf */
213235Sraf
223235Sraf/*
23*11913SRoger.Faulkner@Sun.COM * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
243235Sraf * Use is subject to license terms.
253235Sraf */
263235Sraf
277298SMark.J.Nelson@Sun.COM	.file	"vforkx.s"
283235Sraf
293235Sraf#include "SYS.h"
303235Sraf#include <assym.h>
313235Sraf
323235Sraf/*
333235Sraf * pid = vforkx(flags);
343235Sraf * syscall trap: forksys(2, flags)
353235Sraf *
363235Sraf * pid = vfork();
373235Sraf * syscall trap: forksys(2, 0)
383235Sraf *
393235Sraf * From the syscall:
403235Sraf * %edx == 0 in parent process, %edx = 1 in child process.
413235Sraf * %eax == pid of child in parent, %eax == pid of parent in child.
423235Sraf *
433235Sraf * The child gets a zero return value.
443235Sraf * The parent gets the pid of the child.
453235Sraf */
463235Sraf
473235Sraf/*
483235Sraf * The child of vfork() will execute in the parent's address space,
493235Sraf * thereby changing the stack before the parent runs again.
503235Sraf * Therefore we have to be careful how we return from vfork().
513235Sraf * Pity the poor debugger developer who has to deal with this kludge.
523235Sraf *
533235Sraf * We block all blockable signals while performing the vfork() system call
543235Sraf * trap.  This enables us to set curthread->ul_vfork safely, so that we
553235Sraf * don't end up in a signal handler with curthread->ul_vfork set wrong.
563235Sraf */
573235Sraf
583235Sraf	ENTRY_NP(vforkx)
593235Sraf	movq	%rdi, %r8		/* flags */
603235Sraf	jmp	0f
613235Sraf	ENTRY_NP(vfork)
623235Sraf	xorq	%r8, %r8		/* flags = 0 */
633235Sraf0:
643235Sraf	popq	%r9			/* save return %rip in %r9 */
65*11913SRoger.Faulkner@Sun.COM	pushq	%r8			/* save the flags on the stack */
66*11913SRoger.Faulkner@Sun.COM	movl	$MASKSET3, %r8d		/* block all signals */
67*11913SRoger.Faulkner@Sun.COM	movl	$MASKSET2, %ecx
68*11913SRoger.Faulkner@Sun.COM	movl	$MASKSET1, %edx
693235Sraf	movl	$MASKSET0, %esi
703235Sraf	movl	$SIG_SETMASK, %edi
713235Sraf	__SYSCALL(lwp_sigmask)
723235Sraf
73*11913SRoger.Faulkner@Sun.COM	popq	%rsi			/* fetch flags from the stack */
743235Sraf	movl	$2, %edi
753235Sraf	__SYSCALL(forksys)		/* vforkx(flags) */
763235Sraf	jae 	1f
773235Sraf
783235Sraf	/* reconstruct stack before jumping to __cerror */
793235Sraf	pushq	%r9
80*11913SRoger.Faulkner@Sun.COM	movq	%rax, %r9		/* save the vfork() error number */
813235Sraf
82*11913SRoger.Faulkner@Sun.COM	movl	%fs:UL_SIGMASK+12, %r8d	/* reinstate signals */
83*11913SRoger.Faulkner@Sun.COM	movl	%fs:UL_SIGMASK+8, %ecx
84*11913SRoger.Faulkner@Sun.COM	movl	%fs:UL_SIGMASK+4, %edx
853235Sraf	movl	%fs:UL_SIGMASK, %esi
863235Sraf	movl	$SIG_SETMASK, %edi
873235Sraf	__SYSCALL(lwp_sigmask)
883235Sraf
89*11913SRoger.Faulkner@Sun.COM	movq	%r9, %rax		/* restore the vfork() error number */
903235Sraf	jmp	__cerror
913235Sraf
923235Sraf1:
933235Sraf	/*
943235Sraf	 * To determine if we are (still) a child of vfork(), the child
953235Sraf	 * increments curthread->ul_vfork by one and the parent decrements
963235Sraf	 * it by one.  If the result is zero, then we are not a child of
973235Sraf	 * vfork(), else we are.  We do this to deal with the case of
983235Sraf	 * a vfork() child calling vfork().
993235Sraf	 */
1003235Sraf	cmpl	$0, %edx
1013235Sraf	jne	2f
1023235Sraf	movl	%fs:UL_VFORK, %edx
1033235Sraf	cmpl	$0, %edx		/* don't let it go negative */
1043235Sraf	je	3f
1053235Sraf	subl	$1, %edx		/* curthread->ul_vfork--; */
1063235Sraf	jmp	3f
1073235Sraf2:
1083235Sraf	xorl	%eax, %eax		/* zero the return value in the child */
1093235Sraf	movl	%fs:UL_VFORK, %edx
1103235Sraf	addl	$1, %edx		/* curthread->ul_vfork++; */
1113235Sraf3:
1123235Sraf	movl	%edx, %fs:UL_VFORK
1133235Sraf	/*
1143235Sraf	 * Clear the schedctl interface in both parent and child.
1153235Sraf	 * (The child might have modified the parent.)
1163235Sraf	 */
1173235Sraf	xorq	%rdx, %rdx
1183235Sraf	movq	%rdx, %fs:UL_SCHEDCTL
1193235Sraf	movq	%rdx, %fs:UL_SCHEDCTL_CALLED
120*11913SRoger.Faulkner@Sun.COM	pushq	%rax			/* save the vfork() return value */
1213235Sraf
122*11913SRoger.Faulkner@Sun.COM	movl	%fs:UL_SIGMASK+12, %r8d	/* reinstate signals */
123*11913SRoger.Faulkner@Sun.COM	movl	%fs:UL_SIGMASK+8, %ecx
124*11913SRoger.Faulkner@Sun.COM	movl	%fs:UL_SIGMASK+4, %edx
1253235Sraf	movl	%fs:UL_SIGMASK, %esi
1263235Sraf	movl	$SIG_SETMASK, %edi
1273235Sraf	__SYSCALL(lwp_sigmask)
1283235Sraf
129*11913SRoger.Faulkner@Sun.COM	popq	%rax			/* restore the vfork() return value */
1303235Sraf	jmp	*%r9			/* jump back to the caller */
1313235Sraf	SET_SIZE(vfork)
1323235Sraf	SET_SIZE(vforkx)
133