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
5// +build linux
6// +build ppc64 ppc64le
7
8//
9// System calls and other sys.stuff for ppc64, Linux
10//
11
12#include "go_asm.h"
13#include "go_tls.h"
14#include "textflag.h"
15#include "asm_ppc64x.h"
16
17#define SYS_exit		  1
18#define SYS_read		  3
19#define SYS_write		  4
20#define SYS_open		  5
21#define SYS_close		  6
22#define SYS_getpid		 20
23#define SYS_kill		 37
24#define SYS_brk			 45
25#define SYS_fcntl		 55
26#define SYS_gettimeofday	 78
27#define SYS_select		 82	// always return -ENOSYS
28#define SYS_mmap		 90
29#define SYS_munmap		 91
30#define SYS_setitimer		104
31#define SYS_clone		120
32#define SYS_newselect		142
33#define SYS_sched_yield		158
34#define SYS_rt_sigreturn	172
35#define SYS_rt_sigaction	173
36#define SYS_rt_sigprocmask	174
37#define SYS_sigaltstack		185
38#define SYS_ugetrlimit		190
39#define SYS_madvise		205
40#define SYS_mincore		206
41#define SYS_gettid		207
42#define SYS_tkill		208
43#define SYS_futex		221
44#define SYS_sched_getaffinity	223
45#define SYS_exit_group		234
46#define SYS_epoll_create	236
47#define SYS_epoll_ctl		237
48#define SYS_epoll_wait		238
49#define SYS_clock_gettime	246
50#define SYS_epoll_create1	315
51
52TEXT runtime·exit(SB),NOSPLIT|NOFRAME,$0-4
53	MOVW	code+0(FP), R3
54	SYSCALL	$SYS_exit_group
55	RET
56
57// func exitThread(wait *uint32)
58TEXT runtime·exitThread(SB),NOSPLIT|NOFRAME,$0-8
59	MOVD	wait+0(FP), R1
60	// We're done using the stack.
61	MOVW	$0, R2
62	SYNC
63	MOVW	R2, (R1)
64	MOVW	$0, R3	// exit code
65	SYSCALL	$SYS_exit
66	JMP	0(PC)
67
68TEXT runtime·open(SB),NOSPLIT|NOFRAME,$0-20
69	MOVD	name+0(FP), R3
70	MOVW	mode+8(FP), R4
71	MOVW	perm+12(FP), R5
72	SYSCALL	$SYS_open
73	BVC	2(PC)
74	MOVW	$-1, R3
75	MOVW	R3, ret+16(FP)
76	RET
77
78TEXT runtime·closefd(SB),NOSPLIT|NOFRAME,$0-12
79	MOVW	fd+0(FP), R3
80	SYSCALL	$SYS_close
81	BVC	2(PC)
82	MOVW	$-1, R3
83	MOVW	R3, ret+8(FP)
84	RET
85
86TEXT runtime·write(SB),NOSPLIT|NOFRAME,$0-28
87	MOVD	fd+0(FP), R3
88	MOVD	p+8(FP), R4
89	MOVW	n+16(FP), R5
90	SYSCALL	$SYS_write
91	BVC	2(PC)
92	MOVW	$-1, R3
93	MOVW	R3, ret+24(FP)
94	RET
95
96TEXT runtime·read(SB),NOSPLIT|NOFRAME,$0-28
97	MOVW	fd+0(FP), R3
98	MOVD	p+8(FP), R4
99	MOVW	n+16(FP), R5
100	SYSCALL	$SYS_read
101	BVC	2(PC)
102	MOVW	$-1, R3
103	MOVW	R3, ret+24(FP)
104	RET
105
106TEXT runtime·getrlimit(SB),NOSPLIT|NOFRAME,$0-20
107	MOVW	kind+0(FP), R3
108	MOVD	limit+8(FP), R4
109	SYSCALL	$SYS_ugetrlimit
110	MOVW	R3, ret+16(FP)
111	RET
112
113TEXT runtime·usleep(SB),NOSPLIT,$16-4
114	MOVW	usec+0(FP), R3
115	MOVD	R3, R5
116	MOVW	$1000000, R4
117	DIVD	R4, R3
118	MOVD	R3, 8(R1)
119	MULLD	R3, R4
120	SUB	R4, R5
121	MOVD	R5, 16(R1)
122
123	// select(0, 0, 0, 0, &tv)
124	MOVW	$0, R3
125	MOVW	$0, R4
126	MOVW	$0, R5
127	MOVW	$0, R6
128	ADD	$8, R1, R7
129	SYSCALL	$SYS_newselect
130	RET
131
132TEXT runtime·gettid(SB),NOSPLIT,$0-4
133	SYSCALL	$SYS_gettid
134	MOVW	R3, ret+0(FP)
135	RET
136
137TEXT runtime·raise(SB),NOSPLIT|NOFRAME,$0
138	SYSCALL	$SYS_gettid
139	MOVW	R3, R3	// arg 1 tid
140	MOVW	sig+0(FP), R4	// arg 2
141	SYSCALL	$SYS_tkill
142	RET
143
144TEXT runtime·raiseproc(SB),NOSPLIT|NOFRAME,$0
145	SYSCALL	$SYS_getpid
146	MOVW	R3, R3	// arg 1 pid
147	MOVW	sig+0(FP), R4	// arg 2
148	SYSCALL	$SYS_kill
149	RET
150
151TEXT runtime·setitimer(SB),NOSPLIT|NOFRAME,$0-24
152	MOVW	mode+0(FP), R3
153	MOVD	new+8(FP), R4
154	MOVD	old+16(FP), R5
155	SYSCALL	$SYS_setitimer
156	RET
157
158TEXT runtime·mincore(SB),NOSPLIT|NOFRAME,$0-28
159	MOVD	addr+0(FP), R3
160	MOVD	n+8(FP), R4
161	MOVD	dst+16(FP), R5
162	SYSCALL	$SYS_mincore
163	NEG	R3		// caller expects negative errno
164	MOVW	R3, ret+24(FP)
165	RET
166
167// func walltime() (sec int64, nsec int32)
168TEXT runtime·walltime(SB),NOSPLIT,$16
169	MOVD	$0, R3 // CLOCK_REALTIME
170	MOVD	$0(R1), R4
171	SYSCALL	$SYS_clock_gettime
172	MOVD	0(R1), R3	// sec
173	MOVD	8(R1), R5	// nsec
174	MOVD	R3, sec+0(FP)
175	MOVW	R5, nsec+8(FP)
176	RET
177
178TEXT runtime·nanotime(SB),NOSPLIT,$16
179	MOVW	$1, R3 // CLOCK_MONOTONIC
180	MOVD	$0(R1), R4
181	SYSCALL	$SYS_clock_gettime
182	MOVD	0(R1), R3	// sec
183	MOVD	8(R1), R5	// nsec
184	// sec is in R3, nsec in R5
185	// return nsec in R3
186	MOVD	$1000000000, R4
187	MULLD	R4, R3
188	ADD	R5, R3
189	MOVD	R3, ret+0(FP)
190	RET
191
192TEXT runtime·rtsigprocmask(SB),NOSPLIT|NOFRAME,$0-28
193	MOVW	how+0(FP), R3
194	MOVD	new+8(FP), R4
195	MOVD	old+16(FP), R5
196	MOVW	size+24(FP), R6
197	SYSCALL	$SYS_rt_sigprocmask
198	BVC	2(PC)
199	MOVD	R0, 0xf0(R0)	// crash
200	RET
201
202TEXT runtime·rt_sigaction(SB),NOSPLIT|NOFRAME,$0-36
203	MOVD	sig+0(FP), R3
204	MOVD	new+8(FP), R4
205	MOVD	old+16(FP), R5
206	MOVD	size+24(FP), R6
207	SYSCALL	$SYS_rt_sigaction
208	MOVW	R3, ret+32(FP)
209	RET
210
211TEXT runtime·sigfwd(SB),NOSPLIT,$0-32
212	MOVW	sig+8(FP), R3
213	MOVD	info+16(FP), R4
214	MOVD	ctx+24(FP), R5
215	MOVD	fn+0(FP), R12
216	MOVD	R12, CTR
217	BL	(CTR)
218	MOVD	24(R1), R2
219	RET
220
221#ifdef GOARCH_ppc64le
222// ppc64le doesn't need function descriptors
223TEXT runtime·sigtramp(SB),NOSPLIT,$64
224#else
225// function descriptor for the real sigtramp
226TEXT runtime·sigtramp(SB),NOSPLIT|NOFRAME,$0
227	DWORD	$runtime·_sigtramp(SB)
228	DWORD	$0
229	DWORD	$0
230TEXT runtime·_sigtramp(SB),NOSPLIT,$64
231#endif
232	// initialize essential registers (just in case)
233	BL	runtime·reginit(SB)
234
235	// this might be called in external code context,
236	// where g is not set.
237	MOVB	runtime·iscgo(SB), R6
238	CMP 	R6, $0
239	BEQ	2(PC)
240	BL	runtime·load_g(SB)
241
242	MOVW	R3, FIXED_FRAME+0(R1)
243	MOVD	R4, FIXED_FRAME+8(R1)
244	MOVD	R5, FIXED_FRAME+16(R1)
245	MOVD	$runtime·sigtrampgo(SB), R12
246	MOVD	R12, CTR
247	BL	(CTR)
248	MOVD	24(R1), R2
249	RET
250
251#ifdef GOARCH_ppc64le
252// ppc64le doesn't need function descriptors
253TEXT runtime·cgoSigtramp(SB),NOSPLIT|NOFRAME,$0
254	// The stack unwinder, presumably written in C, may not be able to
255	// handle Go frame correctly. So, this function is NOFRAME, and we
256	// we save/restore LR manually.
257	MOVD	LR, R10
258
259	// We're coming from C code, initialize essential registers.
260	CALL	runtime·reginit(SB)
261
262	// If no traceback function, do usual sigtramp.
263	MOVD	runtime·cgoTraceback(SB), R6
264	CMP	$0, R6
265	BEQ	sigtramp
266
267	// If no traceback support function, which means that
268	// runtime/cgo was not linked in, do usual sigtramp.
269	MOVD	_cgo_callers(SB), R6
270	CMP	$0, R6
271	BEQ	sigtramp
272
273	// Set up g register.
274	CALL	runtime·load_g(SB)
275
276	// Figure out if we are currently in a cgo call.
277	// If not, just do usual sigtramp.
278	CMP	$0, g
279	BEQ	sigtrampnog // g == nil
280	MOVD	g_m(g), R6
281	CMP	$0, R6
282	BEQ	sigtramp    // g.m == nil
283	MOVW	m_ncgo(R6), R7
284	CMPW	$0, R7
285	BEQ	sigtramp    // g.m.ncgo = 0
286	MOVD	m_curg(R6), R7
287	CMP	$0, R7
288	BEQ	sigtramp    // g.m.curg == nil
289	MOVD	g_syscallsp(R7), R7
290	CMP	$0, R7
291	BEQ	sigtramp    // g.m.curg.syscallsp == 0
292	MOVD	m_cgoCallers(R6), R7 // R7 is the fifth arg in C calling convention.
293	CMP	$0, R7
294	BEQ	sigtramp    // g.m.cgoCallers == nil
295	MOVW	m_cgoCallersUse(R6), R8
296	CMPW	$0, R8
297	BNE	sigtramp    // g.m.cgoCallersUse != 0
298
299	// Jump to a function in runtime/cgo.
300	// That function, written in C, will call the user's traceback
301	// function with proper unwind info, and will then call back here.
302	// The first three arguments, and the fifth, are already in registers.
303	// Set the two remaining arguments now.
304	MOVD	runtime·cgoTraceback(SB), R6
305	MOVD	$runtime·sigtramp(SB), R8
306	MOVD	_cgo_callers(SB), R12
307	MOVD	R12, CTR
308	MOVD	R10, LR // restore LR
309	JMP	(CTR)
310
311sigtramp:
312	MOVD	R10, LR // restore LR
313	JMP	runtime·sigtramp(SB)
314
315sigtrampnog:
316	// Signal arrived on a non-Go thread. If this is SIGPROF, get a
317	// stack trace.
318	CMPW	R3, $27 // 27 == SIGPROF
319	BNE	sigtramp
320
321	// Lock sigprofCallersUse (cas from 0 to 1).
322	MOVW	$1, R7
323	MOVD	$runtime·sigprofCallersUse(SB), R8
324	SYNC
325	LWAR    (R8), R6
326	CMPW    $0, R6
327	BNE     sigtramp
328	STWCCC  R7, (R8)
329	BNE     -4(PC)
330	ISYNC
331
332	// Jump to the traceback function in runtime/cgo.
333	// It will call back to sigprofNonGo, which will ignore the
334	// arguments passed in registers.
335	// First three arguments to traceback function are in registers already.
336	MOVD	runtime·cgoTraceback(SB), R6
337	MOVD	$runtime·sigprofCallers(SB), R7
338	MOVD	$runtime·sigprofNonGoWrapper<>(SB), R8
339	MOVD	_cgo_callers(SB), R12
340	MOVD	R12, CTR
341	MOVD	R10, LR // restore LR
342	JMP	(CTR)
343#else
344// function descriptor for the real sigtramp
345TEXT runtime·cgoSigtramp(SB),NOSPLIT|NOFRAME,$0
346	DWORD	$runtime·_cgoSigtramp(SB)
347	DWORD	$0
348	DWORD	$0
349TEXT runtime·_cgoSigtramp(SB),NOSPLIT,$0
350	JMP	runtime·sigtramp(SB)
351#endif
352
353TEXT runtime·sigprofNonGoWrapper<>(SB),NOSPLIT,$0
354	// We're coming from C code, set up essential register, then call sigprofNonGo.
355	CALL	runtime·reginit(SB)
356	CALL	runtime·sigprofNonGo(SB)
357	RET
358
359TEXT runtime·mmap(SB),NOSPLIT|NOFRAME,$0
360	MOVD	addr+0(FP), R3
361	MOVD	n+8(FP), R4
362	MOVW	prot+16(FP), R5
363	MOVW	flags+20(FP), R6
364	MOVW	fd+24(FP), R7
365	MOVW	off+28(FP), R8
366
367	SYSCALL	$SYS_mmap
368	BVC	ok
369	MOVD	$0, p+32(FP)
370	MOVD	R3, err+40(FP)
371	RET
372ok:
373	MOVD	R3, p+32(FP)
374	MOVD	$0, err+40(FP)
375	RET
376
377TEXT runtime·munmap(SB),NOSPLIT|NOFRAME,$0
378	MOVD	addr+0(FP), R3
379	MOVD	n+8(FP), R4
380	SYSCALL	$SYS_munmap
381	BVC	2(PC)
382	MOVD	R0, 0xf0(R0)
383	RET
384
385TEXT runtime·madvise(SB),NOSPLIT|NOFRAME,$0
386	MOVD	addr+0(FP), R3
387	MOVD	n+8(FP), R4
388	MOVW	flags+16(FP), R5
389	SYSCALL	$SYS_madvise
390	// ignore failure - maybe pages are locked
391	RET
392
393// int64 futex(int32 *uaddr, int32 op, int32 val,
394//	struct timespec *timeout, int32 *uaddr2, int32 val2);
395TEXT runtime·futex(SB),NOSPLIT|NOFRAME,$0
396	MOVD	addr+0(FP), R3
397	MOVW	op+8(FP), R4
398	MOVW	val+12(FP), R5
399	MOVD	ts+16(FP), R6
400	MOVD	addr2+24(FP), R7
401	MOVW	val3+32(FP), R8
402	SYSCALL	$SYS_futex
403	MOVW	R3, ret+40(FP)
404	RET
405
406// int64 clone(int32 flags, void *stk, M *mp, G *gp, void (*fn)(void));
407TEXT runtime·clone(SB),NOSPLIT|NOFRAME,$0
408	MOVW	flags+0(FP), R3
409	MOVD	stk+8(FP), R4
410
411	// Copy mp, gp, fn off parent stack for use by child.
412	// Careful: Linux system call clobbers ???.
413	MOVD	mp+16(FP), R7
414	MOVD	gp+24(FP), R8
415	MOVD	fn+32(FP), R12
416
417	MOVD	R7, -8(R4)
418	MOVD	R8, -16(R4)
419	MOVD	R12, -24(R4)
420	MOVD	$1234, R7
421	MOVD	R7, -32(R4)
422
423	SYSCALL $SYS_clone
424
425	// In parent, return.
426	CMP	R3, $0
427	BEQ	3(PC)
428	MOVW	R3, ret+40(FP)
429	RET
430
431	// In child, on new stack.
432	// initialize essential registers
433	BL	runtime·reginit(SB)
434	MOVD	-32(R1), R7
435	CMP	R7, $1234
436	BEQ	2(PC)
437	MOVD	R0, 0(R0)
438
439	// Initialize m->procid to Linux tid
440	SYSCALL $SYS_gettid
441
442	MOVD	-24(R1), R12       // fn
443	MOVD	-16(R1), R8        // g
444	MOVD	-8(R1), R7         // m
445
446	CMP	R7, $0
447	BEQ	nog
448	CMP	R8, $0
449	BEQ	nog
450
451	MOVD	R3, m_procid(R7)
452
453	// TODO: setup TLS.
454
455	// In child, set up new stack
456	MOVD	R7, g_m(R8)
457	MOVD	R8, g
458	//CALL	runtime·stackcheck(SB)
459
460nog:
461	// Call fn
462	MOVD	R12, CTR
463	BL	(CTR)
464
465	// It shouldn't return.	 If it does, exit that thread.
466	MOVW	$111, R3
467	SYSCALL	$SYS_exit
468	BR	-2(PC)	// keep exiting
469
470TEXT runtime·sigaltstack(SB),NOSPLIT|NOFRAME,$0
471	MOVD	new+0(FP), R3
472	MOVD	old+8(FP), R4
473	SYSCALL	$SYS_sigaltstack
474	BVC	2(PC)
475	MOVD	R0, 0xf0(R0)  // crash
476	RET
477
478TEXT runtime·osyield(SB),NOSPLIT|NOFRAME,$0
479	SYSCALL	$SYS_sched_yield
480	RET
481
482TEXT runtime·sched_getaffinity(SB),NOSPLIT|NOFRAME,$0
483	MOVD	pid+0(FP), R3
484	MOVD	len+8(FP), R4
485	MOVD	buf+16(FP), R5
486	SYSCALL	$SYS_sched_getaffinity
487	MOVW	R3, ret+24(FP)
488	RET
489
490// int32 runtime·epollcreate(int32 size);
491TEXT runtime·epollcreate(SB),NOSPLIT|NOFRAME,$0
492	MOVW    size+0(FP), R3
493	SYSCALL	$SYS_epoll_create
494	MOVW	R3, ret+8(FP)
495	RET
496
497// int32 runtime·epollcreate1(int32 flags);
498TEXT runtime·epollcreate1(SB),NOSPLIT|NOFRAME,$0
499	MOVW	flags+0(FP), R3
500	SYSCALL	$SYS_epoll_create1
501	MOVW	R3, ret+8(FP)
502	RET
503
504// func epollctl(epfd, op, fd int32, ev *epollEvent) int
505TEXT runtime·epollctl(SB),NOSPLIT|NOFRAME,$0
506	MOVW	epfd+0(FP), R3
507	MOVW	op+4(FP), R4
508	MOVW	fd+8(FP), R5
509	MOVD	ev+16(FP), R6
510	SYSCALL	$SYS_epoll_ctl
511	MOVW	R3, ret+24(FP)
512	RET
513
514// int32 runtime·epollwait(int32 epfd, EpollEvent *ev, int32 nev, int32 timeout);
515TEXT runtime·epollwait(SB),NOSPLIT|NOFRAME,$0
516	MOVW	epfd+0(FP), R3
517	MOVD	ev+8(FP), R4
518	MOVW	nev+16(FP), R5
519	MOVW	timeout+20(FP), R6
520	SYSCALL	$SYS_epoll_wait
521	MOVW	R3, ret+24(FP)
522	RET
523
524// void runtime·closeonexec(int32 fd);
525TEXT runtime·closeonexec(SB),NOSPLIT|NOFRAME,$0
526	MOVW    fd+0(FP), R3  // fd
527	MOVD    $2, R4  // F_SETFD
528	MOVD    $1, R5  // FD_CLOEXEC
529	SYSCALL	$SYS_fcntl
530	RET
531
532// func sbrk0() uintptr
533TEXT runtime·sbrk0(SB),NOSPLIT|NOFRAME,$0
534	// Implemented as brk(NULL).
535	MOVD	$0, R3
536	SYSCALL	$SYS_brk
537	MOVD	R3, ret+0(FP)
538	RET
539