1// Copyright 2014 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
9type mts struct {
10	tv_sec  int64
11	tv_nsec int64
12}
13
14type mscratch struct {
15	v [6]uintptr
16}
17
18type mOS struct {
19	waitsema uintptr // semaphore for parking on locks
20	perrno   *int32  // pointer to tls errno
21	// these are here because they are too large to be on the stack
22	// of low-level NOSPLIT functions.
23	//LibCall       libcall;
24	ts      mts
25	scratch mscratch
26}
27
28type libcFunc uintptr
29
30//go:linkname asmsysvicall6x runtime.asmsysvicall6
31var asmsysvicall6x libcFunc // name to take addr of asmsysvicall6
32
33func asmsysvicall6() // declared for vet; do NOT call
34
35//go:nosplit
36func sysvicall0(fn *libcFunc) uintptr {
37	// Leave caller's PC/SP around for traceback.
38	gp := getg()
39	var mp *m
40	if gp != nil {
41		mp = gp.m
42	}
43	if mp != nil && mp.libcallsp == 0 {
44		mp.libcallg.set(gp)
45		mp.libcallpc = getcallerpc()
46		// sp must be the last, because once async cpu profiler finds
47		// all three values to be non-zero, it will use them
48		mp.libcallsp = getcallersp()
49	} else {
50		mp = nil // See comment in sys_darwin.go:libcCall
51	}
52
53	var libcall libcall
54	libcall.fn = uintptr(unsafe.Pointer(fn))
55	libcall.n = 0
56	libcall.args = uintptr(unsafe.Pointer(fn)) // it's unused but must be non-nil, otherwise crashes
57	asmcgocall(unsafe.Pointer(&asmsysvicall6x), unsafe.Pointer(&libcall))
58	if mp != nil {
59		mp.libcallsp = 0
60	}
61	return libcall.r1
62}
63
64//go:nosplit
65func sysvicall1(fn *libcFunc, a1 uintptr) uintptr {
66	r1, _ := sysvicall1Err(fn, a1)
67	return r1
68}
69
70//go:nosplit
71
72// sysvicall1Err returns both the system call result and the errno value.
73// This is used by sysvicall1 and pipe.
74func sysvicall1Err(fn *libcFunc, a1 uintptr) (r1, err uintptr) {
75	// Leave caller's PC/SP around for traceback.
76	gp := getg()
77	var mp *m
78	if gp != nil {
79		mp = gp.m
80	}
81	if mp != nil && mp.libcallsp == 0 {
82		mp.libcallg.set(gp)
83		mp.libcallpc = getcallerpc()
84		// sp must be the last, because once async cpu profiler finds
85		// all three values to be non-zero, it will use them
86		mp.libcallsp = getcallersp()
87	} else {
88		mp = nil
89	}
90
91	var libcall libcall
92	libcall.fn = uintptr(unsafe.Pointer(fn))
93	libcall.n = 1
94	// TODO(rsc): Why is noescape necessary here and below?
95	libcall.args = uintptr(noescape(unsafe.Pointer(&a1)))
96	asmcgocall(unsafe.Pointer(&asmsysvicall6x), unsafe.Pointer(&libcall))
97	if mp != nil {
98		mp.libcallsp = 0
99	}
100	return libcall.r1, libcall.err
101}
102
103//go:nosplit
104func sysvicall2(fn *libcFunc, a1, a2 uintptr) uintptr {
105	r1, _ := sysvicall2Err(fn, a1, a2)
106	return r1
107}
108
109//go:nosplit
110//go:cgo_unsafe_args
111
112// sysvicall2Err returns both the system call result and the errno value.
113// This is used by sysvicall2 and pipe2.
114func sysvicall2Err(fn *libcFunc, a1, a2 uintptr) (uintptr, uintptr) {
115	// Leave caller's PC/SP around for traceback.
116	gp := getg()
117	var mp *m
118	if gp != nil {
119		mp = gp.m
120	}
121	if mp != nil && mp.libcallsp == 0 {
122		mp.libcallg.set(gp)
123		mp.libcallpc = getcallerpc()
124		// sp must be the last, because once async cpu profiler finds
125		// all three values to be non-zero, it will use them
126		mp.libcallsp = getcallersp()
127	} else {
128		mp = nil
129	}
130
131	var libcall libcall
132	libcall.fn = uintptr(unsafe.Pointer(fn))
133	libcall.n = 2
134	libcall.args = uintptr(noescape(unsafe.Pointer(&a1)))
135	asmcgocall(unsafe.Pointer(&asmsysvicall6x), unsafe.Pointer(&libcall))
136	if mp != nil {
137		mp.libcallsp = 0
138	}
139	return libcall.r1, libcall.err
140}
141
142//go:nosplit
143func sysvicall3(fn *libcFunc, a1, a2, a3 uintptr) uintptr {
144	r1, _ := sysvicall3Err(fn, a1, a2, a3)
145	return r1
146}
147
148//go:nosplit
149//go:cgo_unsafe_args
150
151// sysvicall3Err returns both the system call result and the errno value.
152// This is used by sysicall3 and write1.
153func sysvicall3Err(fn *libcFunc, a1, a2, a3 uintptr) (r1, err uintptr) {
154	// Leave caller's PC/SP around for traceback.
155	gp := getg()
156	var mp *m
157	if gp != nil {
158		mp = gp.m
159	}
160	if mp != nil && mp.libcallsp == 0 {
161		mp.libcallg.set(gp)
162		mp.libcallpc = getcallerpc()
163		// sp must be the last, because once async cpu profiler finds
164		// all three values to be non-zero, it will use them
165		mp.libcallsp = getcallersp()
166	} else {
167		mp = nil
168	}
169
170	var libcall libcall
171	libcall.fn = uintptr(unsafe.Pointer(fn))
172	libcall.n = 3
173	libcall.args = uintptr(noescape(unsafe.Pointer(&a1)))
174	asmcgocall(unsafe.Pointer(&asmsysvicall6x), unsafe.Pointer(&libcall))
175	if mp != nil {
176		mp.libcallsp = 0
177	}
178	return libcall.r1, libcall.err
179}
180
181//go:nosplit
182func sysvicall4(fn *libcFunc, a1, a2, a3, a4 uintptr) uintptr {
183	// Leave caller's PC/SP around for traceback.
184	gp := getg()
185	var mp *m
186	if gp != nil {
187		mp = gp.m
188	}
189	if mp != nil && mp.libcallsp == 0 {
190		mp.libcallg.set(gp)
191		mp.libcallpc = getcallerpc()
192		// sp must be the last, because once async cpu profiler finds
193		// all three values to be non-zero, it will use them
194		mp.libcallsp = getcallersp()
195	} else {
196		mp = nil
197	}
198
199	var libcall libcall
200	libcall.fn = uintptr(unsafe.Pointer(fn))
201	libcall.n = 4
202	libcall.args = uintptr(noescape(unsafe.Pointer(&a1)))
203	asmcgocall(unsafe.Pointer(&asmsysvicall6x), unsafe.Pointer(&libcall))
204	if mp != nil {
205		mp.libcallsp = 0
206	}
207	return libcall.r1
208}
209
210//go:nosplit
211func sysvicall5(fn *libcFunc, a1, a2, a3, a4, a5 uintptr) uintptr {
212	// Leave caller's PC/SP around for traceback.
213	gp := getg()
214	var mp *m
215	if gp != nil {
216		mp = gp.m
217	}
218	if mp != nil && mp.libcallsp == 0 {
219		mp.libcallg.set(gp)
220		mp.libcallpc = getcallerpc()
221		// sp must be the last, because once async cpu profiler finds
222		// all three values to be non-zero, it will use them
223		mp.libcallsp = getcallersp()
224	} else {
225		mp = nil
226	}
227
228	var libcall libcall
229	libcall.fn = uintptr(unsafe.Pointer(fn))
230	libcall.n = 5
231	libcall.args = uintptr(noescape(unsafe.Pointer(&a1)))
232	asmcgocall(unsafe.Pointer(&asmsysvicall6x), unsafe.Pointer(&libcall))
233	if mp != nil {
234		mp.libcallsp = 0
235	}
236	return libcall.r1
237}
238
239//go:nosplit
240func sysvicall6(fn *libcFunc, a1, a2, a3, a4, a5, a6 uintptr) uintptr {
241	// Leave caller's PC/SP around for traceback.
242	gp := getg()
243	var mp *m
244	if gp != nil {
245		mp = gp.m
246	}
247	if mp != nil && mp.libcallsp == 0 {
248		mp.libcallg.set(gp)
249		mp.libcallpc = getcallerpc()
250		// sp must be the last, because once async cpu profiler finds
251		// all three values to be non-zero, it will use them
252		mp.libcallsp = getcallersp()
253	} else {
254		mp = nil
255	}
256
257	var libcall libcall
258	libcall.fn = uintptr(unsafe.Pointer(fn))
259	libcall.n = 6
260	libcall.args = uintptr(noescape(unsafe.Pointer(&a1)))
261	asmcgocall(unsafe.Pointer(&asmsysvicall6x), unsafe.Pointer(&libcall))
262	if mp != nil {
263		mp.libcallsp = 0
264	}
265	return libcall.r1
266}
267