1657b1f3dSraf/* 2657b1f3dSraf * CDDL HEADER START 3657b1f3dSraf * 4657b1f3dSraf * The contents of this file are subject to the terms of the 5657b1f3dSraf * Common Development and Distribution License (the "License"). 6657b1f3dSraf * You may not use this file except in compliance with the License. 7657b1f3dSraf * 8657b1f3dSraf * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9657b1f3dSraf * or http://www.opensolaris.org/os/licensing. 10657b1f3dSraf * See the License for the specific language governing permissions 11657b1f3dSraf * and limitations under the License. 12657b1f3dSraf * 13657b1f3dSraf * When distributing Covered Code, include this CDDL HEADER in each 14657b1f3dSraf * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15657b1f3dSraf * If applicable, add the following below this CDDL HEADER, with the 16657b1f3dSraf * fields enclosed by brackets "[]" replaced with your own identifying 17657b1f3dSraf * information: Portions Copyright [yyyy] [name of copyright owner] 18657b1f3dSraf * 19657b1f3dSraf * CDDL HEADER END 20657b1f3dSraf */ 21657b1f3dSraf 22657b1f3dSraf/* 23*bdf0047cSRoger A. Faulkner * Copyright 2010 Sun Microsystems, Inc. All rights reserved. 24657b1f3dSraf * Use is subject to license terms. 25657b1f3dSraf */ 26657b1f3dSraf 279a70fc3bSMark J. Nelson .file "vforkx.s" 28657b1f3dSraf 29657b1f3dSraf#include "SYS.h" 30657b1f3dSraf#include <assym.h> 31657b1f3dSraf 32657b1f3dSraf/* 33657b1f3dSraf * pid = vforkx(flags); 34657b1f3dSraf * syscall trap: forksys(2, flags) 35657b1f3dSraf * 36657b1f3dSraf * pid = vfork(); 37657b1f3dSraf * syscall trap: forksys(2, 0) 38657b1f3dSraf * 39657b1f3dSraf * From the syscall: 40657b1f3dSraf * %edx == 0 in parent process, %edx = 1 in child process. 41657b1f3dSraf * %eax == pid of child in parent, %eax == pid of parent in child. 42657b1f3dSraf * 43657b1f3dSraf * The child gets a zero return value. 44657b1f3dSraf * The parent gets the pid of the child. 45657b1f3dSraf */ 46657b1f3dSraf 47657b1f3dSraf/* 48657b1f3dSraf * The child of vfork() will execute in the parent's address space, 49657b1f3dSraf * thereby changing the stack before the parent runs again. 50657b1f3dSraf * Therefore we have to be careful how we return from vfork(). 51657b1f3dSraf * Pity the poor debugger developer who has to deal with this kludge. 52657b1f3dSraf * 53657b1f3dSraf * We block all blockable signals while performing the vfork() system call 54657b1f3dSraf * trap. This enables us to set curthread->ul_vfork safely, so that we 55657b1f3dSraf * don't end up in a signal handler with curthread->ul_vfork set wrong. 56657b1f3dSraf */ 57657b1f3dSraf 58657b1f3dSraf ENTRY_NP(vforkx) 59657b1f3dSraf movl 4(%esp), %eax /* flags */ 60657b1f3dSraf jmp 0f 61657b1f3dSraf ENTRY_NP(vfork) 62657b1f3dSraf xorl %eax, %eax /* flags = 0 */ 63657b1f3dSraf0: 64657b1f3dSraf popl %ecx /* save return %eip in %ecx */ 65657b1f3dSraf pushl %eax /* flags */ 66*bdf0047cSRoger A. Faulkner pushl $MASKSET3 /* block all signals */ 67*bdf0047cSRoger A. Faulkner pushl $MASKSET2 68*bdf0047cSRoger A. Faulkner pushl $MASKSET1 69657b1f3dSraf pushl $MASKSET0 70657b1f3dSraf pushl $SIG_SETMASK 71657b1f3dSraf pushl %ecx 72657b1f3dSraf __SYSCALLINT(lwp_sigmask) 73*bdf0047cSRoger A. Faulkner addl $24, %esp 74657b1f3dSraf 75657b1f3dSraf pushl $2 76657b1f3dSraf pushl %ecx 77657b1f3dSraf __SYSCALLINT(forksys) /* vforkx(flags) */ 78657b1f3dSraf jae 1f 79657b1f3dSraf 80657b1f3dSraf /* reconstruct stack before jumping to __cerror */ 81657b1f3dSraf addl $12, %esp 82657b1f3dSraf pushl %ecx 83657b1f3dSraf pushl %eax /* save the vfork() error number */ 84657b1f3dSraf 85*bdf0047cSRoger A. Faulkner pushl %gs:UL_SIGMASK+12 /* reinstate signals */ 86*bdf0047cSRoger A. Faulkner pushl %gs:UL_SIGMASK+8 87*bdf0047cSRoger A. Faulkner pushl %gs:UL_SIGMASK+4 88657b1f3dSraf pushl %gs:UL_SIGMASK 89657b1f3dSraf pushl $SIG_SETMASK 90657b1f3dSraf pushl %ecx 91657b1f3dSraf __SYSCALLINT(lwp_sigmask) 92*bdf0047cSRoger A. Faulkner addl $24, %esp 93657b1f3dSraf 94657b1f3dSraf popl %eax /* restore the vfork() error number */ 95657b1f3dSraf jmp __cerror 96657b1f3dSraf 97657b1f3dSraf1: 98657b1f3dSraf addl $12, %esp 99657b1f3dSraf /* 100657b1f3dSraf * To determine if we are (still) a child of vfork(), the child 101657b1f3dSraf * increments curthread->ul_vfork by one and the parent decrements 102657b1f3dSraf * it by one. If the result is zero, then we are not a child of 103657b1f3dSraf * vfork(), else we are. We do this to deal with the case of 104657b1f3dSraf * a vfork() child calling vfork(). 105657b1f3dSraf */ 106657b1f3dSraf cmpl $0, %edx 107657b1f3dSraf jne 2f 108657b1f3dSraf movl %gs:UL_VFORK, %edx 109657b1f3dSraf cmpl $0, %edx /* don't let it go negative */ 110657b1f3dSraf je 3f 111657b1f3dSraf subl $1, %edx /* curthread->ul_vfork--; */ 112657b1f3dSraf jmp 3f 113657b1f3dSraf2: 114657b1f3dSraf xorl %eax, %eax /* zero the return value in the child */ 115657b1f3dSraf movl %gs:UL_VFORK, %edx 116657b1f3dSraf addl $1, %edx /* curthread->ul_vfork++; */ 117657b1f3dSraf3: 118657b1f3dSraf movl %edx, %gs:UL_VFORK 119657b1f3dSraf /* 120657b1f3dSraf * Clear the schedctl interface in both parent and child. 121657b1f3dSraf * (The child might have modified the parent.) 122657b1f3dSraf */ 123657b1f3dSraf xorl %edx, %edx 124657b1f3dSraf movl %edx, %gs:UL_SCHEDCTL 125657b1f3dSraf movl %edx, %gs:UL_SCHEDCTL_CALLED 126657b1f3dSraf pushl %eax /* save the vfork() return value */ 127657b1f3dSraf 128*bdf0047cSRoger A. Faulkner pushl %gs:UL_SIGMASK+12 /* reinstate signals */ 129*bdf0047cSRoger A. Faulkner pushl %gs:UL_SIGMASK+8 130*bdf0047cSRoger A. Faulkner pushl %gs:UL_SIGMASK+4 131657b1f3dSraf pushl %gs:UL_SIGMASK 132657b1f3dSraf pushl $SIG_SETMASK 133657b1f3dSraf pushl %ecx 134657b1f3dSraf __SYSCALLINT(lwp_sigmask) 135*bdf0047cSRoger A. Faulkner addl $24, %esp 136657b1f3dSraf 137657b1f3dSraf popl %eax /* restore the vfork() return value */ 138657b1f3dSraf jmp *%ecx /* jump back to the caller */ 139657b1f3dSraf SET_SIZE(vfork) 140657b1f3dSraf SET_SIZE(vforkx) 141