xref: /onnv-gate/usr/src/lib/libc/i386/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	movl	4(%esp), %eax		/* flags */
603235Sraf	jmp	0f
613235Sraf	ENTRY_NP(vfork)
623235Sraf	xorl	%eax, %eax		/* flags = 0 */
633235Sraf0:
643235Sraf	popl	%ecx			/* save return %eip in %ecx */
653235Sraf	pushl	%eax			/* flags */
66*11913SRoger.Faulkner@Sun.COM	pushl	$MASKSET3		/* block all signals */
67*11913SRoger.Faulkner@Sun.COM	pushl	$MASKSET2
68*11913SRoger.Faulkner@Sun.COM	pushl	$MASKSET1
693235Sraf	pushl	$MASKSET0
703235Sraf	pushl	$SIG_SETMASK
713235Sraf	pushl	%ecx
723235Sraf	__SYSCALLINT(lwp_sigmask)
73*11913SRoger.Faulkner@Sun.COM	addl	$24, %esp
743235Sraf
753235Sraf	pushl	$2
763235Sraf	pushl	%ecx
773235Sraf	__SYSCALLINT(forksys)		/* vforkx(flags) */
783235Sraf	jae 	1f
793235Sraf
803235Sraf	/* reconstruct stack before jumping to __cerror */
813235Sraf	addl	$12, %esp
823235Sraf	pushl	%ecx
833235Sraf	pushl	%eax			/* save the vfork() error number */
843235Sraf
85*11913SRoger.Faulkner@Sun.COM	pushl	%gs:UL_SIGMASK+12	/* reinstate signals */
86*11913SRoger.Faulkner@Sun.COM	pushl	%gs:UL_SIGMASK+8
87*11913SRoger.Faulkner@Sun.COM	pushl	%gs:UL_SIGMASK+4
883235Sraf	pushl	%gs:UL_SIGMASK
893235Sraf	pushl	$SIG_SETMASK
903235Sraf	pushl	%ecx
913235Sraf	__SYSCALLINT(lwp_sigmask)
92*11913SRoger.Faulkner@Sun.COM	addl	$24, %esp
933235Sraf
943235Sraf	popl	%eax			/* restore the vfork() error number */
953235Sraf	jmp	__cerror
963235Sraf
973235Sraf1:
983235Sraf	addl	$12, %esp
993235Sraf	/*
1003235Sraf	 * To determine if we are (still) a child of vfork(), the child
1013235Sraf	 * increments curthread->ul_vfork by one and the parent decrements
1023235Sraf	 * it by one.  If the result is zero, then we are not a child of
1033235Sraf	 * vfork(), else we are.  We do this to deal with the case of
1043235Sraf	 * a vfork() child calling vfork().
1053235Sraf	 */
1063235Sraf	cmpl	$0, %edx
1073235Sraf	jne	2f
1083235Sraf	movl	%gs:UL_VFORK, %edx
1093235Sraf	cmpl	$0, %edx		/* don't let it go negative */
1103235Sraf	je	3f
1113235Sraf	subl	$1, %edx		/* curthread->ul_vfork--; */
1123235Sraf	jmp	3f
1133235Sraf2:
1143235Sraf	xorl	%eax, %eax		/* zero the return value in the child */
1153235Sraf	movl	%gs:UL_VFORK, %edx
1163235Sraf	addl	$1, %edx		/* curthread->ul_vfork++; */
1173235Sraf3:
1183235Sraf	movl	%edx, %gs:UL_VFORK
1193235Sraf	/*
1203235Sraf	 * Clear the schedctl interface in both parent and child.
1213235Sraf	 * (The child might have modified the parent.)
1223235Sraf	 */
1233235Sraf	xorl	%edx, %edx
1243235Sraf	movl	%edx, %gs:UL_SCHEDCTL
1253235Sraf	movl	%edx, %gs:UL_SCHEDCTL_CALLED
1263235Sraf	pushl	%eax			/* save the vfork() return value */
1273235Sraf
128*11913SRoger.Faulkner@Sun.COM	pushl	%gs:UL_SIGMASK+12	/* reinstate signals */
129*11913SRoger.Faulkner@Sun.COM	pushl	%gs:UL_SIGMASK+8
130*11913SRoger.Faulkner@Sun.COM	pushl	%gs:UL_SIGMASK+4
1313235Sraf	pushl	%gs:UL_SIGMASK
1323235Sraf	pushl	$SIG_SETMASK
1333235Sraf	pushl	%ecx
1343235Sraf	__SYSCALLINT(lwp_sigmask)
135*11913SRoger.Faulkner@Sun.COM	addl	$24, %esp
1363235Sraf
1373235Sraf	popl	%eax			/* restore the vfork() return value */
1383235Sraf	jmp	*%ecx			/* jump back to the caller */
1393235Sraf	SET_SIZE(vfork)
1403235Sraf	SET_SIZE(vforkx)
141