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 movq %rdi, %r8 /* flags */ 60657b1f3dSraf jmp 0f 61657b1f3dSraf ENTRY_NP(vfork) 62657b1f3dSraf xorq %r8, %r8 /* flags = 0 */ 63657b1f3dSraf0: 64657b1f3dSraf popq %r9 /* save return %rip in %r9 */ 65*bdf0047cSRoger A. Faulkner pushq %r8 /* save the flags on the stack */ 66*bdf0047cSRoger A. Faulkner movl $MASKSET3, %r8d /* block all signals */ 67*bdf0047cSRoger A. Faulkner movl $MASKSET2, %ecx 68*bdf0047cSRoger A. Faulkner movl $MASKSET1, %edx 69657b1f3dSraf movl $MASKSET0, %esi 70657b1f3dSraf movl $SIG_SETMASK, %edi 71657b1f3dSraf __SYSCALL(lwp_sigmask) 72657b1f3dSraf 73*bdf0047cSRoger A. Faulkner popq %rsi /* fetch flags from the stack */ 74657b1f3dSraf movl $2, %edi 75657b1f3dSraf __SYSCALL(forksys) /* vforkx(flags) */ 76657b1f3dSraf jae 1f 77657b1f3dSraf 78657b1f3dSraf /* reconstruct stack before jumping to __cerror */ 79657b1f3dSraf pushq %r9 80*bdf0047cSRoger A. Faulkner movq %rax, %r9 /* save the vfork() error number */ 81657b1f3dSraf 82*bdf0047cSRoger A. Faulkner movl %fs:UL_SIGMASK+12, %r8d /* reinstate signals */ 83*bdf0047cSRoger A. Faulkner movl %fs:UL_SIGMASK+8, %ecx 84*bdf0047cSRoger A. Faulkner movl %fs:UL_SIGMASK+4, %edx 85657b1f3dSraf movl %fs:UL_SIGMASK, %esi 86657b1f3dSraf movl $SIG_SETMASK, %edi 87657b1f3dSraf __SYSCALL(lwp_sigmask) 88657b1f3dSraf 89*bdf0047cSRoger A. Faulkner movq %r9, %rax /* restore the vfork() error number */ 90657b1f3dSraf jmp __cerror 91657b1f3dSraf 92657b1f3dSraf1: 93657b1f3dSraf /* 94657b1f3dSraf * To determine if we are (still) a child of vfork(), the child 95657b1f3dSraf * increments curthread->ul_vfork by one and the parent decrements 96657b1f3dSraf * it by one. If the result is zero, then we are not a child of 97657b1f3dSraf * vfork(), else we are. We do this to deal with the case of 98657b1f3dSraf * a vfork() child calling vfork(). 99657b1f3dSraf */ 100657b1f3dSraf cmpl $0, %edx 101657b1f3dSraf jne 2f 102657b1f3dSraf movl %fs:UL_VFORK, %edx 103657b1f3dSraf cmpl $0, %edx /* don't let it go negative */ 104657b1f3dSraf je 3f 105657b1f3dSraf subl $1, %edx /* curthread->ul_vfork--; */ 106657b1f3dSraf jmp 3f 107657b1f3dSraf2: 108657b1f3dSraf xorl %eax, %eax /* zero the return value in the child */ 109657b1f3dSraf movl %fs:UL_VFORK, %edx 110657b1f3dSraf addl $1, %edx /* curthread->ul_vfork++; */ 111657b1f3dSraf3: 112657b1f3dSraf movl %edx, %fs:UL_VFORK 113657b1f3dSraf /* 114657b1f3dSraf * Clear the schedctl interface in both parent and child. 115657b1f3dSraf * (The child might have modified the parent.) 116657b1f3dSraf */ 117657b1f3dSraf xorq %rdx, %rdx 118657b1f3dSraf movq %rdx, %fs:UL_SCHEDCTL 119657b1f3dSraf movq %rdx, %fs:UL_SCHEDCTL_CALLED 120*bdf0047cSRoger A. Faulkner pushq %rax /* save the vfork() return value */ 121657b1f3dSraf 122*bdf0047cSRoger A. Faulkner movl %fs:UL_SIGMASK+12, %r8d /* reinstate signals */ 123*bdf0047cSRoger A. Faulkner movl %fs:UL_SIGMASK+8, %ecx 124*bdf0047cSRoger A. Faulkner movl %fs:UL_SIGMASK+4, %edx 125657b1f3dSraf movl %fs:UL_SIGMASK, %esi 126657b1f3dSraf movl $SIG_SETMASK, %edi 127657b1f3dSraf __SYSCALL(lwp_sigmask) 128657b1f3dSraf 129*bdf0047cSRoger A. Faulkner popq %rax /* restore the vfork() return value */ 130657b1f3dSraf jmp *%r9 /* jump back to the caller */ 131657b1f3dSraf SET_SIZE(vfork) 132657b1f3dSraf SET_SIZE(vforkx) 133