Home | History | Annotate | Download | only in runtime
      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 // for EABI, as we don't support OABI
     14 #define SYS_BASE 0x0
     15 
     16 #define SYS_exit (SYS_BASE + 1)
     17 #define SYS_read (SYS_BASE + 3)
     18 #define SYS_write (SYS_BASE + 4)
     19 #define SYS_open (SYS_BASE + 5)
     20 #define SYS_close (SYS_BASE + 6)
     21 #define SYS_getpid (SYS_BASE + 20)
     22 #define SYS_kill (SYS_BASE + 37)
     23 #define SYS_gettimeofday (SYS_BASE + 78)
     24 #define SYS_clone (SYS_BASE + 120)
     25 #define SYS_rt_sigreturn (SYS_BASE + 173)
     26 #define SYS_rt_sigaction (SYS_BASE + 174)
     27 #define SYS_rt_sigprocmask (SYS_BASE + 175)
     28 #define SYS_sigaltstack (SYS_BASE + 186)
     29 #define SYS_mmap2 (SYS_BASE + 192)
     30 #define SYS_futex (SYS_BASE + 240)
     31 #define SYS_exit_group (SYS_BASE + 248)
     32 #define SYS_munmap (SYS_BASE + 91)
     33 #define SYS_madvise (SYS_BASE + 220)
     34 #define SYS_setitimer (SYS_BASE + 104)
     35 #define SYS_mincore (SYS_BASE + 219)
     36 #define SYS_gettid (SYS_BASE + 224)
     37 #define SYS_tkill (SYS_BASE + 238)
     38 #define SYS_sched_yield (SYS_BASE + 158)
     39 #define SYS_pselect6 (SYS_BASE + 335)
     40 #define SYS_ugetrlimit (SYS_BASE + 191)
     41 #define SYS_sched_getaffinity (SYS_BASE + 242)
     42 #define SYS_clock_gettime (SYS_BASE + 263)
     43 #define SYS_epoll_create (SYS_BASE + 250)
     44 #define SYS_epoll_ctl (SYS_BASE + 251)
     45 #define SYS_epoll_wait (SYS_BASE + 252)
     46 #define SYS_epoll_create1 (SYS_BASE + 357)
     47 #define SYS_fcntl (SYS_BASE + 55)
     48 #define SYS_access (SYS_BASE + 33)
     49 #define SYS_connect (SYS_BASE + 283)
     50 #define SYS_socket (SYS_BASE + 281)
     51 #define SYS_brk (SYS_BASE + 45)
     52 
     53 #define ARM_BASE (SYS_BASE + 0x0f0000)
     54 
     55 TEXT runtimeopen(SB),NOSPLIT,$0
     56 	MOVW	name+0(FP), R0
     57 	MOVW	mode+4(FP), R1
     58 	MOVW	perm+8(FP), R2
     59 	MOVW	$SYS_open, R7
     60 	SWI	$0
     61 	MOVW	$0xfffff001, R1
     62 	CMP	R1, R0
     63 	MOVW.HI	$-1, R0
     64 	MOVW	R0, ret+12(FP)
     65 	RET
     66 
     67 TEXT runtimeclosefd(SB),NOSPLIT,$0
     68 	MOVW	fd+0(FP), R0
     69 	MOVW	$SYS_close, R7
     70 	SWI	$0
     71 	MOVW	$0xfffff001, R1
     72 	CMP	R1, R0
     73 	MOVW.HI	$-1, R0
     74 	MOVW	R0, ret+4(FP)
     75 	RET
     76 
     77 TEXT runtimewrite(SB),NOSPLIT,$0
     78 	MOVW	fd+0(FP), R0
     79 	MOVW	p+4(FP), R1
     80 	MOVW	n+8(FP), R2
     81 	MOVW	$SYS_write, R7
     82 	SWI	$0
     83 	MOVW	$0xfffff001, R1
     84 	CMP	R1, R0
     85 	MOVW.HI	$-1, R0
     86 	MOVW	R0, ret+12(FP)
     87 	RET
     88 
     89 TEXT runtimeread(SB),NOSPLIT,$0
     90 	MOVW	fd+0(FP), R0
     91 	MOVW	p+4(FP), R1
     92 	MOVW	n+8(FP), R2
     93 	MOVW	$SYS_read, R7
     94 	SWI	$0
     95 	MOVW	$0xfffff001, R1
     96 	CMP	R1, R0
     97 	MOVW.HI	$-1, R0
     98 	MOVW	R0, ret+12(FP)
     99 	RET
    100 
    101 TEXT runtimegetrlimit(SB),NOSPLIT,$0
    102 	MOVW	kind+0(FP), R0
    103 	MOVW	limit+4(FP), R1
    104 	MOVW	$SYS_ugetrlimit, R7
    105 	SWI	$0
    106 	MOVW	R0, ret+8(FP)
    107 	RET
    108 
    109 TEXT runtimeexit(SB),NOSPLIT,$-4
    110 	MOVW	code+0(FP), R0
    111 	MOVW	$SYS_exit_group, R7
    112 	SWI	$0
    113 	MOVW	$1234, R0
    114 	MOVW	$1002, R1
    115 	MOVW	R0, (R1)	// fail hard
    116 
    117 TEXT exit1<>(SB),NOSPLIT,$-4
    118 	MOVW	code+0(FP), R0
    119 	MOVW	$SYS_exit, R7
    120 	SWI	$0
    121 	MOVW	$1234, R0
    122 	MOVW	$1003, R1
    123 	MOVW	R0, (R1)	// fail hard
    124 
    125 // func exitThread(wait *uint32)
    126 TEXT runtimeexitThread(SB),NOSPLIT,$-4-4
    127 	MOVW	wait+0(FP), R0
    128 	// We're done using the stack.
    129 	// Alas, there's no reliable way to make this write atomic
    130 	// without potentially using the stack. So it goes.
    131 	MOVW	$0, R1
    132 	MOVW	R1, (R0)
    133 	MOVW	$0, R0	// exit code
    134 	MOVW	$SYS_exit, R7
    135 	SWI	$0
    136 	MOVW	$1234, R0
    137 	MOVW	$1004, R1
    138 	MOVW	R0, (R1)	// fail hard
    139 	JMP	0(PC)
    140 
    141 TEXT runtimegettid(SB),NOSPLIT,$0-4
    142 	MOVW	$SYS_gettid, R7
    143 	SWI	$0
    144 	MOVW	R0, ret+0(FP)
    145 	RET
    146 
    147 TEXT	runtimeraise(SB),NOSPLIT,$-4
    148 	MOVW	$SYS_gettid, R7
    149 	SWI	$0
    150 	// arg 1 tid already in R0 from gettid
    151 	MOVW	sig+0(FP), R1	// arg 2 - signal
    152 	MOVW	$SYS_tkill, R7
    153 	SWI	$0
    154 	RET
    155 
    156 TEXT	runtimeraiseproc(SB),NOSPLIT,$-4
    157 	MOVW	$SYS_getpid, R7
    158 	SWI	$0
    159 	// arg 1 tid already in R0 from getpid
    160 	MOVW	sig+0(FP), R1	// arg 2 - signal
    161 	MOVW	$SYS_kill, R7
    162 	SWI	$0
    163 	RET
    164 
    165 TEXT runtimemmap(SB),NOSPLIT,$0
    166 	MOVW	addr+0(FP), R0
    167 	MOVW	n+4(FP), R1
    168 	MOVW	prot+8(FP), R2
    169 	MOVW	flags+12(FP), R3
    170 	MOVW	fd+16(FP), R4
    171 	MOVW	off+20(FP), R5
    172 	MOVW	$SYS_mmap2, R7
    173 	SWI	$0
    174 	MOVW	$0xfffff001, R6
    175 	CMP		R6, R0
    176 	MOVW	$0, R1
    177 	RSB.HI	$0, R0
    178 	MOVW.HI	R0, R1		// if error, put in R1
    179 	MOVW.HI	$0, R0
    180 	MOVW	R0, p+24(FP)
    181 	MOVW	R1, err+28(FP)
    182 	RET
    183 
    184 TEXT runtimemunmap(SB),NOSPLIT,$0
    185 	MOVW	addr+0(FP), R0
    186 	MOVW	n+4(FP), R1
    187 	MOVW	$SYS_munmap, R7
    188 	SWI	$0
    189 	MOVW	$0xfffff001, R6
    190 	CMP 	R6, R0
    191 	MOVW.HI	$0, R8  // crash on syscall failure
    192 	MOVW.HI	R8, (R8)
    193 	RET
    194 
    195 TEXT runtimemadvise(SB),NOSPLIT,$0
    196 	MOVW	addr+0(FP), R0
    197 	MOVW	n+4(FP), R1
    198 	MOVW	flags+8(FP), R2
    199 	MOVW	$SYS_madvise, R7
    200 	SWI	$0
    201 	// ignore failure - maybe pages are locked
    202 	RET
    203 
    204 TEXT runtimesetitimer(SB),NOSPLIT,$0
    205 	MOVW	mode+0(FP), R0
    206 	MOVW	new+4(FP), R1
    207 	MOVW	old+8(FP), R2
    208 	MOVW	$SYS_setitimer, R7
    209 	SWI	$0
    210 	RET
    211 
    212 TEXT runtimemincore(SB),NOSPLIT,$0
    213 	MOVW	addr+0(FP), R0
    214 	MOVW	n+4(FP), R1
    215 	MOVW	dst+8(FP), R2
    216 	MOVW	$SYS_mincore, R7
    217 	SWI	$0
    218 	MOVW	R0, ret+12(FP)
    219 	RET
    220 
    221 TEXT runtimewalltime(SB), NOSPLIT, $32
    222 	MOVW	$0, R0  // CLOCK_REALTIME
    223 	MOVW	$8(R13), R1  // timespec
    224 	MOVW	$SYS_clock_gettime, R7
    225 	SWI	$0
    226 
    227 	MOVW	8(R13), R0  // sec
    228 	MOVW	12(R13), R2  // nsec
    229 
    230 	MOVW	R0, sec_lo+0(FP)
    231 	MOVW	$0, R1
    232 	MOVW	R1, sec_hi+4(FP)
    233 	MOVW	R2, nsec+8(FP)
    234 	RET
    235 
    236 // int64 nanotime(void)
    237 TEXT runtimenanotime(SB),NOSPLIT,$32
    238 	MOVW	$1, R0  // CLOCK_MONOTONIC
    239 	MOVW	$8(R13), R1  // timespec
    240 	MOVW	$SYS_clock_gettime, R7
    241 	SWI	$0
    242 
    243 	MOVW	8(R13), R0  // sec
    244 	MOVW	12(R13), R2  // nsec
    245 
    246 	MOVW	$1000000000, R3
    247 	MULLU	R0, R3, (R1, R0)
    248 	MOVW	$0, R4
    249 	ADD.S	R2, R0
    250 	ADC	R4, R1
    251 
    252 	MOVW	R0, ret_lo+0(FP)
    253 	MOVW	R1, ret_hi+4(FP)
    254 	RET
    255 
    256 // int32 futex(int32 *uaddr, int32 op, int32 val,
    257 //	struct timespec *timeout, int32 *uaddr2, int32 val2);
    258 TEXT runtimefutex(SB),NOSPLIT,$0
    259 	MOVW    addr+0(FP), R0
    260 	MOVW    op+4(FP), R1
    261 	MOVW    val+8(FP), R2
    262 	MOVW    ts+12(FP), R3
    263 	MOVW    addr2+16(FP), R4
    264 	MOVW    val3+20(FP), R5
    265 	MOVW	$SYS_futex, R7
    266 	SWI	$0
    267 	MOVW	R0, ret+24(FP)
    268 	RET
    269 
    270 // int32 clone(int32 flags, void *stack, M *mp, G *gp, void (*fn)(void));
    271 TEXT runtimeclone(SB),NOSPLIT,$0
    272 	MOVW	flags+0(FP), R0
    273 	MOVW	stk+4(FP), R1
    274 	MOVW	$0, R2	// parent tid ptr
    275 	MOVW	$0, R3	// tls_val
    276 	MOVW	$0, R4	// child tid ptr
    277 	MOVW	$0, R5
    278 
    279 	// Copy mp, gp, fn off parent stack for use by child.
    280 	// TODO(kaib): figure out which registers are clobbered by clone and avoid stack copying
    281 	MOVW	$-16(R1), R1
    282 	MOVW	mp+8(FP), R6
    283 	MOVW	R6, 0(R1)
    284 	MOVW	gp+12(FP), R6
    285 	MOVW	R6, 4(R1)
    286 	MOVW	fn+16(FP), R6
    287 	MOVW	R6, 8(R1)
    288 	MOVW	$1234, R6
    289 	MOVW	R6, 12(R1)
    290 
    291 	MOVW	$SYS_clone, R7
    292 	SWI	$0
    293 
    294 	// In parent, return.
    295 	CMP	$0, R0
    296 	BEQ	3(PC)
    297 	MOVW	R0, ret+20(FP)
    298 	RET
    299 
    300 	// Paranoia: check that SP is as we expect. Use R13 to avoid linker 'fixup'
    301 	MOVW	12(R13), R0
    302 	MOVW	$1234, R1
    303 	CMP	R0, R1
    304 	BEQ	2(PC)
    305 	BL	runtimeabort(SB)
    306 
    307 	MOVW	0(R13), R8    // m
    308 	MOVW	4(R13), R0    // g
    309 
    310 	CMP	$0, R8
    311 	BEQ	nog
    312 	CMP	$0, R0
    313 	BEQ	nog
    314 
    315 	MOVW	R0, g
    316 	MOVW	R8, g_m(g)
    317 
    318 	// paranoia; check they are not nil
    319 	MOVW	0(R8), R0
    320 	MOVW	0(g), R0
    321 
    322 	BL	runtimeemptyfunc(SB)	// fault if stack check is wrong
    323 
    324 	// Initialize m->procid to Linux tid
    325 	MOVW	$SYS_gettid, R7
    326 	SWI	$0
    327 	MOVW	g_m(g), R8
    328 	MOVW	R0, m_procid(R8)
    329 
    330 nog:
    331 	// Call fn
    332 	MOVW	8(R13), R0
    333 	MOVW	$16(R13), R13
    334 	BL	(R0)
    335 
    336 	// It shouldn't return. If it does, exit that thread.
    337 	SUB	$16, R13 // restore the stack pointer to avoid memory corruption
    338 	MOVW	$0, R0
    339 	MOVW	R0, 4(R13)
    340 	BL	exit1<>(SB)
    341 
    342 	MOVW	$1234, R0
    343 	MOVW	$1005, R1
    344 	MOVW	R0, (R1)
    345 
    346 TEXT runtimesigaltstack(SB),NOSPLIT,$0
    347 	MOVW	new+0(FP), R0
    348 	MOVW	old+4(FP), R1
    349 	MOVW	$SYS_sigaltstack, R7
    350 	SWI	$0
    351 	MOVW	$0xfffff001, R6
    352 	CMP 	R6, R0
    353 	MOVW.HI	$0, R8  // crash on syscall failure
    354 	MOVW.HI	R8, (R8)
    355 	RET
    356 
    357 TEXT runtimesigfwd(SB),NOSPLIT,$0-16
    358 	MOVW	sig+4(FP), R0
    359 	MOVW	info+8(FP), R1
    360 	MOVW	ctx+12(FP), R2
    361 	MOVW	fn+0(FP), R11
    362 	MOVW	R13, R4
    363 	SUB	$24, R13
    364 	BIC	$0x7, R13 // alignment for ELF ABI
    365 	BL	(R11)
    366 	MOVW	R4, R13
    367 	RET
    368 
    369 TEXT runtimesigtramp(SB),NOSPLIT,$12
    370 	// this might be called in external code context,
    371 	// where g is not set.
    372 	// first save R0, because runtimeload_g will clobber it
    373 	MOVW	R0, 4(R13)
    374 	MOVB	runtimeiscgo(SB), R0
    375 	CMP 	$0, R0
    376 	BL.NE	runtimeload_g(SB)
    377 
    378 	MOVW	R1, 8(R13)
    379 	MOVW	R2, 12(R13)
    380 	MOVW  	$runtimesigtrampgo(SB), R11
    381 	BL	(R11)
    382 	RET
    383 
    384 TEXT runtimecgoSigtramp(SB),NOSPLIT,$0
    385 	MOVW  	$runtimesigtramp(SB), R11
    386 	B	(R11)
    387 
    388 TEXT runtimertsigprocmask(SB),NOSPLIT,$0
    389 	MOVW	how+0(FP), R0
    390 	MOVW	new+4(FP), R1
    391 	MOVW	old+8(FP), R2
    392 	MOVW	size+12(FP), R3
    393 	MOVW	$SYS_rt_sigprocmask, R7
    394 	SWI	$0
    395 	RET
    396 
    397 TEXT runtimert_sigaction(SB),NOSPLIT,$0
    398 	MOVW	sig+0(FP), R0
    399 	MOVW	new+4(FP), R1
    400 	MOVW	old+8(FP), R2
    401 	MOVW	size+12(FP), R3
    402 	MOVW	$SYS_rt_sigaction, R7
    403 	SWI	$0
    404 	MOVW	R0, ret+16(FP)
    405 	RET
    406 
    407 TEXT runtimeusleep(SB),NOSPLIT,$12
    408 	MOVW	usec+0(FP), R0
    409 	CALL	runtimeusplitR0(SB)
    410 	MOVW	R0, 4(R13)
    411 	MOVW	$1000, R0	// usec to nsec
    412 	MUL	R0, R1
    413 	MOVW	R1, 8(R13)
    414 	MOVW	$0, R0
    415 	MOVW	$0, R1
    416 	MOVW	$0, R2
    417 	MOVW	$0, R3
    418 	MOVW	$4(R13), R4
    419 	MOVW	$0, R5
    420 	MOVW	$SYS_pselect6, R7
    421 	SWI	$0
    422 	RET
    423 
    424 // As for cas, memory barriers are complicated on ARM, but the kernel
    425 // provides a user helper. ARMv5 does not support SMP and has no
    426 // memory barrier instruction at all. ARMv6 added SMP support and has
    427 // a memory barrier, but it requires writing to a coprocessor
    428 // register. ARMv7 introduced the DMB instruction, but it's expensive
    429 // even on single-core devices. The kernel helper takes care of all of
    430 // this for us.
    431 
    432 TEXT publicationBarrier<>(SB),NOSPLIT,$0
    433 	// void __kuser_memory_barrier(void);
    434 	MOVW	$0xffff0fa0, R15 // R15 is hardware PC.
    435 
    436 TEXT publicationBarrier(SB),NOSPLIT,$0
    437 	BL	publicationBarrier<>(SB)
    438 	RET
    439 
    440 TEXT runtimeosyield(SB),NOSPLIT,$0
    441 	MOVW	$SYS_sched_yield, R7
    442 	SWI	$0
    443 	RET
    444 
    445 TEXT runtimesched_getaffinity(SB),NOSPLIT,$0
    446 	MOVW	pid+0(FP), R0
    447 	MOVW	len+4(FP), R1
    448 	MOVW	buf+8(FP), R2
    449 	MOVW	$SYS_sched_getaffinity, R7
    450 	SWI	$0
    451 	MOVW	R0, ret+12(FP)
    452 	RET
    453 
    454 // int32 runtimeepollcreate(int32 size)
    455 TEXT runtimeepollcreate(SB),NOSPLIT,$0
    456 	MOVW	size+0(FP), R0
    457 	MOVW	$SYS_epoll_create, R7
    458 	SWI	$0
    459 	MOVW	R0, ret+4(FP)
    460 	RET
    461 
    462 // int32 runtimeepollcreate1(int32 flags)
    463 TEXT runtimeepollcreate1(SB),NOSPLIT,$0
    464 	MOVW	flags+0(FP), R0
    465 	MOVW	$SYS_epoll_create1, R7
    466 	SWI	$0
    467 	MOVW	R0, ret+4(FP)
    468 	RET
    469 
    470 // func epollctl(epfd, op, fd int32, ev *epollEvent) int
    471 TEXT runtimeepollctl(SB),NOSPLIT,$0
    472 	MOVW	epfd+0(FP), R0
    473 	MOVW	op+4(FP), R1
    474 	MOVW	fd+8(FP), R2
    475 	MOVW	ev+12(FP), R3
    476 	MOVW	$SYS_epoll_ctl, R7
    477 	SWI	$0
    478 	MOVW	R0, ret+16(FP)
    479 	RET
    480 
    481 // int32 runtimeepollwait(int32 epfd, EpollEvent *ev, int32 nev, int32 timeout)
    482 TEXT runtimeepollwait(SB),NOSPLIT,$0
    483 	MOVW	epfd+0(FP), R0
    484 	MOVW	ev+4(FP), R1
    485 	MOVW	nev+8(FP), R2
    486 	MOVW	timeout+12(FP), R3
    487 	MOVW	$SYS_epoll_wait, R7
    488 	SWI	$0
    489 	MOVW	R0, ret+16(FP)
    490 	RET
    491 
    492 // void runtimecloseonexec(int32 fd)
    493 TEXT runtimecloseonexec(SB),NOSPLIT,$0
    494 	MOVW	fd+0(FP), R0	// fd
    495 	MOVW	$2, R1	// F_SETFD
    496 	MOVW	$1, R2	// FD_CLOEXEC
    497 	MOVW	$SYS_fcntl, R7
    498 	SWI	$0
    499 	RET
    500 
    501 // b __kuser_get_tls @ 0xffff0fe0
    502 TEXT runtimeread_tls_fallback(SB),NOSPLIT,$-4
    503 	MOVW	$0xffff0fe0, R0
    504 	B	(R0)
    505 
    506 TEXT runtimeaccess(SB),NOSPLIT,$0
    507 	MOVW	name+0(FP), R0
    508 	MOVW	mode+4(FP), R1
    509 	MOVW	$SYS_access, R7
    510 	SWI	$0
    511 	MOVW	R0, ret+8(FP)
    512 	RET
    513 
    514 TEXT runtimeconnect(SB),NOSPLIT,$0
    515 	MOVW	fd+0(FP), R0
    516 	MOVW	addr+4(FP), R1
    517 	MOVW	len+8(FP), R2
    518 	MOVW	$SYS_connect, R7
    519 	SWI	$0
    520 	MOVW	R0, ret+12(FP)
    521 	RET
    522 
    523 TEXT runtimesocket(SB),NOSPLIT,$0
    524 	MOVW	domain+0(FP), R0
    525 	MOVW	typ+4(FP), R1
    526 	MOVW	prot+8(FP), R2
    527 	MOVW	$SYS_socket, R7
    528 	SWI	$0
    529 	MOVW	R0, ret+12(FP)
    530 	RET
    531 
    532 // func sbrk0() uintptr
    533 TEXT runtimesbrk0(SB),NOSPLIT,$0-4
    534 	// Implemented as brk(NULL).
    535 	MOVW	$0, R0
    536 	MOVW	$SYS_brk, R7
    537 	SWI	$0
    538 	MOVW	R0, ret+0(FP)
    539 	RET
    540