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