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