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//
6// System calls and other sys.stuff for arm64, Linux
7//
8
9#include "go_asm.h"
10#include "go_tls.h"
11#include "textflag.h"
12#include "cgo/abi_arm64.h"
13
14#define AT_FDCWD -100
15
16#define CLOCK_REALTIME 0
17#define CLOCK_MONOTONIC 1
18
19#define SYS_exit		93
20#define SYS_read		63
21#define SYS_write		64
22#define SYS_openat		56
23#define SYS_close		57
24#define SYS_pipe2		59
25#define SYS_nanosleep		101
26#define SYS_mmap		222
27#define SYS_munmap		215
28#define SYS_setitimer		103
29#define SYS_clone		220
30#define SYS_sched_yield		124
31#define SYS_rt_sigreturn	139
32#define SYS_rt_sigaction	134
33#define SYS_rt_sigprocmask	135
34#define SYS_sigaltstack		132
35#define SYS_madvise		233
36#define SYS_mincore		232
37#define SYS_getpid		172
38#define SYS_gettid		178
39#define SYS_kill		129
40#define SYS_tgkill		131
41#define SYS_futex		98
42#define SYS_sched_getaffinity	123
43#define SYS_exit_group		94
44#define SYS_clock_gettime	113
45#define SYS_faccessat		48
46#define SYS_socket		198
47#define SYS_connect		203
48#define SYS_brk			214
49#define SYS_timer_create	107
50#define SYS_timer_settime	110
51#define SYS_timer_delete	111
52
53TEXT runtime·exit(SB),NOSPLIT|NOFRAME,$0-4
54	MOVW	code+0(FP), R0
55	MOVD	$SYS_exit_group, R8
56	SVC
57	RET
58
59// func exitThread(wait *atomic.Uint32)
60TEXT runtime·exitThread(SB),NOSPLIT|NOFRAME,$0-8
61	MOVD	wait+0(FP), R0
62	// We're done using the stack.
63	MOVW	$0, R1
64	STLRW	R1, (R0)
65	MOVW	$0, R0	// exit code
66	MOVD	$SYS_exit, R8
67	SVC
68	JMP	0(PC)
69
70TEXT runtime·open(SB),NOSPLIT|NOFRAME,$0-20
71	MOVD	$AT_FDCWD, R0
72	MOVD	name+0(FP), R1
73	MOVW	mode+8(FP), R2
74	MOVW	perm+12(FP), R3
75	MOVD	$SYS_openat, R8
76	SVC
77	CMN	$4095, R0
78	BCC	done
79	MOVW	$-1, R0
80done:
81	MOVW	R0, ret+16(FP)
82	RET
83
84TEXT runtime·closefd(SB),NOSPLIT|NOFRAME,$0-12
85	MOVW	fd+0(FP), R0
86	MOVD	$SYS_close, R8
87	SVC
88	CMN	$4095, R0
89	BCC	done
90	MOVW	$-1, R0
91done:
92	MOVW	R0, ret+8(FP)
93	RET
94
95TEXT runtime·write1(SB),NOSPLIT|NOFRAME,$0-28
96	MOVD	fd+0(FP), R0
97	MOVD	p+8(FP), R1
98	MOVW	n+16(FP), R2
99	MOVD	$SYS_write, R8
100	SVC
101	MOVW	R0, ret+24(FP)
102	RET
103
104TEXT runtime·read(SB),NOSPLIT|NOFRAME,$0-28
105	MOVW	fd+0(FP), R0
106	MOVD	p+8(FP), R1
107	MOVW	n+16(FP), R2
108	MOVD	$SYS_read, R8
109	SVC
110	MOVW	R0, ret+24(FP)
111	RET
112
113// func pipe2(flags int32) (r, w int32, errno int32)
114TEXT runtime·pipe2(SB),NOSPLIT|NOFRAME,$0-20
115	MOVD	$r+8(FP), R0
116	MOVW	flags+0(FP), R1
117	MOVW	$SYS_pipe2, R8
118	SVC
119	MOVW	R0, errno+16(FP)
120	RET
121
122TEXT runtime·usleep(SB),NOSPLIT,$24-4
123	MOVWU	usec+0(FP), R3
124	MOVD	R3, R5
125	MOVW	$1000000, R4
126	UDIV	R4, R3
127	MOVD	R3, 8(RSP)
128	MUL	R3, R4
129	SUB	R4, R5
130	MOVW	$1000, R4
131	MUL	R4, R5
132	MOVD	R5, 16(RSP)
133
134	// nanosleep(&ts, 0)
135	ADD	$8, RSP, R0
136	MOVD	$0, R1
137	MOVD	$SYS_nanosleep, R8
138	SVC
139	RET
140
141TEXT runtime·gettid(SB),NOSPLIT,$0-4
142	MOVD	$SYS_gettid, R8
143	SVC
144	MOVW	R0, ret+0(FP)
145	RET
146
147TEXT runtime·raise(SB),NOSPLIT|NOFRAME,$0
148	MOVD	$SYS_getpid, R8
149	SVC
150	MOVW	R0, R19
151	MOVD	$SYS_gettid, R8
152	SVC
153	MOVW	R0, R1	// arg 2 tid
154	MOVW	R19, R0	// arg 1 pid
155	MOVW	sig+0(FP), R2	// arg 3
156	MOVD	$SYS_tgkill, R8
157	SVC
158	RET
159
160TEXT runtime·raiseproc(SB),NOSPLIT|NOFRAME,$0
161	MOVD	$SYS_getpid, R8
162	SVC
163	MOVW	R0, R0		// arg 1 pid
164	MOVW	sig+0(FP), R1	// arg 2
165	MOVD	$SYS_kill, R8
166	SVC
167	RET
168
169TEXT ·getpid(SB),NOSPLIT|NOFRAME,$0-8
170	MOVD	$SYS_getpid, R8
171	SVC
172	MOVD	R0, ret+0(FP)
173	RET
174
175TEXT ·tgkill(SB),NOSPLIT,$0-24
176	MOVD	tgid+0(FP), R0
177	MOVD	tid+8(FP), R1
178	MOVD	sig+16(FP), R2
179	MOVD	$SYS_tgkill, R8
180	SVC
181	RET
182
183TEXT runtime·setitimer(SB),NOSPLIT|NOFRAME,$0-24
184	MOVW	mode+0(FP), R0
185	MOVD	new+8(FP), R1
186	MOVD	old+16(FP), R2
187	MOVD	$SYS_setitimer, R8
188	SVC
189	RET
190
191TEXT runtime·timer_create(SB),NOSPLIT,$0-28
192	MOVW	clockid+0(FP), R0
193	MOVD	sevp+8(FP), R1
194	MOVD	timerid+16(FP), R2
195	MOVD	$SYS_timer_create, R8
196	SVC
197	MOVW	R0, ret+24(FP)
198	RET
199
200TEXT runtime·timer_settime(SB),NOSPLIT,$0-28
201	MOVW	timerid+0(FP), R0
202	MOVW	flags+4(FP), R1
203	MOVD	new+8(FP), R2
204	MOVD	old+16(FP), R3
205	MOVD	$SYS_timer_settime, R8
206	SVC
207	MOVW	R0, ret+24(FP)
208	RET
209
210TEXT runtime·timer_delete(SB),NOSPLIT,$0-12
211	MOVW	timerid+0(FP), R0
212	MOVD	$SYS_timer_delete, R8
213	SVC
214	MOVW	R0, ret+8(FP)
215	RET
216
217TEXT runtime·mincore(SB),NOSPLIT|NOFRAME,$0-28
218	MOVD	addr+0(FP), R0
219	MOVD	n+8(FP), R1
220	MOVD	dst+16(FP), R2
221	MOVD	$SYS_mincore, R8
222	SVC
223	MOVW	R0, ret+24(FP)
224	RET
225
226// func walltime() (sec int64, nsec int32)
227TEXT runtime·walltime(SB),NOSPLIT,$24-12
228	MOVD	RSP, R20	// R20 is unchanged by C code
229	MOVD	RSP, R1
230
231	MOVD	g_m(g), R21	// R21 = m
232
233	// Set vdsoPC and vdsoSP for SIGPROF traceback.
234	// Save the old values on stack and restore them on exit,
235	// so this function is reentrant.
236	MOVD	m_vdsoPC(R21), R2
237	MOVD	m_vdsoSP(R21), R3
238	MOVD	R2, 8(RSP)
239	MOVD	R3, 16(RSP)
240
241	MOVD	$ret-8(FP), R2 // caller's SP
242	MOVD	LR, m_vdsoPC(R21)
243	MOVD	R2, m_vdsoSP(R21)
244
245	MOVD	m_curg(R21), R0
246	CMP	g, R0
247	BNE	noswitch
248
249	MOVD	m_g0(R21), R3
250	MOVD	(g_sched+gobuf_sp)(R3), R1	// Set RSP to g0 stack
251
252noswitch:
253	SUB	$16, R1
254	BIC	$15, R1	// Align for C code
255	MOVD	R1, RSP
256
257	MOVW	$CLOCK_REALTIME, R0
258	MOVD	runtime·vdsoClockgettimeSym(SB), R2
259	CBZ	R2, fallback
260
261	// Store g on gsignal's stack, so if we receive a signal
262	// during VDSO code we can find the g.
263	// If we don't have a signal stack, we won't receive signal,
264	// so don't bother saving g.
265	// When using cgo, we already saved g on TLS, also don't save
266	// g here.
267	// Also don't save g if we are already on the signal stack.
268	// We won't get a nested signal.
269	MOVBU	runtime·iscgo(SB), R22
270	CBNZ	R22, nosaveg
271	MOVD	m_gsignal(R21), R22          // g.m.gsignal
272	CBZ	R22, nosaveg
273	CMP	g, R22
274	BEQ	nosaveg
275	MOVD	(g_stack+stack_lo)(R22), R22 // g.m.gsignal.stack.lo
276	MOVD	g, (R22)
277
278	BL	(R2)
279
280	MOVD	ZR, (R22)  // clear g slot, R22 is unchanged by C code
281
282	B	finish
283
284nosaveg:
285	BL	(R2)
286	B	finish
287
288fallback:
289	MOVD	$SYS_clock_gettime, R8
290	SVC
291
292finish:
293	MOVD	0(RSP), R3	// sec
294	MOVD	8(RSP), R5	// nsec
295
296	MOVD	R20, RSP	// restore SP
297	// Restore vdsoPC, vdsoSP
298	// We don't worry about being signaled between the two stores.
299	// If we are not in a signal handler, we'll restore vdsoSP to 0,
300	// and no one will care about vdsoPC. If we are in a signal handler,
301	// we cannot receive another signal.
302	MOVD	16(RSP), R1
303	MOVD	R1, m_vdsoSP(R21)
304	MOVD	8(RSP), R1
305	MOVD	R1, m_vdsoPC(R21)
306
307	MOVD	R3, sec+0(FP)
308	MOVW	R5, nsec+8(FP)
309	RET
310
311TEXT runtime·nanotime1(SB),NOSPLIT,$24-8
312	MOVD	RSP, R20	// R20 is unchanged by C code
313	MOVD	RSP, R1
314
315	MOVD	g_m(g), R21	// R21 = m
316
317	// Set vdsoPC and vdsoSP for SIGPROF traceback.
318	// Save the old values on stack and restore them on exit,
319	// so this function is reentrant.
320	MOVD	m_vdsoPC(R21), R2
321	MOVD	m_vdsoSP(R21), R3
322	MOVD	R2, 8(RSP)
323	MOVD	R3, 16(RSP)
324
325	MOVD	$ret-8(FP), R2 // caller's SP
326	MOVD	LR, m_vdsoPC(R21)
327	MOVD	R2, m_vdsoSP(R21)
328
329	MOVD	m_curg(R21), R0
330	CMP	g, R0
331	BNE	noswitch
332
333	MOVD	m_g0(R21), R3
334	MOVD	(g_sched+gobuf_sp)(R3), R1	// Set RSP to g0 stack
335
336noswitch:
337	SUB	$32, R1
338	BIC	$15, R1
339	MOVD	R1, RSP
340
341	MOVW	$CLOCK_MONOTONIC, R0
342	MOVD	runtime·vdsoClockgettimeSym(SB), R2
343	CBZ	R2, fallback
344
345	// Store g on gsignal's stack, so if we receive a signal
346	// during VDSO code we can find the g.
347	// If we don't have a signal stack, we won't receive signal,
348	// so don't bother saving g.
349	// When using cgo, we already saved g on TLS, also don't save
350	// g here.
351	// Also don't save g if we are already on the signal stack.
352	// We won't get a nested signal.
353	MOVBU	runtime·iscgo(SB), R22
354	CBNZ	R22, nosaveg
355	MOVD	m_gsignal(R21), R22          // g.m.gsignal
356	CBZ	R22, nosaveg
357	CMP	g, R22
358	BEQ	nosaveg
359	MOVD	(g_stack+stack_lo)(R22), R22 // g.m.gsignal.stack.lo
360	MOVD	g, (R22)
361
362	BL	(R2)
363
364	MOVD	ZR, (R22)  // clear g slot, R22 is unchanged by C code
365
366	B	finish
367
368nosaveg:
369	BL	(R2)
370	B	finish
371
372fallback:
373	MOVD	$SYS_clock_gettime, R8
374	SVC
375
376finish:
377	MOVD	0(RSP), R3	// sec
378	MOVD	8(RSP), R5	// nsec
379
380	MOVD	R20, RSP	// restore SP
381	// Restore vdsoPC, vdsoSP
382	// We don't worry about being signaled between the two stores.
383	// If we are not in a signal handler, we'll restore vdsoSP to 0,
384	// and no one will care about vdsoPC. If we are in a signal handler,
385	// we cannot receive another signal.
386	MOVD	16(RSP), R1
387	MOVD	R1, m_vdsoSP(R21)
388	MOVD	8(RSP), R1
389	MOVD	R1, m_vdsoPC(R21)
390
391	// sec is in R3, nsec in R5
392	// return nsec in R3
393	MOVD	$1000000000, R4
394	MUL	R4, R3
395	ADD	R5, R3
396	MOVD	R3, ret+0(FP)
397	RET
398
399TEXT runtime·rtsigprocmask(SB),NOSPLIT|NOFRAME,$0-28
400	MOVW	how+0(FP), R0
401	MOVD	new+8(FP), R1
402	MOVD	old+16(FP), R2
403	MOVW	size+24(FP), R3
404	MOVD	$SYS_rt_sigprocmask, R8
405	SVC
406	CMN	$4095, R0
407	BCC	done
408	MOVD	$0, R0
409	MOVD	R0, (R0)	// crash
410done:
411	RET
412
413TEXT runtime·rt_sigaction(SB),NOSPLIT|NOFRAME,$0-36
414	MOVD	sig+0(FP), R0
415	MOVD	new+8(FP), R1
416	MOVD	old+16(FP), R2
417	MOVD	size+24(FP), R3
418	MOVD	$SYS_rt_sigaction, R8
419	SVC
420	MOVW	R0, ret+32(FP)
421	RET
422
423// Call the function stored in _cgo_sigaction using the GCC calling convention.
424TEXT runtime·callCgoSigaction(SB),NOSPLIT,$0
425	MOVD	sig+0(FP), R0
426	MOVD	new+8(FP), R1
427	MOVD	old+16(FP), R2
428	MOVD	 _cgo_sigaction(SB), R3
429	SUB	$16, RSP		// reserve 16 bytes for sp-8 where fp may be saved.
430	BL	R3
431	ADD	$16, RSP
432	MOVW	R0, ret+24(FP)
433	RET
434
435TEXT runtime·sigfwd(SB),NOSPLIT,$0-32
436	MOVW	sig+8(FP), R0
437	MOVD	info+16(FP), R1
438	MOVD	ctx+24(FP), R2
439	MOVD	fn+0(FP), R11
440	BL	(R11)
441	RET
442
443// Called from c-abi, R0: sig, R1: info, R2: cxt
444TEXT runtime·sigtramp(SB),NOSPLIT|TOPFRAME,$176
445	// Save callee-save registers in the case of signal forwarding.
446	// Please refer to https://golang.org/issue/31827 .
447	SAVE_R19_TO_R28(8*4)
448	SAVE_F8_TO_F15(8*14)
449
450	// this might be called in external code context,
451	// where g is not set.
452	// first save R0, because runtime·load_g will clobber it
453	MOVW	R0, 8(RSP)
454	MOVBU	runtime·iscgo(SB), R0
455	CBZ	R0, 2(PC)
456	BL	runtime·load_g(SB)
457
458	// Restore signum to R0.
459	MOVW	8(RSP), R0
460	// R1 and R2 already contain info and ctx, respectively.
461	MOVD	$runtime·sigtrampgo<ABIInternal>(SB), R3
462	BL	(R3)
463
464	// Restore callee-save registers.
465	RESTORE_R19_TO_R28(8*4)
466	RESTORE_F8_TO_F15(8*14)
467
468	RET
469
470// Called from c-abi, R0: sig, R1: info, R2: cxt
471TEXT runtime·sigprofNonGoWrapper<>(SB),NOSPLIT,$176
472	// Save callee-save registers because it's a callback from c code.
473	SAVE_R19_TO_R28(8*4)
474	SAVE_F8_TO_F15(8*14)
475
476	// R0, R1 and R2 already contain sig, info and ctx, respectively.
477	CALL	runtime·sigprofNonGo<ABIInternal>(SB)
478
479	// Restore callee-save registers.
480	RESTORE_R19_TO_R28(8*4)
481	RESTORE_F8_TO_F15(8*14)
482	RET
483
484// Called from c-abi, R0: sig, R1: info, R2: cxt
485TEXT runtime·cgoSigtramp(SB),NOSPLIT|NOFRAME,$0
486	// The stack unwinder, presumably written in C, may not be able to
487	// handle Go frame correctly. So, this function is NOFRAME, and we
488	// save/restore LR manually.
489	MOVD	LR, R10
490	// Save R27, g because they will be clobbered,
491	// we need to restore them before jump to sigtramp.
492	MOVD	R27, R11
493	MOVD	g, R12
494
495	// If no traceback function, do usual sigtramp.
496	MOVD	runtime·cgoTraceback(SB), R6
497	CBZ	R6, sigtramp
498
499	// If no traceback support function, which means that
500	// runtime/cgo was not linked in, do usual sigtramp.
501	MOVD	_cgo_callers(SB), R7
502	CBZ	R7, sigtramp
503
504	// Figure out if we are currently in a cgo call.
505	// If not, just do usual sigtramp.
506	// first save R0, because runtime·load_g will clobber it.
507	MOVD	R0, R8
508	// Set up g register.
509	CALL	runtime·load_g(SB)
510	MOVD	R8, R0
511
512	CBZ	g, sigtrampnog // g == nil
513	MOVD	g_m(g), R6
514	CBZ	R6, sigtramp    // g.m == nil
515	MOVW	m_ncgo(R6), R7
516	CBZW	R7, sigtramp    // g.m.ncgo = 0
517	MOVD	m_curg(R6), R8
518	CBZ	R8, sigtramp    // g.m.curg == nil
519	MOVD	g_syscallsp(R8), R7
520	CBZ	R7,	sigtramp    // g.m.curg.syscallsp == 0
521	MOVD	m_cgoCallers(R6), R4 // R4 is the fifth arg in C calling convention.
522	CBZ	R4,	sigtramp    // g.m.cgoCallers == nil
523	MOVW	m_cgoCallersUse(R6), R8
524	CBNZW	R8, sigtramp    // g.m.cgoCallersUse != 0
525
526	// Jump to a function in runtime/cgo.
527	// That function, written in C, will call the user's traceback
528	// function with proper unwind info, and will then call back here.
529	// The first three arguments, and the fifth, are already in registers.
530	// Set the two remaining arguments now.
531	MOVD	runtime·cgoTraceback(SB), R3
532	MOVD	$runtime·sigtramp(SB), R5
533	MOVD	_cgo_callers(SB), R13
534	MOVD	R10, LR // restore
535	MOVD	R11, R27
536	MOVD	R12, g
537	B	(R13)
538
539sigtramp:
540	MOVD	R10, LR // restore
541	MOVD	R11, R27
542	MOVD	R12, g
543	B	runtime·sigtramp(SB)
544
545sigtrampnog:
546	// Signal arrived on a non-Go thread. If this is SIGPROF, get a
547	// stack trace.
548	CMPW	$27, R0 // 27 == SIGPROF
549	BNE	sigtramp
550
551	// Lock sigprofCallersUse (cas from 0 to 1).
552	MOVW	$1, R7
553	MOVD	$runtime·sigprofCallersUse(SB), R8
554load_store_loop:
555	LDAXRW	(R8), R9
556	CBNZW	R9, sigtramp // Skip stack trace if already locked.
557	STLXRW	R7, (R8), R9
558	CBNZ	R9, load_store_loop
559
560	// Jump to the traceback function in runtime/cgo.
561	// It will call back to sigprofNonGo, which will ignore the
562	// arguments passed in registers.
563	// First three arguments to traceback function are in registers already.
564	MOVD	runtime·cgoTraceback(SB), R3
565	MOVD	$runtime·sigprofCallers(SB), R4
566	MOVD	$runtime·sigprofNonGoWrapper<>(SB), R5
567	MOVD	_cgo_callers(SB), R13
568	MOVD	R10, LR // restore
569	MOVD	R11, R27
570	MOVD	R12, g
571	B	(R13)
572
573TEXT runtime·sysMmap(SB),NOSPLIT|NOFRAME,$0
574	MOVD	addr+0(FP), R0
575	MOVD	n+8(FP), R1
576	MOVW	prot+16(FP), R2
577	MOVW	flags+20(FP), R3
578	MOVW	fd+24(FP), R4
579	MOVW	off+28(FP), R5
580
581	MOVD	$SYS_mmap, R8
582	SVC
583	CMN	$4095, R0
584	BCC	ok
585	NEG	R0,R0
586	MOVD	$0, p+32(FP)
587	MOVD	R0, err+40(FP)
588	RET
589ok:
590	MOVD	R0, p+32(FP)
591	MOVD	$0, err+40(FP)
592	RET
593
594// Call the function stored in _cgo_mmap using the GCC calling convention.
595// This must be called on the system stack.
596TEXT runtime·callCgoMmap(SB),NOSPLIT,$0
597	MOVD	addr+0(FP), R0
598	MOVD	n+8(FP), R1
599	MOVW	prot+16(FP), R2
600	MOVW	flags+20(FP), R3
601	MOVW	fd+24(FP), R4
602	MOVW	off+28(FP), R5
603	MOVD	_cgo_mmap(SB), R9
604	SUB	$16, RSP		// reserve 16 bytes for sp-8 where fp may be saved.
605	BL	R9
606	ADD	$16, RSP
607	MOVD	R0, ret+32(FP)
608	RET
609
610TEXT runtime·sysMunmap(SB),NOSPLIT|NOFRAME,$0
611	MOVD	addr+0(FP), R0
612	MOVD	n+8(FP), R1
613	MOVD	$SYS_munmap, R8
614	SVC
615	CMN	$4095, R0
616	BCC	cool
617	MOVD	R0, 0xf0(R0)
618cool:
619	RET
620
621// Call the function stored in _cgo_munmap using the GCC calling convention.
622// This must be called on the system stack.
623TEXT runtime·callCgoMunmap(SB),NOSPLIT,$0
624	MOVD	addr+0(FP), R0
625	MOVD	n+8(FP), R1
626	MOVD	_cgo_munmap(SB), R9
627	SUB	$16, RSP		// reserve 16 bytes for sp-8 where fp may be saved.
628	BL	R9
629	ADD	$16, RSP
630	RET
631
632TEXT runtime·madvise(SB),NOSPLIT|NOFRAME,$0
633	MOVD	addr+0(FP), R0
634	MOVD	n+8(FP), R1
635	MOVW	flags+16(FP), R2
636	MOVD	$SYS_madvise, R8
637	SVC
638	MOVW	R0, ret+24(FP)
639	RET
640
641// int64 futex(int32 *uaddr, int32 op, int32 val,
642//	struct timespec *timeout, int32 *uaddr2, int32 val2);
643TEXT runtime·futex(SB),NOSPLIT|NOFRAME,$0
644	MOVD	addr+0(FP), R0
645	MOVW	op+8(FP), R1
646	MOVW	val+12(FP), R2
647	MOVD	ts+16(FP), R3
648	MOVD	addr2+24(FP), R4
649	MOVW	val3+32(FP), R5
650	MOVD	$SYS_futex, R8
651	SVC
652	MOVW	R0, ret+40(FP)
653	RET
654
655// int64 clone(int32 flags, void *stk, M *mp, G *gp, void (*fn)(void));
656TEXT runtime·clone(SB),NOSPLIT|NOFRAME,$0
657	MOVW	flags+0(FP), R0
658	MOVD	stk+8(FP), R1
659
660	// Copy mp, gp, fn off parent stack for use by child.
661	MOVD	mp+16(FP), R10
662	MOVD	gp+24(FP), R11
663	MOVD	fn+32(FP), R12
664
665	MOVD	R10, -8(R1)
666	MOVD	R11, -16(R1)
667	MOVD	R12, -24(R1)
668	MOVD	$1234, R10
669	MOVD	R10, -32(R1)
670
671	MOVD	$SYS_clone, R8
672	SVC
673
674	// In parent, return.
675	CMP	ZR, R0
676	BEQ	child
677	MOVW	R0, ret+40(FP)
678	RET
679child:
680
681	// In child, on new stack.
682	MOVD	-32(RSP), R10
683	MOVD	$1234, R0
684	CMP	R0, R10
685	BEQ	good
686	MOVD	$0, R0
687	MOVD	R0, (R0)	// crash
688
689good:
690	// Initialize m->procid to Linux tid
691	MOVD	$SYS_gettid, R8
692	SVC
693
694	MOVD	-24(RSP), R12     // fn
695	MOVD	-16(RSP), R11     // g
696	MOVD	-8(RSP), R10      // m
697
698	CMP	$0, R10
699	BEQ	nog
700	CMP	$0, R11
701	BEQ	nog
702
703	MOVD	R0, m_procid(R10)
704
705	// TODO: setup TLS.
706
707	// In child, set up new stack
708	MOVD	R10, g_m(R11)
709	MOVD	R11, g
710	//CALL	runtime·stackcheck(SB)
711
712nog:
713	// Call fn
714	MOVD	R12, R0
715	BL	(R0)
716
717	// It shouldn't return.	 If it does, exit that thread.
718	MOVW	$111, R0
719again:
720	MOVD	$SYS_exit, R8
721	SVC
722	B	again	// keep exiting
723
724TEXT runtime·sigaltstack(SB),NOSPLIT|NOFRAME,$0
725	MOVD	new+0(FP), R0
726	MOVD	old+8(FP), R1
727	MOVD	$SYS_sigaltstack, R8
728	SVC
729	CMN	$4095, R0
730	BCC	ok
731	MOVD	$0, R0
732	MOVD	R0, (R0)	// crash
733ok:
734	RET
735
736TEXT runtime·osyield(SB),NOSPLIT|NOFRAME,$0
737	MOVD	$SYS_sched_yield, R8
738	SVC
739	RET
740
741TEXT runtime·sched_getaffinity(SB),NOSPLIT|NOFRAME,$0
742	MOVD	pid+0(FP), R0
743	MOVD	len+8(FP), R1
744	MOVD	buf+16(FP), R2
745	MOVD	$SYS_sched_getaffinity, R8
746	SVC
747	MOVW	R0, ret+24(FP)
748	RET
749
750// int access(const char *name, int mode)
751TEXT runtime·access(SB),NOSPLIT,$0-20
752	MOVD	$AT_FDCWD, R0
753	MOVD	name+0(FP), R1
754	MOVW	mode+8(FP), R2
755	MOVD	$SYS_faccessat, R8
756	SVC
757	MOVW	R0, ret+16(FP)
758	RET
759
760// int connect(int fd, const struct sockaddr *addr, socklen_t len)
761TEXT runtime·connect(SB),NOSPLIT,$0-28
762	MOVW	fd+0(FP), R0
763	MOVD	addr+8(FP), R1
764	MOVW	len+16(FP), R2
765	MOVD	$SYS_connect, R8
766	SVC
767	MOVW	R0, ret+24(FP)
768	RET
769
770// int socket(int domain, int typ, int prot)
771TEXT runtime·socket(SB),NOSPLIT,$0-20
772	MOVW	domain+0(FP), R0
773	MOVW	typ+4(FP), R1
774	MOVW	prot+8(FP), R2
775	MOVD	$SYS_socket, R8
776	SVC
777	MOVW	R0, ret+16(FP)
778	RET
779
780// func sbrk0() uintptr
781TEXT runtime·sbrk0(SB),NOSPLIT,$0-8
782	// Implemented as brk(NULL).
783	MOVD	$0, R0
784	MOVD	$SYS_brk, R8
785	SVC
786	MOVD	R0, ret+0(FP)
787	RET
788