1// Copyright 2018 The Go Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style
3// license that can be found in the LICENSE file.
4
5package runtime
6
7import "unsafe"
8
9// This file handles some syscalls from the syscall package
10// Especially, syscalls use during forkAndExecInChild which must not split the stack
11
12//go:cgo_import_dynamic libc_chdir chdir "libc.a/shr_64.o"
13//go:cgo_import_dynamic libc_chroot chroot "libc.a/shr_64.o"
14//go:cgo_import_dynamic libc_dup2 dup2 "libc.a/shr_64.o"
15//go:cgo_import_dynamic libc_execve execve "libc.a/shr_64.o"
16//go:cgo_import_dynamic libc_fcntl fcntl "libc.a/shr_64.o"
17//go:cgo_import_dynamic libc_fork fork "libc.a/shr_64.o"
18//go:cgo_import_dynamic libc_ioctl ioctl "libc.a/shr_64.o"
19//go:cgo_import_dynamic libc_setgid setgid "libc.a/shr_64.o"
20//go:cgo_import_dynamic libc_setgroups setgroups "libc.a/shr_64.o"
21//go:cgo_import_dynamic libc_setrlimit setrlimit "libc.a/shr_64.o"
22//go:cgo_import_dynamic libc_setsid setsid "libc.a/shr_64.o"
23//go:cgo_import_dynamic libc_setuid setuid "libc.a/shr_64.o"
24//go:cgo_import_dynamic libc_setpgid setpgid "libc.a/shr_64.o"
25
26//go:linkname libc_chdir libc_chdir
27//go:linkname libc_chroot libc_chroot
28//go:linkname libc_dup2 libc_dup2
29//go:linkname libc_execve libc_execve
30//go:linkname libc_fcntl libc_fcntl
31//go:linkname libc_fork libc_fork
32//go:linkname libc_ioctl libc_ioctl
33//go:linkname libc_setgid libc_setgid
34//go:linkname libc_setgroups libc_setgroups
35//go:linkname libc_setrlimit libc_setrlimit
36//go:linkname libc_setsid libc_setsid
37//go:linkname libc_setuid libc_setuid
38//go:linkname libc_setpgid libc_setpgid
39
40var (
41	libc_chdir,
42	libc_chroot,
43	libc_dup2,
44	libc_execve,
45	libc_fcntl,
46	libc_fork,
47	libc_ioctl,
48	libc_setgid,
49	libc_setgroups,
50	libc_setrlimit,
51	libc_setsid,
52	libc_setuid,
53	libc_setpgid libFunc
54)
55
56// In syscall_syscall6 and syscall_rawsyscall6, r2 is always 0
57// as it's never used on AIX
58// TODO: remove r2 from zsyscall_aix_$GOARCH.go
59
60// Syscall is needed because some packages (like net) need it too.
61// The best way is to return EINVAL and let Golang handles its failure
62// If the syscall can't fail, this function can redirect it to a real syscall.
63//
64// This is exported via linkname to assembly in the syscall package.
65//
66//go:nosplit
67//go:linkname syscall_Syscall
68func syscall_Syscall(fn, a1, a2, a3 uintptr) (r1, r2, err uintptr) {
69	return 0, 0, _EINVAL
70}
71
72// This is syscall.RawSyscall, it exists to satisfy some build dependency,
73// but it doesn't work.
74//
75// This is exported via linkname to assembly in the syscall package.
76//
77//go:linkname syscall_RawSyscall
78func syscall_RawSyscall(trap, a1, a2, a3 uintptr) (r1, r2, err uintptr) {
79	panic("RawSyscall not available on AIX")
80}
81
82// This is exported via linkname to assembly in the syscall package.
83//
84//go:nosplit
85//go:cgo_unsafe_args
86//go:linkname syscall_syscall6
87func syscall_syscall6(fn, nargs, a1, a2, a3, a4, a5, a6 uintptr) (r1, r2, err uintptr) {
88	c := libcall{
89		fn:   fn,
90		n:    nargs,
91		args: uintptr(unsafe.Pointer(&a1)),
92	}
93
94	entersyscallblock()
95	asmcgocall(unsafe.Pointer(&asmsyscall6), unsafe.Pointer(&c))
96	exitsyscall()
97	return c.r1, 0, c.err
98}
99
100// This is exported via linkname to assembly in the syscall package.
101//
102//go:nosplit
103//go:cgo_unsafe_args
104//go:linkname syscall_rawSyscall6
105func syscall_rawSyscall6(fn, nargs, a1, a2, a3, a4, a5, a6 uintptr) (r1, r2, err uintptr) {
106	c := libcall{
107		fn:   fn,
108		n:    nargs,
109		args: uintptr(unsafe.Pointer(&a1)),
110	}
111
112	asmcgocall(unsafe.Pointer(&asmsyscall6), unsafe.Pointer(&c))
113
114	return c.r1, 0, c.err
115}
116
117//go:linkname syscall_chdir syscall.chdir
118//go:nosplit
119func syscall_chdir(path uintptr) (err uintptr) {
120	_, err = syscall1(&libc_chdir, path)
121	return
122}
123
124//go:linkname syscall_chroot1 syscall.chroot1
125//go:nosplit
126func syscall_chroot1(path uintptr) (err uintptr) {
127	_, err = syscall1(&libc_chroot, path)
128	return
129}
130
131// like close, but must not split stack, for fork.
132//
133//go:linkname syscall_closeFD syscall.closeFD
134//go:nosplit
135func syscall_closeFD(fd int32) int32 {
136	_, err := syscall1(&libc_close, uintptr(fd))
137	return int32(err)
138}
139
140//go:linkname syscall_dup2child syscall.dup2child
141//go:nosplit
142func syscall_dup2child(old, new uintptr) (val, err uintptr) {
143	val, err = syscall2(&libc_dup2, old, new)
144	return
145}
146
147//go:linkname syscall_execve syscall.execve
148//go:nosplit
149func syscall_execve(path, argv, envp uintptr) (err uintptr) {
150	_, err = syscall3(&libc_execve, path, argv, envp)
151	return
152}
153
154// like exit, but must not split stack, for fork.
155//
156//go:linkname syscall_exit syscall.exit
157//go:nosplit
158func syscall_exit(code uintptr) {
159	syscall1(&libc_exit, code)
160}
161
162//go:linkname syscall_fcntl1 syscall.fcntl1
163//go:nosplit
164func syscall_fcntl1(fd, cmd, arg uintptr) (val, err uintptr) {
165	val, err = syscall3(&libc_fcntl, fd, cmd, arg)
166	return
167}
168
169//go:linkname syscall_forkx syscall.forkx
170//go:nosplit
171func syscall_forkx(flags uintptr) (pid uintptr, err uintptr) {
172	pid, err = syscall1(&libc_fork, flags)
173	return
174}
175
176//go:linkname syscall_getpid syscall.getpid
177//go:nosplit
178func syscall_getpid() (pid, err uintptr) {
179	pid, err = syscall0(&libc_getpid)
180	return
181}
182
183//go:linkname syscall_ioctl syscall.ioctl
184//go:nosplit
185func syscall_ioctl(fd, req, arg uintptr) (err uintptr) {
186	_, err = syscall3(&libc_ioctl, fd, req, arg)
187	return
188}
189
190//go:linkname syscall_setgid syscall.setgid
191//go:nosplit
192func syscall_setgid(gid uintptr) (err uintptr) {
193	_, err = syscall1(&libc_setgid, gid)
194	return
195}
196
197//go:linkname syscall_setgroups1 syscall.setgroups1
198//go:nosplit
199func syscall_setgroups1(ngid, gid uintptr) (err uintptr) {
200	_, err = syscall2(&libc_setgroups, ngid, gid)
201	return
202}
203
204//go:linkname syscall_setrlimit1 syscall.setrlimit1
205//go:nosplit
206func syscall_setrlimit1(which uintptr, lim unsafe.Pointer) (err uintptr) {
207	_, err = syscall2(&libc_setrlimit, which, uintptr(lim))
208	return
209}
210
211//go:linkname syscall_setsid syscall.setsid
212//go:nosplit
213func syscall_setsid() (pid, err uintptr) {
214	pid, err = syscall0(&libc_setsid)
215	return
216}
217
218//go:linkname syscall_setuid syscall.setuid
219//go:nosplit
220func syscall_setuid(uid uintptr) (err uintptr) {
221	_, err = syscall1(&libc_setuid, uid)
222	return
223}
224
225//go:linkname syscall_setpgid syscall.setpgid
226//go:nosplit
227func syscall_setpgid(pid, pgid uintptr) (err uintptr) {
228	_, err = syscall2(&libc_setpgid, pid, pgid)
229	return
230}
231
232//go:linkname syscall_write1 syscall.write1
233//go:nosplit
234func syscall_write1(fd, buf, nbyte uintptr) (n, err uintptr) {
235	n, err = syscall3(&libc_write, fd, buf, nbyte)
236	return
237}
238