summaryrefslogtreecommitdiff
path: root/libc/sysdeps/linux/sh/vfork.S
blob: d311bff12c48d5877a1baff12ecfd5f8a6add384 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
/* Copyright (C) 1999, 2000 Free Software Foundation, Inc.
   Copyright (C) 2001 Hewlett-Packard Australia

 This program is free software; you can redistribute it and/or modify it under
 the terms of the GNU Library General Public License as published by the Free
 Software Foundation; either version 2 of the License, or (at your option) any
 later version.

 This program 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 Library General Public License for more
 details.

 You should have received a copy of the GNU Library General Public License
 along with this program; if not, write to the Free Software Foundation, Inc.,
 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA

 Derived in part from the Linux-8086 C library, the GNU C Library, and several
 other sundry sources.  Files within this library are copyright by their
 respective copyright holders.
*/

#include <features.h>
#include <sys/syscall.h>
#define _ERRNO_H
#include <bits/errno.h>
#include <bits/sysnum.h>

/* 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.  */

.text
.globl	__vfork
.hidden	__vfork
.type	__vfork,@function
.align 4

__vfork:
	mov.w	.L2, r3
	trapa	#__SH_SYSCALL_TRAP_BASE
	mov     r0, r1
#ifdef __sh2__
/* 12 arithmetic shifts for the crappy sh2, because shad doesn't exist!	 */
	shar	r1
	shar	r1
	shar	r1
	shar	r1
	shar	r1
	shar	r1
	shar	r1
	shar	r1
	shar	r1
	shar	r1
	shar	r1
	shar	r1
#else
	mov	#-12, r2
	shad	r2, r1
#endif

	not	r1, r1			/* r1=0 means r0 = -1 to -4095 */
	tst	r1, r1			/* i.e. error in linux */
	bf	2f
	mov.w	.L1, r1
	cmp/eq	r1, r0
	bf/s	__syscall_error
	 mov	r0, r4

	/* If we don't have vfork, use fork.  */
	mov.w	.L3, r3
	trapa	#__SH_SYSCALL_TRAP_BASE
	mov     r0, r1
#ifdef __sh2__
/* 12 arithmetic shifts for the crappy sh2, because shad doesn't exist!	 */
	shar	r1
	shar	r1
	shar	r1
	shar	r1
	shar	r1
	shar	r1
	shar	r1
	shar	r1
	shar	r1
	shar	r1
	shar	r1
	shar	r1
#else
	mov	#-12, r2
	shad	r2, r1
#endif

	not	r1, r1			/* r1=0 means r0 = -1 to -4095 */
	tst	r1, r1			/* i.e. error in linux */
	bt/s	__syscall_error
	 mov	r0, r4
2:
	rts
	 nop

	.align	2
.L1:
	.word	-ENOSYS
.L2:
	.word	__NR_vfork
.L3:
	.word	__NR_fork

.size   __vfork, .-__vfork
weak_alias(__vfork,vfork)
libc_hidden_weak(vfork)

#include "syscall_error.S"