1// Copyright 2019 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, OpenBSD
6// System calls are implemented in libc/libpthread, this file
7// contains trampolines that convert from Go to C calling convention.
8// Some direct system call implementations currently remain.
9//
10
11#include "go_asm.h"
12#include "go_tls.h"
13#include "textflag.h"
14#include "cgo/abi_arm64.h"
15
16#define CLOCK_REALTIME	$0
17#define	CLOCK_MONOTONIC	$3
18
19// mstart_stub is the first function executed on a new thread started by pthread_create.
20// It just does some low-level setup and then calls mstart.
21// Note: called with the C calling convention.
22TEXT runtime·mstart_stub(SB),NOSPLIT,$144
23	// R0 points to the m.
24	// We are already on m's g0 stack.
25
26	// Save callee-save registers.
27	SAVE_R19_TO_R28(8)
28	SAVE_F8_TO_F15(88)
29
30	MOVD    m_g0(R0), g
31	BL	runtime·save_g(SB)
32
33	BL	runtime·mstart(SB)
34
35	// Restore callee-save registers.
36	RESTORE_R19_TO_R28(8)
37	RESTORE_F8_TO_F15(88)
38
39	// Go is all done with this OS thread.
40	// Tell pthread everything is ok (we never join with this thread, so
41	// the value here doesn't really matter).
42	MOVD	$0, R0
43
44	RET
45
46TEXT runtime·sigfwd(SB),NOSPLIT,$0-32
47	MOVW	sig+8(FP), R0
48	MOVD	info+16(FP), R1
49	MOVD	ctx+24(FP), R2
50	MOVD	fn+0(FP), R11
51	BL	(R11)			// Alignment for ELF ABI?
52	RET
53
54TEXT runtime·sigtramp(SB),NOSPLIT|TOPFRAME,$192
55	// Save callee-save registers in the case of signal forwarding.
56	// Please refer to https://golang.org/issue/31827 .
57	SAVE_R19_TO_R28(8*4)
58	SAVE_F8_TO_F15(8*14)
59
60	// If called from an external code context, g will not be set.
61	// Save R0, since runtime·load_g will clobber it.
62	MOVW	R0, 8(RSP)		// signum
63	BL	runtime·load_g(SB)
64
65	// Restore signum to R0.
66	MOVW	8(RSP), R0
67	// R1 and R2 already contain info and ctx, respectively.
68	BL	runtime·sigtrampgo<ABIInternal>(SB)
69
70	// Restore callee-save registers.
71	RESTORE_R19_TO_R28(8*4)
72	RESTORE_F8_TO_F15(8*14)
73
74	RET
75
76//
77// These trampolines help convert from Go calling convention to C calling convention.
78// They should be called with asmcgocall.
79// A pointer to the arguments is passed in R0.
80// A single int32 result is returned in R0.
81// (For more results, make an args/results structure.)
82TEXT runtime·pthread_attr_init_trampoline(SB),NOSPLIT,$0
83	MOVD	0(R0), R0		// arg 1 - attr
84	CALL	libc_pthread_attr_init(SB)
85	RET
86
87TEXT runtime·pthread_attr_destroy_trampoline(SB),NOSPLIT,$0
88	MOVD	0(R0), R0		// arg 1 - attr
89	CALL	libc_pthread_attr_destroy(SB)
90	RET
91
92TEXT runtime·pthread_attr_getstacksize_trampoline(SB),NOSPLIT,$0
93	MOVD	8(R0), R1		// arg 2 - size
94	MOVD	0(R0), R0		// arg 1 - attr
95	CALL	libc_pthread_attr_getstacksize(SB)
96	RET
97
98TEXT runtime·pthread_attr_setdetachstate_trampoline(SB),NOSPLIT,$0
99	MOVD	8(R0), R1		// arg 2 - state
100	MOVD	0(R0), R0		// arg 1 - attr
101	CALL	libc_pthread_attr_setdetachstate(SB)
102	RET
103
104TEXT runtime·pthread_create_trampoline(SB),NOSPLIT,$0
105	MOVD	0(R0), R1		// arg 2 - attr
106	MOVD	8(R0), R2		// arg 3 - start
107	MOVD	16(R0), R3		// arg 4 - arg
108	SUB	$16, RSP
109	MOVD	RSP, R0			// arg 1 - &threadid (discard)
110	CALL	libc_pthread_create(SB)
111	ADD	$16, RSP
112	RET
113
114TEXT runtime·thrkill_trampoline(SB),NOSPLIT,$0
115	MOVW	8(R0), R1		// arg 2 - signal
116	MOVD	$0, R2			// arg 3 - tcb
117	MOVW	0(R0), R0		// arg 1 - tid
118	CALL	libc_thrkill(SB)
119	RET
120
121TEXT runtime·thrsleep_trampoline(SB),NOSPLIT,$0
122	MOVW	8(R0), R1		// arg 2 - clock_id
123	MOVD	16(R0), R2		// arg 3 - abstime
124	MOVD	24(R0), R3		// arg 4 - lock
125	MOVD	32(R0), R4		// arg 5 - abort
126	MOVD	0(R0), R0		// arg 1 - id
127	CALL	libc_thrsleep(SB)
128	RET
129
130TEXT runtime·thrwakeup_trampoline(SB),NOSPLIT,$0
131	MOVW	8(R0), R1		// arg 2 - count
132	MOVD	0(R0), R0		// arg 1 - id
133	CALL	libc_thrwakeup(SB)
134	RET
135
136TEXT runtime·exit_trampoline(SB),NOSPLIT,$0
137	MOVW	0(R0), R0		// arg 1 - status
138	CALL	libc_exit(SB)
139	MOVD	$0, R0			// crash on failure
140	MOVD	R0, (R0)
141	RET
142
143TEXT runtime·getthrid_trampoline(SB),NOSPLIT,$0
144	MOVD	R0, R19			// pointer to args
145	CALL	libc_getthrid(SB)
146	MOVW	R0, 0(R19)		// return value
147	RET
148
149TEXT runtime·raiseproc_trampoline(SB),NOSPLIT,$0
150	MOVD	R0, R19			// pointer to args
151	CALL	libc_getpid(SB)		// arg 1 - pid
152	MOVW	0(R19), R1		// arg 2 - signal
153	CALL	libc_kill(SB)
154	RET
155
156TEXT runtime·sched_yield_trampoline(SB),NOSPLIT,$0
157	CALL	libc_sched_yield(SB)
158	RET
159
160TEXT runtime·mmap_trampoline(SB),NOSPLIT,$0
161	MOVD    R0, R19			// pointer to args
162	MOVD	0(R19), R0		// arg 1 - addr
163	MOVD	8(R19), R1		// arg 2 - len
164	MOVW	16(R19), R2		// arg 3 - prot
165	MOVW	20(R19), R3		// arg 4 - flags
166	MOVW	24(R19), R4		// arg 5 - fid
167	MOVW	28(R19), R5		// arg 6 - offset
168	CALL	libc_mmap(SB)
169	MOVD	$0, R1
170	CMP	$-1, R0
171	BNE	noerr
172	CALL	libc_errno(SB)
173	MOVW	(R0), R1		// errno
174	MOVD	$0, R0
175noerr:
176	MOVD	R0, 32(R19)
177	MOVD	R1, 40(R19)
178	RET
179
180TEXT runtime·munmap_trampoline(SB),NOSPLIT,$0
181	MOVD	8(R0), R1		// arg 2 - len
182	MOVD	0(R0), R0		// arg 1 - addr
183	CALL	libc_munmap(SB)
184	CMP	$-1, R0
185	BNE	3(PC)
186	MOVD	$0, R0			// crash on failure
187	MOVD	R0, (R0)
188	RET
189
190TEXT runtime·madvise_trampoline(SB), NOSPLIT, $0
191	MOVD	8(R0), R1		// arg 2 - len
192	MOVW	16(R0), R2		// arg 3 - advice
193	MOVD	0(R0), R0		// arg 1 - addr
194	CALL	libc_madvise(SB)
195	// ignore failure - maybe pages are locked
196	RET
197
198TEXT runtime·open_trampoline(SB),NOSPLIT,$0
199	MOVW	8(R0), R1		// arg 2 - flags
200	MOVW	12(R0), R2		// arg 3 - mode
201	MOVD	0(R0), R0		// arg 1 - path
202	MOVD	$0, R3			// varargs
203	CALL	libc_open(SB)
204	RET
205
206TEXT runtime·close_trampoline(SB),NOSPLIT,$0
207	MOVD	0(R0), R0		// arg 1 - fd
208	CALL	libc_close(SB)
209	RET
210
211TEXT runtime·read_trampoline(SB),NOSPLIT,$0
212	MOVD	8(R0), R1		// arg 2 - buf
213	MOVW	16(R0), R2		// arg 3 - count
214	MOVW	0(R0), R0		// arg 1 - fd
215	CALL	libc_read(SB)
216	CMP	$-1, R0
217	BNE	noerr
218	CALL	libc_errno(SB)
219	MOVW	(R0), R0		// errno
220	NEG	R0, R0			// caller expects negative errno value
221noerr:
222	RET
223
224TEXT runtime·write_trampoline(SB),NOSPLIT,$0
225	MOVD	8(R0), R1		// arg 2 - buf
226	MOVW	16(R0), R2		// arg 3 - count
227	MOVW	0(R0), R0		// arg 1 - fd
228	CALL	libc_write(SB)
229	CMP	$-1, R0
230	BNE	noerr
231	CALL	libc_errno(SB)
232	MOVW	(R0), R0		// errno
233	NEG	R0, R0			// caller expects negative errno value
234noerr:
235	RET
236
237TEXT runtime·pipe2_trampoline(SB),NOSPLIT,$0
238	MOVW	8(R0), R1		// arg 2 - flags
239	MOVD	0(R0), R0		// arg 1 - filedes
240	CALL	libc_pipe2(SB)
241	CMP	$-1, R0
242	BNE	noerr
243	CALL	libc_errno(SB)
244	MOVW	(R0), R0		// errno
245	NEG	R0, R0			// caller expects negative errno value
246noerr:
247	RET
248
249TEXT runtime·setitimer_trampoline(SB),NOSPLIT,$0
250	MOVD	8(R0), R1		// arg 2 - new
251	MOVD	16(R0), R2		// arg 3 - old
252	MOVW	0(R0), R0		// arg 1 - which
253	CALL	libc_setitimer(SB)
254	RET
255
256TEXT runtime·usleep_trampoline(SB),NOSPLIT,$0
257	MOVD	0(R0), R0		// arg 1 - usec
258	CALL	libc_usleep(SB)
259	RET
260
261TEXT runtime·sysctl_trampoline(SB),NOSPLIT,$0
262	MOVW	8(R0), R1		// arg 2 - miblen
263	MOVD	16(R0), R2		// arg 3 - out
264	MOVD	24(R0), R3		// arg 4 - size
265	MOVD	32(R0), R4		// arg 5 - dst
266	MOVD	40(R0), R5		// arg 6 - ndst
267	MOVD	0(R0), R0		// arg 1 - mib
268	CALL	libc_sysctl(SB)
269	RET
270
271TEXT runtime·kqueue_trampoline(SB),NOSPLIT,$0
272	CALL	libc_kqueue(SB)
273	RET
274
275TEXT runtime·kevent_trampoline(SB),NOSPLIT,$0
276	MOVD	8(R0), R1		// arg 2 - keventt
277	MOVW	16(R0), R2		// arg 3 - nch
278	MOVD	24(R0), R3		// arg 4 - ev
279	MOVW	32(R0), R4		// arg 5 - nev
280	MOVD	40(R0), R5		// arg 6 - ts
281	MOVW	0(R0), R0		// arg 1 - kq
282	CALL	libc_kevent(SB)
283	CMP	$-1, R0
284	BNE	noerr
285	CALL	libc_errno(SB)
286	MOVW	(R0), R0		// errno
287	NEG	R0, R0			// caller expects negative errno value
288noerr:
289	RET
290
291TEXT runtime·clock_gettime_trampoline(SB),NOSPLIT,$0
292	MOVD	8(R0), R1		// arg 2 - tp
293	MOVD	0(R0), R0		// arg 1 - clock_id
294	CALL	libc_clock_gettime(SB)
295	CMP	$-1, R0
296	BNE	noerr
297	CALL	libc_errno(SB)
298	MOVW	(R0), R0		// errno
299	NEG	R0, R0			// caller expects negative errno value
300noerr:
301	RET
302
303TEXT runtime·fcntl_trampoline(SB),NOSPLIT,$0
304	MOVD	R0, R19
305	MOVW	0(R19), R0		// arg 1 - fd
306	MOVW	4(R19), R1		// arg 2 - cmd
307	MOVW	8(R19), R2		// arg 3 - arg
308	MOVD	$0, R3			// vararg
309	CALL	libc_fcntl(SB)
310	MOVD	$0, R1
311	CMP	$-1, R0
312	BNE	noerr
313	CALL	libc_errno(SB)
314	MOVW	(R0), R1
315	MOVW	$-1, R0
316noerr:
317	MOVW	R0, 12(R19)
318	MOVW	R1, 16(R19)
319	RET
320
321TEXT runtime·sigaction_trampoline(SB),NOSPLIT,$0
322	MOVD	8(R0), R1		// arg 2 - new
323	MOVD	16(R0), R2		// arg 3 - old
324	MOVW	0(R0), R0		// arg 1 - sig
325	CALL	libc_sigaction(SB)
326	CMP	$-1, R0
327	BNE	3(PC)
328	MOVD	$0, R0			// crash on syscall failure
329	MOVD	R0, (R0)
330	RET
331
332TEXT runtime·sigprocmask_trampoline(SB),NOSPLIT,$0
333	MOVD	8(R0), R1		// arg 2 - new
334	MOVD	16(R0), R2		// arg 3 - old
335	MOVW	0(R0), R0		// arg 1 - how
336	CALL	libc_pthread_sigmask(SB)
337	CMP	$-1, R0
338	BNE	3(PC)
339	MOVD	$0, R0			// crash on syscall failure
340	MOVD	R0, (R0)
341	RET
342
343TEXT runtime·sigaltstack_trampoline(SB),NOSPLIT,$0
344	MOVD	8(R0), R1		// arg 2 - old
345	MOVD	0(R0), R0		// arg 1 - new
346	CALL	libc_sigaltstack(SB)
347	CMP	$-1, R0
348	BNE	3(PC)
349	MOVD	$0, R0			// crash on syscall failure
350	MOVD	R0, (R0)
351	RET
352
353// syscall calls a function in libc on behalf of the syscall package.
354// syscall takes a pointer to a struct like:
355// struct {
356//	fn    uintptr
357//	a1    uintptr
358//	a2    uintptr
359//	a3    uintptr
360//	r1    uintptr
361//	r2    uintptr
362//	err   uintptr
363// }
364// syscall must be called on the g0 stack with the
365// C calling convention (use libcCall).
366//
367// syscall expects a 32-bit result and tests for 32-bit -1
368// to decide there was an error.
369TEXT runtime·syscall(SB),NOSPLIT,$0
370	MOVD    R0, R19			// pointer to args
371
372	MOVD	(0*8)(R19), R11		// fn
373	MOVD	(1*8)(R19), R0		// a1
374	MOVD	(2*8)(R19), R1		// a2
375	MOVD	(3*8)(R19), R2		// a3
376	MOVD	$0, R3			// vararg
377
378	CALL	R11
379
380	MOVD	R0, (4*8)(R19)		// r1
381	MOVD	R1, (5*8)(R19)		// r2
382
383	// Standard libc functions return -1 on error
384	// and set errno.
385	CMPW	$-1, R0
386	BNE	ok
387
388	// Get error code from libc.
389	CALL	libc_errno(SB)
390	MOVW	(R0), R0
391	MOVD	R0, (6*8)(R19)		// err
392
393ok:
394	RET
395
396// syscallX calls a function in libc on behalf of the syscall package.
397// syscallX takes a pointer to a struct like:
398// struct {
399//	fn    uintptr
400//	a1    uintptr
401//	a2    uintptr
402//	a3    uintptr
403//	r1    uintptr
404//	r2    uintptr
405//	err   uintptr
406// }
407// syscallX must be called on the g0 stack with the
408// C calling convention (use libcCall).
409//
410// syscallX is like syscall but expects a 64-bit result
411// and tests for 64-bit -1 to decide there was an error.
412TEXT runtime·syscallX(SB),NOSPLIT,$0
413	MOVD    R0, R19			// pointer to args
414
415	MOVD	(0*8)(R19), R11		// fn
416	MOVD	(1*8)(R19), R0		// a1
417	MOVD	(2*8)(R19), R1		// a2
418	MOVD	(3*8)(R19), R2		// a3
419	MOVD	$0, R3			// vararg
420
421	CALL	R11
422
423	MOVD	R0, (4*8)(R19)		// r1
424	MOVD	R1, (5*8)(R19)		// r2
425
426	// Standard libc functions return -1 on error
427	// and set errno.
428	CMP	$-1, R0
429	BNE	ok
430
431	// Get error code from libc.
432	CALL	libc_errno(SB)
433	MOVW	(R0), R0
434	MOVD	R0, (6*8)(R19)		// err
435
436ok:
437	RET
438
439// syscall6 calls a function in libc on behalf of the syscall package.
440// syscall6 takes a pointer to a struct like:
441// struct {
442//	fn    uintptr
443//	a1    uintptr
444//	a2    uintptr
445//	a3    uintptr
446//	a4    uintptr
447//	a5    uintptr
448//	a6    uintptr
449//	r1    uintptr
450//	r2    uintptr
451//	err   uintptr
452// }
453// syscall6 must be called on the g0 stack with the
454// C calling convention (use libcCall).
455//
456// syscall6 expects a 32-bit result and tests for 32-bit -1
457// to decide there was an error.
458TEXT runtime·syscall6(SB),NOSPLIT,$0
459	MOVD    R0, R19			// pointer to args
460
461	MOVD	(0*8)(R19), R11		// fn
462	MOVD	(1*8)(R19), R0		// a1
463	MOVD	(2*8)(R19), R1		// a2
464	MOVD	(3*8)(R19), R2		// a3
465	MOVD	(4*8)(R19), R3		// a4
466	MOVD	(5*8)(R19), R4		// a5
467	MOVD	(6*8)(R19), R5		// a6
468	MOVD	$0, R6			// vararg
469
470	CALL	R11
471
472	MOVD	R0, (7*8)(R19)		// r1
473	MOVD	R1, (8*8)(R19)		// r2
474
475	// Standard libc functions return -1 on error
476	// and set errno.
477	CMPW	$-1, R0
478	BNE	ok
479
480	// Get error code from libc.
481	CALL	libc_errno(SB)
482	MOVW	(R0), R0
483	MOVD	R0, (9*8)(R19)		// err
484
485ok:
486	RET
487
488// syscall6X calls a function in libc on behalf of the syscall package.
489// syscall6X takes a pointer to a struct like:
490// struct {
491//	fn    uintptr
492//	a1    uintptr
493//	a2    uintptr
494//	a3    uintptr
495//	a4    uintptr
496//	a5    uintptr
497//	a6    uintptr
498//	r1    uintptr
499//	r2    uintptr
500//	err   uintptr
501// }
502// syscall6X must be called on the g0 stack with the
503// C calling convention (use libcCall).
504//
505// syscall6X is like syscall6 but expects a 64-bit result
506// and tests for 64-bit -1 to decide there was an error.
507TEXT runtime·syscall6X(SB),NOSPLIT,$0
508	MOVD    R0, R19			// pointer to args
509
510	MOVD	(0*8)(R19), R11		// fn
511	MOVD	(1*8)(R19), R0		// a1
512	MOVD	(2*8)(R19), R1		// a2
513	MOVD	(3*8)(R19), R2		// a3
514	MOVD	(4*8)(R19), R3		// a4
515	MOVD	(5*8)(R19), R4		// a5
516	MOVD	(6*8)(R19), R5		// a6
517	MOVD	$0, R6			// vararg
518
519	CALL	R11
520
521	MOVD	R0, (7*8)(R19)		// r1
522	MOVD	R1, (8*8)(R19)		// r2
523
524	// Standard libc functions return -1 on error
525	// and set errno.
526	CMP	$-1, R0
527	BNE	ok
528
529	// Get error code from libc.
530	CALL	libc_errno(SB)
531	MOVW	(R0), R0
532	MOVD	R0, (9*8)(R19)		// err
533
534ok:
535	RET
536
537// syscall10 calls a function in libc on behalf of the syscall package.
538// syscall10 takes a pointer to a struct like:
539// struct {
540//	fn    uintptr
541//	a1    uintptr
542//	a2    uintptr
543//	a3    uintptr
544//	a4    uintptr
545//	a5    uintptr
546//	a6    uintptr
547//	a7    uintptr
548//	a8    uintptr
549//	a9    uintptr
550//	a10   uintptr
551//	r1    uintptr
552//	r2    uintptr
553//	err   uintptr
554// }
555// syscall10 must be called on the g0 stack with the
556// C calling convention (use libcCall).
557TEXT runtime·syscall10(SB),NOSPLIT,$0
558	MOVD    R0, R19			// pointer to args
559
560	MOVD	(0*8)(R19), R11		// fn
561	MOVD	(1*8)(R19), R0		// a1
562	MOVD	(2*8)(R19), R1		// a2
563	MOVD	(3*8)(R19), R2		// a3
564	MOVD	(4*8)(R19), R3		// a4
565	MOVD	(5*8)(R19), R4		// a5
566	MOVD	(6*8)(R19), R5		// a6
567	MOVD	(7*8)(R19), R6		// a7
568	MOVD	(8*8)(R19), R7		// a8
569	MOVD	(9*8)(R19), R8		// a9
570	MOVD	(10*8)(R19), R9		// a10
571	MOVD	$0, R10			// vararg
572
573	CALL	R11
574
575	MOVD	R0, (11*8)(R19)		// r1
576	MOVD	R1, (12*8)(R19)		// r2
577
578	// Standard libc functions return -1 on error
579	// and set errno.
580	CMPW	$-1, R0
581	BNE	ok
582
583	// Get error code from libc.
584	CALL	libc_errno(SB)
585	MOVW	(R0), R0
586	MOVD	R0, (13*8)(R19)		// err
587
588ok:
589	RET
590
591// syscall10X calls a function in libc on behalf of the syscall package.
592// syscall10X takes a pointer to a struct like:
593// struct {
594//	fn    uintptr
595//	a1    uintptr
596//	a2    uintptr
597//	a3    uintptr
598//	a4    uintptr
599//	a5    uintptr
600//	a6    uintptr
601//	a7    uintptr
602//	a8    uintptr
603//	a9    uintptr
604//	a10   uintptr
605//	r1    uintptr
606//	r2    uintptr
607//	err   uintptr
608// }
609// syscall10X must be called on the g0 stack with the
610// C calling convention (use libcCall).
611//
612// syscall10X is like syscall10 but expects a 64-bit result
613// and tests for 64-bit -1 to decide there was an error.
614TEXT runtime·syscall10X(SB),NOSPLIT,$0
615	MOVD    R0, R19			// pointer to args
616
617	MOVD	(0*8)(R19), R11		// fn
618	MOVD	(1*8)(R19), R0		// a1
619	MOVD	(2*8)(R19), R1		// a2
620	MOVD	(3*8)(R19), R2		// a3
621	MOVD	(4*8)(R19), R3		// a4
622	MOVD	(5*8)(R19), R4		// a5
623	MOVD	(6*8)(R19), R5		// a6
624	MOVD	(7*8)(R19), R6		// a7
625	MOVD	(8*8)(R19), R7		// a8
626	MOVD	(9*8)(R19), R8		// a9
627	MOVD	(10*8)(R19), R9		// a10
628	MOVD	$0, R10			// vararg
629
630	CALL	R11
631
632	MOVD	R0, (11*8)(R19)		// r1
633	MOVD	R1, (12*8)(R19)		// r2
634
635	// Standard libc functions return -1 on error
636	// and set errno.
637	CMP	$-1, R0
638	BNE	ok
639
640	// Get error code from libc.
641	CALL	libc_errno(SB)
642	MOVW	(R0), R0
643	MOVD	R0, (13*8)(R19)		// err
644
645ok:
646	RET
647
648TEXT runtime·issetugid_trampoline(SB),NOSPLIT,$0
649	MOVD	R0, R19			// pointer to args
650	CALL	libc_issetugid(SB)
651	MOVW	R0, 0(R19)		// return value
652	RET
653