/* Copyright (C) 2005, 2007 Free Software Foundation, Inc.
This file is part of the GNU C Library.
The GNU C Library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
The GNU C Library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with the GNU C Library; if not, see
. */
#include "sysdep.h"
#include
#define _SIGNAL_H
#include
/* Clone the calling process, but without copying the whole address space.
The calling process is suspended until the new process exits or is
replaced by a call to `execve'. Return -1 for errors, 0 to the new process,
and the process ID of the new process to the old process.
Note that it is important that we don't create a new stack frame for the
caller. */
/* The following are defined in linux/sched.h, which unfortunately
is not safe for inclusion in an assembly file. */
#define CLONE_VM 0x00000100 /* set if VM shared between processes */
#define CLONE_VFORK 0x00004000 /* set if the parent wants the child to
wake it up on mm_release */
#ifndef SAVE_PID
#define SAVE_PID
#endif
#ifndef RESTORE_PID
#define RESTORE_PID
#endif
/* pid_t vfork(void);
Implemented as __clone_syscall(CLONE_VFORK | CLONE_VM | SIGCHLD, 0) */
HIDDEN_ENTRY (__vfork)
movi a6, .Ljumptable
extui a2, a0, 30, 2 /* call-size: call4/8/12 = 1/2/3 */
addx4 a4, a2, a6 /* find return address in jumptable */
l32i a4, a4, 0
add a4, a4, a6
slli a2, a2, 30
xor a3, a0, a2 /* remove call-size from return addr */
extui a5, a4, 30, 2 /* get high bits of jump target */
slli a5, a5, 30
or a3, a3, a5 /* stuff them into the return address */
xor a4, a4, a5 /* clear high bits of jump target */
or a0, a4, a2 /* create temporary return address */
retw /* "return" to .L4, .L8, or .L12 */
.align 4
.Ljumptable:
.word 0
.word .L4 - .Ljumptable
.word .L8 - .Ljumptable
.word .L12 - .Ljumptable
/* a7: return address */
.L4: mov a12, a2
mov a13, a3
SAVE_PID
/* Use syscall 'clone'. Set new stack pointer to the same address. */
movi a2, SYS_ify (clone)
movi a3, 0
movi a6, CLONE_VM | CLONE_VFORK | SIGCHLD
syscall
RESTORE_PID
movi a5, -4096
mov a6, a2
mov a2, a12
mov a3, a13
bgeu a6, a5, 1f
jx a7
1: call4 .Lerr /* returns to original caller */
/* a11: return address */
.L8: mov a12, a2
mov a13, a3
mov a14, a6
SAVE_PID
movi a2, SYS_ify (clone)
movi a3, 0
movi a6, CLONE_VM | CLONE_VFORK | SIGCHLD
syscall
RESTORE_PID
movi a9, -4096
mov a10, a2
mov a2, a12
mov a3, a13
mov a6, a14
bgeu a10, a9, 1f
jx a11
1: call8 .Lerr /* returns to original caller */
/* a15: return address */
.L12: mov a12, a2
mov a13, a3
mov a14, a6
SAVE_PID
movi a2, SYS_ify (clone)
movi a3, 0
movi a6, CLONE_VM | CLONE_VFORK | SIGCHLD
syscall
RESTORE_PID
mov a3, a13
movi a13, -4096
mov a6, a14
mov a14, a2
mov a2, a12
bgeu a14, a13, 1f
jx a15
1: call12 .Lerr /* returns to original caller */
.align 4
.Lerr: entry a1, 16
/* Restore the return address. */
extui a4, a0, 30, 2 /* get the call-size bits */
slli a4, a4, 30
slli a3, a3, 2 /* clear high bits of target address */
srli a3, a3, 2
or a0, a3, a4 /* combine them */
PSEUDO_END (__vfork)
.Lpseudo_end:
retw
weak_alias (__vfork, vfork)
libc_hidden_def(vfork)