Home | History | Annotate | Download | only in runtime
      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 // See http://fxr.watson.org/fxr/source/bsd/kern/syscalls.c?v=xnu-1228
      7 // or /usr/include/sys/syscall.h (on a Mac) for system call numbers.
      8 
      9 #include "go_asm.h"
     10 #include "go_tls.h"
     11 #include "textflag.h"
     12 
     13 // Copied from /usr/include/sys/syscall.h
     14 #define	SYS_exit           1
     15 #define	SYS_read           3
     16 #define	SYS_write          4
     17 #define	SYS_open           5
     18 #define	SYS_close          6
     19 #define	SYS_mmap           197
     20 #define	SYS_munmap         73
     21 #define	SYS_madvise        75
     22 #define	SYS_mincore        78
     23 #define	SYS_gettimeofday   116
     24 #define	SYS_kill           37
     25 #define	SYS_getpid         20
     26 #define	SYS___pthread_kill 328
     27 #define	SYS_setitimer      83
     28 #define	SYS___sysctl       202
     29 #define	SYS_sigprocmask    48
     30 #define	SYS_sigaction      46
     31 #define	SYS_sigreturn      184
     32 #define	SYS_select         93
     33 #define	SYS_bsdthread_register 366
     34 #define	SYS_bsdthread_create 360
     35 #define	SYS_bsdthread_terminate 361
     36 #define	SYS_kqueue         362
     37 #define	SYS_kevent         363
     38 #define	SYS_fcntl          92
     39 
     40 TEXT notok<>(SB),NOSPLIT,$0
     41 	MOVW	$0, R8
     42 	MOVW	R8, (R8)
     43 	B		0(PC)
     44 
     45 TEXT runtimeopen(SB),NOSPLIT,$0
     46 	MOVW	name+0(FP), R0
     47 	MOVW	mode+4(FP), R1
     48 	MOVW	perm+8(FP), R2
     49 	MOVW	$SYS_open, R12
     50 	SWI	$0x80
     51 	MOVW.CS	$-1, R0
     52 	MOVW	R0, ret+12(FP)
     53 	RET
     54 
     55 TEXT runtimeclosefd(SB),NOSPLIT,$0
     56 	MOVW	fd+0(FP), R0
     57 	MOVW	$SYS_close, R12
     58 	SWI	$0x80
     59 	MOVW.CS	$-1, R0
     60 	MOVW	R0, ret+4(FP)
     61 	RET
     62 
     63 TEXT runtimewrite(SB),NOSPLIT,$0
     64 	MOVW	fd+0(FP), R0
     65 	MOVW	p+4(FP), R1
     66 	MOVW	n+8(FP), R2
     67 	MOVW	$SYS_write, R12
     68 	SWI	$0x80
     69 	MOVW.CS	$-1, R0
     70 	MOVW	R0, ret+12(FP)
     71 	RET
     72 
     73 TEXT runtimeread(SB),NOSPLIT,$0
     74 	MOVW	fd+0(FP), R0
     75 	MOVW	p+4(FP), R1
     76 	MOVW	n+8(FP), R2
     77 	MOVW	$SYS_read, R12
     78 	SWI	$0x80
     79 	MOVW.CS	$-1, R0
     80 	MOVW	R0, ret+12(FP)
     81 	RET
     82 
     83 TEXT runtimeexit(SB),NOSPLIT,$-4
     84 	MOVW	code+0(FP), R0
     85 	MOVW	$SYS_exit, R12
     86 	SWI	$0x80
     87 	MOVW	$1234, R0
     88 	MOVW	$1002, R1
     89 	MOVW	R0, (R1)	// fail hard
     90 
     91 // Exit this OS thread (like pthread_exit, which eventually
     92 // calls __bsdthread_terminate).
     93 TEXT runtimeexit1(SB),NOSPLIT,$0
     94 	MOVW	$SYS_bsdthread_terminate, R12
     95 	SWI	$0x80
     96 	MOVW	$1234, R0
     97 	MOVW	$1003, R1
     98 	MOVW	R0, (R1)	// fail hard
     99 
    100 TEXT runtimeraise(SB),NOSPLIT,$0
    101 	// Ideally we'd send the signal to the current thread,
    102 	// not the whole process, but that's too hard on OS X.
    103 	JMP	runtimeraiseproc(SB)
    104 
    105 TEXT runtimeraiseproc(SB),NOSPLIT,$24
    106 	MOVW	$SYS_getpid, R12
    107 	SWI	$0x80
    108 	// arg 1 pid already in R0 from getpid
    109 	MOVW	unnamed+0(FP), R1	// arg 2 - signal
    110 	MOVW	$1, R2	// arg 3 - posix
    111 	MOVW	$SYS_kill, R12
    112 	SWI $0x80
    113 	RET
    114 
    115 TEXT runtimemmap(SB),NOSPLIT,$0
    116 	MOVW	addr+0(FP), R0
    117 	MOVW	n+4(FP), R1
    118 	MOVW	prot+8(FP), R2
    119 	MOVW	flags+12(FP), R3
    120 	MOVW	fd+16(FP), R4
    121 	MOVW	off+20(FP), R5
    122 	MOVW	$0, R6 // off_t is uint64_t
    123 	MOVW	$SYS_mmap, R12
    124 	SWI	$0x80
    125 	MOVW	R0, ret+24(FP)
    126 	RET
    127 
    128 TEXT runtimemunmap(SB),NOSPLIT,$0
    129 	MOVW	addr+0(FP), R0
    130 	MOVW	n+4(FP), R1
    131 	MOVW	$SYS_munmap, R12
    132 	SWI	$0x80
    133 	BL.CS	notok<>(SB)
    134 	RET
    135 
    136 TEXT runtimemadvise(SB),NOSPLIT,$0
    137 	MOVW	addr+0(FP), R0
    138 	MOVW	n+4(FP), R1
    139 	MOVW	flags+8(FP), R2
    140 	MOVW	$SYS_madvise, R12
    141 	SWI	$0x80
    142 	BL.CS	notok<>(SB)
    143 	RET
    144 
    145 TEXT runtimesetitimer(SB),NOSPLIT,$0
    146 	MOVW	mode+0(FP), R0
    147 	MOVW	new+4(FP), R1
    148 	MOVW	old+8(FP), R2
    149 	MOVW	$SYS_setitimer, R12
    150 	SWI	$0x80
    151 	RET
    152 
    153 TEXT runtimemincore(SB),NOSPLIT,$0
    154 	MOVW	addr+0(FP), R0
    155 	MOVW	n+4(FP), R1
    156 	MOVW	dst+8(FP), R2
    157 	MOVW	$SYS_mincore, R12
    158 	SWI	$0x80
    159 	MOVW	R0, ret+12(FP)
    160 	RET
    161 
    162 TEXT timenow(SB), 7, $32
    163 	MOVW	$8(R13), R0  // timeval
    164 	MOVW	$0, R1  // zone
    165 	MOVW	$SYS_gettimeofday, R12
    166 	SWI	$0x80 // Note: R0 is tv_sec, R1 is tv_usec
    167 
    168 	MOVW    R1, R2  // usec
    169 
    170 	MOVW	R0, sec+0(FP)
    171 	MOVW	$0, R1
    172 	MOVW	R1, loc+4(FP)
    173 	MOVW	$1000, R3
    174 	MUL	R3, R2
    175 	MOVW	R2, nsec+8(FP)
    176 	RET
    177 
    178 TEXT runtimenanotime(SB),NOSPLIT,$32
    179 	MOVW	$8(R13), R0  // timeval
    180 	MOVW	$0, R1  // zone
    181 	MOVW	$SYS_gettimeofday, R12
    182 	SWI	$0x80 // Note: R0 is tv_sec, R1 is tv_usec
    183 
    184 	MOVW    R1, R2
    185 	MOVW	$1000000000, R3
    186 	MULLU	R0, R3, (R1, R0)
    187 	MOVW	$1000, R3
    188 	MOVW	$0, R4
    189 	MUL	R3, R2
    190 	ADD.S	R2, R0
    191 	ADC	R4, R1
    192 
    193 	MOVW	R0, ret_lo+0(FP)
    194 	MOVW	R1, ret_hi+4(FP)
    195 	RET
    196 
    197 // Sigtramp's job is to call the actual signal handler.
    198 // It is called with the following arguments on the stack:
    199 //	 LR  	"return address" - ignored
    200 //	 R0  	actual handler
    201 //	 R1  	siginfo style - ignored
    202 //	 R2   	signal number
    203 //	 R3   	siginfo
    204 //	 -4(FP)	context, beware that 0(FP) is the saved LR
    205 TEXT runtimesigtramp(SB),NOSPLIT,$0
    206 	// this might be called in external code context,
    207 	// where g is not set.
    208 	// first save R0, because runtimeload_g will clobber it
    209 	MOVM.DB.W [R0], (R13)
    210 	MOVB	runtimeiscgo(SB), R0
    211 	CMP 	$0, R0
    212 	BL.NE	runtimeload_g(SB)
    213 
    214 	CMP 	$0, g
    215 	BNE 	cont
    216 	// fake function call stack frame for badsignal
    217 	// we only need to pass R2 (signal number), but
    218 	// badsignal will expect R2 at 4(R13), so we also
    219 	// push R1 onto stack. turns out we do need R1
    220 	// to do sigreturn.
    221 	MOVM.DB.W [R1,R2], (R13)
    222 	MOVW  	$runtimebadsignal(SB), R11
    223 	BL	(R11)
    224 	MOVM.IA.W [R1], (R13) // saved infostype
    225 	ADD		$(4+4), R13 // +4: also need to remove the pushed R0.
    226 	MOVW    ucontext-4(FP), R0 // load ucontext
    227 	B	ret
    228 
    229 cont:
    230 	// Restore R0
    231 	MOVM.IA.W (R13), [R0]
    232 
    233 	// NOTE: some Darwin/ARM kernels always use the main stack to run the
    234 	// signal handler. We need to switch to gsignal ourselves.
    235 	MOVW	g_m(g), R11
    236 	MOVW	m_gsignal(R11), R5
    237 	MOVW	(g_stack+stack_hi)(R5), R6
    238 	SUB		$28, R6
    239 
    240 	// copy arguments for call to sighandler
    241 	MOVW	R2, 4(R6) // signal num
    242 	MOVW	R3, 8(R6) // signal info
    243 	MOVW	g, 16(R6) // old_g
    244 	MOVW	context-4(FP), R4
    245 	MOVW	R4, 12(R6) // context
    246 
    247 	// Backup ucontext and infostyle
    248 	MOVW    R4, 20(R6)
    249 	MOVW    R1, 24(R6)
    250 
    251 	// switch stack and g
    252 	MOVW	R6, R13 // sigtramp can not re-entrant, so no need to back up R13.
    253 	MOVW	R5, g
    254 
    255 	BL	(R0)
    256 
    257 	// call sigreturn
    258 	MOVW	20(R13), R0	// saved ucontext
    259 	MOVW	24(R13), R1	// saved infostyle
    260 ret:
    261 	MOVW	$SYS_sigreturn, R12 // sigreturn(ucontext, infostyle)
    262 	SWI	$0x80
    263 
    264 	// if sigreturn fails, we can do nothing but exit
    265 	B	runtimeexit(SB)
    266 
    267 TEXT runtimesigprocmask(SB),NOSPLIT,$0
    268 	MOVW	sig+0(FP), R0
    269 	MOVW	new+4(FP), R1
    270 	MOVW	old+8(FP), R2
    271 	MOVW	$SYS_sigprocmask, R12
    272 	SWI	$0x80
    273 	BL.CS	notok<>(SB)
    274 	RET
    275 
    276 TEXT runtimesigaction(SB),NOSPLIT,$0
    277 	MOVW	mode+0(FP), R0
    278 	MOVW	new+4(FP), R1
    279 	MOVW	old+8(FP), R2
    280 	MOVW	$SYS_sigaction, R12
    281 	SWI	$0x80
    282 	RET
    283 
    284 TEXT runtimeusleep(SB),NOSPLIT,$12
    285 	MOVW	usec+0(FP), R0
    286 	CALL	runtimeusplitR0(SB)
    287 	MOVW	R0, a-12(SP)
    288 	MOVW	R1, b-8(SP)
    289 
    290 	// select(0, 0, 0, 0, &tv)
    291 	MOVW	$0, R0
    292 	MOVW	$0, R1
    293 	MOVW	$0, R2
    294 	MOVW	$0, R3
    295 	MOVW	$a-12(SP), R4
    296 	MOVW	$SYS_select, R12
    297 	SWI	$0x80
    298 	RET
    299 
    300 TEXT runtimecas(SB),NOSPLIT,$0
    301 	B	runtimearmcas(SB)
    302 
    303 TEXT runtimecasp1(SB),NOSPLIT,$0
    304 	B	runtimecas(SB)
    305 
    306 TEXT publicationBarrier(SB),NOSPLIT,$-4-0
    307 	B	runtimearmPublicationBarrier(SB)
    308 
    309 TEXT runtimesysctl(SB),NOSPLIT,$0
    310 	MOVW	mib+0(FP), R0
    311 	MOVW	miblen+4(FP), R1
    312 	MOVW	out+8(FP), R2
    313 	MOVW	size+12(FP), R3
    314 	MOVW	dst+16(FP), R4
    315 	MOVW	ndst+20(FP), R5
    316 	MOVW	$SYS___sysctl, R12 // syscall entry
    317 	SWI	$0x80
    318 	BCC     sysctl_ret
    319 	RSB     $0, R0, R0
    320 	MOVW	R0, ret+24(FP)
    321 	RET
    322 sysctl_ret:
    323 	MOVW	$0, R0
    324 	MOVW	R0, ret+24(FP)
    325 	RET
    326 
    327 // Thread related functions
    328 // func bsdthread_create(stk, arg unsafe.Pointer, fn uintptr) int32
    329 TEXT runtimebsdthread_create(SB),NOSPLIT,$0
    330 	// Set up arguments to bsdthread_create system call.
    331 	// The ones in quotes pass through to the thread callback
    332 	// uninterpreted, so we can put whatever we want there.
    333 	MOVW    fn+8(FP),    R0 // "func"
    334 	MOVW    arg+4(FP),   R1 // "arg"
    335 	MOVW    stk+0(FP),   R2 // stack
    336 	MOVW	$0x01000000, R4	// flags = PTHREAD_START_CUSTOM
    337 	MOVW	$0,          R5 // paranoia
    338 	MOVW	$SYS_bsdthread_create, R12
    339 	SWI	$0x80
    340 	BCC		create_ret
    341 	RSB 	$0, R0, R0
    342 	MOVW	R0, ret+12(FP)
    343 	RET
    344 create_ret:
    345 	MOVW	$0, R0
    346 	MOVW	R0, ret+12(FP)
    347 	RET
    348 
    349 // The thread that bsdthread_create creates starts executing here,
    350 // because we registered this function using bsdthread_register
    351 // at startup.
    352 //	R0 = "pthread"
    353 //	R1 = mach thread port
    354 //	R2 = "func" (= fn)
    355 //	R3 = "arg" (= m)
    356 //	R4 = stack
    357 //	R5 = flags (= 0)
    358 // XXX: how to deal with R4/SP? ref: Libc-594.9.1/arm/pthreads/thread_start.s
    359 TEXT runtimebsdthread_start(SB),NOSPLIT,$0
    360 	MOVW    R1, m_procid(R3) // thread port is m->procid
    361 	MOVW	m_g0(R3), g
    362 	MOVW	R3, g_m(g)
    363 	// ARM don't have runtimestackcheck(SB)
    364 	// disable runfast mode of vfp
    365 	EOR     R12, R12
    366 	WORD    $0xeee1ca10 // fmxr	fpscr, ip
    367 	BL      (R2) // fn
    368 	BL      runtimeexit1(SB)
    369 	RET
    370 
    371 // int32 bsdthread_register(void)
    372 // registers callbacks for threadstart (see bsdthread_create above
    373 // and wqthread and pthsize (not used).  returns 0 on success.
    374 TEXT runtimebsdthread_register(SB),NOSPLIT,$0
    375 	MOVW	$runtimebsdthread_start(SB), R0	// threadstart
    376 	MOVW	$0, R1	// wqthread, not used by us
    377 	MOVW	$0, R2	// pthsize, not used by us
    378 	MOVW	$0, R3 	// dummy_value [sic]
    379 	MOVW	$0, R4	// targetconc_ptr
    380 	MOVW	$0, R5	// dispatchqueue_offset
    381 	MOVW	$SYS_bsdthread_register, R12	// bsdthread_register
    382 	SWI	$0x80
    383 	MOVW	R0, ret+0(FP)
    384 	RET
    385 
    386 // uint32 mach_msg_trap(void*, uint32, uint32, uint32, uint32, uint32, uint32)
    387 TEXT runtimemach_msg_trap(SB),NOSPLIT,$0
    388 	MOVW    h+0(FP), R0
    389 	MOVW    op+4(FP), R1
    390 	MOVW    send_size+8(FP), R2
    391 	MOVW    rcv_size+12(FP), R3
    392 	MOVW    rcv_name+16(FP), R4
    393 	MOVW    timeout+20(FP), R5
    394 	MOVW    notify+24(FP), R6
    395 	MVN     $30, R12
    396 	SWI	$0x80
    397 	MOVW	R0, ret+28(FP)
    398 	RET
    399 
    400 TEXT runtimemach_task_self(SB),NOSPLIT,$0
    401 	MVN     $27, R12 // task_self_trap
    402 	SWI	$0x80
    403 	MOVW	R0, ret+0(FP)
    404 	RET
    405 
    406 TEXT runtimemach_thread_self(SB),NOSPLIT,$0
    407 	MVN 	$26, R12 // thread_self_trap
    408 	SWI	$0x80
    409 	MOVW	R0, ret+0(FP)
    410 	RET
    411 
    412 TEXT runtimemach_reply_port(SB),NOSPLIT,$0
    413 	MVN 	$25, R12	// mach_reply_port
    414 	SWI	$0x80
    415 	MOVW	R0, ret+0(FP)
    416 	RET
    417 
    418 // Mach provides trap versions of the semaphore ops,
    419 // instead of requiring the use of RPC.
    420 
    421 // uint32 mach_semaphore_wait(uint32)
    422 TEXT runtimemach_semaphore_wait(SB),NOSPLIT,$0
    423 	MOVW	sema+0(FP), R0
    424 	MVN 	$35, R12	// semaphore_wait_trap
    425 	SWI	$0x80
    426 	MOVW	R0, ret+4(FP)
    427 	RET
    428 
    429 // uint32 mach_semaphore_timedwait(uint32, uint32, uint32)
    430 TEXT runtimemach_semaphore_timedwait(SB),NOSPLIT,$0
    431 	MOVW	sema+0(FP), R0
    432 	MOVW	sec+4(FP), R1
    433 	MOVW	nsec+8(FP), R2
    434 	MVN 	$37, R12	// semaphore_timedwait_trap
    435 	SWI	$0x80
    436 	MOVW	R0, ret+12(FP)
    437 	RET
    438 
    439 // uint32 mach_semaphore_signal(uint32)
    440 TEXT runtimemach_semaphore_signal(SB),NOSPLIT,$0
    441 	MOVW    sema+0(FP), R0
    442 	MVN 	$32, R12	// semaphore_signal_trap
    443 	SWI	$0x80
    444 	MOVW	R0, ret+4(FP)
    445 	RET
    446 
    447 // uint32 mach_semaphore_signal_all(uint32)
    448 TEXT runtimemach_semaphore_signal_all(SB),NOSPLIT,$0
    449 	MOVW	sema+0(FP), R0
    450 	MVN 	$33, R12	// semaphore_signal_all_trap
    451 	SWI	$0x80
    452 	MOVW	R0, ret+4(FP)
    453 	RET
    454 
    455 // int32 runtimekqueue(void)
    456 TEXT runtimekqueue(SB),NOSPLIT,$0
    457 	MOVW	$SYS_kqueue, R12
    458 	SWI	$0x80
    459 	RSB.CS	$0, R0, R0
    460 	MOVW	R0, ret+0(FP)
    461 	RET
    462 
    463 // int32 runtimekevent(int kq, Kevent *changelist, int nchanges, Kevent *eventlist, int events, Timespec *timeout)
    464 TEXT runtimekevent(SB),NOSPLIT,$0
    465 	MOVW	$SYS_kevent, R12
    466 	MOVW	kq+0(FP), R0
    467 	MOVW	ch+4(FP), R1
    468 	MOVW	nch+8(FP), R2
    469 	MOVW	ev+12(FP), R3
    470 	MOVW	nev+16(FP), R4
    471 	MOVW	ts+20(FP), R5
    472 	SWI	$0x80
    473 	RSB.CS	$0, R0, R0
    474 	MOVW	R0, ret+24(FP)
    475 	RET
    476 
    477 // int32 runtimecloseonexec(int32 fd)
    478 TEXT runtimecloseonexec(SB),NOSPLIT,$0
    479 	MOVW	$SYS_fcntl, R12
    480 	MOVW	fd+0(FP), R0
    481 	MOVW	$2, R1	// F_SETFD
    482 	MOVW	$1, R2	// FD_CLOEXEC
    483 	SWI	$0x80
    484 	RET
    485 
    486 // sigaltstack on some darwin/arm version is buggy and will always
    487 // run the signal handler on the main stack, so our sigtramp has
    488 // to do the stack switch ourselves.
    489 TEXT runtimesigaltstack(SB),NOSPLIT,$0
    490 	RET
    491