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//
6// System calls and other sys.stuff for riscv64, Linux
7//
8
9#include "textflag.h"
10#include "go_asm.h"
11
12#define AT_FDCWD -100
13#define CLOCK_REALTIME 0
14#define CLOCK_MONOTONIC 1
15
16#define SYS_brk			214
17#define SYS_clock_gettime	113
18#define SYS_clone		220
19#define SYS_close		57
20#define SYS_connect		203
21#define SYS_exit		93
22#define SYS_exit_group		94
23#define SYS_faccessat		48
24#define SYS_futex		98
25#define SYS_getpid		172
26#define SYS_gettid		178
27#define SYS_gettimeofday	169
28#define SYS_kill		129
29#define SYS_madvise		233
30#define SYS_mincore		232
31#define SYS_mmap		222
32#define SYS_munmap		215
33#define SYS_nanosleep		101
34#define SYS_openat		56
35#define SYS_pipe2		59
36#define SYS_pselect6		72
37#define SYS_read		63
38#define SYS_rt_sigaction	134
39#define SYS_rt_sigprocmask	135
40#define SYS_rt_sigreturn	139
41#define SYS_sched_getaffinity	123
42#define SYS_sched_yield		124
43#define SYS_setitimer		103
44#define SYS_sigaltstack		132
45#define SYS_socket		198
46#define SYS_tgkill		131
47#define SYS_timer_create	107
48#define SYS_timer_delete	111
49#define SYS_timer_settime	110
50#define SYS_tkill		130
51#define SYS_write		64
52
53// func exit(code int32)
54TEXT runtime·exit(SB),NOSPLIT|NOFRAME,$0-4
55	MOVW	code+0(FP), A0
56	MOV	$SYS_exit_group, A7
57	ECALL
58	RET
59
60// func exitThread(wait *atomic.Uint32)
61TEXT runtime·exitThread(SB),NOSPLIT|NOFRAME,$0-8
62	MOV	wait+0(FP), A0
63	// We're done using the stack.
64	FENCE
65	MOVW	ZERO, (A0)
66	FENCE
67	MOV	$0, A0	// exit code
68	MOV	$SYS_exit, A7
69	ECALL
70	JMP	0(PC)
71
72// func open(name *byte, mode, perm int32) int32
73TEXT runtime·open(SB),NOSPLIT|NOFRAME,$0-20
74	MOV	$AT_FDCWD, A0
75	MOV	name+0(FP), A1
76	MOVW	mode+8(FP), A2
77	MOVW	perm+12(FP), A3
78	MOV	$SYS_openat, A7
79	ECALL
80	MOV	$-4096, T0
81	BGEU	T0, A0, 2(PC)
82	MOV	$-1, A0
83	MOVW	A0, ret+16(FP)
84	RET
85
86// func closefd(fd int32) int32
87TEXT runtime·closefd(SB),NOSPLIT|NOFRAME,$0-12
88	MOVW	fd+0(FP), A0
89	MOV	$SYS_close, A7
90	ECALL
91	MOV	$-4096, T0
92	BGEU	T0, A0, 2(PC)
93	MOV	$-1, A0
94	MOVW	A0, ret+8(FP)
95	RET
96
97// func write1(fd uintptr, p unsafe.Pointer, n int32) int32
98TEXT runtime·write1(SB),NOSPLIT|NOFRAME,$0-28
99	MOV	fd+0(FP), A0
100	MOV	p+8(FP), A1
101	MOVW	n+16(FP), A2
102	MOV	$SYS_write, A7
103	ECALL
104	MOVW	A0, ret+24(FP)
105	RET
106
107// func read(fd int32, p unsafe.Pointer, n int32) int32
108TEXT runtime·read(SB),NOSPLIT|NOFRAME,$0-28
109	MOVW	fd+0(FP), A0
110	MOV	p+8(FP), A1
111	MOVW	n+16(FP), A2
112	MOV	$SYS_read, A7
113	ECALL
114	MOVW	A0, ret+24(FP)
115	RET
116
117// func pipe2(flags int32) (r, w int32, errno int32)
118TEXT runtime·pipe2(SB),NOSPLIT|NOFRAME,$0-20
119	MOV	$r+8(FP), A0
120	MOVW	flags+0(FP), A1
121	MOV	$SYS_pipe2, A7
122	ECALL
123	MOVW	A0, errno+16(FP)
124	RET
125
126// func usleep(usec uint32)
127TEXT runtime·usleep(SB),NOSPLIT,$24-4
128	MOVWU	usec+0(FP), A0
129	MOV	$1000, A1
130	MUL	A1, A0, A0
131	MOV	$1000000000, A1
132	DIV	A1, A0, A2
133	MOV	A2, 8(X2)
134	REM	A1, A0, A3
135	MOV	A3, 16(X2)
136	ADD	$8, X2, A0
137	MOV	ZERO, A1
138	MOV	$SYS_nanosleep, A7
139	ECALL
140	RET
141
142// func gettid() uint32
143TEXT runtime·gettid(SB),NOSPLIT,$0-4
144	MOV	$SYS_gettid, A7
145	ECALL
146	MOVW	A0, ret+0(FP)
147	RET
148
149// func raise(sig uint32)
150TEXT runtime·raise(SB),NOSPLIT|NOFRAME,$0
151	MOV	$SYS_gettid, A7
152	ECALL
153	// arg 1 tid - already in A0
154	MOVW	sig+0(FP), A1	// arg 2
155	MOV	$SYS_tkill, A7
156	ECALL
157	RET
158
159// func raiseproc(sig uint32)
160TEXT runtime·raiseproc(SB),NOSPLIT|NOFRAME,$0
161	MOV	$SYS_getpid, A7
162	ECALL
163	// arg 1 pid - already in A0
164	MOVW	sig+0(FP), A1	// arg 2
165	MOV	$SYS_kill, A7
166	ECALL
167	RET
168
169// func getpid() int
170TEXT ·getpid(SB),NOSPLIT|NOFRAME,$0-8
171	MOV	$SYS_getpid, A7
172	ECALL
173	MOV	A0, ret+0(FP)
174	RET
175
176// func tgkill(tgid, tid, sig int)
177TEXT ·tgkill(SB),NOSPLIT|NOFRAME,$0-24
178	MOV	tgid+0(FP), A0
179	MOV	tid+8(FP), A1
180	MOV	sig+16(FP), A2
181	MOV	$SYS_tgkill, A7
182	ECALL
183	RET
184
185// func setitimer(mode int32, new, old *itimerval)
186TEXT runtime·setitimer(SB),NOSPLIT|NOFRAME,$0-24
187	MOVW	mode+0(FP), A0
188	MOV	new+8(FP), A1
189	MOV	old+16(FP), A2
190	MOV	$SYS_setitimer, A7
191	ECALL
192	RET
193
194// func timer_create(clockid int32, sevp *sigevent, timerid *int32) int32
195TEXT runtime·timer_create(SB),NOSPLIT,$0-28
196	MOVW	clockid+0(FP), A0
197	MOV	sevp+8(FP), A1
198	MOV	timerid+16(FP), A2
199	MOV	$SYS_timer_create, A7
200	ECALL
201	MOVW	A0, ret+24(FP)
202	RET
203
204// func timer_settime(timerid int32, flags int32, new, old *itimerspec) int32
205TEXT runtime·timer_settime(SB),NOSPLIT,$0-28
206	MOVW	timerid+0(FP), A0
207	MOVW	flags+4(FP), A1
208	MOV	new+8(FP), A2
209	MOV	old+16(FP), A3
210	MOV	$SYS_timer_settime, A7
211	ECALL
212	MOVW	A0, ret+24(FP)
213	RET
214
215// func timer_delete(timerid int32) int32
216TEXT runtime·timer_delete(SB),NOSPLIT,$0-12
217	MOVW	timerid+0(FP), A0
218	MOV	$SYS_timer_delete, A7
219	ECALL
220	MOVW	A0, ret+8(FP)
221	RET
222
223// func mincore(addr unsafe.Pointer, n uintptr, dst *byte) int32
224TEXT runtime·mincore(SB),NOSPLIT|NOFRAME,$0-28
225	MOV	addr+0(FP), A0
226	MOV	n+8(FP), A1
227	MOV	dst+16(FP), A2
228	MOV	$SYS_mincore, A7
229	ECALL
230	MOVW	A0, ret+24(FP)
231	RET
232
233// func walltime() (sec int64, nsec int32)
234TEXT runtime·walltime(SB),NOSPLIT,$40-12
235	MOV	$CLOCK_REALTIME, A0
236
237	MOV	runtime·vdsoClockgettimeSym(SB), A7
238	BEQZ	A7, fallback
239	MOV	X2, S2 // S2,S3,S4 is unchanged by C code
240	MOV	g_m(g), S3 // S3 = m
241
242	// Save the old values on stack for reentrant
243	MOV	m_vdsoPC(S3), T0
244	MOV	T0, 24(X2)
245	MOV	m_vdsoSP(S3), T0
246	MOV	T0, 32(X2)
247
248	MOV	RA, m_vdsoPC(S3)
249	MOV	$ret-8(FP), T1 // caller's SP
250	MOV	T1, m_vdsoSP(S3)
251
252	MOV	m_curg(S3), T1
253	BNE	g, T1, noswitch
254
255	MOV	m_g0(S3), T1
256	MOV	(g_sched+gobuf_sp)(T1), X2
257
258noswitch:
259	SUB	$24, X2 // Space for result
260	ANDI	$~7, X2 // Align for C code
261	MOV	$8(X2), A1
262
263	// Store g on gsignal's stack, see sys_linux_arm64.s for detail
264	MOVBU	runtime·iscgo(SB), S4
265	BNEZ	S4, nosaveg
266	MOV	m_gsignal(S3), S4 // g.m.gsignal
267	BEQZ	S4, nosaveg
268	BEQ	g, S4, nosaveg
269	MOV	(g_stack+stack_lo)(S4), S4 // g.m.gsignal.stack.lo
270	MOV	g, (S4)
271
272	JALR	RA, A7
273
274	MOV	ZERO, (S4)
275	JMP	finish
276
277nosaveg:
278	JALR	RA, A7
279
280finish:
281	MOV	8(X2), T0	// sec
282	MOV	16(X2), T1	// nsec
283
284	MOV	S2, X2	// restore stack
285	MOV	24(X2), A2
286	MOV	A2, m_vdsoPC(S3)
287
288	MOV	32(X2), A3
289	MOV	A3, m_vdsoSP(S3)
290
291	MOV	T0, sec+0(FP)
292	MOVW	T1, nsec+8(FP)
293	RET
294
295fallback:
296	MOV	$8(X2), A1
297	MOV	$SYS_clock_gettime, A7
298	ECALL
299	MOV	8(X2), T0	// sec
300	MOV	16(X2), T1	// nsec
301	MOV	T0, sec+0(FP)
302	MOVW	T1, nsec+8(FP)
303	RET
304
305// func nanotime1() int64
306TEXT runtime·nanotime1(SB),NOSPLIT,$40-8
307	MOV	$CLOCK_MONOTONIC, A0
308
309	MOV	runtime·vdsoClockgettimeSym(SB), A7
310	BEQZ	A7, fallback
311
312	MOV	X2, S2 // S2 = RSP, S2 is unchanged by C code
313	MOV	g_m(g), S3 // S3 = m
314	// Save the old values on stack for reentrant
315	MOV	m_vdsoPC(S3), T0
316	MOV	T0, 24(X2)
317	MOV	m_vdsoSP(S3), T0
318	MOV	T0, 32(X2)
319
320	MOV	RA, m_vdsoPC(S3)
321	MOV	$ret-8(FP), T0 // caller's SP
322	MOV	T0, m_vdsoSP(S3)
323
324	MOV	m_curg(S3), T1
325	BNE	g, T1, noswitch
326
327	MOV	m_g0(S3), T1
328	MOV	(g_sched+gobuf_sp)(T1), X2
329
330noswitch:
331	SUB	$24, X2 // Space for result
332	ANDI	$~7, X2 // Align for C code
333	MOV	$8(X2), A1
334
335	// Store g on gsignal's stack, see sys_linux_arm64.s for detail
336	MOVBU	runtime·iscgo(SB), S4
337	BNEZ	S4, nosaveg
338	MOV	m_gsignal(S3), S4 // g.m.gsignal
339	BEQZ	S4, nosaveg
340	BEQ	g, S4, nosaveg
341	MOV	(g_stack+stack_lo)(S4), S4 // g.m.gsignal.stack.lo
342	MOV	g, (S4)
343
344	JALR	RA, A7
345
346	MOV	ZERO, (S4)
347	JMP	finish
348
349nosaveg:
350	JALR	RA, A7
351
352finish:
353	MOV	8(X2), T0	// sec
354	MOV	16(X2), T1	// nsec
355	// restore stack
356	MOV	S2, X2
357	MOV	24(X2), T2
358	MOV	T2, m_vdsoPC(S3)
359
360	MOV	32(X2), T2
361	MOV	T2, m_vdsoSP(S3)
362	// sec is in T0, nsec in T1
363	// return nsec in T0
364	MOV	$1000000000, T2
365	MUL	T2, T0
366	ADD	T1, T0
367	MOV	T0, ret+0(FP)
368	RET
369
370fallback:
371	MOV	$8(X2), A1
372	MOV	$SYS_clock_gettime, A7
373	ECALL
374	MOV	8(X2), T0	// sec
375	MOV	16(X2), T1	// nsec
376	MOV	$1000000000, T2
377	MUL	T2, T0
378	ADD	T1, T0
379	MOV	T0, ret+0(FP)
380	RET
381
382// func rtsigprocmask(how int32, new, old *sigset, size int32)
383TEXT runtime·rtsigprocmask(SB),NOSPLIT|NOFRAME,$0-28
384	MOVW	how+0(FP), A0
385	MOV	new+8(FP), A1
386	MOV	old+16(FP), A2
387	MOVW	size+24(FP), A3
388	MOV	$SYS_rt_sigprocmask, A7
389	ECALL
390	MOV	$-4096, T0
391	BLTU	A0, T0, 2(PC)
392	WORD	$0	// crash
393	RET
394
395// func rt_sigaction(sig uintptr, new, old *sigactiont, size uintptr) int32
396TEXT runtime·rt_sigaction(SB),NOSPLIT|NOFRAME,$0-36
397	MOV	sig+0(FP), A0
398	MOV	new+8(FP), A1
399	MOV	old+16(FP), A2
400	MOV	size+24(FP), A3
401	MOV	$SYS_rt_sigaction, A7
402	ECALL
403	MOVW	A0, ret+32(FP)
404	RET
405
406// func sigfwd(fn uintptr, sig uint32, info *siginfo, ctx unsafe.Pointer)
407TEXT runtime·sigfwd(SB),NOSPLIT,$0-32
408	MOVW	sig+8(FP), A0
409	MOV	info+16(FP), A1
410	MOV	ctx+24(FP), A2
411	MOV	fn+0(FP), T1
412	JALR	RA, T1
413	RET
414
415// func sigtramp(signo, ureg, ctxt unsafe.Pointer)
416TEXT runtime·sigtramp(SB),NOSPLIT|TOPFRAME,$64
417	MOVW	A0, 8(X2)
418	MOV	A1, 16(X2)
419	MOV	A2, 24(X2)
420
421	// this might be called in external code context,
422	// where g is not set.
423	MOVBU	runtime·iscgo(SB), A0
424	BEQ	A0, ZERO, 2(PC)
425	CALL	runtime·load_g(SB)
426
427	MOV	$runtime·sigtrampgo(SB), A0
428	JALR	RA, A0
429	RET
430
431// func cgoSigtramp()
432TEXT runtime·cgoSigtramp(SB),NOSPLIT,$0
433	MOV	$runtime·sigtramp(SB), T1
434	JALR	ZERO, T1
435
436// func mmap(addr unsafe.Pointer, n uintptr, prot, flags, fd int32, off uint32) (p unsafe.Pointer, err int)
437TEXT runtime·mmap(SB),NOSPLIT|NOFRAME,$0
438	MOV	addr+0(FP), A0
439	MOV	n+8(FP), A1
440	MOVW	prot+16(FP), A2
441	MOVW	flags+20(FP), A3
442	MOVW	fd+24(FP), A4
443	MOVW	off+28(FP), A5
444	MOV	$SYS_mmap, A7
445	ECALL
446	MOV	$-4096, T0
447	BGEU	T0, A0, 5(PC)
448	SUB	A0, ZERO, A0
449	MOV	ZERO, p+32(FP)
450	MOV	A0, err+40(FP)
451	RET
452ok:
453	MOV	A0, p+32(FP)
454	MOV	ZERO, err+40(FP)
455	RET
456
457// func munmap(addr unsafe.Pointer, n uintptr)
458TEXT runtime·munmap(SB),NOSPLIT|NOFRAME,$0
459	MOV	addr+0(FP), A0
460	MOV	n+8(FP), A1
461	MOV	$SYS_munmap, A7
462	ECALL
463	MOV	$-4096, T0
464	BLTU	A0, T0, 2(PC)
465	WORD	$0	// crash
466	RET
467
468// func madvise(addr unsafe.Pointer, n uintptr, flags int32)
469TEXT runtime·madvise(SB),NOSPLIT|NOFRAME,$0
470	MOV	addr+0(FP), A0
471	MOV	n+8(FP), A1
472	MOVW	flags+16(FP), A2
473	MOV	$SYS_madvise, A7
474	ECALL
475	MOVW	A0, ret+24(FP)
476	RET
477
478// func futex(addr unsafe.Pointer, op int32, val uint32, ts, addr2 unsafe.Pointer, val3 uint32) int32
479TEXT runtime·futex(SB),NOSPLIT|NOFRAME,$0
480	MOV	addr+0(FP), A0
481	MOVW	op+8(FP), A1
482	MOVW	val+12(FP), A2
483	MOV	ts+16(FP), A3
484	MOV	addr2+24(FP), A4
485	MOVW	val3+32(FP), A5
486	MOV	$SYS_futex, A7
487	ECALL
488	MOVW	A0, ret+40(FP)
489	RET
490
491// func clone(flags int32, stk, mp, gp, fn unsafe.Pointer) int32
492TEXT runtime·clone(SB),NOSPLIT|NOFRAME,$0
493	MOVW	flags+0(FP), A0
494	MOV	stk+8(FP), A1
495
496	// Copy mp, gp, fn off parent stack for use by child.
497	MOV	mp+16(FP), T0
498	MOV	gp+24(FP), T1
499	MOV	fn+32(FP), T2
500
501	MOV	T0, -8(A1)
502	MOV	T1, -16(A1)
503	MOV	T2, -24(A1)
504	MOV	$1234, T0
505	MOV	T0, -32(A1)
506
507	MOV	$SYS_clone, A7
508	ECALL
509
510	// In parent, return.
511	BEQ	ZERO, A0, child
512	MOVW	ZERO, ret+40(FP)
513	RET
514
515child:
516	// In child, on new stack.
517	MOV	-32(X2), T0
518	MOV	$1234, A0
519	BEQ	A0, T0, good
520	WORD	$0	// crash
521
522good:
523	// Initialize m->procid to Linux tid
524	MOV	$SYS_gettid, A7
525	ECALL
526
527	MOV	-24(X2), T2	// fn
528	MOV	-16(X2), T1	// g
529	MOV	-8(X2), T0	// m
530
531	BEQ	ZERO, T0, nog
532	BEQ	ZERO, T1, nog
533
534	MOV	A0, m_procid(T0)
535
536	// In child, set up new stack
537	MOV	T0, g_m(T1)
538	MOV	T1, g
539
540nog:
541	// Call fn
542	JALR	RA, T2
543
544	// It shouldn't return.  If it does, exit this thread.
545	MOV	$111, A0
546	MOV	$SYS_exit, A7
547	ECALL
548	JMP	-3(PC)	// keep exiting
549
550// func sigaltstack(new, old *stackt)
551TEXT runtime·sigaltstack(SB),NOSPLIT|NOFRAME,$0
552	MOV	new+0(FP), A0
553	MOV	old+8(FP), A1
554	MOV	$SYS_sigaltstack, A7
555	ECALL
556	MOV	$-4096, T0
557	BLTU	A0, T0, 2(PC)
558	WORD	$0	// crash
559	RET
560
561// func osyield()
562TEXT runtime·osyield(SB),NOSPLIT|NOFRAME,$0
563	MOV	$SYS_sched_yield, A7
564	ECALL
565	RET
566
567// func sched_getaffinity(pid, len uintptr, buf *uintptr) int32
568TEXT runtime·sched_getaffinity(SB),NOSPLIT|NOFRAME,$0
569	MOV	pid+0(FP), A0
570	MOV	len+8(FP), A1
571	MOV	buf+16(FP), A2
572	MOV	$SYS_sched_getaffinity, A7
573	ECALL
574	MOV	A0, ret+24(FP)
575	RET
576
577// func sbrk0() uintptr
578TEXT runtime·sbrk0(SB),NOSPLIT,$0-8
579	// Implemented as brk(NULL).
580	MOV	$0, A0
581	MOV	$SYS_brk, A7
582	ECALL
583	MOVW	A0, ret+0(FP)
584	RET
585