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// System calls and other sys.stuff for ARM, Darwin
6// System calls are implemented in libSystem, this file contains
7// trampolines that convert from Go to C calling convention.
8
9#include "go_asm.h"
10#include "go_tls.h"
11#include "textflag.h"
12
13TEXT notok<>(SB),NOSPLIT,$0
14	MOVW	$0, R8
15	MOVW	R8, (R8)
16	B		0(PC)
17
18TEXT runtime·open_trampoline(SB),NOSPLIT,$0
19	MOVW	4(R0), R1	// arg 2 mode
20	MOVW	8(R0), R2	// arg 3 perm
21	MOVW	0(R0), R0	// arg 1 name
22	BL	libc_open(SB)
23	RET
24
25TEXT runtime·close_trampoline(SB),NOSPLIT,$0
26	MOVW	0(R0), R0	// arg 1 fd
27	BL	libc_close(SB)
28	RET
29
30TEXT runtime·write_trampoline(SB),NOSPLIT,$0
31	MOVW	4(R0), R1	// arg 2 buf
32	MOVW	8(R0), R2	// arg 3 count
33	MOVW	0(R0), R0	// arg 1 fd
34	BL	libc_write(SB)
35	MOVW	$-1, R1
36	CMP	R0, R1
37	BNE	noerr
38	BL	libc_error(SB)
39	MOVW	(R0), R0
40	RSB	$0, R0, R0	// caller expects negative errno value
41noerr:
42	RET
43
44TEXT runtime·read_trampoline(SB),NOSPLIT,$0
45	MOVW	4(R0), R1	// arg 2 buf
46	MOVW	8(R0), R2	// arg 3 count
47	MOVW	0(R0), R0	// arg 1 fd
48	BL	libc_read(SB)
49	MOVW	$-1, R1
50	CMP	R0, R1
51	BNE	noerr
52	BL	libc_error(SB)
53	MOVW	(R0), R0
54	RSB	$0, R0, R0	// caller expects negative errno value
55noerr:
56	RET
57
58TEXT runtime·pipe_trampoline(SB),NOSPLIT,$0
59	BL	libc_pipe(SB)	// pointer already in R0
60	CMP	$0, R0
61	BEQ	3(PC)
62	BL	libc_error(SB)	// return negative errno value
63	RSB	$0, R0, R0
64	RET
65
66TEXT runtime·exit_trampoline(SB),NOSPLIT|NOFRAME,$0
67	MOVW	0(R0), R0	// arg 0 code
68	BL libc_exit(SB)
69	MOVW	$1234, R0
70	MOVW	$1002, R1
71	MOVW	R0, (R1)	// fail hard
72
73TEXT runtime·raiseproc_trampoline(SB),NOSPLIT,$0
74	MOVW	0(R0), R8	// signal
75	BL	libc_getpid(SB)
76	// arg 1 pid already in R0 from getpid
77	MOVW	R8, R1	// arg 2 signal
78	BL	libc_kill(SB)
79	RET
80
81TEXT runtime·mmap_trampoline(SB),NOSPLIT,$0
82	MOVW	R0, R8
83	MOVW	0(R8), R0	// arg 1 addr
84	MOVW	4(R8), R1	// arg 2 len
85	MOVW	8(R8), R2	// arg 3 prot
86	MOVW	12(R8), R3	// arg 4 flags
87	MOVW	16(R8), R4	// arg 5 fid
88	MOVW	20(R8), R5	// arg 6 offset
89	MOVW	$0, R6	// off_t is uint64_t
90	// Only R0-R3 are used for arguments, the rest
91	// go on the stack.
92	MOVM.DB.W [R4-R6], (R13)
93	BL	libc_mmap(SB)
94	ADD $12, R13
95	MOVW	$0, R1
96	MOVW	$-1, R2
97	CMP	R0, R2
98	BNE ok
99	BL	libc_error(SB)
100	MOVW	(R0), R1
101	MOVW	$0, R0
102ok:
103	MOVW	R0, 24(R8)	// ret 1 addr
104	MOVW	R1, 28(R8)	// ret 2 err
105	RET
106
107TEXT runtime·munmap_trampoline(SB),NOSPLIT,$0
108	MOVW	4(R0), R1	// arg 2 len
109	MOVW	0(R0), R0	// arg 1 addr
110	BL libc_munmap(SB)
111	MOVW	$-1, R2
112	CMP	R0, R2
113	BL.EQ	notok<>(SB)
114	RET
115
116TEXT runtime·madvise_trampoline(SB),NOSPLIT,$0
117	MOVW	4(R0), R1	// arg 2 len
118	MOVW	8(R0), R2	// arg 3 advice
119	MOVW	0(R0), R0	// arg 1 addr
120	BL	libc_madvise(SB)
121	MOVW	$-1, R2
122	CMP	R0, R2
123	BL.EQ	notok<>(SB)
124	RET
125
126TEXT runtime·setitimer_trampoline(SB),NOSPLIT,$0
127	MOVW	4(R0), R1	// arg 2 new
128	MOVW	8(R0), R2	// arg 3 old
129	MOVW	0(R0), R0	// arg 1 which
130	BL	libc_setitimer(SB)
131	RET
132
133TEXT runtime·walltime_trampoline(SB),NOSPLIT,$0
134	// R0 already has *timeval
135	MOVW	$0, R1 // no timezone needed
136	BL	libc_gettimeofday(SB)
137	RET
138
139GLOBL timebase<>(SB),NOPTR,$(machTimebaseInfo__size)
140
141TEXT runtime·nanotime_trampoline(SB),NOSPLIT,$0
142	MOVW	R0, R8
143	BL	libc_mach_absolute_time(SB)
144	MOVW	R0, 0(R8)
145	MOVW	R1, 4(R8)
146	MOVW	timebase<>+machTimebaseInfo_numer(SB), R6
147	MOVW	$timebase<>+machTimebaseInfo_denom(SB), R5
148	MOVW	(R5), R7
149	DMB	MB_ISH	// memory barrier for atomic read
150	CMP	$0, R7
151	BNE	initialized
152
153	SUB	$(machTimebaseInfo__size+7)/8*8, R13
154	MOVW	R13, R0
155	BL	libc_mach_timebase_info(SB)
156	MOVW	machTimebaseInfo_numer(R13), R6
157	MOVW	machTimebaseInfo_denom(R13), R7
158	ADD	$(machTimebaseInfo__size+7)/8*8, R13
159
160	MOVW	R6, timebase<>+machTimebaseInfo_numer(SB)
161	MOVW	$timebase<>+machTimebaseInfo_denom(SB), R5
162	DMB	MB_ISH	// memory barrier for atomic write
163	MOVW	R7, (R5)
164	DMB	MB_ISH
165
166initialized:
167	MOVW	R6, 8(R8)
168	MOVW	R7, 12(R8)
169	RET
170
171TEXT runtime·sigfwd(SB),NOSPLIT,$0-16
172	MOVW	sig+4(FP), R0
173	MOVW	info+8(FP), R1
174	MOVW	ctx+12(FP), R2
175	MOVW	fn+0(FP), R11
176	MOVW	R13, R4
177	SUB	$24, R13
178	BIC	$0x7, R13 // alignment for ELF ABI
179	BL	(R11)
180	MOVW	R4, R13
181	RET
182
183TEXT runtime·sigtramp(SB),NOSPLIT,$0
184	// Reserve space for callee-save registers and arguments.
185	MOVM.DB.W [R4-R11], (R13)
186	SUB	$16, R13
187
188	// Save arguments.
189	MOVW	R0, 4(R13)	// sig
190	MOVW	R1, 8(R13)	// info
191	MOVW	R2, 12(R13)	// ctx
192
193	// this might be called in external code context,
194	// where g is not set.
195	MOVB	runtime·iscgo(SB), R0
196	CMP 	$0, R0
197	BL.NE	runtime·load_g(SB)
198
199	MOVW	R13, R6
200	CMP	$0, g
201	BEQ nog
202
203	// iOS always use the main stack to run the signal handler.
204	// We need to switch to gsignal ourselves.
205	MOVW	g_m(g), R11
206	MOVW	m_gsignal(R11), R5
207	MOVW	(g_stack+stack_hi)(R5), R6
208
209nog:
210	// Restore arguments.
211	MOVW	4(R13), R0
212	MOVW	8(R13), R1
213	MOVW	12(R13), R2
214
215	// Reserve space for args and the stack pointer on the
216	// gsignal stack.
217	SUB $24, R6
218	// Save stack pointer.
219	MOVW	R13, R4
220	MOVW	R4, 16(R6)
221	// Switch to gsignal stack.
222	MOVW	R6, R13
223
224	// Call sigtrampgo
225	MOVW	R0, 4(R13)
226	MOVW	R1, 8(R13)
227	MOVW	R2, 12(R13)
228	BL	runtime·sigtrampgo(SB)
229
230	// Switch to old stack.
231	MOVW	16(R13), R5
232	MOVW	R5, R13
233
234	// Restore callee-save registers.
235	ADD	$16, R13
236	MOVM.IA.W (R13), [R4-R11]
237
238	RET
239
240TEXT runtime·cgoSigtramp(SB),NOSPLIT,$0
241	JMP	runtime·sigtramp(SB)
242
243TEXT runtime·sigprocmask_trampoline(SB),NOSPLIT,$0
244	MOVW	4(R0), R1	// arg 2 new
245	MOVW	8(R0), R2	// arg 3 old
246	MOVW	0(R0), R0	// arg 1 how
247	BL	libc_pthread_sigmask(SB)
248	CMP	$0, R0
249	BL.NE	notok<>(SB)
250	RET
251
252TEXT runtime·sigaction_trampoline(SB),NOSPLIT,$0
253	MOVW	4(R0), R1	// arg 2 new
254	MOVW	8(R0), R2	// arg 3 old
255	MOVW	0(R0), R0	// arg 1 how
256	BL	libc_sigaction(SB)
257	RET
258
259TEXT runtime·usleep_trampoline(SB),NOSPLIT,$0
260	MOVW	0(R0), R0	// arg 1 usec
261	BL libc_usleep(SB)
262	RET
263
264TEXT ·publicationBarrier(SB),NOSPLIT|NOFRAME,$0-0
265	B	runtime·armPublicationBarrier(SB)
266
267TEXT runtime·sysctl_trampoline(SB),NOSPLIT,$0
268	MOVW	4(R0), R1	// arg 2 miblen
269	MOVW	8(R0), R2	// arg 3 out
270	MOVW	12(R0), R3	// arg 4 size
271	MOVW	16(R0), R4	// arg 5 dst
272	MOVW	20(R0), R5	// arg 6 ndst
273	MOVW	0(R0), R0	// arg 1 mib
274	// Only R0-R3 are used for arguments, the rest
275	// go on the stack.
276	MOVM.DB.W [R4-R5], (R13)
277	BL	libc_sysctl(SB)
278	ADD $(2*4), R13
279	RET
280
281TEXT runtime·kqueue_trampoline(SB),NOSPLIT,$0
282	BL	libc_kqueue(SB)
283	RET
284
285// int32 runtime·kevent(int kq, Kevent *changelist, int nchanges, Kevent *eventlist, int events, Timespec *timeout)
286TEXT runtime·kevent_trampoline(SB),NOSPLIT,$0
287	MOVW	4(R0), R1	// arg 2 keventss
288	MOVW	8(R0), R2	// arg 3 nch
289	MOVW	12(R0), R3	// arg 4 ev
290	MOVW	16(R0), R4	// arg 5 nev
291	MOVW	20(R0), R5	// arg 6 ts
292	MOVW	0(R0), R0	// arg 1 kq
293	// Only R0-R3 are used for arguments, the rest
294	// go on the stack.
295	MOVM.DB.W [R4-R5], (R13)
296	BL	libc_kevent(SB)
297	ADD	$(2*4), R13
298	MOVW	$-1, R2
299	CMP	R0, R2
300	BNE	ok
301	BL	libc_error(SB)
302	MOVW	(R0), R0	// errno
303	RSB	$0, R0, R0	// caller wants it as a negative error code
304ok:
305	RET
306
307TEXT runtime·fcntl_trampoline(SB),NOSPLIT,$0
308	MOVW	4(R0), R1	// arg 2 cmd
309	MOVW	8(R0), R2	// arg 3 arg
310	MOVW	0(R0), R0	// arg 1 fd
311	BL	libc_fcntl(SB)
312	RET
313
314// sigaltstack is not supported on iOS, so our sigtramp has
315// to do the stack switch ourselves.
316TEXT runtime·sigaltstack_trampoline(SB),NOSPLIT,$0
317	MOVW	$43, R0
318	BL	libc_exit(SB)
319	RET
320
321// Thread related functions
322// Note: On darwin/arm, the runtime always use runtime/cgo to
323// create threads, so all thread related functions will just exit with a
324// unique status.
325
326TEXT runtime·mstart_stub(SB),NOSPLIT,$0
327	MOVW	$44, R0
328	BL	libc_exit(SB)
329	RET
330
331TEXT runtime·pthread_attr_init_trampoline(SB),NOSPLIT,$0
332	MOVW	$45, R0
333	BL	libc_exit(SB)
334	RET
335
336TEXT runtime·pthread_attr_getstacksize_trampoline(SB),NOSPLIT,$0
337	MOVW	$46, R0
338	BL	libc_exit(SB)
339	RET
340
341TEXT runtime·pthread_attr_setdetachstate_trampoline(SB),NOSPLIT,$0
342	MOVW	$47, R0
343	BL	libc_exit(SB)
344	RET
345
346TEXT runtime·pthread_create_trampoline(SB),NOSPLIT,$0
347	MOVW	$48, R0
348	BL	libc_exit(SB)
349	RET
350
351TEXT runtime·raise_trampoline(SB),NOSPLIT,$0
352	MOVW	0(R0), R0	// arg 1 sig
353	BL	libc_raise(SB)
354	RET
355
356TEXT runtime·pthread_mutex_init_trampoline(SB),NOSPLIT,$0
357	MOVW	4(R0), R1	// arg 2 attr
358	MOVW	0(R0), R0	// arg 1 mutex
359	BL	libc_pthread_mutex_init(SB)
360	RET
361
362TEXT runtime·pthread_mutex_lock_trampoline(SB),NOSPLIT,$0
363	MOVW	0(R0), R0	// arg 1 mutex
364	BL	libc_pthread_mutex_lock(SB)
365	RET
366
367TEXT runtime·pthread_mutex_unlock_trampoline(SB),NOSPLIT,$0
368	MOVW	0(R0), R0	// arg 1 mutex
369	BL	libc_pthread_mutex_unlock(SB)
370	RET
371
372TEXT runtime·pthread_cond_init_trampoline(SB),NOSPLIT,$0
373	MOVW	4(R0), R1	// arg 2 attr
374	MOVW	0(R0), R0	// arg 1 cond
375	BL	libc_pthread_cond_init(SB)
376	RET
377
378TEXT runtime·pthread_cond_wait_trampoline(SB),NOSPLIT,$0
379	MOVW	4(R0), R1	// arg 2 mutex
380	MOVW	0(R0), R0	// arg 1 cond
381	BL	libc_pthread_cond_wait(SB)
382	RET
383
384TEXT runtime·pthread_cond_timedwait_relative_np_trampoline(SB),NOSPLIT,$0
385	MOVW	4(R0), R1	// arg 2 mutex
386	MOVW	8(R0), R2	// arg 3 timeout
387	MOVW	0(R0), R0	// arg 1 cond
388	BL	libc_pthread_cond_timedwait_relative_np(SB)
389	RET
390
391TEXT runtime·pthread_cond_signal_trampoline(SB),NOSPLIT,$0
392	MOVW	0(R0), R0	// arg 1 cond
393	BL	libc_pthread_cond_signal(SB)
394	RET
395
396TEXT runtime·pthread_self_trampoline(SB),NOSPLIT,$0
397	MOVW	R0, R4		// R4 is callee-save
398	BL	libc_pthread_self(SB)
399	MOVW	R0, 0(R4)	// return value
400	RET
401
402TEXT runtime·pthread_kill_trampoline(SB),NOSPLIT,$0
403	MOVW	4(R0), R1	// arg 2 sig
404	MOVW	0(R0), R0	// arg 1 thread
405	BL	libc_pthread_kill(SB)
406	RET
407
408// syscall calls a function in libc on behalf of the syscall package.
409// syscall takes a pointer to a struct like:
410// struct {
411//	fn    uintptr
412//	a1    uintptr
413//	a2    uintptr
414//	a3    uintptr
415//	r1    uintptr
416//	r2    uintptr
417//	err   uintptr
418// }
419// syscall must be called on the g0 stack with the
420// C calling convention (use libcCall).
421TEXT runtime·syscall(SB),NOSPLIT,$0
422	MOVW.W	R0, -4(R13)	// push structure pointer
423	MOVW	0(R0), R12	// fn
424	MOVW	8(R0), R1	// a2
425	MOVW	12(R0), R2	// a3
426	MOVW	4(R0), R0	// a1
427	BL	(R12)
428	MOVW.P	4(R13), R2	// pop structure pointer
429	MOVW	R0, 16(R2)	// save r1
430	MOVW	R1, 20(R2)	// save r2
431	MOVW	$-1, R3
432	CMP	R0, R3
433	BNE	ok
434	MOVW.W	R2, -4(R13)	// push structure pointer
435	BL	libc_error(SB)
436	MOVW	(R0), R0
437	MOVW.P	4(R13), R2	// pop structure pointer
438	MOVW	R0, 24(R2)	// save err
439ok:
440	RET
441
442// syscallPtr is like syscall except the libc function reports an
443// error by returning NULL and setting errno.
444TEXT runtime·syscallPtr(SB),NOSPLIT,$0
445	MOVW.W	R0, -4(R13)	// push structure pointer
446	MOVW	0(R0), R12	// fn
447	MOVW	8(R0), R1	// a2
448	MOVW	12(R0), R2	// a3
449	MOVW	4(R0), R0	// a1
450	BL	(R12)
451	MOVW.P	4(R13), R2	// pop structure pointer
452	MOVW	R0, 16(R2)	// save r1
453	MOVW	R1, 20(R2)	// save r2
454	MOVW	$0, R3
455	CMP	R0, R3
456	BNE	ok
457	MOVW.W	R2, -4(R13)	// push structure pointer
458	BL	libc_error(SB)
459	MOVW	(R0), R0
460	MOVW.P	4(R13), R2	// pop structure pointer
461	MOVW	R0, 24(R2)	// save err
462ok:
463	RET
464
465// syscall6 calls a function in libc on behalf of the syscall package.
466// syscall6 takes a pointer to a struct like:
467// struct {
468//	fn    uintptr
469//	a1    uintptr
470//	a2    uintptr
471//	a3    uintptr
472//	a4    uintptr
473//	a5    uintptr
474//	a6    uintptr
475//	r1    uintptr
476//	r2    uintptr
477//	err   uintptr
478// }
479// syscall6 must be called on the g0 stack with the
480// C calling convention (use libcCall).
481TEXT runtime·syscall6(SB),NOSPLIT,$0
482	MOVW.W	R0, -4(R13)	// push structure pointer
483	MOVW	0(R0), R12	// fn
484	MOVW	24(R0), R1	// a6
485	MOVW.W	R1, -4(R13)
486	MOVW	20(R0), R1	// a5
487	MOVW.W	R1, -4(R13)
488	MOVW	8(R0), R1	// a2
489	MOVW	12(R0), R2	// a3
490	MOVW	16(R0), R3	// a4
491	MOVW	4(R0), R0	// a1
492	BL	(R12)
493	ADD	$8, R13
494	MOVW.P	4(R13), R2	// pop structure pointer
495	MOVW	R0, 28(R2)	// save r1
496	MOVW	R1, 32(R2)	// save r2
497	MOVW	$-1, R3
498	CMP	R0, R3
499	BNE	ok
500	MOVW.W	R2, -4(R13)	// push structure pointer
501	BL	libc_error(SB)
502	MOVW	(R0), R0
503	MOVW.P	4(R13), R2	// pop structure pointer
504	MOVW	R0, 36(R2)	// save err
505ok:
506	RET
507
508// syscall6X calls a function in libc on behalf of the syscall package.
509// syscall6X takes a pointer to a struct like:
510// struct {
511//	fn    uintptr
512//	a1    uintptr
513//	a2    uintptr
514//	a3    uintptr
515//	a4    uintptr
516//	a5    uintptr
517//	a6    uintptr
518//	r1    uintptr
519//	r2    uintptr
520//	err   uintptr
521// }
522// syscall6X must be called on the g0 stack with the
523// C calling convention (use libcCall).
524TEXT runtime·syscall6X(SB),NOSPLIT,$0
525	MOVW.W	R0, -4(R13)	// push structure pointer
526	MOVW	0(R0), R12	// fn
527	MOVW	24(R0), R1	// a6
528	MOVW.W	R1, -4(R13)
529	MOVW	20(R0), R1	// a5
530	MOVW.W	R1, -4(R13)
531	MOVW	8(R0), R1	// a2
532	MOVW	12(R0), R2	// a3
533	MOVW	16(R0), R3	// a4
534	MOVW	4(R0), R0	// a1
535	BL	(R12)
536	ADD	$8, R13
537	MOVW.P	4(R13), R2	// pop structure pointer
538	MOVW	R0, 28(R2)	// save r1
539	MOVW	R1, 32(R2)	// save r2
540	MOVW	$-1, R3
541	CMP	R0, R3
542	BNE	ok
543	CMP	R1, R3
544	BNE	ok
545	MOVW.W	R2, -4(R13)	// push structure pointer
546	BL	libc_error(SB)
547	MOVW	(R0), R0
548	MOVW.P	4(R13), R2	// pop structure pointer
549	MOVW	R0, 36(R2)	// save err
550ok:
551	RET
552
553// syscall9 calls a function in libc on behalf of the syscall package.
554// syscall9 takes a pointer to a struct like:
555// struct {
556//	fn    uintptr
557//	a1    uintptr
558//	a2    uintptr
559//	a3    uintptr
560//	a4    uintptr
561//	a5    uintptr
562//	a6    uintptr
563//	a7    uintptr
564//	a8    uintptr
565//	a9    uintptr
566//	r1    uintptr
567//	r2    uintptr
568//	err   uintptr
569// }
570// syscall9 must be called on the g0 stack with the
571// C calling convention (use libcCall).
572TEXT runtime·syscall9(SB),NOSPLIT,$0
573	MOVW.W	R0, -4(R13)	// push structure pointer
574	MOVW	0(R0), R12	// fn
575	MOVW	36(R0), R1	// a9
576	MOVW.W	R1, -4(R13)
577	MOVW	32(R0), R1	// a8
578	MOVW.W	R1, -4(R13)
579	MOVW	28(R0), R1	// a7
580	MOVW.W	R1, -4(R13)
581	MOVW	24(R0), R1	// a6
582	MOVW.W	R1, -4(R13)
583	MOVW	20(R0), R1	// a5
584	MOVW.W	R1, -4(R13)
585	MOVW	8(R0), R1	// a2
586	MOVW	12(R0), R2	// a3
587	MOVW	16(R0), R3	// a4
588	MOVW	4(R0), R0	// a1
589	BL	(R12)
590	ADD	$20, R13
591	MOVW.P	4(R13), R2	// pop structure pointer
592	MOVW	R0, 40(R2)	// save r1
593	MOVW	R1, 44(R2)	// save r2
594	MOVW	$-1, R3
595	CMP	R0, R3
596	BNE	ok
597	MOVW.W	R2, -4(R13)	// push structure pointer
598	BL	libc_error(SB)
599	MOVW	(R0), R0
600	MOVW.P	4(R13), R2	// pop structure pointer
601	MOVW	R0, 48(R2)	// save err
602ok:
603	RET
604