From: Shenghou Ma Date: Fri, 26 Dec 2014 06:07:10 +0000 (-0500) Subject: runtime: darwin/arm support X-Git-Tag: go1.5beta1~2112 X-Git-Url: http://www.git.cypherpunks.su/?a=commitdiff_plain;h=56e8f8e8224a718ae005321b65986e72a695e7f2;p=gostls13.git runtime: darwin/arm support Change-Id: I63110daad2d62ae72ab1f33a40464d76e6205627 Reviewed-on: https://go-review.googlesource.com/2121 Reviewed-by: David Crawshaw --- diff --git a/src/runtime/defs_darwin_arm.go b/src/runtime/defs_darwin_arm.go new file mode 100644 index 0000000000..92bab509fb --- /dev/null +++ b/src/runtime/defs_darwin_arm.go @@ -0,0 +1,245 @@ +// Note: cgo can't handle some Darwin/ARM structures, so this file can't +// be auto generated by cgo yet. +// Created based on output of `cgo -cdefs defs_darwin.go` and Darwin/ARM +// specific header (mainly mcontext and ucontext related stuff) + +package runtime + +import "unsafe" + +const ( + _EINTR = 0x4 + _EFAULT = 0xe + + _PROT_NONE = 0x0 + _PROT_READ = 0x1 + _PROT_WRITE = 0x2 + _PROT_EXEC = 0x4 + + _MAP_ANON = 0x1000 + _MAP_PRIVATE = 0x2 + _MAP_FIXED = 0x10 + + _MADV_DONTNEED = 0x4 + _MADV_FREE = 0x5 + + _MACH_MSG_TYPE_MOVE_RECEIVE = 0x10 + _MACH_MSG_TYPE_MOVE_SEND = 0x11 + _MACH_MSG_TYPE_MOVE_SEND_ONCE = 0x12 + _MACH_MSG_TYPE_COPY_SEND = 0x13 + _MACH_MSG_TYPE_MAKE_SEND = 0x14 + _MACH_MSG_TYPE_MAKE_SEND_ONCE = 0x15 + _MACH_MSG_TYPE_COPY_RECEIVE = 0x16 + + _MACH_MSG_PORT_DESCRIPTOR = 0x0 + _MACH_MSG_OOL_DESCRIPTOR = 0x1 + _MACH_MSG_OOL_PORTS_DESCRIPTOR = 0x2 + _MACH_MSG_OOL_VOLATILE_DESCRIPTOR = 0x3 + + _MACH_MSGH_BITS_COMPLEX = 0x80000000 + + _MACH_SEND_MSG = 0x1 + _MACH_RCV_MSG = 0x2 + _MACH_RCV_LARGE = 0x4 + + _MACH_SEND_TIMEOUT = 0x10 + _MACH_SEND_INTERRUPT = 0x40 + _MACH_SEND_ALWAYS = 0x10000 + _MACH_SEND_TRAILER = 0x20000 + _MACH_RCV_TIMEOUT = 0x100 + _MACH_RCV_NOTIFY = 0x200 + _MACH_RCV_INTERRUPT = 0x400 + _MACH_RCV_OVERWRITE = 0x1000 + + _NDR_PROTOCOL_2_0 = 0x0 + _NDR_INT_BIG_ENDIAN = 0x0 + _NDR_INT_LITTLE_ENDIAN = 0x1 + _NDR_FLOAT_IEEE = 0x0 + _NDR_CHAR_ASCII = 0x0 + + _SA_SIGINFO = 0x40 + _SA_RESTART = 0x2 + _SA_ONSTACK = 0x1 + _SA_USERTRAMP = 0x100 + _SA_64REGSET = 0x200 + + _SIGHUP = 0x1 + _SIGINT = 0x2 + _SIGQUIT = 0x3 + _SIGILL = 0x4 + _SIGTRAP = 0x5 + _SIGABRT = 0x6 + _SIGEMT = 0x7 + _SIGFPE = 0x8 + _SIGKILL = 0x9 + _SIGBUS = 0xa + _SIGSEGV = 0xb + _SIGSYS = 0xc + _SIGPIPE = 0xd + _SIGALRM = 0xe + _SIGTERM = 0xf + _SIGURG = 0x10 + _SIGSTOP = 0x11 + _SIGTSTP = 0x12 + _SIGCONT = 0x13 + _SIGCHLD = 0x14 + _SIGTTIN = 0x15 + _SIGTTOU = 0x16 + _SIGIO = 0x17 + _SIGXCPU = 0x18 + _SIGXFSZ = 0x19 + _SIGVTALRM = 0x1a + _SIGPROF = 0x1b + _SIGWINCH = 0x1c + _SIGINFO = 0x1d + _SIGUSR1 = 0x1e + _SIGUSR2 = 0x1f + + _FPE_INTDIV = 0x7 + _FPE_INTOVF = 0x8 + _FPE_FLTDIV = 0x1 + _FPE_FLTOVF = 0x2 + _FPE_FLTUND = 0x3 + _FPE_FLTRES = 0x4 + _FPE_FLTINV = 0x5 + _FPE_FLTSUB = 0x6 + + _BUS_ADRALN = 0x1 + _BUS_ADRERR = 0x2 + _BUS_OBJERR = 0x3 + + _SEGV_MAPERR = 0x1 + _SEGV_ACCERR = 0x2 + + _ITIMER_REAL = 0x0 + _ITIMER_VIRTUAL = 0x1 + _ITIMER_PROF = 0x2 + + _EV_ADD = 0x1 + _EV_DELETE = 0x2 + _EV_CLEAR = 0x20 + _EV_RECEIPT = 0x40 + _EV_ERROR = 0x4000 + _EVFILT_READ = -0x1 + _EVFILT_WRITE = -0x2 +) + +type machbody struct { + msgh_descriptor_count uint32 +} + +type machheader struct { + msgh_bits uint32 + msgh_size uint32 + msgh_remote_port uint32 + msgh_local_port uint32 + msgh_reserved uint32 + msgh_id int32 +} + +type machndr struct { + mig_vers uint8 + if_vers uint8 + reserved1 uint8 + mig_encoding uint8 + int_rep uint8 + char_rep uint8 + float_rep uint8 + reserved2 uint8 +} + +type machport struct { + name uint32 + pad1 uint32 + pad2 uint16 + disposition uint8 + _type uint8 +} + +type stackt struct { + ss_sp *byte + ss_size uintptr + ss_flags int32 +} + +type sigactiont struct { + __sigaction_u [4]byte + sa_tramp unsafe.Pointer + sa_mask uint32 + sa_flags int32 +} + +type siginfo struct { + si_signo int32 + si_errno int32 + si_code int32 + si_pid int32 + si_uid uint32 + si_status int32 + si_addr *byte + si_value [4]byte + si_band int32 + __pad [7]uint32 +} + +type timeval struct { + tv_sec int32 + tv_usec int32 +} + +func (tv *timeval) set_usec(x int32) { + tv.tv_usec = x +} + +type itimerval struct { + it_interval timeval + it_value timeval +} + +type timespec struct { + tv_sec int32 + tv_nsec int32 +} + +type floatstate32 struct { + r [32]uint32 + fpscr uint32 +} + +type regs32 struct { + r [13]uint32 // r0 to r12 + sp uint32 // r13 + lr uint32 // r14 + pc uint32 // r15 + cpsr uint32 +} + +type exceptionstate32 struct { + trapno uint32 // NOTE: on 386, the trapno field is split into trapno and cpu + err uint32 + faultvaddr uint32 +} + +type mcontext32 struct { + es exceptionstate32 + ss regs32 + fs floatstate32 +} + +type ucontext struct { + uc_onstack int32 + uc_sigmask uint32 + uc_stack stackt + uc_link *ucontext + uc_mcsize uint32 + uc_mcontext *mcontext32 +} + +type keventt struct { + ident uint32 + filter int16 + flags uint16 + fflags uint32 + data int32 + udata *byte +} diff --git a/src/runtime/os_darwin_arm.go b/src/runtime/os_darwin_arm.go new file mode 100644 index 0000000000..d3336c012a --- /dev/null +++ b/src/runtime/os_darwin_arm.go @@ -0,0 +1,17 @@ +// 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. + +package runtime + +func checkgoarm() { + return // TODO(minux) +} + +//go:nosplit +func cputicks() int64 { + // Currently cputicks() is used in blocking profiler and to seed runtime·fastrand1(). + // runtime·nanotime() is a poor approximation of CPU ticks that is enough for the profiler. + // TODO: need more entropy to better seed fastrand1. + return nanotime() +} diff --git a/src/runtime/rt0_darwin_arm.s b/src/runtime/rt0_darwin_arm.s new file mode 100644 index 0000000000..4d31e3a78a --- /dev/null +++ b/src/runtime/rt0_darwin_arm.s @@ -0,0 +1,18 @@ +// 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. + +#include "textflag.h" + +TEXT _rt0_arm_darwin(SB),7,$-4 + // prepare arguments for main (_rt0_go) + MOVW (R13), R0 // argc + MOVW $4(R13), R1 // argv + MOVW $main(SB), R4 + B (R4) + +TEXT main(SB),NOSPLIT,$-8 + // save argc and argv onto stack + MOVM.DB.W [R0-R1], (R13) + MOVW $runtime·rt0_go(SB), R4 + B (R4) diff --git a/src/runtime/signal_darwin_arm.go b/src/runtime/signal_darwin_arm.go new file mode 100644 index 0000000000..1441a655ef --- /dev/null +++ b/src/runtime/signal_darwin_arm.go @@ -0,0 +1,44 @@ +// 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. + +package runtime + +import "unsafe" + +type sigctxt struct { + info *siginfo + ctxt unsafe.Pointer +} + +func (c *sigctxt) regs() *regs32 { return &(*ucontext)(c.ctxt).uc_mcontext.ss } +func (c *sigctxt) r0() uint32 { return c.regs().r[0] } +func (c *sigctxt) r1() uint32 { return c.regs().r[1] } +func (c *sigctxt) r2() uint32 { return c.regs().r[2] } +func (c *sigctxt) r3() uint32 { return c.regs().r[3] } +func (c *sigctxt) r4() uint32 { return c.regs().r[4] } +func (c *sigctxt) r5() uint32 { return c.regs().r[5] } +func (c *sigctxt) r6() uint32 { return c.regs().r[6] } +func (c *sigctxt) r7() uint32 { return c.regs().r[7] } +func (c *sigctxt) r8() uint32 { return c.regs().r[8] } +func (c *sigctxt) r9() uint32 { return c.regs().r[9] } +func (c *sigctxt) r10() uint32 { return c.regs().r[10] } +func (c *sigctxt) fp() uint32 { return c.regs().r[11] } +func (c *sigctxt) ip() uint32 { return c.regs().r[12] } +func (c *sigctxt) sp() uint32 { return c.regs().sp } +func (c *sigctxt) lr() uint32 { return c.regs().lr } +func (c *sigctxt) pc() uint32 { return c.regs().pc } +func (c *sigctxt) cpsr() uint32 { return c.regs().cpsr } +func (c *sigctxt) fault() uint32 { return uint32(uintptr(unsafe.Pointer(c.info.si_addr))) } +func (c *sigctxt) sigcode() uint32 { return uint32(c.info.si_code) } +func (c *sigctxt) trap() uint32 { return 0 } +func (c *sigctxt) error() uint32 { return 0 } +func (c *sigctxt) oldmask() uint32 { return 0 } + +func (c *sigctxt) set_pc(x uint32) { c.regs().pc = x } +func (c *sigctxt) set_sp(x uint32) { c.regs().sp = x } +func (c *sigctxt) set_lr(x uint32) { c.regs().lr = x } +func (c *sigctxt) set_r10(x uint32) { c.regs().r[10] = x } + +func (c *sigctxt) set_sigcode(x uint32) { c.info.si_code = int32(x) } +func (c *sigctxt) set_sigaddr(x uint32) { c.info.si_addr = (*byte)(unsafe.Pointer(uintptr(x))) } diff --git a/src/runtime/stack.h b/src/runtime/stack.h index b790e70103..88c7e02f40 100644 --- a/src/runtime/stack.h +++ b/src/runtime/stack.h @@ -7,14 +7,22 @@ enum { #ifdef GOOS_windows -#define StackSystem (512*sizeof(uintptr)) -#else +#define STACKSYSTEM (512 * sizeof(uintptr)) +#endif // GOOS_windows #ifdef GOOS_plan9 -#define StackSystem (512) -#else - StackSystem = 0, -#endif // Plan 9 -#endif // Windows +#define STACKSYSTEM 512 +#endif // GOOS_plan9 +#ifdef GOOS_darwin +#ifdef GOARCH_arm +#define STACKSYSTEM 1024 +#endif // GOARCH_arm +#endif // GOOS_darwin + +#ifndef STACKSYSTEM +#define STACKSYSTEM 0 +#endif + + StackSystem = STACKSYSTEM, StackBig = 4096, StackGuard = 640 + StackSystem, diff --git a/src/runtime/stack2.go b/src/runtime/stack2.go index 8a78b1ad96..07a7d38f0c 100644 --- a/src/runtime/stack2.go +++ b/src/runtime/stack2.go @@ -57,9 +57,9 @@ functions to make sure that this limit cannot be violated. const ( // StackSystem is a number of additional bytes to add // to each stack below the usual guard area for OS-specific - // purposes like signal handling. Used on Windows and on - // Plan 9 because they do not use a separate stack. - _StackSystem = goos_windows*512*ptrSize + goos_plan9*512 + // purposes like signal handling. Used on Windows, Plan 9, + // and Darwin/ARM because they do not use a separate stack. + _StackSystem = goos_windows*512*ptrSize + goos_plan9*512 + goos_darwin*goarch_arm*1024 // The minimum size of stack used by Go code _StackMin = 2048 diff --git a/src/runtime/sys_darwin_arm.s b/src/runtime/sys_darwin_arm.s new file mode 100644 index 0000000000..e1b2b664b6 --- /dev/null +++ b/src/runtime/sys_darwin_arm.s @@ -0,0 +1,481 @@ +// 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 +// See http://fxr.watson.org/fxr/source/bsd/kern/syscalls.c?v=xnu-1228 +// or /usr/include/sys/syscall.h (on a Mac) for system call numbers. + +#include "go_asm.h" +#include "go_tls.h" +#include "textflag.h" + +// Copied from /usr/include/sys/syscall.h +#define SYS_exit 1 +#define SYS_read 3 +#define SYS_write 4 +#define SYS_open 5 +#define SYS_close 6 +#define SYS_mmap 197 +#define SYS_munmap 73 +#define SYS_madvise 75 +#define SYS_mincore 78 +#define SYS_gettimeofday 116 +#define SYS_kill 37 +#define SYS_getpid 20 +#define SYS___pthread_kill 328 +#define SYS_setitimer 83 +#define SYS___sysctl 202 +#define SYS_sigprocmask 48 +#define SYS_sigaction 46 +#define SYS_sigreturn 184 +#define SYS_select 93 +#define SYS_bsdthread_register 366 +#define SYS_bsdthread_create 360 +#define SYS_bsdthread_terminate 361 +#define SYS_kqueue 362 +#define SYS_kevent 363 +#define SYS_fcntl 92 + +TEXT notok<>(SB),NOSPLIT,$0 + MOVW $0, R8 + MOVW R8, (R8) + B 0(PC) + +TEXT runtime·open(SB),NOSPLIT,$0 + MOVW name+0(FP), R0 + MOVW mode+4(FP), R1 + MOVW perm+8(FP), R2 + MOVW $SYS_open, R12 + SWI $0x80 + MOVW R0, ret+12(FP) + RET + +TEXT runtime·close(SB),NOSPLIT,$0 + MOVW fd+0(FP), R0 + MOVW $SYS_close, R12 + SWI $0x80 + MOVW R0, ret+4(FP) + RET + +TEXT runtime·write(SB),NOSPLIT,$0 + MOVW fd+0(FP), R0 + MOVW p+4(FP), R1 + MOVW n+8(FP), R2 + MOVW $SYS_write, R12 + SWI $0x80 + MOVW R0, ret+12(FP) + RET + +TEXT runtime·read(SB),NOSPLIT,$0 + MOVW fd+0(FP), R0 + MOVW p+4(FP), R1 + MOVW n+8(FP), R2 + MOVW $SYS_read, R12 + SWI $0x80 + MOVW R0, ret+12(FP) + RET + +TEXT runtime·exit(SB),NOSPLIT,$-4 + MOVW 0(FP), R0 + MOVW $SYS_exit, R12 + SWI $0x80 + MOVW $1234, R0 + MOVW $1002, R1 + MOVW R0, (R1) // fail hard + +// Exit this OS thread (like pthread_exit, which eventually +// calls __bsdthread_terminate). +TEXT runtime·exit1(SB),NOSPLIT,$0 + MOVW $SYS_bsdthread_terminate, R12 + SWI $0x80 + MOVW $1234, R0 + MOVW $1003, R1 + MOVW R0, (R1) // fail hard + +TEXT runtime·raise(SB),NOSPLIT,$24 + MOVW $SYS_getpid, R12 + SWI $0x80 + // arg 1 pid already in R0 from getpid + MOVW sig+0(FP), R1 // arg 2 - signal + MOVW $1, R2 // arg 3 - posix + MOVW $SYS_kill, R12 + SWI $0x80 + RET + +TEXT runtime·mmap(SB),NOSPLIT,$0 + MOVW addr+0(FP), R0 + MOVW n+4(FP), R1 + MOVW prot+8(FP), R2 + MOVW flags+12(FP), R3 + MOVW fd+16(FP), R4 + MOVW off+20(FP), R5 + MOVW $0, R6 // off_t is uint64_t + MOVW $SYS_mmap, R12 + SWI $0x80 + MOVW R0, ret+24(FP) + RET + +TEXT runtime·munmap(SB),NOSPLIT,$0 + MOVW 0(FP), R0 + MOVW 4(FP), R1 + MOVW $SYS_munmap, R12 + SWI $0x80 + BL.CS notok<>(SB) + RET + +TEXT runtime·madvise(SB),NOSPLIT,$0 + MOVW 0(FP), R0 + MOVW 4(FP), R1 + MOVW 8(FP), R2 + MOVW $SYS_madvise, R12 + SWI $0x80 + BL.CS notok<>(SB) + RET + +TEXT runtime·setitimer(SB),NOSPLIT,$0 + MOVW 0(FP), R0 + MOVW 4(FP), R1 + MOVW 8(FP), R2 + MOVW $SYS_setitimer, R12 + SWI $0x80 + RET + +TEXT runtime·mincore(SB),NOSPLIT,$0 + MOVW 0(FP), R0 + MOVW 4(FP), R1 + MOVW 8(FP), R2 + MOVW $SYS_mincore, R12 + SWI $0x80 + RET + +TEXT time·now(SB), 7, $32 + MOVW $8(R13), R0 // timeval + MOVW $0, R1 // zone + MOVW $SYS_gettimeofday, R12 + SWI $0x80 // Note: R0 is tv_sec, R1 is tv_usec + + MOVW R1, R2 // usec + + MOVW R0, 0(FP) + MOVW $0, R1 + MOVW R1, 4(FP) + MOVW $1000, R3 + MUL R3, R2 + MOVW R2, 8(FP) + RET + +TEXT runtime·nanotime(SB),NOSPLIT,$32 + MOVW $8(R13), R0 // timeval + MOVW $0, R1 // zone + MOVW $SYS_gettimeofday, R12 + SWI $0x80 // Note: R0 is tv_sec, R1 is tv_usec + + MOVW R1, R2 + MOVW $1000000000, R3 + MULLU R0, R3, (R1, R0) + MOVW $1000, R3 + MOVW $0, R4 + MUL R3, R2 + ADD.S R2, R0 + ADC R4, R1 + + MOVW R0, 0(FP) + MOVW R1, 4(FP) + RET + +// Sigtramp's job is to call the actual signal handler. +// It is called with the following arguments on the stack: +// LR "return address" - ignored +// R0 actual handler +// R1 siginfo style - ignored +// R2 signal number +// R3 siginfo +// -4(FP) context, beware that 0(FP) is the saved LR +TEXT runtime·sigtramp(SB),NOSPLIT,$0 + // this might be called in external code context, + // where g is not set. + // first save R0, because runtime·load_g will clobber it + MOVM.DB.W [R0], (R13) + MOVB runtime·iscgo(SB), R0 + CMP $0, R0 + BL.NE runtime·load_g(SB) + + CMP $0, g + BNE cont + // fake function call stack frame for badsignal + // we only need to pass R2 (signal number), but + // badsignal will expect R2 at 4(R13), so we also + // push R1 onto stack. turns out we do need R1 + // to do sigreturn. + MOVM.DB.W [R1,R2], (R13) + MOVW $runtime·badsignal(SB), R11 + BL (R11) + MOVM.IA.W [R1], (R13) // saved infostype + ADD $(4+4), R13 // +4: also need to remove the pushed R0. + MOVW -4(FP), R0 // load ucontext + B ret + +cont: + // Restore R0 + MOVM.IA.W (R13), [R0] + + // NOTE: some Darwin/ARM kernels 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 + SUB $28, R6 + + // copy arguments for call to sighandler + MOVW R2, 4(R6) // signal num + MOVW R3, 8(R6) // signal info + MOVW g, 16(R6) // old_g + MOVW -4(FP), R4 + MOVW R4, 12(R6) // context + + // Backup ucontext and infostyle + MOVW R4, 20(R6) + MOVW R1, 24(R6) + + // switch stack and g + MOVW R6, R13 // sigtramp can not re-entrant, so no need to back up R13. + MOVW R5, g + + BL (R0) + + // call sigreturn + MOVW 20(R13), R0 // saved ucontext + MOVW 24(R13), R1 // saved infostyle +ret: + MOVW $SYS_sigreturn, R12 // sigreturn(ucontext, infostyle) + SWI $0x80 + + // if sigreturn fails, we can do nothing but exit + B runtime·exit(SB) + +TEXT runtime·sigprocmask(SB),NOSPLIT,$0 + MOVW 0(FP), R0 + MOVW 4(FP), R1 + MOVW 8(FP), R2 + MOVW $SYS_sigprocmask, R12 + SWI $0x80 + BL.CS notok<>(SB) + RET + +TEXT runtime·sigaction(SB),NOSPLIT,$0 + MOVW 0(FP), R0 + MOVW 4(FP), R1 + MOVW 8(FP), R2 + MOVW $SYS_sigaction, R12 + SWI $0x80 + RET + +TEXT runtime·usleep(SB),NOSPLIT,$12 + MOVW usec+0(FP), R0 + MOVW R0, R1 + MOVW $1000000, R2 + DIV R2, R0 + MOD R2, R1 + MOVW R0, -12(SP) + MOVW R1, -8(SP) + + // select(0, 0, 0, 0, &tv) + MOVW $0, R0 + MOVW $0, R1 + MOVW $0, R2 + MOVW $0, R3 + MOVW $-12(SP), R4 + MOVW $SYS_select, R12 + SWI $0x80 + RET + +TEXT runtime·cas(SB),NOSPLIT,$0 + B runtime·armcas(SB) + +TEXT runtime·casp1(SB),NOSPLIT,$0 + B runtime·cas(SB) + +TEXT runtime·sysctl(SB),NOSPLIT,$0 + MOVW 0(FP), R0 + MOVW 4(FP), R1 + MOVW 8(FP), R2 + MOVW 12(FP), R3 + MOVW 16(FP), R4 + MOVW 20(FP), R5 + MOVW $SYS___sysctl, R12 // syscall entry + SWI $0x80 + BCC sysctl_ret + RSB $0, R0, R0 + MOVW R0, ret+24(FP) + RET +sysctl_ret: + MOVW $0, R0 + MOVW R0, ret+24(FP) + RET + +// Thread related functions +// void bsdthread_create(void *stk, M *m, G *g, void (*fn)(void)) +TEXT runtime·bsdthread_create(SB),NOSPLIT,$0 + // Set up arguments to bsdthread_create system call. + // The ones in quotes pass through to the thread callback + // uninterpreted, so we can put whatever we want there. + MOVW fn+12(FP), R0 // "func" + MOVW mm+4(FP), R1 // "arg" + MOVW stk+0(FP), R2 // stack + MOVW gg+8(FP), R3 // "pthread" + MOVW $0x01000000, R4 // flags = PTHREAD_START_CUSTOM + MOVW $0, R5 // paranoia + MOVW $SYS_bsdthread_create, R12 + SWI $0x80 + BCC create_ret + RSB $0, R0, R0 + MOVW R0, ret+16(FP) + RET +create_ret: + MOVW $0, R0 + MOVW R0, ret+16(FP) + RET + +// The thread that bsdthread_create creates starts executing here, +// because we registered this function using bsdthread_register +// at startup. +// R0 = "pthread" +// R1 = mach thread port +// R2 = "func" (= fn) +// R3 = "arg" (= m) +// R4 = stack +// R5 = flags (= 0) +// XXX: how to deal with R4/SP? ref: Libc-594.9.1/arm/pthreads/thread_start.s +TEXT runtime·bsdthread_start(SB),NOSPLIT,$0 + MOVW R1, m_procid(R3) // thread port is m->procid + MOVW m_g0(R3), g + MOVW R3, g_m(g) + // ARM don't have runtime·stackcheck(SB) + // disable runfast mode of vfp + EOR R12, R12 + WORD $0xeee1ca10 // fmxr fpscr, ip + BL (R2) // fn + BL runtime·exit1(SB) + RET + +// int32 bsdthread_register(void) +// registers callbacks for threadstart (see bsdthread_create above +// and wqthread and pthsize (not used). returns 0 on success. +TEXT runtime·bsdthread_register(SB),NOSPLIT,$0 + MOVW $runtime·bsdthread_start(SB), R0 // threadstart + MOVW $0, R1 // wqthread, not used by us + MOVW $0, R2 // pthsize, not used by us + MOVW $0, R3 // dummy_value [sic] + MOVW $0, R4 // targetconc_ptr + MOVW $0, R5 // dispatchqueue_offset + MOVW $SYS_bsdthread_register, R12 // bsdthread_register + SWI $0x80 + MOVW R0, ret+0(FP) + RET + +// uint32 mach_msg_trap(void*, uint32, uint32, uint32, uint32, uint32, uint32) +TEXT runtime·mach_msg_trap(SB),NOSPLIT,$0 + MOVW 0(FP), R0 + MOVW 4(FP), R1 + MOVW 8(FP), R2 + MOVW 12(FP), R3 + MOVW 16(FP), R4 + MOVW 20(FP), R5 + MOVW 24(FP), R6 + MVN $30, R12 + SWI $0x80 + MOVW R0, 28(FP) + RET + +TEXT runtime·mach_task_self(SB),NOSPLIT,$0 + MVN $27, R12 // task_self_trap + SWI $0x80 + MOVW R0, 0(FP) + RET + +TEXT runtime·mach_thread_self(SB),NOSPLIT,$0 + MVN $26, R12 // thread_self_trap + SWI $0x80 + MOVW R0, 0(FP) + RET + +TEXT runtime·mach_reply_port(SB),NOSPLIT,$0 + MVN $25, R12 // mach_reply_port + SWI $0x80 + MOVW R0, 0(FP) + RET + +// Mach provides trap versions of the semaphore ops, +// instead of requiring the use of RPC. + +// uint32 mach_semaphore_wait(uint32) +TEXT runtime·mach_semaphore_wait(SB),NOSPLIT,$0 + MOVW 0(FP), R0 + MVN $35, R12 // semaphore_wait_trap + SWI $0x80 + MOVW R0, ret+4(FP) + RET + +// uint32 mach_semaphore_timedwait(uint32, uint32, uint32) +TEXT runtime·mach_semaphore_timedwait(SB),NOSPLIT,$0 + MOVW 0(FP), R0 + MOVW 4(FP), R1 + MOVW 8(FP), R2 + MVN $37, R12 // semaphore_timedwait_trap + SWI $0x80 + MOVW R0, ret+12(FP) + RET + +// uint32 mach_semaphore_signal(uint32) +TEXT runtime·mach_semaphore_signal(SB),NOSPLIT,$0 + MOVW 0(FP), R0 + MVN $32, R12 // semaphore_signal_trap + SWI $0x80 + MOVW R0, ret+4(FP) + RET + +// uint32 mach_semaphore_signal_all(uint32) +TEXT runtime·mach_semaphore_signal_all(SB),NOSPLIT,$0 + MOVW 0(FP), R0 + MVN $33, R12 // semaphore_signal_all_trap + SWI $0x80 + MOVW R0, ret+4(FP) + RET + +// int32 runtime·kqueue(void) +TEXT runtime·kqueue(SB),NOSPLIT,$0 + MOVW $SYS_kqueue, R12 + SWI $0x80 + RSB.CS $0, R0, R0 + MOVW R0, ret+0(FP) + RET + +// int32 runtime·kevent(int kq, Kevent *changelist, int nchanges, Kevent *eventlist, int events, Timespec *timeout) +TEXT runtime·kevent(SB),NOSPLIT,$0 + MOVW $SYS_kevent, R12 + MOVW kq+0(FP), R0 + MOVW changelist+4(FP), R1 + MOVW nchanges+8(FP), R2 + MOVW eventlist+12(FP), R3 + MOVW nevents+16(FP), R4 + MOVW timeout+20(FP), R5 + SWI $0x80 + RSB.CS $0, R0, R0 + MOVW R0, ret+24(FP) + RET + +// int32 runtime·closeonexec(int32 fd) +TEXT runtime·closeonexec(SB),NOSPLIT,$0 + MOVW $SYS_fcntl, R12 + MOVW 0(FP), R0 + MOVW $2, R1 // F_SETFD + MOVW $1, R2 // FD_CLOEXEC + SWI $0x80 + RET + +// sigaltstack on some darwin/arm version is buggy and will always +// run the signal handler on the main stack, so our sigtramp has +// to do the stack switch ourselves. +TEXT runtime·sigaltstack(SB),NOSPLIT,$0 + RET diff --git a/src/runtime/tls_arm.s b/src/runtime/tls_arm.s index 4b01d12c46..2dbab722b0 100644 --- a/src/runtime/tls_arm.s +++ b/src/runtime/tls_arm.s @@ -15,11 +15,14 @@ // Note: both functions will clobber R0 and R11 and // can be called from 5c ABI code. -// On android, runtime.tlsg is a normal variable. +// On android and darwin, runtime.tlsg is a normal variable. // TLS offset is computed in x_cgo_inittls. #ifdef GOOS_android #define TLSG_IS_VARIABLE #endif +#ifdef GOOS_darwin +#define TLSG_IS_VARIABLE +#endif // save_g saves the g register into pthread-provided // thread-local memory, so that we can call externally compiled @@ -37,6 +40,7 @@ TEXT runtime·save_g(SB),NOSPLIT,$-4 // a call to runtime.read_tls_fallback which jumps to __kuser_get_tls. // The replacement function saves LR in R11 over the call to read_tls_fallback. MRC 15, 0, R0, C13, C0, 3 // fetch TLS base pointer + BIC $3, R0 // Darwin/ARM might return unaligned pointer // $runtime.tlsg(SB) is a special linker symbol. // It is the offset from the TLS base pointer to our // thread-local storage for g. @@ -60,6 +64,7 @@ TEXT runtime·load_g(SB),NOSPLIT,$0 #endif // See save_g MRC 15, 0, R0, C13, C0, 3 // fetch TLS base pointer + BIC $3, R0 // Darwin/ARM might return unaligned pointer // $runtime.tlsg(SB) is a special linker symbol. // It is the offset from the TLS base pointer to our // thread-local storage for g.