1// Copyright 2015 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
5// System calls and other sys.stuff for ARM64, Darwin
6// System calls are implemented in libSystem, this file contains
7// trampolines that convert from Go to C calling convention.
8
9#include "go_asm.h"
10#include "go_tls.h"
11#include "textflag.h"
12#include "cgo/abi_arm64.h"
13
14#define CLOCK_REALTIME		0
15
16TEXT notok<>(SB),NOSPLIT,$0
17	MOVD	$0, R8
18	MOVD	R8, (R8)
19	B	0(PC)
20
21TEXT runtime·open_trampoline(SB),NOSPLIT,$0
22	SUB	$16, RSP
23	MOVW	8(R0), R1	// arg 2 flags
24	MOVW	12(R0), R2	// arg 3 mode
25	MOVW	R2, (RSP)	// arg 3 is variadic, pass on stack
26	MOVD	0(R0), R0	// arg 1 pathname
27	BL	libc_open(SB)
28	ADD	$16, RSP
29	RET
30
31TEXT runtime·close_trampoline(SB),NOSPLIT,$0
32	MOVW	0(R0), R0	// arg 1 fd
33	BL	libc_close(SB)
34	RET
35
36TEXT runtime·write_trampoline(SB),NOSPLIT,$0
37	MOVD	8(R0), R1	// arg 2 buf
38	MOVW	16(R0), R2	// arg 3 count
39	MOVW	0(R0), R0	// arg 1 fd
40	BL	libc_write(SB)
41	MOVD	$-1, R1
42	CMP	R0, R1
43	BNE	noerr
44	BL	libc_error(SB)
45	MOVW	(R0), R0
46	NEG	R0, R0		// caller expects negative errno value
47noerr:
48	RET
49
50TEXT runtime·read_trampoline(SB),NOSPLIT,$0
51	MOVD	8(R0), R1	// arg 2 buf
52	MOVW	16(R0), R2	// arg 3 count
53	MOVW	0(R0), R0	// arg 1 fd
54	BL	libc_read(SB)
55	MOVD	$-1, R1
56	CMP	R0, R1
57	BNE	noerr
58	BL	libc_error(SB)
59	MOVW	(R0), R0
60	NEG	R0, R0		// caller expects negative errno value
61noerr:
62	RET
63
64TEXT runtime·pipe_trampoline(SB),NOSPLIT,$0
65	BL	libc_pipe(SB)	// pointer already in R0
66	CMP	$0, R0
67	BEQ	3(PC)
68	BL	libc_error(SB)	// return negative errno value
69	NEG	R0, R0
70	RET
71
72TEXT runtime·exit_trampoline(SB),NOSPLIT|NOFRAME,$0
73	MOVW	0(R0), R0
74	BL	libc_exit(SB)
75	MOVD	$1234, R0
76	MOVD	$1002, R1
77	MOVD	R0, (R1)	// fail hard
78
79TEXT runtime·raiseproc_trampoline(SB),NOSPLIT,$0
80	MOVD	0(R0), R19	// signal
81	BL	libc_getpid(SB)
82	// arg 1 pid already in R0 from getpid
83	MOVD	R19, R1	// arg 2 signal
84	BL	libc_kill(SB)
85	RET
86
87TEXT runtime·mmap_trampoline(SB),NOSPLIT,$0
88	MOVD	R0, R19
89	MOVD	0(R19), R0	// arg 1 addr
90	MOVD	8(R19), R1	// arg 2 len
91	MOVW	16(R19), R2	// arg 3 prot
92	MOVW	20(R19), R3	// arg 4 flags
93	MOVW	24(R19), R4	// arg 5 fd
94	MOVW	28(R19), R5	// arg 6 off
95	BL	libc_mmap(SB)
96	MOVD	$0, R1
97	MOVD	$-1, R2
98	CMP	R0, R2
99	BNE	ok
100	BL	libc_error(SB)
101	MOVW	(R0), R1
102	MOVD	$0, R0
103ok:
104	MOVD	R0, 32(R19) // ret 1 p
105	MOVD	R1, 40(R19)	// ret 2 err
106	RET
107
108TEXT runtime·munmap_trampoline(SB),NOSPLIT,$0
109	MOVD	8(R0), R1	// arg 2 len
110	MOVD	0(R0), R0	// arg 1 addr
111	BL	libc_munmap(SB)
112	CMP	$0, R0
113	BEQ	2(PC)
114	BL	notok<>(SB)
115	RET
116
117TEXT runtime·madvise_trampoline(SB),NOSPLIT,$0
118	MOVD	8(R0), R1	// arg 2 len
119	MOVW	16(R0), R2	// arg 3 advice
120	MOVD	0(R0), R0	// arg 1 addr
121	BL	libc_madvise(SB)
122	RET
123
124TEXT runtime·mlock_trampoline(SB),NOSPLIT,$0
125	MOVD	8(R0), R1	// arg 2 len
126	MOVD	0(R0), R0	// arg 1 addr
127	BL	libc_mlock(SB)
128	RET
129
130TEXT runtime·setitimer_trampoline(SB),NOSPLIT,$0
131	MOVD	8(R0), R1	// arg 2 new
132	MOVD	16(R0), R2	// arg 3 old
133	MOVW	0(R0), R0	// arg 1 which
134	BL	libc_setitimer(SB)
135	RET
136
137TEXT runtime·walltime_trampoline(SB),NOSPLIT,$0
138	MOVD	R0, R1			// arg 2 timespec
139	MOVW	$CLOCK_REALTIME, R0 	// arg 1 clock_id
140	BL	libc_clock_gettime(SB)
141	RET
142
143GLOBL timebase<>(SB),NOPTR,$(machTimebaseInfo__size)
144
145TEXT runtime·nanotime_trampoline(SB),NOSPLIT,$40
146	MOVD	R0, R19
147	BL	libc_mach_absolute_time(SB)
148	MOVD	R0, 0(R19)
149	MOVW	timebase<>+machTimebaseInfo_numer(SB), R20
150	MOVD	$timebase<>+machTimebaseInfo_denom(SB), R21
151	LDARW	(R21), R21	// atomic read
152	CMP	$0, R21
153	BNE	initialized
154
155	SUB	$(machTimebaseInfo__size+15)/16*16, RSP
156	MOVD	RSP, R0
157	BL	libc_mach_timebase_info(SB)
158	MOVW	machTimebaseInfo_numer(RSP), R20
159	MOVW	machTimebaseInfo_denom(RSP), R21
160	ADD	$(machTimebaseInfo__size+15)/16*16, RSP
161
162	MOVW	R20, timebase<>+machTimebaseInfo_numer(SB)
163	MOVD	$timebase<>+machTimebaseInfo_denom(SB), R22
164	STLRW	R21, (R22)	// atomic write
165
166initialized:
167	MOVW	R20, 8(R19)
168	MOVW	R21, 12(R19)
169	RET
170
171TEXT runtime·sigfwd(SB),NOSPLIT,$0-32
172	MOVW	sig+8(FP), R0
173	MOVD	info+16(FP), R1
174	MOVD	ctx+24(FP), R2
175	MOVD	fn+0(FP), R11
176	BL	(R11)
177	RET
178
179TEXT runtime·sigtramp(SB),NOSPLIT|TOPFRAME,$176
180	// Save callee-save registers in the case of signal forwarding.
181	// Please refer to https://golang.org/issue/31827 .
182	SAVE_R19_TO_R28(8*4)
183	SAVE_F8_TO_F15(8*14)
184
185	// Save arguments.
186	MOVW	R0, (8*1)(RSP)	// sig
187	MOVD	R1, (8*2)(RSP)	// info
188	MOVD	R2, (8*3)(RSP)	// ctx
189
190	// this might be called in external code context,
191	// where g is not set.
192	BL	runtime·load_g(SB)
193
194#ifdef GOOS_ios
195	MOVD	RSP, R6
196	CMP	$0, g
197	BEQ	nog
198	// iOS always use the main stack to run the signal handler.
199	// We need to switch to gsignal ourselves.
200	MOVD	g_m(g), R11
201	MOVD	m_gsignal(R11), R5
202	MOVD	(g_stack+stack_hi)(R5), R6
203
204nog:
205	// Restore arguments.
206	MOVW	(8*1)(RSP), R0
207	MOVD	(8*2)(RSP), R1
208	MOVD	(8*3)(RSP), R2
209
210	// Reserve space for args and the stack pointer on the
211	// gsignal stack.
212	SUB	$48, R6
213	// Save stack pointer.
214	MOVD	RSP, R4
215	MOVD	R4, (8*4)(R6)
216	// Switch to gsignal stack.
217	MOVD	R6, RSP
218
219	// Save arguments.
220	MOVW	R0, (8*1)(RSP)
221	MOVD	R1, (8*2)(RSP)
222	MOVD	R2, (8*3)(RSP)
223#endif
224
225	// Call sigtrampgo.
226	MOVD	$runtime·sigtrampgo(SB), R11
227	BL	(R11)
228
229#ifdef GOOS_ios
230	// Switch to old stack.
231	MOVD	(8*4)(RSP), R5
232	MOVD	R5, RSP
233#endif
234
235	// Restore callee-save registers.
236	RESTORE_R19_TO_R28(8*4)
237	RESTORE_F8_TO_F15(8*14)
238
239	RET
240
241TEXT runtime·cgoSigtramp(SB),NOSPLIT,$0
242	JMP	runtime·sigtramp(SB)
243
244TEXT runtime·sigprocmask_trampoline(SB),NOSPLIT,$0
245	MOVD	8(R0), R1	// arg 2 new
246	MOVD	16(R0), R2	// arg 3 old
247	MOVW	0(R0), R0	// arg 1 how
248	BL	libc_pthread_sigmask(SB)
249	CMP	$0, R0
250	BEQ	2(PC)
251	BL	notok<>(SB)
252	RET
253
254TEXT runtime·sigaction_trampoline(SB),NOSPLIT,$0
255	MOVD	8(R0), R1	// arg 2 new
256	MOVD	16(R0), R2	// arg 3 old
257	MOVW	0(R0), R0	// arg 1 how
258	BL	libc_sigaction(SB)
259	CMP	$0, R0
260	BEQ	2(PC)
261	BL	notok<>(SB)
262	RET
263
264TEXT runtime·usleep_trampoline(SB),NOSPLIT,$0
265	MOVW	0(R0), R0	// arg 1 usec
266	BL	libc_usleep(SB)
267	RET
268
269TEXT runtime·sysctl_trampoline(SB),NOSPLIT,$0
270	MOVW	8(R0), R1	// arg 2 miblen
271	MOVD	16(R0), R2	// arg 3 oldp
272	MOVD	24(R0), R3	// arg 4 oldlenp
273	MOVD	32(R0), R4	// arg 5 newp
274	MOVD	40(R0), R5	// arg 6 newlen
275	MOVD	0(R0), R0	// arg 1 mib
276	BL	libc_sysctl(SB)
277	RET
278
279TEXT runtime·sysctlbyname_trampoline(SB),NOSPLIT,$0
280	MOVD	8(R0), R1	// arg 2 oldp
281	MOVD	16(R0), R2	// arg 3 oldlenp
282	MOVD	24(R0), R3	// arg 4 newp
283	MOVD	32(R0), R4	// arg 5 newlen
284	MOVD	0(R0), R0	// arg 1 name
285	BL	libc_sysctlbyname(SB)
286	RET
287
288
289TEXT runtime·kqueue_trampoline(SB),NOSPLIT,$0
290	BL	libc_kqueue(SB)
291	RET
292
293TEXT runtime·kevent_trampoline(SB),NOSPLIT,$0
294	MOVD	8(R0), R1	// arg 2 keventt
295	MOVW	16(R0), R2	// arg 3 nch
296	MOVD	24(R0), R3	// arg 4 ev
297	MOVW	32(R0), R4	// arg 5 nev
298	MOVD	40(R0), R5	// arg 6 ts
299	MOVW	0(R0), R0	// arg 1 kq
300	BL	libc_kevent(SB)
301	MOVD	$-1, R2
302	CMP	R0, R2
303	BNE	ok
304	BL	libc_error(SB)
305	MOVW	(R0), R0	// errno
306	NEG	R0, R0	// caller wants it as a negative error code
307ok:
308	RET
309
310TEXT runtime·fcntl_trampoline(SB),NOSPLIT,$0
311	SUB	$16, RSP
312	MOVD	R0, R19
313	MOVW	0(R19), R0	// arg 1 fd
314	MOVW	4(R19), R1	// arg 2 cmd
315	MOVW	8(R19), R2	// arg 3 arg
316	MOVW	R2, (RSP)	// arg 3 is variadic, pass on stack
317	BL	libc_fcntl(SB)
318	MOVD	$0, R1
319	MOVD	$-1, R2
320	CMP	R0, R2
321	BNE	noerr
322	BL	libc_error(SB)
323	MOVW	(R0), R1
324	MOVW	$-1, R0
325noerr:
326	MOVW	R0, 12(R19)
327	MOVW	R1, 16(R19)
328	ADD	$16, RSP
329	RET
330
331TEXT runtime·sigaltstack_trampoline(SB),NOSPLIT,$0
332#ifdef GOOS_ios
333	// sigaltstack on iOS is not supported and will always
334	// run the signal handler on the main stack, so our sigtramp has
335	// to do the stack switch ourselves.
336	MOVW	$43, R0
337	BL	libc_exit(SB)
338#else
339	MOVD	8(R0), R1		// arg 2 old
340	MOVD	0(R0), R0		// arg 1 new
341	CALL	libc_sigaltstack(SB)
342	CBZ	R0, 2(PC)
343	BL	notok<>(SB)
344#endif
345	RET
346
347// Thread related functions
348
349// mstart_stub is the first function executed on a new thread started by pthread_create.
350// It just does some low-level setup and then calls mstart.
351// Note: called with the C calling convention.
352TEXT runtime·mstart_stub(SB),NOSPLIT,$160
353	// R0 points to the m.
354	// We are already on m's g0 stack.
355
356	// Save callee-save registers.
357	SAVE_R19_TO_R28(8)
358	SAVE_F8_TO_F15(88)
359
360	MOVD	m_g0(R0), g
361	BL	·save_g(SB)
362
363	BL	runtime·mstart(SB)
364
365	// Restore callee-save registers.
366	RESTORE_R19_TO_R28(8)
367	RESTORE_F8_TO_F15(88)
368
369	// Go is all done with this OS thread.
370	// Tell pthread everything is ok (we never join with this thread, so
371	// the value here doesn't really matter).
372	MOVD	$0, R0
373
374	RET
375
376TEXT runtime·pthread_attr_init_trampoline(SB),NOSPLIT,$0
377	MOVD	0(R0), R0	// arg 1 attr
378	BL	libc_pthread_attr_init(SB)
379	RET
380
381TEXT runtime·pthread_attr_getstacksize_trampoline(SB),NOSPLIT,$0
382	MOVD	8(R0), R1	// arg 2 size
383	MOVD	0(R0), R0	// arg 1 attr
384	BL	libc_pthread_attr_getstacksize(SB)
385	RET
386
387TEXT runtime·pthread_attr_setdetachstate_trampoline(SB),NOSPLIT,$0
388	MOVD	8(R0), R1	// arg 2 state
389	MOVD	0(R0), R0	// arg 1 attr
390	BL	libc_pthread_attr_setdetachstate(SB)
391	RET
392
393TEXT runtime·pthread_create_trampoline(SB),NOSPLIT,$0
394	SUB	$16, RSP
395	MOVD	0(R0), R1	// arg 2 state
396	MOVD	8(R0), R2	// arg 3 start
397	MOVD	16(R0), R3	// arg 4 arg
398	MOVD	RSP, R0 	// arg 1 &threadid (which we throw away)
399	BL	libc_pthread_create(SB)
400	ADD	$16, RSP
401	RET
402
403TEXT runtime·raise_trampoline(SB),NOSPLIT,$0
404	MOVW	0(R0), R0	// arg 1 sig
405	BL	libc_raise(SB)
406	RET
407
408TEXT runtime·pthread_mutex_init_trampoline(SB),NOSPLIT,$0
409	MOVD	8(R0), R1	// arg 2 attr
410	MOVD	0(R0), R0	// arg 1 mutex
411	BL	libc_pthread_mutex_init(SB)
412	RET
413
414TEXT runtime·pthread_mutex_lock_trampoline(SB),NOSPLIT,$0
415	MOVD	0(R0), R0	// arg 1 mutex
416	BL	libc_pthread_mutex_lock(SB)
417	RET
418
419TEXT runtime·pthread_mutex_unlock_trampoline(SB),NOSPLIT,$0
420	MOVD	0(R0), R0	// arg 1 mutex
421	BL	libc_pthread_mutex_unlock(SB)
422	RET
423
424TEXT runtime·pthread_cond_init_trampoline(SB),NOSPLIT,$0
425	MOVD	8(R0), R1	// arg 2 attr
426	MOVD	0(R0), R0	// arg 1 cond
427	BL	libc_pthread_cond_init(SB)
428	RET
429
430TEXT runtime·pthread_cond_wait_trampoline(SB),NOSPLIT,$0
431	MOVD	8(R0), R1	// arg 2 mutex
432	MOVD	0(R0), R0	// arg 1 cond
433	BL	libc_pthread_cond_wait(SB)
434	RET
435
436TEXT runtime·pthread_cond_timedwait_relative_np_trampoline(SB),NOSPLIT,$0
437	MOVD	8(R0), R1	// arg 2 mutex
438	MOVD	16(R0), R2	// arg 3 timeout
439	MOVD	0(R0), R0	// arg 1 cond
440	BL	libc_pthread_cond_timedwait_relative_np(SB)
441	RET
442
443TEXT runtime·pthread_cond_signal_trampoline(SB),NOSPLIT,$0
444	MOVD	0(R0), R0	// arg 1 cond
445	BL	libc_pthread_cond_signal(SB)
446	RET
447
448TEXT runtime·pthread_self_trampoline(SB),NOSPLIT,$0
449	MOVD	R0, R19		// R19 is callee-save
450	BL	libc_pthread_self(SB)
451	MOVD	R0, 0(R19)	// return value
452	RET
453
454TEXT runtime·pthread_kill_trampoline(SB),NOSPLIT,$0
455	MOVD	8(R0), R1	// arg 2 sig
456	MOVD	0(R0), R0	// arg 1 thread
457	BL	libc_pthread_kill(SB)
458	RET
459
460TEXT runtime·pthread_key_create_trampoline(SB),NOSPLIT,$0
461	MOVD	8(R0), R1	// arg 2 destructor
462	MOVD	0(R0), R0	// arg 1 *key
463	BL	libc_pthread_key_create(SB)
464	RET
465
466TEXT runtime·pthread_setspecific_trampoline(SB),NOSPLIT,$0
467	MOVD	8(R0), R1	// arg 2 value
468	MOVD	0(R0), R0	// arg 1 key
469	BL	libc_pthread_setspecific(SB)
470	RET
471
472TEXT runtime·osinit_hack_trampoline(SB),NOSPLIT,$0
473	MOVD	$0, R0	// arg 1 val
474	BL	libc_notify_is_valid_token(SB)
475	BL	libc_xpc_date_create_from_current(SB)
476	RET
477
478// syscall calls a function in libc on behalf of the syscall package.
479// syscall takes a pointer to a struct like:
480// struct {
481//	fn    uintptr
482//	a1    uintptr
483//	a2    uintptr
484//	a3    uintptr
485//	r1    uintptr
486//	r2    uintptr
487//	err   uintptr
488// }
489// syscall must be called on the g0 stack with the
490// C calling convention (use libcCall).
491TEXT runtime·syscall(SB),NOSPLIT,$0
492	SUB	$16, RSP	// push structure pointer
493	MOVD	R0, 8(RSP)
494
495	MOVD	0(R0), R12	// fn
496	MOVD	16(R0), R1	// a2
497	MOVD	24(R0), R2	// a3
498	MOVD	8(R0), R0	// a1
499
500	// If fn is declared as vararg, we have to pass the vararg arguments on the stack.
501	// (Because ios decided not to adhere to the standard arm64 calling convention, sigh...)
502	// The only libSystem calls we support that are vararg are open, fcntl, and ioctl,
503	// which are all of the form fn(x, y, ...). So we just need to put the 3rd arg
504	// on the stack as well.
505	// If we ever have other vararg libSystem calls, we might need to handle more cases.
506	MOVD	R2, (RSP)
507
508	BL	(R12)
509
510	MOVD	8(RSP), R2	// pop structure pointer
511	ADD	$16, RSP
512	MOVD	R0, 32(R2)	// save r1
513	MOVD	R1, 40(R2)	// save r2
514	CMPW	$-1, R0
515	BNE	ok
516	SUB	$16, RSP	// push structure pointer
517	MOVD	R2, 8(RSP)
518	BL	libc_error(SB)
519	MOVW	(R0), R0
520	MOVD	8(RSP), R2	// pop structure pointer
521	ADD	$16, RSP
522	MOVD	R0, 48(R2)	// save err
523ok:
524	RET
525
526// syscallX calls a function in libc on behalf of the syscall package.
527// syscallX takes a pointer to a struct like:
528// struct {
529//	fn    uintptr
530//	a1    uintptr
531//	a2    uintptr
532//	a3    uintptr
533//	r1    uintptr
534//	r2    uintptr
535//	err   uintptr
536// }
537// syscallX must be called on the g0 stack with the
538// C calling convention (use libcCall).
539TEXT runtime·syscallX(SB),NOSPLIT,$0
540	SUB	$16, RSP	// push structure pointer
541	MOVD	R0, (RSP)
542
543	MOVD	0(R0), R12	// fn
544	MOVD	16(R0), R1	// a2
545	MOVD	24(R0), R2	// a3
546	MOVD	8(R0), R0	// a1
547	BL	(R12)
548
549	MOVD	(RSP), R2	// pop structure pointer
550	ADD	$16, RSP
551	MOVD	R0, 32(R2)	// save r1
552	MOVD	R1, 40(R2)	// save r2
553	CMP	$-1, R0
554	BNE	ok
555	SUB	$16, RSP	// push structure pointer
556	MOVD	R2, (RSP)
557	BL	libc_error(SB)
558	MOVW	(R0), R0
559	MOVD	(RSP), R2	// pop structure pointer
560	ADD	$16, RSP
561	MOVD	R0, 48(R2)	// save err
562ok:
563	RET
564
565// syscallPtr is like syscallX except that the libc function reports an
566// error by returning NULL and setting errno.
567TEXT runtime·syscallPtr(SB),NOSPLIT,$0
568	SUB	$16, RSP	// push structure pointer
569	MOVD	R0, (RSP)
570
571	MOVD	0(R0), R12	// fn
572	MOVD	16(R0), R1	// a2
573	MOVD	24(R0), R2	// a3
574	MOVD	8(R0), R0	// a1
575	BL	(R12)
576
577	MOVD	(RSP), R2	// pop structure pointer
578	ADD	$16, RSP
579	MOVD	R0, 32(R2)	// save r1
580	MOVD	R1, 40(R2)	// save r2
581	CMP	$0, R0
582	BNE	ok
583	SUB	$16, RSP	// push structure pointer
584	MOVD	R2, (RSP)
585	BL	libc_error(SB)
586	MOVW	(R0), R0
587	MOVD	(RSP), R2	// pop structure pointer
588	ADD	$16, RSP
589	MOVD	R0, 48(R2)	// save err
590ok:
591	RET
592
593// syscall6 calls a function in libc on behalf of the syscall package.
594// syscall6 takes a pointer to a struct like:
595// struct {
596//	fn    uintptr
597//	a1    uintptr
598//	a2    uintptr
599//	a3    uintptr
600//	a4    uintptr
601//	a5    uintptr
602//	a6    uintptr
603//	r1    uintptr
604//	r2    uintptr
605//	err   uintptr
606// }
607// syscall6 must be called on the g0 stack with the
608// C calling convention (use libcCall).
609TEXT runtime·syscall6(SB),NOSPLIT,$0
610	SUB	$16, RSP	// push structure pointer
611	MOVD	R0, 8(RSP)
612
613	MOVD	0(R0), R12	// fn
614	MOVD	16(R0), R1	// a2
615	MOVD	24(R0), R2	// a3
616	MOVD	32(R0), R3	// a4
617	MOVD	40(R0), R4	// a5
618	MOVD	48(R0), R5	// a6
619	MOVD	8(R0), R0	// a1
620
621	// If fn is declared as vararg, we have to pass the vararg arguments on the stack.
622	// See syscall above. The only function this applies to is openat, for which the 4th
623	// arg must be on the stack.
624	MOVD	R3, (RSP)
625
626	BL	(R12)
627
628	MOVD	8(RSP), R2	// pop structure pointer
629	ADD	$16, RSP
630	MOVD	R0, 56(R2)	// save r1
631	MOVD	R1, 64(R2)	// save r2
632	CMPW	$-1, R0
633	BNE	ok
634	SUB	$16, RSP	// push structure pointer
635	MOVD	R2, 8(RSP)
636	BL	libc_error(SB)
637	MOVW	(R0), R0
638	MOVD	8(RSP), R2	// pop structure pointer
639	ADD	$16, RSP
640	MOVD	R0, 72(R2)	// save err
641ok:
642	RET
643
644// syscall6X calls a function in libc on behalf of the syscall package.
645// syscall6X takes a pointer to a struct like:
646// struct {
647//	fn    uintptr
648//	a1    uintptr
649//	a2    uintptr
650//	a3    uintptr
651//	a4    uintptr
652//	a5    uintptr
653//	a6    uintptr
654//	r1    uintptr
655//	r2    uintptr
656//	err   uintptr
657// }
658// syscall6X must be called on the g0 stack with the
659// C calling convention (use libcCall).
660TEXT runtime·syscall6X(SB),NOSPLIT,$0
661	SUB	$16, RSP	// push structure pointer
662	MOVD	R0, (RSP)
663
664	MOVD	0(R0), R12	// fn
665	MOVD	16(R0), R1	// a2
666	MOVD	24(R0), R2	// a3
667	MOVD	32(R0), R3	// a4
668	MOVD	40(R0), R4	// a5
669	MOVD	48(R0), R5	// a6
670	MOVD	8(R0), R0	// a1
671	BL	(R12)
672
673	MOVD	(RSP), R2	// pop structure pointer
674	ADD	$16, RSP
675	MOVD	R0, 56(R2)	// save r1
676	MOVD	R1, 64(R2)	// save r2
677	CMP	$-1, R0
678	BNE	ok
679	SUB	$16, RSP	// push structure pointer
680	MOVD	R2, (RSP)
681	BL	libc_error(SB)
682	MOVW	(R0), R0
683	MOVD	(RSP), R2	// pop structure pointer
684	ADD	$16, RSP
685	MOVD	R0, 72(R2)	// save err
686ok:
687	RET
688
689// syscall9 calls a function in libc on behalf of the syscall package.
690// syscall9 takes a pointer to a struct like:
691// struct {
692//	fn    uintptr
693//	a1    uintptr
694//	a2    uintptr
695//	a3    uintptr
696//	a4    uintptr
697//	a5    uintptr
698//	a6    uintptr
699//	a7    uintptr
700//	a8    uintptr
701//	a9    uintptr
702//	r1    uintptr
703//	r2    uintptr
704//	err   uintptr
705// }
706// syscall9 must be called on the g0 stack with the
707// C calling convention (use libcCall).
708TEXT runtime·syscall9(SB),NOSPLIT,$0
709	SUB	$16, RSP	// push structure pointer
710	MOVD	R0, 8(RSP)
711
712	MOVD	0(R0), R12	// fn
713	MOVD	16(R0), R1	// a2
714	MOVD	24(R0), R2	// a3
715	MOVD	32(R0), R3	// a4
716	MOVD	40(R0), R4	// a5
717	MOVD	48(R0), R5	// a6
718	MOVD	56(R0), R6	// a7
719	MOVD	64(R0), R7	// a8
720	MOVD	72(R0), R8	// a9
721	MOVD	8(R0), R0	// a1
722
723	// If fn is declared as vararg, we have to pass the vararg arguments on the stack.
724	// See syscall above. The only function this applies to is openat, for which the 4th
725	// arg must be on the stack.
726	MOVD	R3, (RSP)
727
728	BL	(R12)
729
730	MOVD	8(RSP), R2	// pop structure pointer
731	ADD	$16, RSP
732	MOVD	R0, 80(R2)	// save r1
733	MOVD	R1, 88(R2)	// save r2
734	CMPW	$-1, R0
735	BNE	ok
736	SUB	$16, RSP	// push structure pointer
737	MOVD	R2, 8(RSP)
738	BL	libc_error(SB)
739	MOVW	(R0), R0
740	MOVD	8(RSP), R2	// pop structure pointer
741	ADD	$16, RSP
742	MOVD	R0, 96(R2)	// save err
743ok:
744	RET
745
746// syscall_x509 is for crypto/x509. It is like syscall6 but does not check for errors,
747// takes 5 uintptrs and 1 float64, and only returns one value,
748// for use with standard C ABI functions.
749TEXT runtime·syscall_x509(SB),NOSPLIT,$0
750	SUB	$16, RSP	// push structure pointer
751	MOVD	R0, (RSP)
752
753	MOVD	0(R0), R12	// fn
754	MOVD	16(R0), R1	// a2
755	MOVD	24(R0), R2	// a3
756	MOVD	32(R0), R3	// a4
757	MOVD	40(R0), R4	// a5
758	FMOVD	48(R0), F0	// f1
759	MOVD	8(R0), R0	// a1
760	BL	(R12)
761
762	MOVD	(RSP), R2	// pop structure pointer
763	ADD	$16, RSP
764	MOVD	R0, 56(R2)	// save r1
765	RET
766
767TEXT runtime·issetugid_trampoline(SB),NOSPLIT,$0
768	BL	libc_issetugid(SB)
769	RET
770
771// mach_vm_region_trampoline calls mach_vm_region from libc.
772TEXT runtime·mach_vm_region_trampoline(SB),NOSPLIT,$0
773	MOVD	0(R0), R1	// address
774	MOVD	8(R0), R2	// size
775	MOVW	16(R0), R3	// flavor
776	MOVD	24(R0), R4	// info
777	MOVD	32(R0), R5	// count
778	MOVD	40(R0), R6  // object_name
779	MOVD	$libc_mach_task_self_(SB), R0
780	MOVW	0(R0), R0
781	BL	libc_mach_vm_region(SB)
782	RET
783
784// proc_regionfilename_trampoline calls proc_regionfilename for
785// the current process.
786TEXT runtime·proc_regionfilename_trampoline(SB),NOSPLIT,$0
787	MOVD	8(R0), R1	// address
788	MOVD	16(R0), R2	// buffer
789	MOVD	24(R0), R3	// buffer_size
790	MOVD	0(R0), R0 // pid
791	BL	libc_proc_regionfilename(SB)
792	RET
793