Text file src/runtime/sys_linux_arm.s
1 // Copyright 2009 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 arm, Linux
7 //
8
9 #include "go_asm.h"
10 #include "go_tls.h"
11 #include "textflag.h"
12
13 #define CLOCK_REALTIME 0
14 #define CLOCK_MONOTONIC 1
15
16 // for EABI, as we don't support OABI
17 #define SYS_BASE 0x0
18
19 #define SYS_exit (SYS_BASE + 1)
20 #define SYS_read (SYS_BASE + 3)
21 #define SYS_write (SYS_BASE + 4)
22 #define SYS_open (SYS_BASE + 5)
23 #define SYS_close (SYS_BASE + 6)
24 #define SYS_getpid (SYS_BASE + 20)
25 #define SYS_kill (SYS_BASE + 37)
26 #define SYS_clone (SYS_BASE + 120)
27 #define SYS_rt_sigreturn (SYS_BASE + 173)
28 #define SYS_rt_sigaction (SYS_BASE + 174)
29 #define SYS_rt_sigprocmask (SYS_BASE + 175)
30 #define SYS_sigaltstack (SYS_BASE + 186)
31 #define SYS_mmap2 (SYS_BASE + 192)
32 #define SYS_futex (SYS_BASE + 240)
33 #define SYS_exit_group (SYS_BASE + 248)
34 #define SYS_munmap (SYS_BASE + 91)
35 #define SYS_madvise (SYS_BASE + 220)
36 #define SYS_setitimer (SYS_BASE + 104)
37 #define SYS_mincore (SYS_BASE + 219)
38 #define SYS_gettid (SYS_BASE + 224)
39 #define SYS_tgkill (SYS_BASE + 268)
40 #define SYS_sched_yield (SYS_BASE + 158)
41 #define SYS_nanosleep (SYS_BASE + 162)
42 #define SYS_sched_getaffinity (SYS_BASE + 242)
43 #define SYS_clock_gettime (SYS_BASE + 263)
44 #define SYS_epoll_create (SYS_BASE + 250)
45 #define SYS_epoll_ctl (SYS_BASE + 251)
46 #define SYS_epoll_wait (SYS_BASE + 252)
47 #define SYS_epoll_create1 (SYS_BASE + 357)
48 #define SYS_fcntl (SYS_BASE + 55)
49 #define SYS_access (SYS_BASE + 33)
50 #define SYS_connect (SYS_BASE + 283)
51 #define SYS_socket (SYS_BASE + 281)
52 #define SYS_brk (SYS_BASE + 45)
53
54 #define ARM_BASE (SYS_BASE + 0x0f0000)
55
56 TEXT runtime·open(SB),NOSPLIT,$0
57 MOVW name+0(FP), R0
58 MOVW mode+4(FP), R1
59 MOVW perm+8(FP), R2
60 MOVW $SYS_open, R7
61 SWI $0
62 MOVW $0xfffff001, R1
63 CMP R1, R0
64 MOVW.HI $-1, R0
65 MOVW R0, ret+12(FP)
66 RET
67
68 TEXT runtime·closefd(SB),NOSPLIT,$0
69 MOVW fd+0(FP), R0
70 MOVW $SYS_close, R7
71 SWI $0
72 MOVW $0xfffff001, R1
73 CMP R1, R0
74 MOVW.HI $-1, R0
75 MOVW R0, ret+4(FP)
76 RET
77
78 TEXT runtime·write(SB),NOSPLIT,$0
79 MOVW fd+0(FP), R0
80 MOVW p+4(FP), R1
81 MOVW n+8(FP), R2
82 MOVW $SYS_write, R7
83 SWI $0
84 MOVW $0xfffff001, R1
85 CMP R1, R0
86 MOVW.HI $-1, R0
87 MOVW R0, ret+12(FP)
88 RET
89
90 TEXT runtime·read(SB),NOSPLIT,$0
91 MOVW fd+0(FP), R0
92 MOVW p+4(FP), R1
93 MOVW n+8(FP), R2
94 MOVW $SYS_read, R7
95 SWI $0
96 MOVW $0xfffff001, R1
97 CMP R1, R0
98 MOVW.HI $-1, R0
99 MOVW R0, ret+12(FP)
100 RET
101
102 TEXT runtime·exit(SB),NOSPLIT|NOFRAME,$0
103 MOVW code+0(FP), R0
104 MOVW $SYS_exit_group, R7
105 SWI $0
106 MOVW $1234, R0
107 MOVW $1002, R1
108 MOVW R0, (R1) // fail hard
109
110 TEXT exit1<>(SB),NOSPLIT|NOFRAME,$0
111 MOVW code+0(FP), R0
112 MOVW $SYS_exit, R7
113 SWI $0
114 MOVW $1234, R0
115 MOVW $1003, R1
116 MOVW R0, (R1) // fail hard
117
118 // func exitThread(wait *uint32)
119 TEXT runtime·exitThread(SB),NOSPLIT|NOFRAME,$0-4
120 MOVW wait+0(FP), R0
121 // We're done using the stack.
122 // Alas, there's no reliable way to make this write atomic
123 // without potentially using the stack. So it goes.
124 MOVW $0, R1
125 MOVW R1, (R0)
126 MOVW $0, R0 // exit code
127 MOVW $SYS_exit, R7
128 SWI $0
129 MOVW $1234, R0
130 MOVW $1004, R1
131 MOVW R0, (R1) // fail hard
132 JMP 0(PC)
133
134 TEXT runtime·gettid(SB),NOSPLIT,$0-4
135 MOVW $SYS_gettid, R7
136 SWI $0
137 MOVW R0, ret+0(FP)
138 RET
139
140 TEXT runtime·raise(SB),NOSPLIT|NOFRAME,$0
141 MOVW $SYS_getpid, R7
142 SWI $0
143 MOVW R0, R4
144 MOVW $SYS_gettid, R7
145 SWI $0
146 MOVW R0, R1 // arg 2 tid
147 MOVW R4, R0 // arg 1 pid
148 MOVW sig+0(FP), R2 // arg 3
149 MOVW $SYS_tgkill, R7
150 SWI $0
151 RET
152
153 TEXT runtime·raiseproc(SB),NOSPLIT|NOFRAME,$0
154 MOVW $SYS_getpid, R7
155 SWI $0
156 // arg 1 tid already in R0 from getpid
157 MOVW sig+0(FP), R1 // arg 2 - signal
158 MOVW $SYS_kill, R7
159 SWI $0
160 RET
161
162 TEXT runtime·mmap(SB),NOSPLIT,$0
163 MOVW addr+0(FP), R0
164 MOVW n+4(FP), R1
165 MOVW prot+8(FP), R2
166 MOVW flags+12(FP), R3
167 MOVW fd+16(FP), R4
168 MOVW off+20(FP), R5
169 MOVW $SYS_mmap2, R7
170 SWI $0
171 MOVW $0xfffff001, R6
172 CMP R6, R0
173 MOVW $0, R1
174 RSB.HI $0, R0
175 MOVW.HI R0, R1 // if error, put in R1
176 MOVW.HI $0, R0
177 MOVW R0, p+24(FP)
178 MOVW R1, err+28(FP)
179 RET
180
181 TEXT runtime·munmap(SB),NOSPLIT,$0
182 MOVW addr+0(FP), R0
183 MOVW n+4(FP), R1
184 MOVW $SYS_munmap, R7
185 SWI $0
186 MOVW $0xfffff001, R6
187 CMP R6, R0
188 MOVW.HI $0, R8 // crash on syscall failure
189 MOVW.HI R8, (R8)
190 RET
191
192 TEXT runtime·madvise(SB),NOSPLIT,$0
193 MOVW addr+0(FP), R0
194 MOVW n+4(FP), R1
195 MOVW flags+8(FP), R2
196 MOVW $SYS_madvise, R7
197 SWI $0
198 MOVW R0, ret+12(FP)
199 RET
200
201 TEXT runtime·setitimer(SB),NOSPLIT,$0
202 MOVW mode+0(FP), R0
203 MOVW new+4(FP), R1
204 MOVW old+8(FP), R2
205 MOVW $SYS_setitimer, R7
206 SWI $0
207 RET
208
209 TEXT runtime·mincore(SB),NOSPLIT,$0
210 MOVW addr+0(FP), R0
211 MOVW n+4(FP), R1
212 MOVW dst+8(FP), R2
213 MOVW $SYS_mincore, R7
214 SWI $0
215 MOVW R0, ret+12(FP)
216 RET
217
218 TEXT runtime·walltime(SB),NOSPLIT,$0-12
219 // We don't know how much stack space the VDSO code will need,
220 // so switch to g0.
221
222 // Save old SP. Use R13 instead of SP to avoid linker rewriting the offsets.
223 MOVW R13, R4 // R4 is unchanged by C code.
224
225 MOVW g_m(g), R5 // R5 is unchanged by C code.
226
227 // Set vdsoPC and vdsoSP for SIGPROF traceback.
228 MOVW LR, m_vdsoPC(R5)
229 MOVW R13, m_vdsoSP(R5)
230
231 MOVW m_curg(R5), R0
232
233 CMP g, R0 // Only switch if on curg.
234 B.NE noswitch
235
236 MOVW m_g0(R5), R0
237 MOVW (g_sched+gobuf_sp)(R0), R13 // Set SP to g0 stack
238
239 noswitch:
240 SUB $24, R13 // Space for results
241 BIC $0x7, R13 // Align for C code
242
243 MOVW $CLOCK_REALTIME, R0
244 MOVW $8(R13), R1 // timespec
245 MOVW runtime·vdsoClockgettimeSym(SB), R11
246 CMP $0, R11
247 B.EQ fallback
248
249 BL (R11)
250 JMP finish
251
252 fallback:
253 MOVW $SYS_clock_gettime, R7
254 SWI $0
255
256 finish:
257 MOVW 8(R13), R0 // sec
258 MOVW 12(R13), R2 // nsec
259
260 MOVW R4, R13 // Restore real SP
261 MOVW $0, R1
262 MOVW R1, m_vdsoSP(R5)
263
264 MOVW R0, sec_lo+0(FP)
265 MOVW R1, sec_hi+4(FP)
266 MOVW R2, nsec+8(FP)
267 RET
268
269 // int64 nanotime(void)
270 TEXT runtime·nanotime(SB),NOSPLIT,$0-8
271 // Switch to g0 stack. See comment above in runtime·walltime.
272
273 // Save old SP. Use R13 instead of SP to avoid linker rewriting the offsets.
274 MOVW R13, R4 // R4 is unchanged by C code.
275
276 MOVW g_m(g), R5 // R5 is unchanged by C code.
277
278 // Set vdsoPC and vdsoSP for SIGPROF traceback.
279 MOVW LR, m_vdsoPC(R5)
280 MOVW R13, m_vdsoSP(R5)
281
282 MOVW m_curg(R5), R0
283
284 CMP g, R0 // Only switch if on curg.
285 B.NE noswitch
286
287 MOVW m_g0(R5), R0
288 MOVW (g_sched+gobuf_sp)(R0), R13 // Set SP to g0 stack
289
290 noswitch:
291 SUB $24, R13 // Space for results
292 BIC $0x7, R13 // Align for C code
293
294 MOVW $CLOCK_MONOTONIC, R0
295 MOVW $8(R13), R1 // timespec
296 MOVW runtime·vdsoClockgettimeSym(SB), R11
297 CMP $0, R11
298 B.EQ fallback
299
300 BL (R11)
301 JMP finish
302
303 fallback:
304 MOVW $SYS_clock_gettime, R7
305 SWI $0
306
307 finish:
308 MOVW 8(R13), R0 // sec
309 MOVW 12(R13), R2 // nsec
310
311 MOVW R4, R13 // Restore real SP
312 MOVW $0, R4
313 MOVW R4, m_vdsoSP(R5)
314
315 MOVW $1000000000, R3
316 MULLU R0, R3, (R1, R0)
317 ADD.S R2, R0
318 ADC R4, R1
319
320 MOVW R0, ret_lo+0(FP)
321 MOVW R1, ret_hi+4(FP)
322 RET
323
324 // int32 futex(int32 *uaddr, int32 op, int32 val,
325 // struct timespec *timeout, int32 *uaddr2, int32 val2);
326 TEXT runtime·futex(SB),NOSPLIT,$0
327 MOVW addr+0(FP), R0
328 MOVW op+4(FP), R1
329 MOVW val+8(FP), R2
330 MOVW ts+12(FP), R3
331 MOVW addr2+16(FP), R4
332 MOVW val3+20(FP), R5
333 MOVW $SYS_futex, R7
334 SWI $0
335 MOVW R0, ret+24(FP)
336 RET
337
338 // int32 clone(int32 flags, void *stack, M *mp, G *gp, void (*fn)(void));
339 TEXT runtime·clone(SB),NOSPLIT,$0
340 MOVW flags+0(FP), R0
341 MOVW stk+4(FP), R1
342 MOVW $0, R2 // parent tid ptr
343 MOVW $0, R3 // tls_val
344 MOVW $0, R4 // child tid ptr
345 MOVW $0, R5
346
347 // Copy mp, gp, fn off parent stack for use by child.
348 MOVW $-16(R1), R1
349 MOVW mp+8(FP), R6
350 MOVW R6, 0(R1)
351 MOVW gp+12(FP), R6
352 MOVW R6, 4(R1)
353 MOVW fn+16(FP), R6
354 MOVW R6, 8(R1)
355 MOVW $1234, R6
356 MOVW R6, 12(R1)
357
358 MOVW $SYS_clone, R7
359 SWI $0
360
361 // In parent, return.
362 CMP $0, R0
363 BEQ 3(PC)
364 MOVW R0, ret+20(FP)
365 RET
366
367 // Paranoia: check that SP is as we expect. Use R13 to avoid linker 'fixup'
368 NOP R13 // tell vet SP/R13 changed - stop checking offsets
369 MOVW 12(R13), R0
370 MOVW $1234, R1
371 CMP R0, R1
372 BEQ 2(PC)
373 BL runtime·abort(SB)
374
375 MOVW 0(R13), R8 // m
376 MOVW 4(R13), R0 // g
377
378 CMP $0, R8
379 BEQ nog
380 CMP $0, R0
381 BEQ nog
382
383 MOVW R0, g
384 MOVW R8, g_m(g)
385
386 // paranoia; check they are not nil
387 MOVW 0(R8), R0
388 MOVW 0(g), R0
389
390 BL runtime·emptyfunc(SB) // fault if stack check is wrong
391
392 // Initialize m->procid to Linux tid
393 MOVW $SYS_gettid, R7
394 SWI $0
395 MOVW g_m(g), R8
396 MOVW R0, m_procid(R8)
397
398 nog:
399 // Call fn
400 MOVW 8(R13), R0
401 MOVW $16(R13), R13
402 BL (R0)
403
404 // It shouldn't return. If it does, exit that thread.
405 SUB $16, R13 // restore the stack pointer to avoid memory corruption
406 MOVW $0, R0
407 MOVW R0, 4(R13)
408 BL exit1<>(SB)
409
410 MOVW $1234, R0
411 MOVW $1005, R1
412 MOVW R0, (R1)
413
414 TEXT runtime·sigaltstack(SB),NOSPLIT,$0
415 MOVW new+0(FP), R0
416 MOVW old+4(FP), R1
417 MOVW $SYS_sigaltstack, R7
418 SWI $0
419 MOVW $0xfffff001, R6
420 CMP R6, R0
421 MOVW.HI $0, R8 // crash on syscall failure
422 MOVW.HI R8, (R8)
423 RET
424
425 TEXT runtime·sigfwd(SB),NOSPLIT,$0-16
426 MOVW sig+4(FP), R0
427 MOVW info+8(FP), R1
428 MOVW ctx+12(FP), R2
429 MOVW fn+0(FP), R11
430 MOVW R13, R4
431 SUB $24, R13
432 BIC $0x7, R13 // alignment for ELF ABI
433 BL (R11)
434 MOVW R4, R13
435 RET
436
437 TEXT runtime·sigtramp(SB),NOSPLIT,$12
438 // this might be called in external code context,
439 // where g is not set.
440 // first save R0, because runtime·load_g will clobber it
441 MOVW R0, 4(R13)
442 MOVB runtime·iscgo(SB), R0
443 CMP $0, R0
444 BL.NE runtime·load_g(SB)
445
446 MOVW R1, 8(R13)
447 MOVW R2, 12(R13)
448 MOVW $runtime·sigtrampgo(SB), R11
449 BL (R11)
450 RET
451
452 TEXT runtime·cgoSigtramp(SB),NOSPLIT,$0
453 MOVW $runtime·sigtramp(SB), R11
454 B (R11)
455
456 TEXT runtime·rtsigprocmask(SB),NOSPLIT,$0
457 MOVW how+0(FP), R0
458 MOVW new+4(FP), R1
459 MOVW old+8(FP), R2
460 MOVW size+12(FP), R3
461 MOVW $SYS_rt_sigprocmask, R7
462 SWI $0
463 RET
464
465 TEXT runtime·rt_sigaction(SB),NOSPLIT,$0
466 MOVW sig+0(FP), R0
467 MOVW new+4(FP), R1
468 MOVW old+8(FP), R2
469 MOVW size+12(FP), R3
470 MOVW $SYS_rt_sigaction, R7
471 SWI $0
472 MOVW R0, ret+16(FP)
473 RET
474
475 TEXT runtime·usleep(SB),NOSPLIT,$12
476 MOVW usec+0(FP), R0
477 CALL runtime·usplitR0(SB)
478 MOVW R0, 4(R13)
479 MOVW $1000, R0 // usec to nsec
480 MUL R0, R1
481 MOVW R1, 8(R13)
482 MOVW $4(R13), R0
483 MOVW $0, R1
484 MOVW $SYS_nanosleep, R7
485 SWI $0
486 RET
487
488 // As for cas, memory barriers are complicated on ARM, but the kernel
489 // provides a user helper. ARMv5 does not support SMP and has no
490 // memory barrier instruction at all. ARMv6 added SMP support and has
491 // a memory barrier, but it requires writing to a coprocessor
492 // register. ARMv7 introduced the DMB instruction, but it's expensive
493 // even on single-core devices. The kernel helper takes care of all of
494 // this for us.
495
496 TEXT kernelPublicationBarrier<>(SB),NOSPLIT,$0
497 // void __kuser_memory_barrier(void);
498 MOVW $0xffff0fa0, R11
499 CALL (R11)
500 RET
501
502 TEXT ·publicationBarrier(SB),NOSPLIT,$0
503 MOVB ·goarm(SB), R11
504 CMP $7, R11
505 BLT 2(PC)
506 JMP ·armPublicationBarrier(SB)
507 JMP kernelPublicationBarrier<>(SB) // extra layer so this function is leaf and no SP adjustment on GOARM=7
508
509 TEXT runtime·osyield(SB),NOSPLIT,$0
510 MOVW $SYS_sched_yield, R7
511 SWI $0
512 RET
513
514 TEXT runtime·sched_getaffinity(SB),NOSPLIT,$0
515 MOVW pid+0(FP), R0
516 MOVW len+4(FP), R1
517 MOVW buf+8(FP), R2
518 MOVW $SYS_sched_getaffinity, R7
519 SWI $0
520 MOVW R0, ret+12(FP)
521 RET
522
523 // int32 runtime·epollcreate(int32 size)
524 TEXT runtime·epollcreate(SB),NOSPLIT,$0
525 MOVW size+0(FP), R0
526 MOVW $SYS_epoll_create, R7
527 SWI $0
528 MOVW R0, ret+4(FP)
529 RET
530
531 // int32 runtime·epollcreate1(int32 flags)
532 TEXT runtime·epollcreate1(SB),NOSPLIT,$0
533 MOVW flags+0(FP), R0
534 MOVW $SYS_epoll_create1, R7
535 SWI $0
536 MOVW R0, ret+4(FP)
537 RET
538
539 // func epollctl(epfd, op, fd int32, ev *epollEvent) int
540 TEXT runtime·epollctl(SB),NOSPLIT,$0
541 MOVW epfd+0(FP), R0
542 MOVW op+4(FP), R1
543 MOVW fd+8(FP), R2
544 MOVW ev+12(FP), R3
545 MOVW $SYS_epoll_ctl, R7
546 SWI $0
547 MOVW R0, ret+16(FP)
548 RET
549
550 // int32 runtime·epollwait(int32 epfd, EpollEvent *ev, int32 nev, int32 timeout)
551 TEXT runtime·epollwait(SB),NOSPLIT,$0
552 MOVW epfd+0(FP), R0
553 MOVW ev+4(FP), R1
554 MOVW nev+8(FP), R2
555 MOVW timeout+12(FP), R3
556 MOVW $SYS_epoll_wait, R7
557 SWI $0
558 MOVW R0, ret+16(FP)
559 RET
560
561 // void runtime·closeonexec(int32 fd)
562 TEXT runtime·closeonexec(SB),NOSPLIT,$0
563 MOVW fd+0(FP), R0 // fd
564 MOVW $2, R1 // F_SETFD
565 MOVW $1, R2 // FD_CLOEXEC
566 MOVW $SYS_fcntl, R7
567 SWI $0
568 RET
569
570 // b __kuser_get_tls @ 0xffff0fe0
571 TEXT runtime·read_tls_fallback(SB),NOSPLIT|NOFRAME,$0
572 MOVW $0xffff0fe0, R0
573 B (R0)
574
575 TEXT runtime·access(SB),NOSPLIT,$0
576 MOVW name+0(FP), R0
577 MOVW mode+4(FP), R1
578 MOVW $SYS_access, R7
579 SWI $0
580 MOVW R0, ret+8(FP)
581 RET
582
583 TEXT runtime·connect(SB),NOSPLIT,$0
584 MOVW fd+0(FP), R0
585 MOVW addr+4(FP), R1
586 MOVW len+8(FP), R2
587 MOVW $SYS_connect, R7
588 SWI $0
589 MOVW R0, ret+12(FP)
590 RET
591
592 TEXT runtime·socket(SB),NOSPLIT,$0
593 MOVW domain+0(FP), R0
594 MOVW typ+4(FP), R1
595 MOVW prot+8(FP), R2
596 MOVW $SYS_socket, R7
597 SWI $0
598 MOVW R0, ret+12(FP)
599 RET
600
601 // func sbrk0() uintptr
602 TEXT runtime·sbrk0(SB),NOSPLIT,$0-4
603 // Implemented as brk(NULL).
604 MOVW $0, R0
605 MOVW $SYS_brk, R7
606 SWI $0
607 MOVW R0, ret+0(FP)
608 RET
609
610 TEXT runtime·sigreturn(SB),NOSPLIT,$0-0
611 RET
View as plain text