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