From: Shenghou Ma Date: Tue, 12 Feb 2013 17:00:04 +0000 (+0800) Subject: runtime: NetBSD/ARM support X-Git-Tag: go1.1rc2~1068 X-Git-Url: http://www.git.cypherpunks.su/?a=commitdiff_plain;h=37aba1aa776c613d5a56fc4d001adbb4b4558a11;p=gostls13.git runtime: NetBSD/ARM support R=rsc, dave CC=golang-dev https://golang.org/cl/7289044 --- diff --git a/src/pkg/runtime/asm_arm.s b/src/pkg/runtime/asm_arm.s index 57df8c9c63..9af5a8a0df 100644 --- a/src/pkg/runtime/asm_arm.s +++ b/src/pkg/runtime/asm_arm.s @@ -72,8 +72,15 @@ TEXT runtime·breakpoint(SB),7,$0 WORD $0xe1200071 // BKPT 0x0001 RET +GLOBL runtime·goarm(SB), $4 TEXT runtime·asminit(SB),7,$0 - // No per-thread init. + // disable runfast (flush-to-zero) mode of vfp if runtime.goarm > 5 + MOVW runtime·goarm(SB), R11 + CMP $5, R11 + BLE 4(PC) + WORD $0xeef1ba10 // vmrs r11, fpscr + BIC $(1<<24), R11 + WORD $0xeee1ba10 // vmsr fpscr, r11 RET /* diff --git a/src/pkg/runtime/defs_netbsd_arm.h b/src/pkg/runtime/defs_netbsd_arm.h new file mode 100644 index 0000000000..f67475c763 --- /dev/null +++ b/src/pkg/runtime/defs_netbsd_arm.h @@ -0,0 +1,140 @@ +// Created by cgo -cdefs - DO NOT EDIT +// cgo -cdefs defs_netbsd.go + + +enum { + PROT_NONE = 0x0, + PROT_READ = 0x1, + PROT_WRITE = 0x2, + PROT_EXEC = 0x4, + + MAP_ANON = 0x1000, + MAP_PRIVATE = 0x2, + MAP_FIXED = 0x10, + + MADV_FREE = 0x6, + + SA_SIGINFO = 0x40, + SA_RESTART = 0x2, + SA_ONSTACK = 0x1, + + EINTR = 0x4, + + 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 = 0x1, + FPE_INTOVF = 0x2, + FPE_FLTDIV = 0x3, + FPE_FLTOVF = 0x4, + FPE_FLTUND = 0x5, + FPE_FLTRES = 0x6, + FPE_FLTINV = 0x7, + FPE_FLTSUB = 0x8, + + BUS_ADRALN = 0x1, + BUS_ADRERR = 0x2, + BUS_OBJERR = 0x3, + + SEGV_MAPERR = 0x1, + SEGV_ACCERR = 0x2, + + ITIMER_REAL = 0x0, + ITIMER_VIRTUAL = 0x1, + ITIMER_PROF = 0x2, +}; + +typedef struct Sigaltstack Sigaltstack; +typedef struct Sigset Sigset; +typedef struct Siginfo Siginfo; +typedef struct StackT StackT; +typedef struct Timespec Timespec; +typedef struct Timeval Timeval; +typedef struct Itimerval Itimerval; +typedef struct McontextT McontextT; +typedef struct UcontextT UcontextT; + +#pragma pack on + +struct Sigaltstack { + byte *ss_sp; + uint32 ss_size; + int32 ss_flags; +}; +struct Sigset { + uint32 __bits[4]; +}; +struct Siginfo { + int32 _signo; + int32 _code; + int32 _errno; + byte _reason[20]; +}; + +struct StackT { + byte *ss_sp; + uint32 ss_size; + int32 ss_flags; +}; + +struct Timespec { + int64 tv_sec; + int32 tv_nsec; +}; +struct Timeval { + int64 tv_sec; + int32 tv_usec; +}; +struct Itimerval { + Timeval it_interval; + Timeval it_value; +}; + +struct McontextT { + uint32 __gregs[17]; +#ifdef __ARM_EABI__ + byte __fpu[4+8*32+4]; +#else + byte __fpu[4+4*33+4]; +#endif + uint32 _mc_tlsbase; +}; +struct UcontextT { + uint32 uc_flags; + UcontextT *uc_link; + Sigset uc_sigmask; + StackT uc_stack; + McontextT uc_mcontext; + int32 __uc_pad[2]; +}; + +#pragma pack off diff --git a/src/pkg/runtime/os_netbsd.h b/src/pkg/runtime/os_netbsd.h index 794b294ff5..09e6832350 100644 --- a/src/pkg/runtime/os_netbsd.h +++ b/src/pkg/runtime/os_netbsd.h @@ -24,3 +24,7 @@ int32 runtime·sysctl(uint32*, uint32, byte*, uintptr*, byte*, uintptr); #define NSIG 33 #define SI_USER 0 + +// From NetBSD's +#define _UC_SIGMASK 0x01 +#define _UC_CPU 0x04 diff --git a/src/pkg/runtime/rt0_netbsd_arm.s b/src/pkg/runtime/rt0_netbsd_arm.s new file mode 100644 index 0000000000..8c1588f2e3 --- /dev/null +++ b/src/pkg/runtime/rt0_netbsd_arm.s @@ -0,0 +1,8 @@ +// Copyright 2013 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. + +// FreeBSD/NetBSD and Linux use the same linkage to main + +TEXT _rt0_arm_netbsd(SB),7,$-4 + B _rt0_arm(SB) diff --git a/src/pkg/runtime/signal_netbsd_arm.c b/src/pkg/runtime/signal_netbsd_arm.c new file mode 100644 index 0000000000..bc39a69b0e --- /dev/null +++ b/src/pkg/runtime/signal_netbsd_arm.c @@ -0,0 +1,197 @@ +// Copyright 2013 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 "runtime.h" +#include "defs_GOOS_GOARCH.h" +#include "signals_GOOS.h" +#include "os_GOOS.h" + +#define r0 __gregs[0] +#define r1 __gregs[1] +#define r2 __gregs[2] +#define r3 __gregs[3] +#define r4 __gregs[4] +#define r5 __gregs[5] +#define r6 __gregs[6] +#define r7 __gregs[7] +#define r8 __gregs[8] +#define r9 __gregs[9] +#define r10 __gregs[10] +#define r11 __gregs[11] +#define r12 __gregs[12] +#define r13 __gregs[13] +#define r14 __gregs[14] +#define r15 __gregs[15] +#define cpsr __gregs[16] + +void +runtime·dumpregs(McontextT *r) +{ + runtime·printf("r0 %x\n", r->r0); + runtime·printf("r1 %x\n", r->r1); + runtime·printf("r2 %x\n", r->r2); + runtime·printf("r3 %x\n", r->r3); + runtime·printf("r4 %x\n", r->r4); + runtime·printf("r5 %x\n", r->r5); + runtime·printf("r6 %x\n", r->r6); + runtime·printf("r7 %x\n", r->r7); + runtime·printf("r8 %x\n", r->r8); + runtime·printf("r9 %x\n", r->r9); + runtime·printf("r10 %x\n", r->r10); + runtime·printf("fp %x\n", r->r11); + runtime·printf("ip %x\n", r->r12); + runtime·printf("sp %x\n", r->r13); + runtime·printf("lr %x\n", r->r14); + runtime·printf("pc %x\n", r->r15); + runtime·printf("cpsr %x\n", r->cpsr); +} + +extern void runtime·lwp_tramp(void); +extern void runtime·sigtramp(void); + +typedef struct sigaction { + union { + void (*_sa_handler)(int32); + void (*_sa_sigaction)(int32, Siginfo*, void *); + } _sa_u; /* signal handler */ + uint32 sa_mask[4]; /* signal mask to apply */ + int32 sa_flags; /* see signal options below */ +} Sigaction; + +void +runtime·sighandler(int32 sig, Siginfo *info, void *context, G *gp) +{ + UcontextT *uc; + McontextT *r; + SigTab *t; + + uc = context; + r = &uc->uc_mcontext; + + if(sig == SIGPROF) { + runtime·sigprof((uint8*)r->r15, (uint8*)r->r13, (uint8*)r->r14, gp); + return; + } + + t = &runtime·sigtab[sig]; + if(info->_code != SI_USER && (t->flags & SigPanic)) { + if(gp == nil || gp == m->g0) + goto Throw; + // Make it look like a call to the signal func. + // We have to pass arguments out of band since + // augmenting the stack frame would break + // the unwinding code. + gp->sig = sig; + gp->sigcode0 = info->_code; + gp->sigcode1 = *(uintptr*)&info->_reason[0]; /* _addr */ + gp->sigpc = r->r15; + + // We arrange lr, and pc to pretend the panicking + // function calls sigpanic directly. + // Always save LR to stack so that panics in leaf + // functions are correctly handled. This smashes + // the stack frame but we're not going back there + // anyway. + r->r13 -= 4; + *(uint32 *)r->r13 = r->r14; + // Don't bother saving PC if it's zero, which is + // probably a call to a nil func: the old link register + // is more useful in the stack trace. + if(r->r15 != 0) + r->r14 = r->r15; + // In case we are panicking from external C code + r->r10 = (uintptr)gp; + r->r9 = (uintptr)m; + r->r15 = (uintptr)runtime·sigpanic; + return; + } + + if(info->_code == SI_USER || (t->flags & SigNotify)) + if(runtime·sigsend(sig)) + return; + if(t->flags & SigKill) + runtime·exit(2); + if(!(t->flags & SigThrow)) + return; + +Throw: + runtime·startpanic(); + + if(sig < 0 || sig >= NSIG) + runtime·printf("Signal %d\n", sig); + else + runtime·printf("%s\n", runtime·sigtab[sig].name); + + runtime·printf("PC=%x\n", r->r15); + if(m->lockedg != nil && m->ncgo > 0 && gp == m->g0) { + runtime·printf("signal arrived during cgo execution\n"); + gp = m->lockedg; + } + runtime·printf("\n"); + + if(runtime·gotraceback()){ + runtime·traceback((void*)r->r15, (void*)r->r13, (void*)r->r14, gp); + runtime·tracebackothers(gp); + runtime·printf("\n"); + runtime·dumpregs(r); + } + +// breakpoint(); + runtime·exit(2); +} + +void +runtime·signalstack(byte *p, int32 n) +{ + Sigaltstack st; + + st.ss_sp = (uint8*)p; + st.ss_size = n; + st.ss_flags = 0; + runtime·sigaltstack(&st, nil); +} + +void +runtime·setsig(int32 i, void (*fn)(int32, Siginfo*, void*, G*), bool restart) +{ + Sigaction sa; + + runtime·memclr((byte*)&sa, sizeof sa); + sa.sa_flags = SA_SIGINFO|SA_ONSTACK; + if(restart) + sa.sa_flags |= SA_RESTART; + sa.sa_mask[0] = ~0U; + sa.sa_mask[1] = ~0U; + sa.sa_mask[2] = ~0U; + sa.sa_mask[3] = ~0U; + if (fn == runtime·sighandler) + fn = (void*)runtime·sigtramp; + sa._sa_u._sa_sigaction = (void*)fn; + runtime·sigaction(i, &sa, nil); +} + +void +runtime·lwp_mcontext_init(McontextT *mc, void *stack, M *mp, G *gp, void (*fn)(void)) +{ + mc->r15 = (uint32)runtime·lwp_tramp; + mc->r13 = (uint32)stack; + mc->r0 = (uint32)mp; + mc->r1 = (uint32)gp; + mc->r2 = (uint32)fn; +} + +void +runtime·checkgoarm(void) +{ + // TODO(minux) +} + +#pragma textflag 7 +int64 +runtime·cputicks() { + // 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 runtime·nanotime(); +} diff --git a/src/pkg/runtime/sys_netbsd_arm.s b/src/pkg/runtime/sys_netbsd_arm.s new file mode 100644 index 0000000000..fe0c2b2e77 --- /dev/null +++ b/src/pkg/runtime/sys_netbsd_arm.s @@ -0,0 +1,293 @@ +// Copyright 2013 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, NetBSD +// /usr/src/sys/kern/syscalls.master for syscall numbers. +// + +#include "zasm_GOOS_GOARCH.h" + +// Exit the entire program (like C exit) +TEXT runtime·exit(SB),7,$-4 + MOVW 0(FP), R0 // arg 1 exit status + SWI $0xa00001 + MOVW.CS $0, R9 // crash on syscall failure + MOVW.CS R9, (R9) + RET + +TEXT runtime·exit1(SB),7,$-4 + SWI $0xa00136 // sys__lwp_exit + MOVW $1, R9 // crash + MOVW R9, (R9) + RET + +TEXT runtime·write(SB),7,$-4 + MOVW 0(FP), R0 // arg 1 - fd + MOVW 4(FP), R1 // arg 2 - buf + MOVW 8(FP), R2 // arg 3 - nbyte + SWI $0xa00004 // sys_write + RET + +// int32 lwp_create(void *context, uintptr flags, void *lwpid) +TEXT runtime·lwp_create(SB),7,$0 + MOVW context+0(FP), R0 + MOVW flags+4(FP), R1 + MOVW lwpid+8(FP), R2 + SWI $0xa00135 // sys__lwp_create + RET + +TEXT runtime·osyield(SB),7,$0 + SWI $0xa0015e // sys_sched_yield + RET + +TEXT runtime·lwp_park(SB),7,$0 + MOVW 0(FP), R0 // arg 1 - abstime + MOVW 4(FP), R1 // arg 2 - unpark + MOVW 8(FP), R2 // arg 3 - hint + MOVW 12(FP), R3 // arg 4 - unparkhint + SWI $0xa001b2 // sys__lwp_park + RET + +TEXT runtime·lwp_unpark(SB),7,$0 + MOVW 0(FP), R0 // arg 1 - lwp + MOVW 4(FP), R1 // arg 2 - hint + SWI $0xa00141 // sys__lwp_unpark + RET + +TEXT runtime·lwp_self(SB),7,$0 + SWI $0xa00137 // sys__lwp_self + RET + +TEXT runtime·lwp_tramp(SB),7,$0 + MOVW R0, R9 // m + MOVW R1, R10 // g + + BL runtime·emptyfunc(SB) // fault if stack check is wrong + BL (R2) + MOVW $2, R9 // crash (not reached) + MOVW R9, (R9) + RET + +TEXT runtime·usleep(SB),7,$16 + MOVW usec+0(FP), R0 + MOVW R0, R2 + MOVW $1000000, R1 + DIV R1, R0 + // 0(R13) is the saved LR, don't use it + MOVW R0, 4(R13) // tv_sec.low + MOVW $0, R0 + MOVW R0, 8(R13) // tv_sec.high + MOD R1, R2 + MOVW $1000, R1 + MUL R1, R2 + MOVW R2, 12(R13) // tv_nsec + + MOVW $4(R13), R0 // arg 1 - rqtp + MOVW $0, R1 // arg 2 - rmtp + SWI $0xa001ae // sys_nanosleep + RET + +TEXT runtime·raisesigpipe(SB),7,$16 + SWI $0xa00137 // sys__lwp_self, the returned R0 is arg 1 + MOVW $13, R1 // arg 2 - signo == SIGPIPE + SWI $0xa0013e // sys__lwp_kill + RET + +TEXT runtime·setitimer(SB),7,$-4 + MOVW 0(FP), R0 // arg 1 - which + MOVW 4(FP), R1 // arg 2 - itv + MOVW 8(FP), R2 // arg 3 - oitv + SWI $0xa001a9 // sys_setitimer + RET + +// func now() (sec int64, nsec int32) +TEXT time·now(SB), 7, $32 + MOVW $0, R0 // CLOCK_REALTIME + MOVW $8(R13), R1 + SWI $0xa001ab // clock_gettime + + MOVW 8(R13), R0 // sec.low + MOVW 12(R13), R1 // sec.high + MOVW 16(R13), R2 // nsec + + MOVW R0, 0(FP) + MOVW R1, 4(FP) + MOVW R2, 8(FP) + RET + +// int64 nanotime(void) so really +// void nanotime(int64 *nsec) +TEXT runtime·nanotime(SB), 7, $32 + MOVW $0, R0 // CLOCK_REALTIME + MOVW $8(R13), R1 + SWI $0xa001ab // clock_gettime + + MOVW 8(R13), R0 // sec.low + MOVW 12(R13), R4 // sec.high + MOVW 16(R13), R2 // nsec + + MOVW $1000000000, R3 + MULLU R0, R3, (R1, R0) + MUL R3, R4 + ADD.S R2, R0 + ADC R4, R1 + + MOVW 0(FP), R3 + MOVW R0, 0(R3) + MOVW R1, 4(R3) + RET + +TEXT runtime·getcontext(SB),7,$-4 + MOVW 0(FP), R0 // arg 1 - context + SWI $0xa00133 // sys_getcontext + MOVW.CS $0, R9 // crash on syscall failure + MOVW.CS R9, (R9) + RET + +TEXT runtime·sigprocmask(SB),7,$0 + MOVW 0(FP), R0 // arg 1 - how + MOVW 4(FP), R1 // arg 2 - set + MOVW 8(FP), R2 // arg 3 - oset + SWI $0xa00125 // sys_sigprocmask + MOVW.CS $0, R9 // crash on syscall failure + MOVW.CS R9, (R9) + RET + +TEXT runtime·sigreturn_tramp(SB),7,$-4 + // in runtime·sigtramp, we saved ucontext into m->tls[0], + // here we just load it and call sys_setcontext + MOVW m_tls(m), R0 + SWI $0xa00134 // sys_setcontext + // something failed, we have to exit + MOVW $0x4242, R0 // magic return number + SWI $0xa00001 // sys_exit + B -2(PC) // continue exit + +TEXT runtime·sigaction(SB),7,$4 + MOVW 0(FP), R0 // arg 1 - signum + MOVW 4(FP), R1 // arg 2 - nsa + MOVW 8(FP), R2 // arg 3 - osa + MOVW $runtime·sigreturn_tramp(SB), R3 // arg 4 - tramp + MOVW $2, R4 // arg 5 - vers + MOVW R4, 4(R13) + ADD $4, R13 // pass arg 5 on stack + SWI $0xa00154 // sys___sigaction_sigtramp + SUB $4, R13 + MOVW.CS $3, R9 // crash on syscall failure + MOVW.CS R9, (R9) + RET + +TEXT runtime·sigtramp(SB),7,$24 + // this might be called in external code context, + // where g and m are not set. + // first save R0, because cgo_load_gm will clobber it + // TODO(adonovan): call runtime·badsignal if m=0, like other platforms? + MOVW R0, 4(R13) // signum + MOVW cgo_load_gm(SB), R0 + CMP $0, R0 + BL.NE (R0) + + // save g + MOVW R10, R4 + MOVW R10, 20(R13) + + // g = m->signal + MOVW m_gsignal(R9), R10 + + // R0 is already saved + MOVW R1, 8(R13) // info + MOVW R2, 12(R13) // context + MOVW R4, 16(R13) // gp + // we also save the ucontext into m->tls[0] for easy + // signal return + MOVW R2, m_tls(m) + + BL runtime·sighandler(SB) + + // restore g + MOVW 20(R13), R10 + RET + +TEXT runtime·mmap(SB),7,$12 + MOVW 0(FP), R0 // arg 1 - addr + MOVW 4(FP), R1 // arg 2 - len + MOVW 8(FP), R2 // arg 3 - prot + MOVW 12(FP), R3 // arg 4 - flags + // arg 5 (fid) and arg6 (offset_lo, offset_hi) are passed on stack + // note the C runtime only passes the 32-bit offset_lo to us + MOVW 16(FP), R4 // arg 5 + MOVW R4, 4(R13) + MOVW 20(FP), R5 // arg 6 lower 32-bit + MOVW R5, 8(R13) + MOVW $0, R6 // higher 32-bit for arg 6 + MOVW R6, 12(R13) + ADD $4, R13 // pass arg 5 and arg 6 on stack + SWI $0xa000c5 // sys_mmap + SUB $4, R13 + RET + +TEXT runtime·munmap(SB),7,$0 + MOVW 0(FP), R0 // arg 1 - addr + MOVW 4(FP), R1 // arg 2 - len + SWI $0xa00049 // sys_munmap + MOVW.CS $0, R9 // crash on syscall failure + MOVW.CS R9, (R9) + RET + +TEXT runtime·madvise(SB),7,$0 + MOVW 0(FP), R0 // arg 1 - addr + MOVW 4(FP), R1 // arg 2 - len + MOVW 8(FP), R2 // arg 3 - behav + SWI $0xa0004b // sys_madvise + // ignore failure - maybe pages are locked + RET + +TEXT runtime·sigaltstack(SB),7,$-4 + MOVW 0(FP), R0 // arg 1 - nss + MOVW 4(FP), R1 // arg 2 - oss + SWI $0xa00119 // sys___sigaltstack14 + MOVW.CS $0, R9 // crash on syscall failure + MOVW.CS R9, (R9) + RET + +TEXT runtime·sysctl(SB),7,$8 + MOVW 0(FP), R0 // arg 1 - name + MOVW 4(FP), R1 // arg 2 - namelen + MOVW 8(FP), R2 // arg 3 - oldp + MOVW 12(FP), R3 // arg 4 - oldlenp + MOVW 16(FP), R4 // arg 5 - newp + MOVW R4, 4(R13) + MOVW 20(FP), R4 // arg 6 - newlen + MOVW R4, 8(R13) + ADD $4, R13 // pass arg 5 and 6 on stack + SWI $0xa000ca // sys___sysctl + SUB $4, R13 + RET + +TEXT runtime·cacheflush(SB),7,$8 + MOVW $1, R0 // drain_writebuf + SWI $0xa000a5 // sysarch + MOVW $0, R0 // icacheflush + MOVW 0(FP), R1 // start + MOVW R1, 4(R13) + MOVW 4(FP), R2 // end + SUB R1, R2 // R2 = length + MOVW R2, 8(R13) + MOVW $4(R13), R1 + SWI $0xa000a5 // sysarch + RET + +TEXT runtime·casp(SB),7,$0 + B runtime·cas(SB) + +// TODO(minux): this is only valid for ARMv6+ +// bool armcas(int32 *val, int32 old, int32 new) +// Atomically: +// if(*val == old){ +// *val = new; +// return 1; +// }else +// return 0; +TEXT runtime·cas(SB),7,$0 + B runtime·armcas(SB) diff --git a/src/pkg/runtime/thread_netbsd.c b/src/pkg/runtime/thread_netbsd.c index 195dcfd2c2..4d174a537b 100644 --- a/src/pkg/runtime/thread_netbsd.c +++ b/src/pkg/runtime/thread_netbsd.c @@ -144,10 +144,6 @@ runtime·semawakeup(M *mp) runtime·atomicstore(&mp->waitsemalock, 0); } -// From NetBSD's -#define _UC_SIGMASK 0x01 -#define _UC_CPU 0x04 - void runtime·newosproc(M *mp, G *gp, void *stk, void (*fn)(void)) {