// Copyright 2014 The Go Authors. All rights reserved.
|
// Use of this source code is governed by a BSD-style
|
// license that can be found in the LICENSE file.
|
|
// System calls and other sys.stuff for ARM, Darwin
|
// System calls are implemented in libSystem, this file contains
|
// trampolines that convert from Go to C calling convention.
|
|
#include "go_asm.h"
|
#include "go_tls.h"
|
#include "textflag.h"
|
|
TEXT notok<>(SB),NOSPLIT,$0
|
MOVW $0, R8
|
MOVW R8, (R8)
|
B 0(PC)
|
|
TEXT runtime·open_trampoline(SB),NOSPLIT,$0
|
MOVW 4(R0), R1 // arg 2 mode
|
MOVW 8(R0), R2 // arg 3 perm
|
MOVW 0(R0), R0 // arg 1 name
|
BL libc_open(SB)
|
RET
|
|
TEXT runtime·close_trampoline(SB),NOSPLIT,$0
|
MOVW 0(R0), R0 // arg 1 fd
|
BL libc_close(SB)
|
RET
|
|
TEXT runtime·write_trampoline(SB),NOSPLIT,$0
|
MOVW 4(R0), R1 // arg 2 buf
|
MOVW 8(R0), R2 // arg 3 count
|
MOVW 0(R0), R0 // arg 1 fd
|
BL libc_write(SB)
|
RET
|
|
TEXT runtime·read_trampoline(SB),NOSPLIT,$0
|
MOVW 4(R0), R1 // arg 2 buf
|
MOVW 8(R0), R2 // arg 3 count
|
MOVW 0(R0), R0 // arg 1 fd
|
BL libc_read(SB)
|
RET
|
|
TEXT runtime·exit_trampoline(SB),NOSPLIT|NOFRAME,$0
|
MOVW 0(R0), R0 // arg 0 code
|
BL libc_exit(SB)
|
MOVW $1234, R0
|
MOVW $1002, R1
|
MOVW R0, (R1) // fail hard
|
|
TEXT runtime·raiseproc_trampoline(SB),NOSPLIT,$0
|
MOVW 0(R0), R8 // signal
|
BL libc_getpid(SB)
|
// arg 1 pid already in R0 from getpid
|
MOVW R8, R1 // arg 2 signal
|
BL libc_kill(SB)
|
RET
|
|
TEXT runtime·mmap_trampoline(SB),NOSPLIT,$0
|
MOVW R0, R8
|
MOVW 0(R8), R0 // arg 1 addr
|
MOVW 4(R8), R1 // arg 2 len
|
MOVW 8(R8), R2 // arg 3 prot
|
MOVW 12(R8), R3 // arg 4 flags
|
MOVW 16(R8), R4 // arg 5 fid
|
MOVW 20(R8), R5 // arg 6 offset
|
MOVW $0, R6 // off_t is uint64_t
|
// Only R0-R3 are used for arguments, the rest
|
// go on the stack.
|
MOVM.DB.W [R4-R6], (R13)
|
BL libc_mmap(SB)
|
ADD $12, R13
|
MOVW $0, R1
|
MOVW $-1, R2
|
CMP R0, R2
|
BNE ok
|
BL libc_error(SB)
|
MOVW (R0), R1
|
MOVW $0, R0
|
ok:
|
MOVW R0, 24(R8) // ret 1 addr
|
MOVW R1, 28(R8) // ret 2 err
|
RET
|
|
TEXT runtime·munmap_trampoline(SB),NOSPLIT,$0
|
MOVW 4(R0), R1 // arg 2 len
|
MOVW 0(R0), R0 // arg 1 addr
|
BL libc_munmap(SB)
|
MOVW $-1, R2
|
CMP R0, R2
|
BL.EQ notok<>(SB)
|
RET
|
|
TEXT runtime·madvise_trampoline(SB),NOSPLIT,$0
|
MOVW 4(R0), R1 // arg 2 len
|
MOVW 8(R0), R2 // arg 3 advice
|
MOVW 0(R0), R0 // arg 1 addr
|
BL libc_madvise(SB)
|
MOVW $-1, R2
|
CMP R0, R2
|
BL.EQ notok<>(SB)
|
RET
|
|
TEXT runtime·setitimer_trampoline(SB),NOSPLIT,$0
|
MOVW 4(R0), R1 // arg 2 new
|
MOVW 8(R0), R2 // arg 3 old
|
MOVW 0(R0), R0 // arg 1 which
|
BL libc_setitimer(SB)
|
RET
|
|
TEXT runtime·walltime_trampoline(SB),NOSPLIT,$0
|
// R0 already has *timeval
|
MOVW $0, R1 // no timezone needed
|
BL libc_gettimeofday(SB)
|
RET
|
|
GLOBL timebase<>(SB),NOPTR,$(machTimebaseInfo__size)
|
|
TEXT runtime·nanotime_trampoline(SB),NOSPLIT,$0
|
MOVW R0, R8
|
BL libc_mach_absolute_time(SB)
|
MOVW R0, 0(R8)
|
MOVW R1, 4(R8)
|
MOVW timebase<>+machTimebaseInfo_numer(SB), R6
|
MOVW $timebase<>+machTimebaseInfo_denom(SB), R5
|
MOVW (R5), R7
|
DMB MB_ISH // memory barrier for atomic read
|
CMP $0, R7
|
BNE initialized
|
|
SUB $(machTimebaseInfo__size+7)/8*8, R13
|
MOVW R13, R0
|
BL libc_mach_timebase_info(SB)
|
MOVW machTimebaseInfo_numer(R13), R6
|
MOVW machTimebaseInfo_denom(R13), R7
|
ADD $(machTimebaseInfo__size+7)/8*8, R13
|
|
MOVW R6, timebase<>+machTimebaseInfo_numer(SB)
|
MOVW $timebase<>+machTimebaseInfo_denom(SB), R5
|
DMB MB_ISH // memory barrier for atomic write
|
MOVW R7, (R5)
|
DMB MB_ISH
|
|
initialized:
|
MOVW R6, 8(R8)
|
MOVW R7, 12(R8)
|
RET
|
|
TEXT runtime·sigfwd(SB),NOSPLIT,$0-16
|
MOVW sig+4(FP), R0
|
MOVW info+8(FP), R1
|
MOVW ctx+12(FP), R2
|
MOVW fn+0(FP), R11
|
MOVW R13, R4
|
SUB $24, R13
|
BIC $0x7, R13 // alignment for ELF ABI
|
BL (R11)
|
MOVW R4, R13
|
RET
|
|
TEXT runtime·sigtramp(SB),NOSPLIT,$0
|
// Reserve space for callee-save registers and arguments.
|
SUB $36, R13
|
|
MOVW R4, 12(R13)
|
MOVW R5, 16(R13)
|
MOVW R6, 20(R13)
|
MOVW R7, 24(R13)
|
MOVW R8, 28(R13)
|
MOVW R11, 32(R13)
|
|
// Save arguments.
|
MOVW R0, 4(R13) // sig
|
MOVW R1, 8(R13) // info
|
MOVW R2, 12(R13) // ctx
|
|
// this might be called in external code context,
|
// where g is not set.
|
MOVB runtime·iscgo(SB), R0
|
CMP $0, R0
|
BL.NE runtime·load_g(SB)
|
|
MOVW R13, R6
|
CMP $0, g
|
BEQ nog
|
|
// iOS always use the main stack to run the signal handler.
|
// We need to switch to gsignal ourselves.
|
MOVW g_m(g), R11
|
MOVW m_gsignal(R11), R5
|
MOVW (g_stack+stack_hi)(R5), R6
|
|
nog:
|
// Restore arguments.
|
MOVW 4(R13), R0
|
MOVW 8(R13), R1
|
MOVW 12(R13), R2
|
|
// Reserve space for args and the stack pointer on the
|
// gsignal stack.
|
SUB $24, R6
|
// Save stack pointer.
|
MOVW R13, R4
|
MOVW R4, 16(R6)
|
// Switch to gsignal stack.
|
MOVW R6, R13
|
|
// Call sigtrampgo
|
MOVW R0, 4(R13)
|
MOVW R1, 8(R13)
|
MOVW R2, 12(R13)
|
BL runtime·sigtrampgo(SB)
|
|
// Switch to old stack.
|
MOVW 16(R13), R5
|
MOVW R5, R13
|
|
// Restore callee-save registers.
|
MOVW 12(R13), R4
|
MOVW 16(R13), R5
|
MOVW 20(R13), R6
|
MOVW 24(R13), R7
|
MOVW 28(R13), R8
|
MOVW 32(R13), R11
|
|
ADD $36, R13
|
|
RET
|
|
TEXT runtime·cgoSigtramp(SB),NOSPLIT,$0
|
JMP runtime·sigtramp(SB)
|
|
TEXT runtime·sigprocmask_trampoline(SB),NOSPLIT,$0
|
MOVW 4(R0), R1 // arg 2 new
|
MOVW 8(R0), R2 // arg 3 old
|
MOVW 0(R0), R0 // arg 1 how
|
BL libc_pthread_sigmask(SB)
|
CMP $0, R0
|
BL.NE notok<>(SB)
|
RET
|
|
TEXT runtime·sigaction_trampoline(SB),NOSPLIT,$0
|
MOVW 4(R0), R1 // arg 2 new
|
MOVW 8(R0), R2 // arg 3 old
|
MOVW 0(R0), R0 // arg 1 how
|
BL libc_sigaction(SB)
|
RET
|
|
TEXT runtime·usleep_trampoline(SB),NOSPLIT,$0
|
MOVW 0(R0), R0 // arg 1 usec
|
BL libc_usleep(SB)
|
RET
|
|
TEXT ·publicationBarrier(SB),NOSPLIT|NOFRAME,$0-0
|
B runtime·armPublicationBarrier(SB)
|
|
TEXT runtime·sysctl_trampoline(SB),NOSPLIT,$0
|
MOVW 4(R0), R1 // arg 2 miblen
|
MOVW 8(R0), R2 // arg 3 out
|
MOVW 12(R0), R3 // arg 4 size
|
MOVW 16(R0), R4 // arg 5 dst
|
MOVW 20(R0), R5 // arg 6 ndst
|
MOVW 0(R0), R0 // arg 1 mib
|
// Only R0-R3 are used for arguments, the rest
|
// go on the stack.
|
MOVM.DB.W [R4-R5], (R13)
|
BL libc_sysctl(SB)
|
ADD $(2*4), R13
|
RET
|
|
TEXT runtime·kqueue_trampoline(SB),NOSPLIT,$0
|
BL libc_kqueue(SB)
|
RET
|
|
// int32 runtime·kevent(int kq, Kevent *changelist, int nchanges, Kevent *eventlist, int events, Timespec *timeout)
|
TEXT runtime·kevent_trampoline(SB),NOSPLIT,$0
|
MOVW 4(R0), R1 // arg 2 keventss
|
MOVW 8(R0), R2 // arg 3 nch
|
MOVW 12(R0), R3 // arg 4 ev
|
MOVW 16(R0), R4 // arg 5 nev
|
MOVW 20(R0), R5 // arg 6 ts
|
MOVW 0(R0), R0 // arg 1 kq
|
// Only R0-R3 are used for arguments, the rest
|
// go on the stack.
|
MOVM.DB.W [R4-R5], (R13)
|
BL libc_kevent(SB)
|
ADD $(2*4), R13
|
MOVW $-1, R2
|
CMP R0, R2
|
BNE ok
|
BL libc_error(SB)
|
MOVW (R0), R0 // errno
|
RSB $0, R0, R0 // caller wants it as a negative error code
|
ok:
|
RET
|
|
TEXT runtime·fcntl_trampoline(SB),NOSPLIT,$0
|
MOVW 4(R0), R1 // arg 2 cmd
|
MOVW 8(R0), R2 // arg 3 arg
|
MOVW 0(R0), R0 // arg 1 fd
|
BL libc_fcntl(SB)
|
RET
|
|
// sigaltstack is not supported on iOS, so our sigtramp has
|
// to do the stack switch ourselves.
|
TEXT runtime·sigaltstack_trampoline(SB),NOSPLIT,$0
|
MOVW $43, R0
|
BL libc_exit(SB)
|
RET
|
|
// Thread related functions
|
// Note: On darwin/arm, the runtime always use runtime/cgo to
|
// create threads, so all thread related functions will just exit with a
|
// unique status.
|
|
TEXT runtime·mstart_stub(SB),NOSPLIT,$0
|
MOVW $44, R0
|
BL libc_exit(SB)
|
RET
|
|
TEXT runtime·pthread_attr_init_trampoline(SB),NOSPLIT,$0
|
MOVW $45, R0
|
BL libc_exit(SB)
|
RET
|
|
TEXT runtime·pthread_attr_setstacksize_trampoline(SB),NOSPLIT,$0
|
MOVW $46, R0
|
BL libc_exit(SB)
|
RET
|
|
TEXT runtime·pthread_attr_setdetachstate_trampoline(SB),NOSPLIT,$0
|
MOVW $47, R0
|
BL libc_exit(SB)
|
RET
|
|
TEXT runtime·pthread_create_trampoline(SB),NOSPLIT,$0
|
MOVW $48, R0
|
BL libc_exit(SB)
|
RET
|
|
TEXT runtime·raise_trampoline(SB),NOSPLIT,$0
|
MOVW 0(R0), R0 // arg 1 sig
|
BL libc_raise(SB)
|
RET
|
|
TEXT runtime·pthread_mutex_init_trampoline(SB),NOSPLIT,$0
|
MOVW 4(R0), R1 // arg 2 attr
|
MOVW 0(R0), R0 // arg 1 mutex
|
BL libc_pthread_mutex_init(SB)
|
RET
|
|
TEXT runtime·pthread_mutex_lock_trampoline(SB),NOSPLIT,$0
|
MOVW 0(R0), R0 // arg 1 mutex
|
BL libc_pthread_mutex_lock(SB)
|
RET
|
|
TEXT runtime·pthread_mutex_unlock_trampoline(SB),NOSPLIT,$0
|
MOVW 0(R0), R0 // arg 1 mutex
|
BL libc_pthread_mutex_unlock(SB)
|
RET
|
|
TEXT runtime·pthread_cond_init_trampoline(SB),NOSPLIT,$0
|
MOVW 4(R0), R1 // arg 2 attr
|
MOVW 0(R0), R0 // arg 1 cond
|
BL libc_pthread_cond_init(SB)
|
RET
|
|
TEXT runtime·pthread_cond_wait_trampoline(SB),NOSPLIT,$0
|
MOVW 4(R0), R1 // arg 2 mutex
|
MOVW 0(R0), R0 // arg 1 cond
|
BL libc_pthread_cond_wait(SB)
|
RET
|
|
TEXT runtime·pthread_cond_timedwait_relative_np_trampoline(SB),NOSPLIT,$0
|
MOVW 4(R0), R1 // arg 2 mutex
|
MOVW 8(R0), R2 // arg 3 timeout
|
MOVW 0(R0), R0 // arg 1 cond
|
BL libc_pthread_cond_timedwait_relative_np(SB)
|
RET
|
|
TEXT runtime·pthread_cond_signal_trampoline(SB),NOSPLIT,$0
|
MOVW 0(R0), R0 // arg 1 cond
|
BL libc_pthread_cond_signal(SB)
|
RET
|
|
// syscall calls a function in libc on behalf of the syscall package.
|
// syscall takes a pointer to a struct like:
|
// struct {
|
// fn uintptr
|
// a1 uintptr
|
// a2 uintptr
|
// a3 uintptr
|
// r1 uintptr
|
// r2 uintptr
|
// err uintptr
|
// }
|
// syscall must be called on the g0 stack with the
|
// C calling convention (use libcCall).
|
TEXT runtime·syscall(SB),NOSPLIT,$0
|
MOVW.W R0, -4(R13) // push structure pointer
|
MOVW 0(R0), R12 // fn
|
MOVW 8(R0), R1 // a2
|
MOVW 12(R0), R2 // a3
|
MOVW 4(R0), R0 // a1
|
BL (R12)
|
MOVW.P 4(R13), R2 // pop structure pointer
|
MOVW R0, 16(R2) // save r1
|
MOVW R1, 20(R2) // save r2
|
MOVW $-1, R3
|
CMP R0, R3
|
BNE ok
|
MOVW.W R2, -4(R13) // push structure pointer
|
BL libc_error(SB)
|
MOVW (R0), R0
|
MOVW.P 4(R13), R2 // pop structure pointer
|
MOVW R0, 24(R2) // save err
|
ok:
|
RET
|
|
// syscallPtr is like syscall except the libc function reports an
|
// error by returning NULL.
|
TEXT runtime·syscallPtr(SB),NOSPLIT,$0
|
MOVW.W R0, -4(R13) // push structure pointer
|
MOVW 0(R0), R12 // fn
|
MOVW 8(R0), R1 // a2
|
MOVW 12(R0), R2 // a3
|
MOVW 4(R0), R0 // a1
|
BL (R12)
|
MOVW.P 4(R13), R2 // pop structure pointer
|
MOVW R0, 16(R2) // save r1
|
MOVW R1, 20(R2) // save r2
|
MOVW $0, R3
|
CMP R0, R3
|
BNE ok
|
MOVW.W R2, -4(R13) // push structure pointer
|
BL libc_error(SB)
|
MOVW (R0), R0
|
MOVW.P 4(R13), R2 // pop structure pointer
|
MOVW R0, 24(R2) // save err
|
ok:
|
RET
|
|
// syscall6 calls a function in libc on behalf of the syscall package.
|
// syscall6 takes a pointer to a struct like:
|
// struct {
|
// fn uintptr
|
// a1 uintptr
|
// a2 uintptr
|
// a3 uintptr
|
// a4 uintptr
|
// a5 uintptr
|
// a6 uintptr
|
// r1 uintptr
|
// r2 uintptr
|
// err uintptr
|
// }
|
// syscall6 must be called on the g0 stack with the
|
// C calling convention (use libcCall).
|
TEXT runtime·syscall6(SB),NOSPLIT,$0
|
MOVW.W R0, -4(R13) // push structure pointer
|
MOVW 0(R0), R12 // fn
|
MOVW 24(R0), R1 // a6
|
MOVW.W R1, -4(R13)
|
MOVW 20(R0), R1 // a5
|
MOVW.W R1, -4(R13)
|
MOVW 8(R0), R1 // a2
|
MOVW 12(R0), R2 // a3
|
MOVW 16(R0), R3 // a4
|
MOVW 4(R0), R0 // a1
|
BL (R12)
|
ADD $8, R13
|
MOVW.P 4(R13), R2 // pop structure pointer
|
MOVW R0, 28(R2) // save r1
|
MOVW R1, 32(R2) // save r2
|
MOVW $-1, R3
|
CMP R0, R3
|
BNE ok
|
MOVW.W R2, -4(R13) // push structure pointer
|
BL libc_error(SB)
|
MOVW (R0), R0
|
MOVW.P 4(R13), R2 // pop structure pointer
|
MOVW R0, 36(R2) // save err
|
ok:
|
RET
|
|
// syscall6X calls a function in libc on behalf of the syscall package.
|
// syscall6X takes a pointer to a struct like:
|
// struct {
|
// fn uintptr
|
// a1 uintptr
|
// a2 uintptr
|
// a3 uintptr
|
// a4 uintptr
|
// a5 uintptr
|
// a6 uintptr
|
// r1 uintptr
|
// r2 uintptr
|
// err uintptr
|
// }
|
// syscall6X must be called on the g0 stack with the
|
// C calling convention (use libcCall).
|
TEXT runtime·syscall6X(SB),NOSPLIT,$0
|
MOVW.W R0, -4(R13) // push structure pointer
|
MOVW 0(R0), R12 // fn
|
MOVW 24(R0), R1 // a6
|
MOVW.W R1, -4(R13)
|
MOVW 20(R0), R1 // a5
|
MOVW.W R1, -4(R13)
|
MOVW 8(R0), R1 // a2
|
MOVW 12(R0), R2 // a3
|
MOVW 16(R0), R3 // a4
|
MOVW 4(R0), R0 // a1
|
BL (R12)
|
ADD $8, R13
|
MOVW.P 4(R13), R2 // pop structure pointer
|
MOVW R0, 28(R2) // save r1
|
MOVW R1, 32(R2) // save r2
|
MOVW $-1, R3
|
CMP R0, R3
|
BNE ok
|
CMP R1, R3
|
BNE ok
|
MOVW.W R2, -4(R13) // push structure pointer
|
BL libc_error(SB)
|
MOVW (R0), R0
|
MOVW.P 4(R13), R2 // pop structure pointer
|
MOVW R0, 36(R2) // save err
|
ok:
|
RET
|
|
// syscall9 calls a function in libc on behalf of the syscall package.
|
// syscall9 takes a pointer to a struct like:
|
// struct {
|
// fn uintptr
|
// a1 uintptr
|
// a2 uintptr
|
// a3 uintptr
|
// a4 uintptr
|
// a5 uintptr
|
// a6 uintptr
|
// a7 uintptr
|
// a8 uintptr
|
// a9 uintptr
|
// r1 uintptr
|
// r2 uintptr
|
// err uintptr
|
// }
|
// syscall9 must be called on the g0 stack with the
|
// C calling convention (use libcCall).
|
TEXT runtime·syscall9(SB),NOSPLIT,$0
|
MOVW.W R0, -4(R13) // push structure pointer
|
MOVW 0(R0), R12 // fn
|
MOVW 36(R0), R1 // a9
|
MOVW.W R1, -4(R13)
|
MOVW 32(R0), R1 // a8
|
MOVW.W R1, -4(R13)
|
MOVW 28(R0), R1 // a7
|
MOVW.W R1, -4(R13)
|
MOVW 24(R0), R1 // a6
|
MOVW.W R1, -4(R13)
|
MOVW 20(R0), R1 // a5
|
MOVW.W R1, -4(R13)
|
MOVW 8(R0), R1 // a2
|
MOVW 12(R0), R2 // a3
|
MOVW 16(R0), R3 // a4
|
MOVW 4(R0), R0 // a1
|
BL (R12)
|
ADD $20, R13
|
MOVW.P 4(R13), R2 // pop structure pointer
|
MOVW R0, 40(R2) // save r1
|
MOVW R1, 44(R2) // save r2
|
MOVW $-1, R3
|
CMP R0, R3
|
BNE ok
|
MOVW.W R2, -4(R13) // push structure pointer
|
BL libc_error(SB)
|
MOVW (R0), R0
|
MOVW.P 4(R13), R2 // pop structure pointer
|
MOVW R0, 48(R2) // save err
|
ok:
|
RET
|